# HG changeset patch # User Bram Moolenaar # Date 1566419404 -7200 # Node ID 7e6b7a4f13bc23ecde33e901f35505ab2189a36b # Parent cde49c54b3f04f0fbcb8109817a20e7055160631 patch 8.1.1908: every popup window consumes a buffer number Commit: https://github.com/vim/vim/commit/00b0d6d8dc2c04b3cb26ea3c3d58527939f01af6 Author: Bram Moolenaar Date: Wed Aug 21 22:25:30 2019 +0200 patch 8.1.1908: every popup window consumes a buffer number Problem: Every popup window consumes a buffer number. Solution: Recycle buffers only used for popup windows. Do not list popup window buffers. diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -62,9 +62,21 @@ static char *msg_qflist = N_("[Quickfix #endif static char *e_auabort = N_("E855: Autocommands caused command to abort"); -/* Number of times free_buffer() was called. */ +// 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,6 +482,7 @@ can_unload_buffer(buf_T *buf) * 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,8 +506,8 @@ close_buffer( 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); + 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,6 +699,14 @@ aucmd_abort: */ 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,7 +1205,8 @@ do_bufdel( if (!VIM_ISDIGIT(*arg)) { p = skiptowhite_esc(arg); - bnr = buflist_findpat(arg, p, command == DOBUF_WIPE, + bnr = buflist_findpat(arg, p, + command == DOBUF_WIPE || command == DOBUF_WIPE_REUSE, FALSE, FALSE); if (bnr < 0) /* failed */ break; @@ -1275,6 +1297,7 @@ empty_curbuf( * 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,7 +1317,7 @@ do_buffer( buf_T *buf; buf_T *bp; int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL - || action == DOBUF_WIPE); + || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); switch (start) { @@ -1395,7 +1418,8 @@ do_buffer( /* 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) + 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,13 +1655,14 @@ do_buffer( * 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 || action == DOBUF_WIPE_REUSE); #ifdef FEAT_SYN_HL long old_tw = curbuf->b_p_tw; #endif @@ -1861,8 +1886,6 @@ no_write_message_nobang(buf_T *buf UNUSE * 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. @@ -1890,6 +1913,7 @@ curbuf_reusable(void) * 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,7 +2089,16 @@ buflist_new( } lastbuf = buf; - buf->b_fnum = top_file_num++; + 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")); diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -4633,8 +4633,9 @@ invalid_range(exarg_T *eap) return _(e_invrange); break; case ADDR_BUFFERS: - if (eap->line1 < firstbuf->b_fnum - || eap->line2 > lastbuf->b_fnum) + // 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: diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1550,8 +1550,7 @@ popup_create(typval_T *argvars, typval_T { // 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); + buf = buflist_new(NULL, NULL, (linenr_T)0, BLN_NEW|BLN_DUMMY|BLN_REUSE); if (buf == NULL) return NULL; ml_open(buf); diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro --- a/src/proto/buffer.pro +++ b/src/proto/buffer.pro @@ -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); diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -2331,4 +2331,13 @@ func Test_popupmenu_info_align_menu() 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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1908, +/**/ 1907, /**/ 1906, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -922,13 +922,14 @@ extern int (*dyn_libintl_wputenv)(const #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 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,12 +978,13 @@ extern int (*dyn_libintl_wputenv)(const #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 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 */ diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -4970,7 +4970,7 @@ win_unlisted(win_T *wp) win_free_popup(win_T *win) { if (bt_popup(win->w_buffer)) - win_close_buffer(win, DOBUF_WIPE, FALSE); + win_close_buffer(win, DOBUF_WIPE_REUSE, FALSE); else close_buffer(win, win->w_buffer, 0, FALSE); # if defined(FEAT_TIMERS)