]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2972: "%bd" tries to delete popup window buffers, which fails v8.2.2972
authorBram Moolenaar <Bram@vim.org>
Thu, 10 Jun 2021 19:07:48 +0000 (21:07 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 10 Jun 2021 19:07:48 +0000 (21:07 +0200)
Problem:    "%bd" tries to delete popup window buffers, which fails. (Ralf
            Schandl)
Solution:   Do not try to delete a popup window buffer. (closes #8349)

src/buffer.c
src/testdir/test_popupwin.vim
src/version.c
src/vim.h

index d8b7ed4f23764a2eaa35711d9bc6ddd63a0544bc..d038e3c922e9b208a84083dcf45ea25b1503c697 100644 (file)
@@ -1180,122 +1180,6 @@ handle_swap_exists(bufref_T *old_curbuf)
     swap_exists_action = SEA_NONE;
 }
 
-/*
- * do_bufdel() - delete or unload buffer(s)
- *
- * addr_count == 0: ":bdel" - delete current buffer
- * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
- *                 buffer "end_bnr", then any other arguments.
- * addr_count == 2: ":N,N bdel" - delete buffers in range
- *
- * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
- * DOBUF_DEL (":bdel")
- *
- * Returns error message or NULL
- */
-    char *
-do_bufdel(
-    int                command,
-    char_u     *arg,           // pointer to extra arguments
-    int                addr_count,
-    int                start_bnr,      // first buffer number in a range
-    int                end_bnr,        // buffer nr or last buffer nr in a range
-    int                forceit)
-{
-    int                do_current = 0; // delete current buffer?
-    int                deleted = 0;    // number of buffers deleted
-    char       *errormsg = NULL; // return value
-    int                bnr;            // buffer number
-    char_u     *p;
-
-    if (addr_count == 0)
-    {
-       (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
-    }
-    else
-    {
-       if (addr_count == 2)
-       {
-           if (*arg)           // both range and argument is not allowed
-               return ex_errmsg(e_trailing_arg, arg);
-           bnr = start_bnr;
-       }
-       else    // addr_count == 1
-           bnr = end_bnr;
-
-       for ( ;!got_int; ui_breakcheck())
-       {
-           /*
-            * delete the current buffer last, otherwise when the
-            * current buffer is deleted, the next buffer becomes
-            * the current one and will be loaded, which may then
-            * also be deleted, etc.
-            */
-           if (bnr == curbuf->b_fnum)
-               do_current = bnr;
-           else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
-                                                              forceit) == OK)
-               ++deleted;
-
-           /*
-            * find next buffer number to delete/unload
-            */
-           if (addr_count == 2)
-           {
-               if (++bnr > end_bnr)
-                   break;
-           }
-           else    // addr_count == 1
-           {
-               arg = skipwhite(arg);
-               if (*arg == NUL)
-                   break;
-               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;
-                   arg = p;
-               }
-               else
-                   bnr = getdigits(&arg);
-           }
-       }
-       if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
-                                         FORWARD, do_current, forceit) == OK)
-           ++deleted;
-
-       if (deleted == 0)
-       {
-           if (command == DOBUF_UNLOAD)
-               STRCPY(IObuff, _("E515: No buffers were unloaded"));
-           else if (command == DOBUF_DEL)
-               STRCPY(IObuff, _("E516: No buffers were deleted"));
-           else
-               STRCPY(IObuff, _("E517: No buffers were wiped out"));
-           errormsg = (char *)IObuff;
-       }
-       else if (deleted >= p_report)
-       {
-           if (command == DOBUF_UNLOAD)
-               smsg(NGETTEXT("%d buffer unloaded",
-                           "%d buffers unloaded", deleted), deleted);
-           else if (command == DOBUF_DEL)
-               smsg(NGETTEXT("%d buffer deleted",
-                           "%d buffers deleted", deleted), deleted);
-           else
-               smsg(NGETTEXT("%d buffer wiped out",
-                           "%d buffers wiped out", deleted), deleted);
-       }
-    }
-
-
-    return errormsg;
-}
-
 /*
  * Make the current buffer empty.
  * Used when it is wiped out and it's the last buffer.
@@ -1354,13 +1238,13 @@ empty_curbuf(
  *
  * Return FAIL or OK.
  */
-    int
-do_buffer(
+    static int
+do_buffer_ext(
     int                action,
     int                start,
     int                dir,            // FORWARD or BACKWARD
     int                count,          // buffer number or number of buffers
-    int                forceit)        // TRUE for :...!
+    int                flags)          // DOBUF_FORCEIT etc.
 {
     buf_T      *buf;
     buf_T      *bp;
@@ -1446,6 +1330,14 @@ do_buffer(
            emsg(_("E88: Cannot go before first buffer"));
        return FAIL;
     }
+#ifdef FEAT_PROP_POPUP
+    if ((flags & DOBUF_NOPOPUP) && bt_popup(buf)
+# ifdef FEAT_TERMINAL
+                               && !bt_terminal(buf)
+#endif
+       )
+       return OK;
+#endif
 
 #ifdef FEAT_GUI
     need_mouse_correct = TRUE;
@@ -1470,7 +1362,7 @@ do_buffer(
                                   && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
            return FAIL;
 
-       if (!forceit && bufIsChanged(buf))
+       if ((flags & DOBUF_FORCEIT) == 0 && bufIsChanged(buf))
        {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
            if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
@@ -1506,7 +1398,7 @@ do_buffer(
            if (bp->b_p_bl && bp != buf)
                break;
        if (bp == NULL && buf == curbuf)
-           return empty_curbuf(TRUE, forceit, action);
+           return empty_curbuf(TRUE, (flags & DOBUF_FORCEIT), action);
 
        /*
         * If the deleted buffer is the current one, close the current window
@@ -1633,7 +1525,7 @@ do_buffer(
     {
        // Autocommands must have wiped out all other buffers.  Only option
        // now is to make the current buffer empty.
-       return empty_curbuf(FALSE, forceit, action);
+       return empty_curbuf(FALSE, (flags & DOBUF_FORCEIT), action);
     }
 
     /*
@@ -1660,7 +1552,7 @@ do_buffer(
     /*
      * Check if the current buffer may be abandoned.
      */
-    if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
+    if (action == DOBUF_GOTO && !can_abandon(curbuf, (flags & DOBUF_FORCEIT)))
     {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
        if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
@@ -1695,6 +1587,134 @@ do_buffer(
     return OK;
 }
 
+    int
+do_buffer(
+    int                action,
+    int                start,
+    int                dir,            // FORWARD or BACKWARD
+    int                count,          // buffer number or number of buffers
+    int                forceit)        // TRUE when using !
+{
+    return do_buffer_ext(action, start, dir, count,
+                                                 forceit ? DOBUF_FORCEIT : 0);
+}
+
+/*
+ * do_bufdel() - delete or unload buffer(s)
+ *
+ * addr_count == 0: ":bdel" - delete current buffer
+ * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
+ *                 buffer "end_bnr", then any other arguments.
+ * addr_count == 2: ":N,N bdel" - delete buffers in range
+ *
+ * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
+ * DOBUF_DEL (":bdel")
+ *
+ * Returns error message or NULL
+ */
+    char *
+do_bufdel(
+    int                command,
+    char_u     *arg,           // pointer to extra arguments
+    int                addr_count,
+    int                start_bnr,      // first buffer number in a range
+    int                end_bnr,        // buffer nr or last buffer nr in a range
+    int                forceit)
+{
+    int                do_current = 0; // delete current buffer?
+    int                deleted = 0;    // number of buffers deleted
+    char       *errormsg = NULL; // return value
+    int                bnr;            // buffer number
+    char_u     *p;
+
+    if (addr_count == 0)
+    {
+       (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
+    }
+    else
+    {
+       if (addr_count == 2)
+       {
+           if (*arg)           // both range and argument is not allowed
+               return ex_errmsg(e_trailing_arg, arg);
+           bnr = start_bnr;
+       }
+       else    // addr_count == 1
+           bnr = end_bnr;
+
+       for ( ;!got_int; ui_breakcheck())
+       {
+           /*
+            * Delete the current buffer last, otherwise when the
+            * current buffer is deleted, the next buffer becomes
+            * the current one and will be loaded, which may then
+            * also be deleted, etc.
+            */
+           if (bnr == curbuf->b_fnum)
+               do_current = bnr;
+           else if (do_buffer_ext(command, DOBUF_FIRST, FORWARD, (int)bnr,
+                         DOBUF_NOPOPUP | (forceit ? DOBUF_FORCEIT : 0)) == OK)
+               ++deleted;
+
+           /*
+            * find next buffer number to delete/unload
+            */
+           if (addr_count == 2)
+           {
+               if (++bnr > end_bnr)
+                   break;
+           }
+           else    // addr_count == 1
+           {
+               arg = skipwhite(arg);
+               if (*arg == NUL)
+                   break;
+               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;
+                   arg = p;
+               }
+               else
+                   bnr = getdigits(&arg);
+           }
+       }
+       if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
+                                         FORWARD, do_current, forceit) == OK)
+           ++deleted;
+
+       if (deleted == 0)
+       {
+           if (command == DOBUF_UNLOAD)
+               STRCPY(IObuff, _("E515: No buffers were unloaded"));
+           else if (command == DOBUF_DEL)
+               STRCPY(IObuff, _("E516: No buffers were deleted"));
+           else
+               STRCPY(IObuff, _("E517: No buffers were wiped out"));
+           errormsg = (char *)IObuff;
+       }
+       else if (deleted >= p_report)
+       {
+           if (command == DOBUF_UNLOAD)
+               smsg(NGETTEXT("%d buffer unloaded",
+                           "%d buffers unloaded", deleted), deleted);
+           else if (command == DOBUF_DEL)
+               smsg(NGETTEXT("%d buffer deleted",
+                           "%d buffers deleted", deleted), deleted);
+           else
+               smsg(NGETTEXT("%d buffer wiped out",
+                           "%d buffers wiped out", deleted), deleted);
+       }
+    }
+
+
+    return errormsg;
+}
+
 /*
  * Set current buffer to "buf".  Executes autocommands and closes current
  * buffer.  "action" tells how to close the current buffer:
index 13957e57c4b91e37f1c175b7e870756d0e0c01d2..faadfe2777489ba46b0d6e178cec7607fde056ec 100644 (file)
@@ -3918,5 +3918,11 @@ func Test_popup_prop_not_visible()
   call delete('XtestPropNotVisble')
 endfunction
 
+func Test_bufdel_skips_popupwin_buffer()
+    let id = popup_create("Some text", {})
+    %bd
+    call popup_close(id)
+endfunc
+
 
 " vim: shiftwidth=2 sts=2
index fb6d550ea7a029add51148806597522033f5c494..af6c11c03a9bd80d9bbf7bde4710a4983445fed3 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2972,
 /**/
     2971,
 /**/
index 61afe9730962d9a111df38be49037d7e79826b87..e1e68f965024a0817cfa033ab48e24c7198640bb 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -994,6 +994,10 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #define DOBUF_LAST     2       // "count" buffer from last buffer
 #define DOBUF_MOD      3       // "count" mod. buffer from current buffer
 
+// Values for flags argument of do_buffer()
+#define DOBUF_FORCEIT  1       // :cmd!
+#define DOBUF_NOPOPUP  2       // skip popup window buffers
+
 // Values for sub_cmd and which_pat argument for search_regcomp()
 // Also used for which_pat argument for searchit()
 #define RE_SEARCH      0       // save/use pat in/from search_pattern