1
0
forked from aniani/vim

patch 8.2.0670: cannot change window when evaluating 'completefunc'

Problem:    Cannot change window when evaluating 'completefunc'.
Solution:   Make a difference between not changing text or buffers and also
            not changing window.
This commit is contained in:
Bram Moolenaar
2020-04-30 22:31:18 +02:00
parent 4e5534fab7
commit 6adb9ea0a6
18 changed files with 67 additions and 43 deletions

View File

@@ -282,7 +282,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED)
curbuf = save_curbuf; curbuf = save_curbuf;
if (use_sandbox) if (use_sandbox)
++sandbox; ++sandbox;
++textlock; ++textwinlock;
vim_free(result); vim_free(result);
result = eval_to_string(bexpr, NULL, TRUE); result = eval_to_string(bexpr, NULL, TRUE);
@@ -299,7 +299,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED)
if (use_sandbox) if (use_sandbox)
--sandbox; --sandbox;
--textlock; --textwinlock;
set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
if (result != NULL && result[0] != NUL) if (result != NULL && result[0] != NUL)

View File

@@ -382,7 +382,7 @@ invoke_listeners(buf_T *buf)
argv[4].v_type = VAR_LIST; argv[4].v_type = VAR_LIST;
argv[4].vval.v_list = buf->b_recorded_changes; argv[4].vval.v_list = buf->b_recorded_changes;
++textlock; ++textwinlock;
for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
{ {
@@ -390,7 +390,7 @@ invoke_listeners(buf_T *buf)
clear_tv(&rettv); clear_tv(&rettv);
} }
--textlock; --textwinlock;
list_unref(buf->b_recorded_changes); list_unref(buf->b_recorded_changes);
buf->b_recorded_changes = NULL; buf->b_recorded_changes = NULL;

View File

@@ -176,9 +176,10 @@ edit(
// Don't allow changes in the buffer while editing the cmdline. The // Don't allow changes in the buffer while editing the cmdline. The
// caller of getcmdline() may get confused. // caller of getcmdline() may get confused.
// Don't allow recursive insert mode when busy with completion. // Don't allow recursive insert mode when busy with completion.
if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) if (textwinlock != 0 || textlock != 0
|| ins_compl_active() || compl_busy || pum_visible())
{ {
emsg(_(e_textlock)); emsg(_(e_textwinlock));
return FALSE; return FALSE;
} }
ins_compl_clear(); // clear stuff for CTRL-X mode ins_compl_clear(); // clear stuff for CTRL-X mode
@@ -5944,7 +5945,7 @@ do_insert_char_pre(int c)
} }
// Lock the text to avoid weird things from happening. // Lock the text to avoid weird things from happening.
++textlock; ++textwinlock;
set_vim_var_string(VV_CHAR, buf, -1); // set v:char set_vim_var_string(VV_CHAR, buf, -1); // set v:char
res = NULL; res = NULL;
@@ -5958,7 +5959,7 @@ do_insert_char_pre(int c)
} }
set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char
--textlock; --textwinlock;
// Restore the State, it may have been changed. // Restore the State, it may have been changed.
State = save_State; State = save_State;

View File

@@ -393,7 +393,7 @@ eval_to_string(
/* /*
* Call eval_to_string() without using current local variables and using * Call eval_to_string() without using current local variables and using
* textlock. When "use_sandbox" is TRUE use the sandbox. * textwinlock. When "use_sandbox" is TRUE use the sandbox.
*/ */
char_u * char_u *
eval_to_string_safe( eval_to_string_safe(
@@ -407,11 +407,11 @@ eval_to_string_safe(
save_funccal(&funccal_entry); save_funccal(&funccal_entry);
if (use_sandbox) if (use_sandbox)
++sandbox; ++sandbox;
++textlock; ++textwinlock;
retval = eval_to_string(arg, nextcmd, FALSE); retval = eval_to_string(arg, nextcmd, FALSE);
if (use_sandbox) if (use_sandbox)
--sandbox; --sandbox;
--textlock; --textwinlock;
restore_funccal(); restore_funccal();
return retval; return retval;
} }
@@ -576,7 +576,7 @@ eval_foldexpr(char_u *arg, int *cp)
++emsg_off; ++emsg_off;
if (use_sandbox) if (use_sandbox)
++sandbox; ++sandbox;
++textlock; ++textwinlock;
*cp = NUL; *cp = NUL;
if (eval0(arg, &tv, NULL, TRUE) == FAIL) if (eval0(arg, &tv, NULL, TRUE) == FAIL)
retval = 0; retval = 0;
@@ -601,7 +601,7 @@ eval_foldexpr(char_u *arg, int *cp)
--emsg_off; --emsg_off;
if (use_sandbox) if (use_sandbox)
--sandbox; --sandbox;
--textlock; --textwinlock;
return (int)retval; return (int)retval;
} }

View File

@@ -1318,12 +1318,12 @@ getcmdline_int(
c = get_expr_register(); c = get_expr_register();
if (c == '=') if (c == '=')
{ {
// Need to save and restore ccline. And set "textlock" // Need to save and restore ccline. And set "textwinlock"
// to avoid nasty things like going to another buffer when // to avoid nasty things like going to another buffer when
// evaluating an expression. // evaluating an expression.
++textlock; ++textwinlock;
p = get_expr_line(); p = get_expr_line();
--textlock; --textwinlock;
if (p != NULL) if (p != NULL)
{ {
@@ -2548,17 +2548,17 @@ check_opt_wim(void)
/* /*
* Return TRUE when the text must not be changed and we can't switch to * Return TRUE when the text must not be changed and we can't switch to
* another window or buffer. Used when editing the command line, evaluating * another window or buffer. TRUE when editing the command line, evaluating
* 'balloonexpr', etc. * 'balloonexpr', etc.
*/ */
int int
text_locked(void) text_and_win_locked(void)
{ {
#ifdef FEAT_CMDWIN #ifdef FEAT_CMDWIN
if (cmdwin_type != 0) if (cmdwin_type != 0)
return TRUE; return TRUE;
#endif #endif
return textlock != 0; return textwinlock != 0;
} }
/* /*
@@ -2578,9 +2578,21 @@ get_text_locked_msg(void)
if (cmdwin_type != 0) if (cmdwin_type != 0)
return e_cmdwin; return e_cmdwin;
#endif #endif
if (textwinlock != 0)
return e_textwinlock;
return e_textlock; return e_textlock;
} }
/*
* Return TRUE when the text must not be changed and/or we cannot switch to
* another window. TRUE while evaluating 'completefunc'.
*/
int
text_locked(void)
{
return text_and_win_locked() || textlock != 0;
}
/* /*
* Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
* and give an error message. * and give an error message.
@@ -3560,11 +3572,11 @@ cmdline_paste(
regname = may_get_selection(regname); regname = may_get_selection(regname);
#endif #endif
// Need to set "textlock" to avoid nasty things like going to another // Need to set "textwinlock" to avoid nasty things like going to another
// buffer when evaluating an expression. // buffer when evaluating an expression.
++textlock; ++textwinlock;
i = get_spec_reg(regname, &arg, &allocated, TRUE); i = get_spec_reg(regname, &arg, &allocated, TRUE);
--textlock; --textwinlock;
if (i) if (i)
{ {

View File

@@ -798,9 +798,15 @@ EXTERN int secure INIT(= FALSE);
// allowed, e.g. when sourcing .exrc or .vimrc // allowed, e.g. when sourcing .exrc or .vimrc
// in current directory // in current directory
EXTERN int textlock INIT(= 0); EXTERN int textwinlock INIT(= 0);
// non-zero when changing text and jumping to // non-zero when changing text and jumping to
// another window or buffer is not allowed // another window or editing another buffer is
// not allowed
EXTERN int textlock INIT(= 0);
// non-zero when changing text is not allowed,
// jumping to another window is allowed,
// editing another buffer is not allowed.
EXTERN int curbuf_lock INIT(= 0); EXTERN int curbuf_lock INIT(= 0);
// non-zero when the current buffer can't be // non-zero when the current buffer can't be
@@ -1681,7 +1687,8 @@ EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
#endif #endif
EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); EXTERN char e_secure[] INIT(= N_("E523: Not allowed here"));
EXTERN char e_textlock[] INIT(= N_("E565: Not allowed to change text here")); EXTERN char e_textlock[] INIT(= N_("E578: Not allowed to change text here"));
EXTERN char e_textwinlock[] INIT(= N_("E565: Not allowed to change text or change window"));
#if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \ #if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \
|| defined(UNIX) || defined(VMS) || defined(UNIX) || defined(VMS)
EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));

View File

@@ -1760,7 +1760,7 @@ get_expr_indent(void)
set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum);
if (use_sandbox) if (use_sandbox)
++sandbox; ++sandbox;
++textlock; ++textwinlock;
// Need to make a copy, the 'indentexpr' option could be changed while // Need to make a copy, the 'indentexpr' option could be changed while
// evaluating it. // evaluating it.
@@ -1773,7 +1773,7 @@ get_expr_indent(void)
if (use_sandbox) if (use_sandbox)
--sandbox; --sandbox;
--textlock; --textwinlock;
// Restore the cursor position so that 'indentexpr' doesn't need to. // Restore the cursor position so that 'indentexpr' doesn't need to.
// Pretend to be in Insert mode, allow cursor past end of line for "o" // Pretend to be in Insert mode, allow cursor past end of line for "o"

View File

@@ -989,9 +989,9 @@ trigger_complete_changed_event(int cur)
dict_set_items_ro(v_event); dict_set_items_ro(v_event);
recursive = TRUE; recursive = TRUE;
textlock++; textwinlock++;
apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf); apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf);
textlock--; textwinlock--;
recursive = FALSE; recursive = FALSE;
dict_free_contents(v_event); dict_free_contents(v_event);
@@ -2217,7 +2217,8 @@ expand_by_function(
pos = curwin->w_cursor; pos = curwin->w_cursor;
curwin_save = curwin; curwin_save = curwin;
curbuf_save = curbuf; curbuf_save = curbuf;
// Lock the text to avoid weird things from happening. // Lock the text to avoid weird things from happening. Do allow switching
// to another window temporarily.
++textlock; ++textlock;
// Call a function, which returns a list or dict. // Call a function, which returns a list or dict.
@@ -2442,8 +2443,8 @@ f_complete(typval_T *argvars, typval_T *rettv UNUSED)
return; return;
} }
// "textlock" is set when evaluating 'completefunc' but we can change text // "textlock" is set when evaluating 'completefunc' but we can change
// here. // text here.
textlock = 0; textlock = 0;
// Check for undo allowed here, because if something was already inserted // Check for undo allowed here, because if something was already inserted

View File

@@ -1570,14 +1570,14 @@ eval_map_expr(
// Forbid changing text or using ":normal" to avoid most of the bad side // Forbid changing text or using ":normal" to avoid most of the bad side
// effects. Also restore the cursor position. // effects. Also restore the cursor position.
++textlock; ++textwinlock;
++ex_normal_lock; ++ex_normal_lock;
set_vim_var_char(c); // set v:char to the typed character set_vim_var_char(c); // set v:char to the typed character
save_cursor = curwin->w_cursor; save_cursor = curwin->w_cursor;
save_msg_col = msg_col; save_msg_col = msg_col;
save_msg_row = msg_row; save_msg_row = msg_row;
p = eval_to_string(expr, NULL, FALSE); p = eval_to_string(expr, NULL, FALSE);
--textlock; --textwinlock;
--ex_normal_lock; --ex_normal_lock;
curwin->w_cursor = save_cursor; curwin->w_cursor = save_cursor;
msg_col = save_msg_col; msg_col = save_msg_col;

View File

@@ -3,9 +3,10 @@ void cmdline_init(void);
char_u *getcmdline(int firstc, long count, int indent, int do_concat); char_u *getcmdline(int firstc, long count, int indent, int do_concat);
char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr, int xp_context, char_u *xp_arg); char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr, int xp_context, char_u *xp_arg);
int check_opt_wim(void); int check_opt_wim(void);
int text_locked(void); int text_and_win_locked(void);
void text_locked_msg(void); void text_locked_msg(void);
char *get_text_locked_msg(void); char *get_text_locked_msg(void);
int text_locked(void);
int curbuf_locked(void); int curbuf_locked(void);
int allbuf_locked(void); int allbuf_locked(void);
char_u *getexline(int c, void *cookie, int indent, int do_concat); char_u *getexline(int c, void *cookie, int indent, int do_concat);

View File

@@ -932,9 +932,9 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
dict_set_items_ro(v_event); dict_set_items_ro(v_event);
recursive = TRUE; recursive = TRUE;
textlock++; textwinlock++;
apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf); apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
textlock--; textwinlock--;
recursive = FALSE; recursive = FALSE;
// Empty the dictionary, v:event is still valid // Empty the dictionary, v:event is still valid

View File

@@ -927,7 +927,7 @@ func Test_edit_completefunc_delete()
set completefunc=CompleteFunc set completefunc=CompleteFunc
call setline(1, ['', 'abcd', '']) call setline(1, ['', 'abcd', ''])
2d 2d
call assert_fails("normal 2G$a\<C-X>\<C-U>", 'E565:') call assert_fails("normal 2G$a\<C-X>\<C-U>", 'E578:')
bwipe! bwipe!
endfunc endfunc

View File

@@ -491,7 +491,7 @@ func Test_completefunc_error()
endfunc endfunc
set completefunc=CompleteFunc2 set completefunc=CompleteFunc2
call setline(1, ['', 'abcd', '']) call setline(1, ['', 'abcd', ''])
call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E565:') call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E578:')
set completefunc& set completefunc&
delfunc CompleteFunc delfunc CompleteFunc

View File

@@ -342,7 +342,7 @@ func Test_completefunc_opens_new_window_one()
setlocal completefunc=DummyCompleteOne setlocal completefunc=DummyCompleteOne
call setline(1, 'one') call setline(1, 'one')
/^one /^one
call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:') call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E578:')
call assert_equal(winid, win_getid()) call assert_equal(winid, win_getid())
call assert_equal('oneDEF', getline(1)) call assert_equal('oneDEF', getline(1))
q! q!

View File

@@ -331,7 +331,7 @@ undo_allowed(void)
// Don't allow changes in the buffer while editing the cmdline. The // Don't allow changes in the buffer while editing the cmdline. The
// caller of getcmdline() may get confused. // caller of getcmdline() may get confused.
if (textlock != 0) if (textwinlock != 0 || textlock != 0)
{ {
emsg(_(e_textlock)); emsg(_(e_textlock));
return FALSE; return FALSE;

View File

@@ -746,6 +746,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
670,
/**/ /**/
669, 669,
/**/ /**/

View File

@@ -4370,7 +4370,7 @@ win_goto(win_T *wp)
return; return;
} }
#endif #endif
if (text_locked()) if (text_and_win_locked())
{ {
beep_flush(); beep_flush();
text_locked_msg(); text_locked_msg();