From 47e97c1ad64342dd89a4cd5209e0a5b5fa3ea828 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 22 Jul 2026 22:03:05 +0800 Subject: [PATCH] vim-patch:9.2.0827: :startinsert enters Insert mode in a non-modifiable buffer (#40906) 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: vim/vim#20804 closes: vim/vim#20806 https://github.com/vim/vim/commit/6ab1976e49135c0d03b06e3cddd26dc86edff085 Co-authored-by: Hirohito Higashi --- src/nvim/ex_docmd.c | 4 +++ test/old/testdir/test_edit.vim | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f34551a299..d8f4983beb 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7380,6 +7380,10 @@ static void ex_normal(exarg_T *eap) /// ":startinsert", ":startreplace" and ":startgreplace" static void ex_startinsert(exarg_T *eap) { + if (!curbuf->b_p_ma && !curbuf->terminal) { + emsg(_(e_modifiable)); + return; + } if (eap->forceit) { // cursor line can be zero on startup if (!curwin->w_cursor.lnum) { diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim index cb78086bcb..e886089d26 100644 --- a/test/old/testdir/test_edit.vim +++ b/test/old/testdir/test_edit.vim @@ -1780,10 +1780,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 @@ -1797,6 +1837,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