To: vim_dev@googlegroups.com Subject: Patch 8.2.0614 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0614 Problem: Get ml_get error when deleting a line in 'completefunc'. (Yegappan Lakshmanan) Solution: Lock the text while evaluating 'completefunc'. Files: src/insexpand.c, src/globals.h, src/edit.c, src/ex_getln.c, src/undo.c, src/testdir/test_edit.vim, src/testdir/test_excmd.vim, src/testdir/test_gf.vim, src/testdir/test_popup.vim, src/testdir/test_ex_mode.vim, runtime/doc/insert.txt *** ../vim-8.2.0613/src/insexpand.c 2020-04-12 19:37:13.514297270 +0200 --- src/insexpand.c 2020-04-21 21:54:18.321792952 +0200 *************** *** 2217,2222 **** --- 2217,2224 ---- 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,2244 **** --- 2241,2247 ---- break; } } + --textlock; if (curwin_save != curwin || curbuf_save != curbuf) { *************** *** 2431,2436 **** --- 2434,2440 ---- f_complete(typval_T *argvars, typval_T *rettv UNUSED) { int startcol; + int save_textlock = textlock; if ((State & INSERT) == 0) { *************** *** 2438,2459 **** return; } // 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; } ! ! startcol = (int)tv_get_number_chk(&argvars[0], NULL); ! if (startcol <= 0) ! return; ! ! set_completion(startcol - 1, argvars[1].vval.v_list); } /* --- 2442,2465 ---- 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)); ! 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; } /* *** ../vim-8.2.0613/src/globals.h 2020-04-19 17:24:48.665264342 +0200 --- src/globals.h 2020-04-21 20:41:50.964300235 +0200 *************** *** 1678,1686 **** 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")); #endif ! EXTERN char e_secure[] INIT(= N_("E523: Not allowed 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")); --- 1678,1687 ---- 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")); #endif ! 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")); *** ../vim-8.2.0613/src/edit.c 2020-04-17 19:41:16.100078313 +0200 --- src/edit.c 2020-04-21 20:52:09.233681112 +0200 *************** *** 175,190 **** #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()) { ! emsg(_(e_secure)); return FALSE; } ins_compl_clear(); // clear stuff for CTRL-X mode --- 175,184 ---- #endif // Don't allow changes in the buffer while editing the cmdline. The // caller of getcmdline() may get confused. // Don't allow recursive insert mode when busy with completion. ! if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) { ! emsg(_(e_textlock)); return FALSE; } ins_compl_clear(); // clear stuff for CTRL-X mode *** ../vim-8.2.0613/src/ex_getln.c 2020-04-14 20:15:45.284566193 +0200 --- src/ex_getln.c 2020-04-21 20:51:33.569810886 +0200 *************** *** 2576,2582 **** if (cmdwin_type != 0) return e_cmdwin; #endif ! return e_secure; } /* --- 2576,2582 ---- if (cmdwin_type != 0) return e_cmdwin; #endif ! return e_textlock; } /* *** ../vim-8.2.0613/src/undo.c 2020-04-12 19:37:13.526297236 +0200 --- src/undo.c 2020-04-21 20:53:06.141477432 +0200 *************** *** 333,339 **** // caller of getcmdline() may get confused. if (textlock != 0) { ! emsg(_(e_secure)); return FALSE; } --- 333,339 ---- // caller of getcmdline() may get confused. if (textlock != 0) { ! emsg(_(e_textlock)); return FALSE; } *** ../vim-8.2.0613/src/testdir/test_edit.vim 2020-03-30 19:30:07.129542925 +0200 --- src/testdir/test_edit.vim 2020-04-21 20:57:02.780666855 +0200 *************** *** 915,920 **** --- 915,937 ---- 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\\", 'E565:') + bwipe! + endfunc + + func Test_edit_CTRL_Z() " Ctrl-Z when insertmode is not set inserts it literally new *************** *** 1240,1246 **** try call feedkeys("ix\", 'tnix') call assert_fails(1, 'textlock') ! catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here endtry " TODO: Might be a bug: should x really be inserted here call assert_equal(['xa'], getline(1, '$')) --- 1257,1263 ---- try call feedkeys("ix\", 'tnix') call assert_fails(1, 'textlock') ! 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,1270 **** try call feedkeys("i\\\", 'tnix') call assert_fails(1, 'change in complete function') ! catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 endtry delfu Complete set completefunc= --- 1281,1287 ---- try call feedkeys("i\\\", 'tnix') call assert_fails(1, 'change in complete function') ! catch /^Vim\%((\a\+)\)\=:E565/ " catch E565 endtry delfu Complete set completefunc= *** ../vim-8.2.0613/src/testdir/test_excmd.vim 2020-03-30 19:30:07.129542925 +0200 --- src/testdir/test_excmd.vim 2020-04-21 21:37:41.425277149 +0200 *************** *** 354,368 **** func Test_run_excmd_with_text_locked() " :quit let cmd = ":\eexecute('quit')\\" ! call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') " :qall let cmd = ":\eexecute('qall')\\" ! call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') " :exit let cmd = ":\eexecute('exit')\\" ! call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') " :close - should be ignored new --- 354,368 ---- func Test_run_excmd_with_text_locked() " :quit let cmd = ":\eexecute('quit')\\" ! call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') " :qall let cmd = ":\eexecute('qall')\\" ! call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') " :exit let cmd = ":\eexecute('exit')\\" ! call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') " :close - should be ignored new *************** *** 370,376 **** call assert_equal(2, winnr('$')) close ! call assert_fails("call feedkeys(\":\=execute('bnext')\\", 'xt')", 'E523:') endfunc " Test for the :verbose command --- 370,376 ---- call assert_equal(2, winnr('$')) close ! call assert_fails("call feedkeys(\":\=execute('bnext')\\", 'xt')", 'E565:') endfunc " Test for the :verbose command *** ../vim-8.2.0613/src/testdir/test_gf.vim 2020-03-10 07:48:06.571619551 +0100 --- src/testdir/test_gf.vim 2020-04-21 21:38:25.129147979 +0200 *************** *** 134,146 **** " gf is not allowed when text is locked au InsertCharPre normal! gF ! let caught_e523 = 0 try call feedkeys("ix\", 'xt') ! catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 ! let caught_e523 = 1 endtry ! call assert_equal(1, caught_e523) au! InsertCharPre bwipe! --- 134,146 ---- " gf is not allowed when text is locked au InsertCharPre normal! gF ! let caught_e565 = 0 try call feedkeys("ix\", 'xt') ! catch /^Vim\%((\a\+)\)\=:E565/ " catch E565 ! let caught_e565 = 1 endtry ! call assert_equal(1, caught_e565) au! InsertCharPre bwipe! *** ../vim-8.2.0613/src/testdir/test_popup.vim 2020-04-08 21:50:18.876619651 +0200 --- src/testdir/test_popup.vim 2020-04-21 21:50:45.361744692 +0200 *************** *** 334,352 **** endif endfunc ! " Test that nothing happens if the 'completefunc' opens ! " a new window (no completion, no crash) 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\\\\", "x")', 'E839:') ! call assert_notequal(winid, win_getid()) ! q! call assert_equal(winid, win_getid()) ! call assert_equal('', getline(1)) q! endfunc --- 334,350 ---- endif endfunc ! " 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\\\\", "x")', 'E565:') call assert_equal(winid, win_getid()) ! call assert_equal('oneDEF', getline(1)) q! endfunc *** ../vim-8.2.0613/src/testdir/test_ex_mode.vim 2020-04-04 14:00:34.197098267 +0200 --- src/testdir/test_ex_mode.vim 2020-04-21 21:40:08.736841926 +0200 *************** *** 158,170 **** func Test_ex_mode_errors() " Not allowed to enter ex mode when text is locked au InsertCharPre normal! gQ ! let caught_e523 = 0 try call feedkeys("ix\", 'xt') ! catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 ! let caught_e523 = 1 endtry ! call assert_equal(1, caught_e523) au! InsertCharPre endfunc --- 158,170 ---- func Test_ex_mode_errors() " Not allowed to enter ex mode when text is locked au InsertCharPre normal! gQ ! let caught_e565 = 0 try call feedkeys("ix\", 'xt') ! catch /^Vim\%((\a\+)\)\=:E565/ " catch E565 ! let caught_e565 = 1 endtry ! call assert_equal(1, caught_e565) au! InsertCharPre endfunc *** ../vim-8.2.0613/runtime/doc/insert.txt 2020-01-04 14:32:35.522717984 +0100 --- runtime/doc/insert.txt 2020-04-21 20:45:07.579358745 +0200 *************** *** 658,665 **** 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. The following mappings are suggested to make typing the completion commands a bit easier (although they will hide other commands): > --- 666,675 ---- 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. ! *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): > *** ../vim-8.2.0613/src/version.c 2020-04-20 22:42:28.232964333 +0200 --- src/version.c 2020-04-21 21:58:20.605666005 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 614, /**/ -- No engineer can take a shower without wondering if some sort of Teflon coating would make showering unnecessary. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///