summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-09-08 22:06:44 +0200
committerBram Moolenaar <Bram@vim.org>2020-09-08 22:06:44 +0200
commit6defa7bf0a8935cc44f3dc12e9c87bbb40f190b7 (patch)
treeac60098e2e1b3730bd44818242b45959b5b90ebe
parent57ad94c5a9ee6f3626e1ec728519a8558a4346c8 (diff)
downloadvim-git-8.2.1636.tar.gz
patch 8.2.1636: get stuck if a popup filter causes an errorv8.2.1636
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)
-rw-r--r--src/popupwin.c30
-rw-r--r--src/structs.h1
-rw-r--r--src/testdir/dumps/Test_popupwin_three_errors_1.dump10
-rw-r--r--src/testdir/dumps/Test_popupwin_three_errors_2.dump10
-rw-r--r--src/testdir/dumps/Test_popupwin_wrong_name.dump10
-rw-r--r--src/testdir/test_popupwin.vim39
-rw-r--r--src/version.c2
7 files changed, 99 insertions, 3 deletions
diff --git a/src/popupwin.c b/src/popupwin.c
index 953e76cc7..23f8efc8e 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -3126,6 +3126,7 @@ invoke_popup_filter(win_T *wp, int c)
typval_T argv[3];
char_u buf[NUMBUFLEN];
linenr_T old_lnum = wp->w_cursor.lnum;
+ int prev_called_emsg = called_emsg;
// Emergency exit: CTRL-C closes the popup.
if (c == Ctrl_C)
@@ -3151,10 +3152,35 @@ invoke_popup_filter(win_T *wp, int c)
argv[2].v_type = VAR_UNKNOWN;
// NOTE: The callback might close the popup and make "wp" invalid.
- call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv);
+ if (call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv) == FAIL)
+ {
+ // Cannot call the function, close the popup to avoid that the filter
+ // eats keys and the user can't get out.
+ popup_close_with_retval(wp, -1);
+ return 1;
+ }
+
if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum)
popup_highlight_curline(wp);
- res = tv_get_bool(&rettv);
+
+ // If an error was given always return FALSE, so that keys are not
+ // consumed and the user can type something.
+ // If we get three errors in a row then close the popup. Decrement the
+ // error count by 1/10 if there are no errors, thus allowing up to 1 in
+ // 10 calls to cause an error.
+ if (win_valid_popup(wp) && called_emsg > prev_called_emsg)
+ {
+ wp->w_filter_errors += 10;
+ if (wp->w_filter_errors >= 30)
+ popup_close_with_retval(wp, -1);
+ res = FALSE;
+ }
+ else
+ {
+ if (win_valid_popup(wp) && wp->w_filter_errors > 0)
+ --wp->w_filter_errors;
+ res = tv_get_bool(&rettv);
+ }
vim_free(argv[1].vval.v_string);
clear_tv(&rettv);
diff --git a/src/structs.h b/src/structs.h
index 528c247b1..dba9be65d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3338,6 +3338,7 @@ struct window_S
// with "cursorline" set
callback_T w_close_cb; // popup close callback
callback_T w_filter_cb; // popup filter callback
+ int w_filter_errors; // popup filter error count
int w_filter_mode; // mode when filter callback is used
win_T *w_popup_curwin; // close popup if curwin differs
diff --git a/src/testdir/dumps/Test_popupwin_three_errors_1.dump b/src/testdir/dumps/Test_popupwin_three_errors_1.dump
new file mode 100644
index 000000000..2bf9a541e
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_three_errors_1.dump
@@ -0,0 +1,10 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @27|o+0#0000001#ffd7ff255|n|e| |t|w|o| |t|h|r|e@1|.@2| +0#4040ff13#ffffff0@29
+|~| @73
+|~| @73
+|~| @73
+|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
+@57|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_popupwin_three_errors_2.dump b/src/testdir/dumps/Test_popupwin_three_errors_2.dump
new file mode 100644
index 000000000..09550a226
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_three_errors_2.dump
@@ -0,0 +1,10 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|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
+@57|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_popupwin_wrong_name.dump b/src/testdir/dumps/Test_popupwin_wrong_name.dump
new file mode 100644
index 000000000..e63ced5a0
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_wrong_name.dump
@@ -0,0 +1,10 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|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|
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index a92dc2550..954086cae 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -3516,7 +3516,44 @@ func Test_popupwin_filter_close_ctrl_c()
call VerifyScreenDump(buf, 'Test_popupwin_ctrl_c', {})
call StopVimInTerminal(buf)
- call delete('XtestPopupCorners')
+ call delete('XtestPopupCtrlC')
+endfunc
+
+func Test_popupwin_filter_close_wrong_name()
+ CheckScreendump
+
+ let lines =<< trim END
+ call popup_create('one two three...', {'filter': 'NoSuchFunc'})
+ END
+ call writefile(lines, 'XtestPopupWrongName')
+
+ let buf = RunVimInTerminal('-S XtestPopupWrongName', #{rows: 10})
+
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_popupwin_wrong_name', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XtestPopupWrongName')
+endfunc
+
+func Test_popupwin_filter_close_three_errors()
+ CheckScreendump
+
+ let lines =<< trim END
+ set cmdheight=2
+ call popup_create('one two three...', {'filter': 'filter'})
+ END
+ call writefile(lines, 'XtestPopupThreeErrors')
+
+ let buf = RunVimInTerminal('-S XtestPopupThreeErrors', #{rows: 10})
+
+ call term_sendkeys(buf, "jj")
+ call VerifyScreenDump(buf, 'Test_popupwin_three_errors_1', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_popupwin_three_errors_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XtestPopupThreeErrors')
endfunc
func Test_popupwin_atcursor_far_right()
diff --git a/src/version.c b/src/version.c
index 2a2de13bb..874bd709c 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1636,
+/**/
1635,
/**/
1634,