Patch 8.2.2972

3 views
Skip to first unread message

Bram Moolenaar

unread,
Jun 10, 2021, 3:08:25 PM6/10/21
to vim...@googlegroups.com

Patch 8.2.2972
Problem: "%bd" tries to delete popup window buffers, which fails. (Ralf
Schandl)
Solution: Do not try to delete a popup window buffer. (closes #8349)
Files: src/buffer.c, src/vim.h, src/testdir/test_popupwin.vim


*** ../vim-8.2.2971/src/buffer.c 2021-05-15 17:23:22.882858583 +0200
--- src/buffer.c 2021-06-10 21:06:17.219219954 +0200
***************
*** 1181,1302 ****
}

/*
- * 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.
*/
--- 1181,1186 ----
***************
*** 1354,1366 ****
*
* Return FAIL or OK.
*/
! int
! do_buffer(
int action,
int start,
int dir, // FORWARD or BACKWARD
int count, // buffer number or number of buffers
! int forceit) // TRUE for :...!
{
buf_T *buf;
buf_T *bp;
--- 1238,1250 ----
*
* Return FAIL or OK.
*/
! static int
! do_buffer_ext(
int action,
int start,
int dir, // FORWARD or BACKWARD
int count, // buffer number or number of buffers
! int flags) // DOBUF_FORCEIT etc.
{
buf_T *buf;
buf_T *bp;
***************
*** 1446,1451 ****
--- 1330,1343 ----
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,1476 ****
&& buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
return FAIL;

! if (!forceit && bufIsChanged(buf))
{
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
--- 1362,1368 ----
&& buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
return FAIL;

! 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,1512 ****
if (bp->b_p_bl && bp != buf)
break;
if (bp == NULL && buf == curbuf)
! return empty_curbuf(TRUE, forceit, action);

/*
* If the deleted buffer is the current one, close the current window
--- 1398,1404 ----
if (bp->b_p_bl && bp != buf)
break;
if (bp == NULL && buf == curbuf)
! return empty_curbuf(TRUE, (flags & DOBUF_FORCEIT), action);

/*
* If the deleted buffer is the current one, close the current window
***************
*** 1633,1639 ****
{
// Autocommands must have wiped out all other buffers. Only option
// now is to make the current buffer empty.
! return empty_curbuf(FALSE, forceit, action);
}

/*
--- 1525,1531 ----
{
// Autocommands must have wiped out all other buffers. Only option
// now is to make the current buffer empty.
! return empty_curbuf(FALSE, (flags & DOBUF_FORCEIT), action);
}

/*
***************
*** 1660,1666 ****
/*
* Check if the current buffer may be abandoned.
*/
! if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
{
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
--- 1552,1558 ----
/*
* Check if the current buffer may be abandoned.
*/
! 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,1700 ****
--- 1587,1720 ----
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:
*** ../vim-8.2.2971/src/vim.h 2021-06-08 20:13:27.359916592 +0200
--- src/vim.h 2021-06-10 20:56:16.236357694 +0200
***************
*** 994,999 ****
--- 994,1003 ----
#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
*** ../vim-8.2.2971/src/testdir/test_popupwin.vim 2021-05-28 14:11:59.725797039 +0200
--- src/testdir/test_popupwin.vim 2021-06-10 21:05:23.419322877 +0200
***************
*** 3918,3922 ****
--- 3918,3928 ----
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
*** ../vim-8.2.2971/src/version.c 2021-06-10 19:39:07.281697681 +0200
--- src/version.c 2021-06-10 21:06:56.383144943 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2972,
/**/

--
If all you have is a hammer, everything looks like a nail.
When your hammer is C++, everything begins to look like a thumb.
-- Steve Hoflich, comp.lang.c++

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages