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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201908212025.x7LKPvFd021104%40masaka.moolenaar.net.

Raspunde prin e-mail lui