To: vim_dev@googlegroups.com Subject: Patch 8.2.2972 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///