Skip to content

Commit 6defa7b

Browse files
committed
patch 8.2.1636: get stuck if a popup filter causes an error
Problem: Get stuck if a popup filter causes an error. Solution: Check whether the function can be called and does not cause an error. (closes #6902)
1 parent 57ad94c commit 6defa7b

7 files changed

Lines changed: 99 additions & 3 deletions

File tree

src/popupwin.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,6 +3126,7 @@ invoke_popup_filter(win_T *wp, int c)
31263126
typval_T argv[3];
31273127
char_u buf[NUMBUFLEN];
31283128
linenr_T old_lnum = wp->w_cursor.lnum;
3129+
int prev_called_emsg = called_emsg;
31293130

31303131
// Emergency exit: CTRL-C closes the popup.
31313132
if (c == Ctrl_C)
@@ -3151,10 +3152,35 @@ invoke_popup_filter(win_T *wp, int c)
31513152
argv[2].v_type = VAR_UNKNOWN;
31523153

31533154
// NOTE: The callback might close the popup and make "wp" invalid.
3154-
call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv);
3155+
if (call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv) == FAIL)
3156+
{
3157+
// Cannot call the function, close the popup to avoid that the filter
3158+
// eats keys and the user can't get out.
3159+
popup_close_with_retval(wp, -1);
3160+
return 1;
3161+
}
3162+
31553163
if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum)
31563164
popup_highlight_curline(wp);
3157-
res = tv_get_bool(&rettv);
3165+
3166+
// If an error was given always return FALSE, so that keys are not
3167+
// consumed and the user can type something.
3168+
// If we get three errors in a row then close the popup. Decrement the
3169+
// error count by 1/10 if there are no errors, thus allowing up to 1 in
3170+
// 10 calls to cause an error.
3171+
if (win_valid_popup(wp) && called_emsg > prev_called_emsg)
3172+
{
3173+
wp->w_filter_errors += 10;
3174+
if (wp->w_filter_errors >= 30)
3175+
popup_close_with_retval(wp, -1);
3176+
res = FALSE;
3177+
}
3178+
else
3179+
{
3180+
if (win_valid_popup(wp) && wp->w_filter_errors > 0)
3181+
--wp->w_filter_errors;
3182+
res = tv_get_bool(&rettv);
3183+
}
31583184

31593185
vim_free(argv[1].vval.v_string);
31603186
clear_tv(&rettv);

src/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3338,6 +3338,7 @@ struct window_S
33383338
// with "cursorline" set
33393339
callback_T w_close_cb; // popup close callback
33403340
callback_T w_filter_cb; // popup filter callback
3341+
int w_filter_errors; // popup filter error count
33413342
int w_filter_mode; // mode when filter callback is used
33423343

33433344
win_T *w_popup_curwin; // close popup if curwin differs
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
> +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @27|o+0#0000001#ffd7ff255|n|e| |t|w|o| |t|h|r|e@1|.@2| +0#4040ff13#ffffff0@29
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|E+0#ffffff16#e000002|8|9|6|:| |A|r|g|u|m|e|n|t| |o|f| |f|i|l|t|e|r|(|)| |m|u|s|t| |b|e| |a| |L|i|s|t|,| |D|i|c|t|i|o|n|a|r|y| |o|r| |B|l|o|b| +0#0000000#ffffff0@13
10+
@57|0|,|0|-|1| @8|A|l@1|
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
> +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|E+0#ffffff16#e000002|8|9|6|:| |A|r|g|u|m|e|n|t| |o|f| |f|i|l|t|e|r|(|)| |m|u|s|t| |b|e| |a| |L|i|s|t|,| |D|i|c|t|i|o|n|a|r|y| |o|r| |B|l|o|b| +0#0000000#ffffff0@13
10+
@57|0|,|0|-|1| @8|A|l@1|
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
> +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|E+0#ffffff16#e000002|1@1|7|:| |U|n|k|n|o|w|n| |f|u|n|c|t|i|o|n|:| |N|o|S|u|c|h|F|u|n|c| +0#0000000#ffffff0@22|0|,|0|-|1| @8|A|l@1|

src/testdir/test_popupwin.vim

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3516,7 +3516,44 @@ func Test_popupwin_filter_close_ctrl_c()
35163516
call VerifyScreenDump(buf, 'Test_popupwin_ctrl_c', {})
35173517

35183518
call StopVimInTerminal(buf)
3519-
call delete('XtestPopupCorners')
3519+
call delete('XtestPopupCtrlC')
3520+
endfunc
3521+
3522+
func Test_popupwin_filter_close_wrong_name()
3523+
CheckScreendump
3524+
3525+
let lines =<< trim END
3526+
call popup_create('one two three...', {'filter': 'NoSuchFunc'})
3527+
END
3528+
call writefile(lines, 'XtestPopupWrongName')
3529+
3530+
let buf = RunVimInTerminal('-S XtestPopupWrongName', #{rows: 10})
3531+
3532+
call term_sendkeys(buf, "j")
3533+
call VerifyScreenDump(buf, 'Test_popupwin_wrong_name', {})
3534+
3535+
call StopVimInTerminal(buf)
3536+
call delete('XtestPopupWrongName')
3537+
endfunc
3538+
3539+
func Test_popupwin_filter_close_three_errors()
3540+
CheckScreendump
3541+
3542+
let lines =<< trim END
3543+
set cmdheight=2
3544+
call popup_create('one two three...', {'filter': 'filter'})
3545+
END
3546+
call writefile(lines, 'XtestPopupThreeErrors')
3547+
3548+
let buf = RunVimInTerminal('-S XtestPopupThreeErrors', #{rows: 10})
3549+
3550+
call term_sendkeys(buf, "jj")
3551+
call VerifyScreenDump(buf, 'Test_popupwin_three_errors_1', {})
3552+
call term_sendkeys(buf, "j")
3553+
call VerifyScreenDump(buf, 'Test_popupwin_three_errors_2', {})
3554+
3555+
call StopVimInTerminal(buf)
3556+
call delete('XtestPopupThreeErrors')
35203557
endfunc
35213558

35223559
func Test_popupwin_atcursor_far_right()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,8 @@ static char *(features[]) =
754754

755755
static int included_patches[] =
756756
{ /* Add new patch number below this line */
757+
/**/
758+
1636,
757759
/**/
758760
1635,
759761
/**/

0 commit comments

Comments
 (0)