]> granicus.if.org Git - vim/commitdiff
patch 8.1.1908: every popup window consumes a buffer number v8.1.1908
authorBram Moolenaar <Bram@vim.org>
Wed, 21 Aug 2019 20:25:30 +0000 (22:25 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 21 Aug 2019 20:25:30 +0000 (22:25 +0200)
Problem:    Every popup window consumes a buffer number.
Solution:   Recycle buffers only used for popup windows.  Do not list popup
            window buffers.

src/buffer.c
src/ex_docmd.c
src/popupwin.c
src/proto/buffer.pro
src/testdir/test_popupwin.vim
src/version.c
src/vim.h
src/window.c

index a9aa30c3e3120bba9151227267815379d3cabd0a..257ae7d888c201a41bfec395c91318de7ff23579 100644 (file)
@@ -62,9 +62,21 @@ static char *msg_qflist = N_("[Quickfix List]");
 #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 UNUSED)
  * 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"));
index aad1bae66f8f18ee20b37a816fe0c8c084f687ae..2b2ef36bdd5302b337128b10473163766ec30aef 100644 (file)
@@ -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:
index 2bac5c8c99d064f79f5c3a526c29fdbc63a827e4..0b360df8946257e36a4ed36f54e9fe14c976caa0 100644 (file)
@@ -1550,8 +1550,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
     {
        // 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);
index 0378b15022a0c14318a133d5edf83403154ee5d7..052536e41af9c6946ce9044ce9e46789fef32842 100644 (file)
@@ -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);
index 358da6d1291eaa713df2f7d008d24cf44042be7f..f742035aa9edf0a0088e6f3e979a05ad9bb57468 100644 (file)
@@ -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
index 41d4d3de44d8ed76ce57502ee35069d72b690646..a6544cd6135ad140e1dc89fcfa378d0a435883ce 100644 (file)
@@ -761,6 +761,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1908,
 /**/
     1907,
 /**/
index 6d89f03ab32eb95ec63c6f43b5886db999962e8c..254d3efbe6dcae38ba5effeec4494113e4d7f134 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -922,13 +922,14 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #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 wchar_t *envstring);
 #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 */
index fabd196efb17f5147cf70bcbfa8f106f45d97ba6..8da5ed0c938da09659547ef8542927d9e6970e01 100644 (file)
@@ -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)