243 lines
7.6 KiB
Diff
243 lines
7.6 KiB
Diff
From ff06f283e3e4b3ec43012dd3b83f8454c98f6639 Mon Sep 17 00:00:00 2001
|
|
From: Bram Moolenaar <Bram@vim.org>
|
|
Date: Tue, 21 Apr 2020 22:01:14 +0200
|
|
Subject: [PATCH] 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'.
|
|
---
|
|
runtime/doc/insert.txt | 6 ++++--
|
|
src/edit.c | 10 ++--------
|
|
src/ex_getln.c | 2 +-
|
|
src/globals.h | 5 +++--
|
|
src/insexpand.c | 22 ++++++++++++++--------
|
|
src/testdir/test_edit.vim | 21 +++++++++++++++++++--
|
|
src/testdir/test_popup.vim | 10 ++++------
|
|
src/undo.c | 2 +-
|
|
8 files changed, 48 insertions(+), 30 deletions(-)
|
|
|
|
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
|
|
index 99c2d40..ff74d62 100644
|
|
--- a/runtime/doc/insert.txt
|
|
+++ b/runtime/doc/insert.txt
|
|
@@ -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.
|
|
Also, when doing completion with 'complete' mappings apply as usual.
|
|
|
|
-Note: While completion is active Insert mode can't be used recursively.
|
|
-Mappings that somehow invoke ":normal i.." will generate an E523 error.
|
|
+ *E565*
|
|
+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
|
|
a bit easier (although they will hide other commands): >
|
|
diff --git a/src/edit.c b/src/edit.c
|
|
index 3f0803f..05518ce 100644
|
|
--- a/src/edit.c
|
|
+++ b/src/edit.c
|
|
@@ -175,16 +175,10 @@ edit(
|
|
#endif
|
|
// Don't allow changes in the buffer while editing the cmdline. The
|
|
// caller of getcmdline() may get confused.
|
|
- if (textlock != 0)
|
|
- {
|
|
- emsg(_(e_secure));
|
|
- return FALSE;
|
|
- }
|
|
-
|
|
// 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;
|
|
}
|
|
ins_compl_clear(); // clear stuff for CTRL-X mode
|
|
diff --git a/src/ex_getln.c b/src/ex_getln.c
|
|
index 9b959fb..18da926 100644
|
|
--- a/src/ex_getln.c
|
|
+++ b/src/ex_getln.c
|
|
@@ -2576,7 +2576,7 @@ get_text_locked_msg(void)
|
|
if (cmdwin_type != 0)
|
|
return e_cmdwin;
|
|
#endif
|
|
- return e_secure;
|
|
+ return e_textlock;
|
|
}
|
|
|
|
/*
|
|
diff --git a/src/globals.h b/src/globals.h
|
|
index 4822bf3..f6c9d60 100644
|
|
--- a/src/globals.h
|
|
+++ b/src/globals.h
|
|
@@ -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"));
|
|
#endif
|
|
#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
|
|
-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) \
|
|
|| defined(UNIX) || defined(VMS)
|
|
EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));
|
|
diff --git a/src/insexpand.c b/src/insexpand.c
|
|
index 0278522..48ab260 100644
|
|
--- a/src/insexpand.c
|
|
+++ b/src/insexpand.c
|
|
@@ -2217,6 +2217,8 @@ expand_by_function(
|
|
pos = curwin->w_cursor;
|
|
curwin_save = curwin;
|
|
curbuf_save = curbuf;
|
|
+ // Lock the text to avoid weird things from happening.
|
|
+ ++textlock;
|
|
|
|
// Call a function, which returns a list or dict.
|
|
if (call_vim_function(funcname, 2, args, &rettv) == OK)
|
|
@@ -2239,6 +2241,7 @@ expand_by_function(
|
|
break;
|
|
}
|
|
}
|
|
+ --textlock;
|
|
|
|
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)
|
|
{
|
|
int startcol;
|
|
+ int save_textlock = textlock;
|
|
|
|
if ((State & INSERT) == 0)
|
|
{
|
|
@@ -2438,22 +2442,24 @@ f_complete(typval_T *argvars, typval_T *rettv UNUSED)
|
|
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
|
|
// the line was already saved for undo and this check isn't done.
|
|
if (!undo_allowed())
|
|
return;
|
|
|
|
if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
|
|
- {
|
|
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);
|
|
}
|
|
-
|
|
- startcol = (int)tv_get_number_chk(&argvars[0], NULL);
|
|
- if (startcol <= 0)
|
|
- return;
|
|
-
|
|
- set_completion(startcol - 1, argvars[1].vval.v_list);
|
|
+ textlock = save_textlock;
|
|
}
|
|
|
|
/*
|
|
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
|
|
index 9096fcd..ce55f6b 100644
|
|
--- a/src/testdir/test_edit.vim
|
|
+++ b/src/testdir/test_edit.vim
|
|
@@ -915,6 +915,23 @@ func Test_edit_CTRL_U()
|
|
bw!
|
|
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()
|
|
" Ctrl-Z when insertmode is not set inserts it literally
|
|
new
|
|
@@ -1240,7 +1257,7 @@ func Test_edit_forbidden()
|
|
try
|
|
call feedkeys("ix\<esc>", 'tnix')
|
|
call assert_fails(1, 'textlock')
|
|
- catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here
|
|
+ catch /^Vim\%((\a\+)\)\=:E565/ " catch E565: not allowed here
|
|
endtry
|
|
" TODO: Might be a bug: should x really be inserted here
|
|
call assert_equal(['xa'], getline(1, '$'))
|
|
@@ -1264,7 +1281,7 @@ func Test_edit_forbidden()
|
|
try
|
|
call feedkeys("i\<c-x>\<c-u>\<esc>", 'tnix')
|
|
call assert_fails(1, 'change in complete function')
|
|
- catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
|
|
+ catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
|
|
endtry
|
|
delfu Complete
|
|
set completefunc=
|
|
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
|
|
index e96d5fd..9890377 100644
|
|
--- a/src/testdir/test_popup.vim
|
|
+++ b/src/testdir/test_popup.vim
|
|
@@ -334,19 +334,17 @@ func DummyCompleteOne(findstart, base)
|
|
endif
|
|
endfunc
|
|
|
|
-" Test that nothing happens if the 'completefunc' opens
|
|
-" a new window (no completion, no crash)
|
|
+" Test that nothing happens if the 'completefunc' tries to open
|
|
+" a new window (fails to open window, continues)
|
|
func Test_completefunc_opens_new_window_one()
|
|
new
|
|
let winid = win_getid()
|
|
setlocal completefunc=DummyCompleteOne
|
|
call setline(1, 'one')
|
|
/^one
|
|
- call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E839:')
|
|
- call assert_notequal(winid, win_getid())
|
|
- q!
|
|
+ call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
|
|
call assert_equal(winid, win_getid())
|
|
- call assert_equal('', getline(1))
|
|
+ call assert_equal('oneDEF', getline(1))
|
|
q!
|
|
endfunc
|
|
|
|
diff --git a/src/undo.c b/src/undo.c
|
|
index c5ce306..c11b048 100644
|
|
--- a/src/undo.c
|
|
+++ b/src/undo.c
|
|
@@ -333,7 +333,7 @@ undo_allowed(void)
|
|
// caller of getcmdline() may get confused.
|
|
if (textlock != 0)
|
|
{
|
|
- emsg(_(e_secure));
|
|
+ emsg(_(e_textlock));
|
|
return FALSE;
|
|
}
|
|
|
|
--
|
|
1.8.3.1
|
|
|