0
0
mirror of https://github.com/vim/vim.git synced 2025-08-31 20:53:42 -04:00

patch 8.2.0614: get ml_get error when deleting a line in 'completefunc'

Problem:    Get ml_get error when deleting a line in 'completefunc'. (Yegappan
            Lakshmanan)
Solution:   Lock the text while evaluating 'completefunc'.
This commit is contained in:
Bram Moolenaar 2020-04-21 22:01:14 +02:00
parent 1966c24881
commit ff06f283e3
12 changed files with 62 additions and 42 deletions

View File

@ -666,8 +666,10 @@ Note: The keys that are valid in CTRL-X mode are not mapped. This allows for
ends CTRL-X mode (any key that is not a valid CTRL-X mode command) is mapped. ends CTRL-X mode (any key that is not a valid CTRL-X mode command) is mapped.
Also, when doing completion with 'complete' mappings apply as usual. Also, when doing completion with 'complete' mappings apply as usual.
Note: While completion is active Insert mode can't be used recursively. *E565*
Mappings that somehow invoke ":normal i.." will generate an E523 error. Note: While completion is active Insert mode can't be used recursively and
buffer text cannot be changed. Mappings that somehow invoke ":normal i.."
will generate an E565 error.
The following mappings are suggested to make typing the completion commands The following mappings are suggested to make typing the completion commands
a bit easier (although they will hide other commands): > a bit easier (although they will hide other commands): >

View File

@ -175,16 +175,10 @@ edit(
#endif #endif
// 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)
{
emsg(_(e_secure));
return FALSE;
}
// Don't allow recursive insert mode when busy with completion. // Don't allow recursive insert mode when busy with completion.
if (ins_compl_active() || compl_busy || pum_visible()) if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible())
{ {
emsg(_(e_secure)); emsg(_(e_textlock));
return FALSE; return FALSE;
} }
ins_compl_clear(); // clear stuff for CTRL-X mode ins_compl_clear(); // clear stuff for CTRL-X mode

View File

@ -2576,7 +2576,7 @@ get_text_locked_msg(void)
if (cmdwin_type != 0) if (cmdwin_type != 0)
return e_cmdwin; return e_cmdwin;
#endif #endif
return e_secure; return e_textlock;
} }
/* /*

View File

@ -1678,9 +1678,10 @@ EXTERN char e_letunexp[] INIT(= N_("E18: Unexpected characters in :let"));
EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
#endif #endif
#ifdef HAVE_SANDBOX #ifdef HAVE_SANDBOX
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"));
#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

@ -2217,6 +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.
++textlock;
// Call a function, which returns a list or dict. // Call a function, which returns a list or dict.
if (call_vim_function(funcname, 2, args, &rettv) == OK) if (call_vim_function(funcname, 2, args, &rettv) == OK)
@ -2239,6 +2241,7 @@ expand_by_function(
break; break;
} }
} }
--textlock;
if (curwin_save != curwin || curbuf_save != curbuf) if (curwin_save != curwin || curbuf_save != curbuf)
{ {
@ -2431,6 +2434,7 @@ set_completion(colnr_T startcol, list_T *list)
f_complete(typval_T *argvars, typval_T *rettv UNUSED) f_complete(typval_T *argvars, typval_T *rettv UNUSED)
{ {
int startcol; int startcol;
int save_textlock = textlock;
if ((State & INSERT) == 0) if ((State & INSERT) == 0)
{ {
@ -2438,22 +2442,24 @@ f_complete(typval_T *argvars, typval_T *rettv UNUSED)
return; return;
} }
// "textlock" is set when evaluating 'completefunc' but we can change text
// here.
textlock = 0;
// Check for undo allowed here, because if something was already inserted // Check for undo allowed here, because if something was already inserted
// the line was already saved for undo and this check isn't done. // the line was already saved for undo and this check isn't done.
if (!undo_allowed()) if (!undo_allowed())
return; return;
if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
{
emsg(_(e_invarg)); emsg(_(e_invarg));
return; else
{
startcol = (int)tv_get_number_chk(&argvars[0], NULL);
if (startcol > 0)
set_completion(startcol - 1, argvars[1].vval.v_list);
} }
textlock = save_textlock;
startcol = (int)tv_get_number_chk(&argvars[0], NULL);
if (startcol <= 0)
return;
set_completion(startcol - 1, argvars[1].vval.v_list);
} }
/* /*

View File

@ -915,6 +915,23 @@ func Test_edit_CTRL_U()
bw! bw!
endfunc endfunc
func Test_edit_completefunc_delete()
func CompleteFunc(findstart, base)
if a:findstart == 1
return col('.') - 1
endif
normal dd
return ['a', 'b']
endfunc
new
set completefunc=CompleteFunc
call setline(1, ['', 'abcd', ''])
2d
call assert_fails("normal 2G$a\<C-X>\<C-U>", 'E565:')
bwipe!
endfunc
func Test_edit_CTRL_Z() func Test_edit_CTRL_Z()
" Ctrl-Z when insertmode is not set inserts it literally " Ctrl-Z when insertmode is not set inserts it literally
new new
@ -1240,7 +1257,7 @@ func Test_edit_forbidden()
try try
call feedkeys("ix\<esc>", 'tnix') call feedkeys("ix\<esc>", 'tnix')
call assert_fails(1, 'textlock') call assert_fails(1, 'textlock')
catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here catch /^Vim\%((\a\+)\)\=:E565/ " catch E565: not allowed here
endtry endtry
" TODO: Might be a bug: should x really be inserted here " TODO: Might be a bug: should x really be inserted here
call assert_equal(['xa'], getline(1, '$')) call assert_equal(['xa'], getline(1, '$'))
@ -1264,7 +1281,7 @@ func Test_edit_forbidden()
try try
call feedkeys("i\<c-x>\<c-u>\<esc>", 'tnix') call feedkeys("i\<c-x>\<c-u>\<esc>", 'tnix')
call assert_fails(1, 'change in complete function') call assert_fails(1, 'change in complete function')
catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
endtry endtry
delfu Complete delfu Complete
set completefunc= set completefunc=

View File

@ -158,13 +158,13 @@ endfunc
func Test_ex_mode_errors() func Test_ex_mode_errors()
" Not allowed to enter ex mode when text is locked " Not allowed to enter ex mode when text is locked
au InsertCharPre <buffer> normal! gQ<CR> au InsertCharPre <buffer> normal! gQ<CR>
let caught_e523 = 0 let caught_e565 = 0
try try
call feedkeys("ix\<esc>", 'xt') call feedkeys("ix\<esc>", 'xt')
catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
let caught_e523 = 1 let caught_e565 = 1
endtry endtry
call assert_equal(1, caught_e523) call assert_equal(1, caught_e565)
au! InsertCharPre au! InsertCharPre
endfunc endfunc

View File

@ -354,15 +354,15 @@ endfunc
func Test_run_excmd_with_text_locked() func Test_run_excmd_with_text_locked()
" :quit " :quit
let cmd = ":\<C-\>eexecute('quit')\<CR>\<C-C>" let cmd = ":\<C-\>eexecute('quit')\<CR>\<C-C>"
call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
" :qall " :qall
let cmd = ":\<C-\>eexecute('qall')\<CR>\<C-C>" let cmd = ":\<C-\>eexecute('qall')\<CR>\<C-C>"
call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
" :exit " :exit
let cmd = ":\<C-\>eexecute('exit')\<CR>\<C-C>" let cmd = ":\<C-\>eexecute('exit')\<CR>\<C-C>"
call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
" :close - should be ignored " :close - should be ignored
new new
@ -370,7 +370,7 @@ func Test_run_excmd_with_text_locked()
call assert_equal(2, winnr('$')) call assert_equal(2, winnr('$'))
close close
call assert_fails("call feedkeys(\":\<C-R>=execute('bnext')\<CR>\", 'xt')", 'E523:') call assert_fails("call feedkeys(\":\<C-R>=execute('bnext')\<CR>\", 'xt')", 'E565:')
endfunc endfunc
" Test for the :verbose command " Test for the :verbose command

View File

@ -134,13 +134,13 @@ func Test_gf_error()
" gf is not allowed when text is locked " gf is not allowed when text is locked
au InsertCharPre <buffer> normal! gF<CR> au InsertCharPre <buffer> normal! gF<CR>
let caught_e523 = 0 let caught_e565 = 0
try try
call feedkeys("ix\<esc>", 'xt') call feedkeys("ix\<esc>", 'xt')
catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
let caught_e523 = 1 let caught_e565 = 1
endtry endtry
call assert_equal(1, caught_e523) call assert_equal(1, caught_e565)
au! InsertCharPre au! InsertCharPre
bwipe! bwipe!

View File

@ -334,19 +334,17 @@ func DummyCompleteOne(findstart, base)
endif endif
endfunc endfunc
" Test that nothing happens if the 'completefunc' opens " Test that nothing happens if the 'completefunc' tries to open
" a new window (no completion, no crash) " a new window (fails to open window, continues)
func Test_completefunc_opens_new_window_one() func Test_completefunc_opens_new_window_one()
new new
let winid = win_getid() let winid = win_getid()
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")', 'E839:') call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
call assert_notequal(winid, win_getid())
q!
call assert_equal(winid, win_getid()) call assert_equal(winid, win_getid())
call assert_equal('', getline(1)) call assert_equal('oneDEF', getline(1))
q! q!
endfunc endfunc

View File

@ -333,7 +333,7 @@ undo_allowed(void)
// caller of getcmdline() may get confused. // caller of getcmdline() may get confused.
if (textlock != 0) if (textlock != 0)
{ {
emsg(_(e_secure)); 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 */
/**/
614,
/**/ /**/
613, 613,
/**/ /**/