From: Hirohito Higashi Date: Wed, 22 Jul 2026 09:23:31 +0000 (+0000) Subject: patch 9.2.0827: :startinsert enters Insert mode in a non-modifiable buffer X-Git-Tag: v9.2.0827^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6ab1976e49135c0d03b06e3cddd26dc86edff085;p=thirdparty%2Fvim.git patch 9.2.0827: :startinsert enters Insert mode in a non-modifiable buffer Problem: ":startinsert" enters Insert mode in a buffer where 'modifiable' is off, the error only appears when a character is typed. Typing "i" gives the error right away (Barrett Ruth) Solution: Give the error when the buffer is not modifiable, like "i" does. Keep ignoring the command in a terminal window, where ":startinsert" is documented to be ineffective, and keep accepting it when 'insertmode' is set, like "i" does (Hirohito Higashi). fixes: #20804 closes: #20806 Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 55db2d8d4d..b23504a85b 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -9372,6 +9372,17 @@ ex_normal(exarg_T *eap) static void ex_startinsert(exarg_T *eap) { +#ifdef FEAT_TERMINAL + // Ignore this when running in an active terminal. + if (term_job_running(curbuf->b_term)) + return; +#endif + if (!curbuf->b_p_ma && !p_im) + { + // Only give this error when 'insertmode' is off. + emsg(_(e_cannot_make_changes_modifiable_is_off)); + return; + } if (eap->forceit) { // cursor line can be zero on startup @@ -9379,11 +9390,6 @@ ex_startinsert(exarg_T *eap) curwin->w_cursor.lnum = 1; set_cursor_for_append_to_line(); } -#ifdef FEAT_TERMINAL - // Ignore this when running in an active terminal. - if (term_job_running(curbuf->b_term)) - return; -#endif // Ignore the command when already in Insert mode. Inserting an // expression register that invokes a function can do this. diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index f76b9196fe..ef68d66336 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -1766,10 +1766,50 @@ func Test_edit_startinsert() call feedkeys(":startinsert!\\\", 'xt') call assert_equal('', getline(1)) + call setline(1, 'foobar') + setl nomodifiable + call assert_fails('startinsert', 'E21:') + + call cursor(1, 1) + call assert_fails('startinsert!', 'E21:') + call assert_equal(1, col('.')) + set backspace& bwipe! endfunc +" ":startinsert" is ineffective in a terminal window: it must not give an +" error and with "!" it must not move the cursor. +func Test_edit_startinsert_in_terminal() + CheckFeature terminal + + let buf = Run_shell_in_terminal({}) + + " Fill the terminal with text. + if has('win32') + call feedkeys("dir\", 'xt') + else + call feedkeys("ls\", 'xt') + endif + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + + " Go to Terminal-Normal mode and put the cursor on a line with text. + call feedkeys("\N", 'xt') + call assert_notequal(0, search('\S', 'w')) + call cursor(line('.'), 1) + + startinsert + startinsert! + call assert_equal(1, col('.')) + + " Clear "restart_edit" in case the commands were not ignored. + stopinsert + + call feedkeys("i", 'xt') + call StopShellInTerminal(buf) + bwipe! +endfunc + " Test for :startreplace and :startgreplace func Test_edit_startreplace() new @@ -1783,6 +1823,19 @@ func Test_edit_startreplace() call assert_equal("axyz\tb", getline(1)) call feedkeys("0i\=execute('startreplace')\12\e", 'xt') call assert_equal("12axyz\tb", getline(1)) + + call setline(1, 'abc') + setl nomodifiable + call assert_fails('startreplace', 'E21:') + call assert_fails('startgreplace', 'E21:') + + call cursor(1, 1) + call assert_fails('startreplace!', 'E21:') + call assert_equal(1, col('.')) + call cursor(1, 1) + call assert_fails('startgreplace!', 'E21:') + call assert_equal(1, col('.')) + bw! endfunc diff --git a/src/version.c b/src/version.c index 0d42fff436..9c342a6419 100644 --- a/src/version.c +++ b/src/version.c @@ -759,6 +759,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 827, /**/ 826, /**/