Patch 8.1.1908
Problem: Every popup window consumes a buffer number.
Solution: Recycle buffers only used for popup windows. Do not list popup
window buffers.
Files: src/popupwin.c, src/window.c, src/vim.h, src/buffer.c,
src/proto/
buffer.pro, src/ex_docmd.c,
src/testdir/test_popupwin.vim
*** ../vim-8.1.1907/src/popupwin.c 2019-08-21 20:57:02.860627886 +0200
--- src/popupwin.c 2019-08-21 21:34:56.643728544 +0200
***************
*** 1550,1557 ****
{
// create a new buffer associated with the popup
new_buffer = TRUE;
! buf = buflist_new(NULL, NULL, (linenr_T)0,
! BLN_NEW|BLN_LISTED|BLN_DUMMY);
if (buf == NULL)
return NULL;
ml_open(buf);
--- 1550,1556 ----
{
// create a new buffer associated with the popup
new_buffer = TRUE;
! buf = buflist_new(NULL, NULL, (linenr_T)0, BLN_NEW|BLN_DUMMY|BLN_REUSE);
if (buf == NULL)
return NULL;
ml_open(buf);
*** ../vim-8.1.1907/src/window.c 2019-08-20 20:13:40.334821916 +0200
--- src/window.c 2019-08-21 21:34:27.183894258 +0200
***************
*** 4970,4976 ****
win_free_popup(win_T *win)
{
if (bt_popup(win->w_buffer))
! win_close_buffer(win, DOBUF_WIPE, FALSE);
else
close_buffer(win, win->w_buffer, 0, FALSE);
# if defined(FEAT_TIMERS)
--- 4970,4976 ----
win_free_popup(win_T *win)
{
if (bt_popup(win->w_buffer))
! win_close_buffer(win, DOBUF_WIPE_REUSE, FALSE);
else
close_buffer(win, win->w_buffer, 0, FALSE);
# if defined(FEAT_TIMERS)
*** ../vim-8.1.1907/src/vim.h 2019-08-21 17:29:08.034793106 +0200
--- src/vim.h 2019-08-21 21:35:31.659531624 +0200
***************
*** 922,934 ****
#define GETFILE_UNUSED 8
#define GETFILE_SUCCESS(x) ((x) <= 0)
! /* Values for buflist_new() flags */
! #define BLN_CURBUF 1 /* may re-use curbuf for new buffer */
! #define BLN_LISTED 2 /* put new buffer in buffer list */
! #define BLN_DUMMY 4 /* allocating dummy buffer */
! #define BLN_NEW 8 /* create a new buffer */
! #define BLN_NOOPT 16 /* don't copy options to existing buffer */
! #define BLN_DUMMY_OK 32 /* also find an existing dummy buffer */
/* Values for in_cinkeys() */
#define KEY_OPEN_FORW 0x101
--- 922,935 ----
#define GETFILE_UNUSED 8
#define GETFILE_SUCCESS(x) ((x) <= 0)
! // Values for buflist_new() flags
! #define BLN_CURBUF 1 // may re-use curbuf for new buffer
! #define BLN_LISTED 2 // put new buffer in buffer list
! #define BLN_DUMMY 4 // allocating dummy buffer
! #define BLN_NEW 8 // create a new buffer
! #define BLN_NOOPT 16 // don't copy options to existing buffer
! #define BLN_DUMMY_OK 32 // also find an existing dummy buffer
! #define BLN_REUSE 64 // may re-use number from buf_reuse
/* Values for in_cinkeys() */
#define KEY_OPEN_FORW 0x101
***************
*** 977,988 ****
#define FM_BLOCKSTOP 0x04 /* stop at start/end of block */
#define FM_SKIPCOMM 0x08 /* skip comments */
! /* Values for action argument for do_buffer() */
! #define DOBUF_GOTO 0 /* go to specified buffer */
! #define DOBUF_SPLIT 1 /* split window and go to specified buffer */
! #define DOBUF_UNLOAD 2 /* unload specified buffer(s) */
! #define DOBUF_DEL 3 /* delete specified buffer(s) from buflist */
! #define DOBUF_WIPE 4 /* delete specified buffer(s) really */
/* Values for start argument for do_buffer() */
#define DOBUF_CURRENT 0 /* "count" buffer from current buffer */
--- 978,990 ----
#define FM_BLOCKSTOP 0x04 /* stop at start/end of block */
#define FM_SKIPCOMM 0x08 /* skip comments */
! // Values for action argument for do_buffer() and close_buffer()
! #define DOBUF_GOTO 0 // go to specified buffer
! #define DOBUF_SPLIT 1 // split window and go to specified buffer
! #define DOBUF_UNLOAD 2 // unload specified buffer(s)
! #define DOBUF_DEL 3 // delete specified buffer(s) from buflist
! #define DOBUF_WIPE 4 // delete specified buffer(s) really
! #define DOBUF_WIPE_REUSE 5 // like DOBUF_WIPE an keep number for reuse
/* Values for start argument for do_buffer() */
#define DOBUF_CURRENT 0 /* "count" buffer from current buffer */
*** ../vim-8.1.1907/src/buffer.c 2019-08-21 14:36:29.383376114 +0200
--- src/buffer.c 2019-08-21 22:16:51.444339503 +0200
***************
*** 62,70 ****
#endif
static char *e_auabort = N_("E855: Autocommands caused command to abort");
! /* Number of times free_buffer() was called. */
static int buf_free_count = 0;
/*
* Read data from buffer for retrying.
*/
--- 62,82 ----
#endif
static char *e_auabort = N_("E855: Autocommands caused command to abort");
! // Number of times free_buffer() was called.
static int buf_free_count = 0;
+ static int top_file_num = 1; // highest file number
+ static garray_T buf_reuse = GA_EMPTY; // file numbers to recycle
+
+ /*
+ * Return the highest possible buffer number.
+ */
+ int
+ get_highest_fnum(void)
+ {
+ return top_file_num - 1;
+ }
+
/*
* Read data from buffer for retrying.
*/
***************
*** 470,475 ****
--- 482,488 ----
* DOBUF_UNLOAD buffer is unloaded
* DOBUF_DELETE buffer is unloaded and removed from buffer list
* DOBUF_WIPE buffer is unloaded and really deleted
+ * DOBUF_WIPE_REUSE idem, and add to buf_reuse list
* When doing all but the first one on the current buffer, the caller should
* get a new buffer very soon!
*
***************
*** 493,500 ****
win_T *the_curwin = curwin;
tabpage_T *the_curtab = curtab;
int unload_buf = (action != 0);
! int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
! int wipe_buf = (action == DOBUF_WIPE);
/*
* Force unloading or deleting when 'bufhidden' says so.
--- 506,513 ----
win_T *the_curwin = curwin;
tabpage_T *the_curtab = curtab;
int unload_buf = (action != 0);
! int wipe_buf = (action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE);
! int del_buf = (action == DOBUF_DEL || wipe_buf);
/*
* Force unloading or deleting when 'bufhidden' says so.
***************
*** 686,691 ****
--- 699,712 ----
*/
if (wipe_buf)
{
+ if (action == DOBUF_WIPE_REUSE)
+ {
+ // we can re-use this buffer number, store it
+ if (buf_reuse.ga_itemsize == 0)
+ ga_init2(&buf_reuse, sizeof(int), 50);
+ if (ga_grow(&buf_reuse, 1) == OK)
+ ((int *)buf_reuse.ga_data)[buf_reuse.ga_len++] = buf->b_fnum;
+ }
if (buf->b_sfname != buf->b_ffname)
VIM_CLEAR(buf->b_sfname);
else
***************
*** 1184,1190 ****
if (!VIM_ISDIGIT(*arg))
{
p = skiptowhite_esc(arg);
! bnr = buflist_findpat(arg, p, command == DOBUF_WIPE,
FALSE, FALSE);
if (bnr < 0) /* failed */
break;
--- 1205,1212 ----
if (!VIM_ISDIGIT(*arg))
{
p = skiptowhite_esc(arg);
! bnr = buflist_findpat(arg, p,
! command == DOBUF_WIPE || command == DOBUF_WIPE_REUSE,
FALSE, FALSE);
if (bnr < 0) /* failed */
break;
***************
*** 1275,1280 ****
--- 1297,1303 ----
* action == DOBUF_UNLOAD unload specified buffer(s)
* action == DOBUF_DEL delete specified buffer(s) from buffer list
* action == DOBUF_WIPE delete specified buffer(s) really
+ * action == DOBUF_WIPE_REUSE idem, and add number to "buf_reuse"
*
* start == DOBUF_CURRENT go to "count" buffer from current buffer
* start == DOBUF_FIRST go to "count" buffer from first buffer
***************
*** 1294,1300 ****
buf_T *buf;
buf_T *bp;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
! || action == DOBUF_WIPE);
switch (start)
{
--- 1317,1323 ----
buf_T *buf;
buf_T *bp;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
! || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE);
switch (start)
{
***************
*** 1395,1401 ****
/* When unloading or deleting a buffer that's already unloaded and
* unlisted: fail silently. */
! if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
return FAIL;
if (!forceit && bufIsChanged(buf))
--- 1418,1425 ----
/* When unloading or deleting a buffer that's already unloaded and
* unlisted: fail silently. */
! if (action != DOBUF_WIPE && action != DOBUF_WIPE_REUSE
! && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
return FAIL;
if (!forceit && bufIsChanged(buf))
***************
*** 1631,1643 ****
* DOBUF_UNLOAD unload it
* DOBUF_DEL delete it
* DOBUF_WIPE wipe it out
*/
void
set_curbuf(buf_T *buf, int action)
{
buf_T *prevbuf;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
! || action == DOBUF_WIPE);
#ifdef FEAT_SYN_HL
long old_tw = curbuf->b_p_tw;
#endif
--- 1655,1668 ----
* DOBUF_UNLOAD unload it
* DOBUF_DEL delete it
* DOBUF_WIPE wipe it out
+ * DOBUF_WIPE_REUSE wipe it out and add to "buf_reuse"
*/
void
set_curbuf(buf_T *buf, int action)
{
buf_T *prevbuf;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
! || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE);
#ifdef FEAT_SYN_HL
long old_tw = curbuf->b_p_tw;
#endif
***************
*** 1861,1868 ****
* functions for dealing with the buffer list
*/
- static int top_file_num = 1; /* highest file number */
-
/*
* Return TRUE if the current buffer is empty, unnamed, unmodified and used in
* only one window. That means it can be re-used.
--- 1886,1891 ----
***************
*** 1890,1895 ****
--- 1913,1919 ----
* If (flags & BLN_NEW) is TRUE, don't use an existing buffer.
* If (flags & BLN_NOOPT) is TRUE, don't copy options from the current buffer
* if the buffer already exists.
+ * If (flags & BLN_REUSE) is TRUE, may use buffer number from "buf_reuse".
* This is the ONLY way to create a new buffer.
*/
buf_T *
***************
*** 2065,2071 ****
}
lastbuf = buf;
! buf->b_fnum = top_file_num++;
if (top_file_num < 0) /* wrap around (may cause duplicates) */
{
emsg(_("W14: Warning: List of file names overflow"));
--- 2089,2104 ----
}
lastbuf = buf;
! if ((flags & BLN_REUSE) && buf_reuse.ga_len > 0)
! {
! // Recycle a previously used buffer number. Used for buffers which
! // are normally hidden, e.g. in a popup window. Avoids that the
! // buffer number grows rapidly.
! --buf_reuse.ga_len;
! buf->b_fnum = ((int *)buf_reuse.ga_data)[buf_reuse.ga_len];
! }
! else
! buf->b_fnum = top_file_num++;
if (top_file_num < 0) /* wrap around (may cause duplicates) */
{
emsg(_("W14: Warning: List of file names overflow"));
*** ../vim-8.1.1907/src/proto/
buffer.pro 2019-08-20 20:13:40.330821936 +0200
--- src/proto/
buffer.pro 2019-08-21 22:17:27.860172902 +0200
***************
*** 1,4 ****
--- 1,5 ----
/* buffer.c */
+ int get_highest_fnum(void);
void buffer_ensure_loaded(buf_T *buf);
int open_buffer(int read_stdin, exarg_T *eap, int flags);
void set_bufref(bufref_T *bufref, buf_T *buf);
*** ../vim-8.1.1907/src/ex_docmd.c 2019-08-21 18:30:58.882719474 +0200
--- src/ex_docmd.c 2019-08-21 22:20:27.471356851 +0200
***************
*** 4633,4640 ****
return _(e_invrange);
break;
case ADDR_BUFFERS:
! if (eap->line1 < firstbuf->b_fnum
! || eap->line2 > lastbuf->b_fnum)
return _(e_invrange);
break;
case ADDR_LOADED_BUFFERS:
--- 4633,4641 ----
return _(e_invrange);
break;
case ADDR_BUFFERS:
! // Only a boundary check, not whether the buffers actually
! // exist.
! if (eap->line1 < 1 || eap->line2 > get_highest_fnum())
return _(e_invrange);
break;
case ADDR_LOADED_BUFFERS:
*** ../vim-8.1.1907/src/testdir/test_popupwin.vim 2019-08-21 20:57:02.864627863 +0200
--- src/testdir/test_popupwin.vim 2019-08-21 22:03:02.559778871 +0200
***************
*** 2331,2334 ****
--- 2331,2343 ----
call delete('XtestInfoPopupNb')
endfunc
+ func Test_popupwin_recycle_bnr()
+ let winid = popup_notification('nothing wrong', {})
+ let bufnr = winbufnr(winid)
+ call popup_clear()
+ let winid = popup_notification('nothing wrong', {})
+ call assert_equal(bufnr, winbufnr(winid))
+ call popup_clear()
+ endfunc
+
" vim: shiftwidth=2 sts=2
*** ../vim-8.1.1907/src/version.c 2019-08-21 20:57:02.864627863 +0200
--- src/version.c 2019-08-21 22:24:24.450291926 +0200
***************
*** 763,764 ****
--- 763,766 ----
{ /* Add new patch number below this line */
+ /**/
+ 1908,
/**/
--
From "know your smileys":
:-| :-| Deja' vu!
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///