# HG changeset patch # User Bram Moolenaar # Date 1600875903 -7200 # Node ID 997bbc35c181ab5043127ac23840096463bb3843 # Parent 5dd250163338861e790bc3c4aeff875b7bfa6d42 patch 8.2.1732: stuck when win_execute() for a popup causes an error Commit: https://github.com/vim/vim/commit/6bf1b52ba2816dffdbd0d994320abfb1586bf666 Author: Bram Moolenaar Date: Wed Sep 23 17:41:26 2020 +0200 patch 8.2.1732: stuck when win_execute() for a popup causes an error Problem: Stuck when win_execute() for a popup causes an error. Solution: Disable the filter callback on error. (issue https://github.com/vim/vim/issues/6999) diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2250,7 +2250,13 @@ popup_close_and_callback(win_T *wp, typv // Just in case a check higher up is missing. if (wp == curwin && ERROR_IF_POPUP_WINDOW) + { + // To avoid getting stuck when win_execute() does something that causes + // an error, stop calling the filter callback. + free_callback(&wp->w_filter_cb); + return; + } CHECK_CURBUF; if (wp->w_close_cb.cb_name != NULL) @@ -3128,7 +3134,8 @@ find_next_popup(int lowest, int handled_ /* * Invoke the filter callback for window "wp" with typed character "c". * Uses the global "mod_mask" for modifiers. - * Returns the return value of the filter. + * Returns the return value of the filter or -1 for CTRL-C in the current + * window. * Careful: The filter may make "wp" invalid! */ static int @@ -3145,12 +3152,18 @@ invoke_popup_filter(win_T *wp, int c) if (c == Ctrl_C) { int save_got_int = got_int; + int was_curwin = wp == curwin; // Reset got_int to avoid the callback isn't called. got_int = FALSE; popup_close_with_retval(wp, -1); got_int |= save_got_int; - return 1; + + // If the popup is the current window it probably fails to close. Then + // do not consume the key. + if (was_curwin && wp == curwin) + return -1; + return TRUE; } argv[0].v_type = VAR_NUMBER; @@ -3238,7 +3251,8 @@ popup_do_filter(int c) popup_reset_handled(POPUP_HANDLED_2); state = get_real_state(); - while (!res && (wp = find_next_popup(FALSE, POPUP_HANDLED_2)) != NULL) + while (res == FALSE + && (wp = find_next_popup(FALSE, POPUP_HANDLED_2)) != NULL) if (wp->w_filter_cb.cb_name != NULL && (wp->w_filter_mode & state) != 0) res = invoke_popup_filter(wp, c); @@ -3254,7 +3268,9 @@ popup_do_filter(int c) } recursive = FALSE; KeyTyped = save_KeyTyped; - return res; + + // When interrupted return FALSE to avoid looping. + return res == -1 ? FALSE : res; } /* diff --git a/src/testdir/dumps/Test_popupwin_win_execute.dump b/src/testdir/dumps/Test_popupwin_win_execute.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_win_execute.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @31| +0#0000000&@8| +0#4040ff13&@32 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/term_util.vim b/src/testdir/term_util.vim --- a/src/testdir/term_util.vim +++ b/src/testdir/term_util.vim @@ -5,6 +5,8 @@ if exists('*CanRunVimInTerminal') finish endif +source shared.vim + " For most tests we need to be able to run terminal Vim with 256 colors. On " MS-Windows the console only has 16 colors and the GUI can't run in a " terminal. @@ -51,6 +53,7 @@ endfunc " "rows" - height of the terminal window (max. 20) " "cols" - width of the terminal window (max. 78) " "statusoff" - number of lines the status is offset from default +" "wait_for_ruler" - if zero then don't wait for ruler to show func RunVimInTerminal(arguments, options) " If Vim doesn't exit a swap file remains, causing other tests to fail. " Remove it here. diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1556,6 +1556,30 @@ func Test_popup_filter_normal_cmd() call delete('XtestPopupNormal') endfunc +" this tests that we don't get stuck with an error in "win_execute()" +func Test_popup_filter_win_execute() + CheckScreendump + + let lines =<< trim END + let g:winid = popup_create('some text', {'filter': 'invalidfilter'}) + call timer_start(0, {-> win_execute(g:winid, 'invalidCommand')}) + END + call writefile(lines, 'XtestPopupWinExecute') + let buf = RunVimInTerminal('-S XtestPopupWinExecute', #{rows: 10, wait_for_ruler: 0}) + + call WaitFor({-> term_getline(buf, 9) =~ 'Not an editor command: invalidCommand'}) + call term_sendkeys(buf, "\") + call WaitFor({-> term_getline(buf, 9) =~ 'Unknown function: invalidfilter'}) + call term_sendkeys(buf, "\") + call WaitFor({-> term_getline(buf, 9) =~ 'Not allowed in a popup window'}) + call term_sendkeys(buf, "\") + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_popupwin_win_execute', {}) + + call StopVimInTerminal(buf) + call delete('XtestPopupWinExecute') +endfunc + func ShowDialog(key, result) let s:cb_res = 999 let winid = popup_dialog('do you want to quit (Yes/no)?', #{ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1732, +/**/ 1731, /**/ 1730,