]> granicus.if.org Git - vim/commitdiff
patch 8.2.0614: get ml_get error when deleting a line in 'completefunc' v8.2.0614
authorBram Moolenaar <Bram@vim.org>
Tue, 21 Apr 2020 20:01:14 +0000 (22:01 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 21 Apr 2020 20:01:14 +0000 (22:01 +0200)
Problem:    Get ml_get error when deleting a line in 'completefunc'. (Yegappan
            Lakshmanan)
Solution:   Lock the text while evaluating 'completefunc'.

12 files changed:
runtime/doc/insert.txt
src/edit.c
src/ex_getln.c
src/globals.h
src/insexpand.c
src/testdir/test_edit.vim
src/testdir/test_ex_mode.vim
src/testdir/test_excmd.vim
src/testdir/test_gf.vim
src/testdir/test_popup.vim
src/undo.c
src/version.c

index 99c2d40e7dae1938323d1ea02fe62ea96baa64a5..ff74d625f4ef16e6a2ee8236e3dd69eafbe5284f 100644 (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.
 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): >
index 3f0803f685b9d836a69432bc2ac4069703025f78..05518ceab8490ec3d581200205557c7452523873 100644 (file)
@@ -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
index 9b959fbad5a1c93fc60f35b3fb48904814667bc1..18da926560de5ae723e8624e32cd9150ef9cdf5c 100644 (file)
@@ -2576,7 +2576,7 @@ get_text_locked_msg(void)
     if (cmdwin_type != 0)
        return e_cmdwin;
 #endif
-    return e_secure;
+    return e_textlock;
 }
 
 /*
index 4822bf3735c97beba1c2df094705589ccf61feff..f6c9d60e2b22af14b1b802bcf5b0a19e69c58727 100644 (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"));
 #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"));
index 0278522684b8db09015e36cf2c03b7b6cea6c23f..48ab260a70f4240c9b6ab4dea5d0b0e4c2189180 100644 (file)
@@ -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;
 }
 
 /*
index 9096fcdeb1ac10d1472d1c6d657d472d4d14cfad..ce55f6be0b53f048c811ceb2c783b0904138bf28 100644 (file)
@@ -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=
index 9f66e3f012b96ee5be138f51480a1eba1a5f301b..d23e0ad9317bc0a0b05b062f47888c769aa9e343 100644 (file)
@@ -158,13 +158,13 @@ endfunc
 func Test_ex_mode_errors()
   " Not allowed to enter ex mode when text is locked
   au InsertCharPre <buffer> normal! gQ<CR>
-  let caught_e523 = 0
+  let caught_e565 = 0
   try
     call feedkeys("ix\<esc>", 'xt')
-  catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
-    let caught_e523 = 1
+  catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
+    let caught_e565 = 1
   endtry
-  call assert_equal(1, caught_e523)
+  call assert_equal(1, caught_e565)
   au! InsertCharPre
 endfunc
 
index 9369c1b90ba310acd00cead4e71708aa42e51a55..868ac6fc40bd3ae3567dacf16675b43aefc39ebd 100644 (file)
@@ -354,15 +354,15 @@ endfunc
 func Test_run_excmd_with_text_locked()
   " :quit
   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
   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
   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
   new
@@ -370,7 +370,7 @@ func Test_run_excmd_with_text_locked()
   call assert_equal(2, winnr('$'))
   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
 
 " Test for the :verbose command
index 829b7c2992baca1af6f59466bc0089769c7253bb..736a31579029ac786e3320485a1d76538baa2e88 100644 (file)
@@ -134,13 +134,13 @@ func Test_gf_error()
 
   " gf is not allowed when text is locked
   au InsertCharPre <buffer> normal! gF<CR>
-  let caught_e523 = 0
+  let caught_e565 = 0
   try
     call feedkeys("ix\<esc>", 'xt')
-  catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
-    let caught_e523 = 1
+  catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
+    let caught_e565 = 1
   endtry
-  call assert_equal(1, caught_e523)
+  call assert_equal(1, caught_e565)
   au! InsertCharPre
 
   bwipe!
index e96d5fda50771d1018ae49120397611f44055040..9890377ea7b386db6ef7fd14021bf4325393a05e 100644 (file)
@@ -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
 
index c5ce306cabaed2caf9fba6f8647bfa16ce856bd7..c11b048a2c346408cfabe4b63602567c989ebda2 100644 (file)
@@ -333,7 +333,7 @@ undo_allowed(void)
     // caller of getcmdline() may get confused.
     if (textlock != 0)
     {
-       emsg(_(e_secure));
+       emsg(_(e_textlock));
        return FALSE;
     }
 
index 9b00c49d9a172f0e2aec6deaafe3242bbfe2bc3a..cb846f08d6ef2daf0cdff3b16e097678c5567d3e 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    614,
 /**/
     613,
 /**/