patch 9.1.1295: clientserver: does not handle :stopinsert correctly

Problem:  clientserver: When in insert mode, a :stopinsert command
          is not correctly processed (user202729)
Solution: If the :stopinsert command is received while waiting for
          input, stuff the NOP key into the type-ahead buffer and
          detect that :stopinsert was used in edit() so that the
          cursor position is decremented.

fixes: #17016
closes: #17024

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Christian Brabandt
2025-04-12 18:09:28 +02:00
parent 6f6c0dba9f
commit cf665ccd37
4 changed files with 59 additions and 1 deletions

View File

@ -608,7 +608,16 @@ edit(
if (c != K_IGNORE && c != K_NOP)
vungetc(c);
count = 0;
nomove = TRUE;
if (!bt_prompt(curwin->w_buffer)
#ifdef FEAT_TERMINAL
&& !bt_terminal(curwin->w_buffer)
#endif
&& stop_insert_mode)
// :stopinsert command via callback or via server command
nomove = FALSE;
else
nomove = TRUE;
ins_compl_prep(ESC);
goto doESCkey;
}

View File

@ -9326,6 +9326,12 @@ ex_stopinsert(exarg_T *eap UNUSED)
{
restart_edit = 0;
stop_insert_mode = TRUE;
#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
// when called from remote_expr in insert mode, make sure insert mode is
// ended by adding K_NOP to the typeahead buffer
if (vgetc_busy)
ins_char_typebuf(K_NOP, 0);
#endif
clearmode();
}

View File

@ -191,6 +191,47 @@ func Test_client_server()
\ has('unix') ? ['E573:.*abc'] : 'E258:')
endfunc
func Test_client_server_stopinsert()
" test does not work on MS-Windows
CheckNotMSWindows
let g:test_is_flaky = 1
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
call Check_X11_Connection()
let fname = 'Xclientserver_stop.txt'
let name = 'XVIMTEST2'
call writefile(['one two three'], fname, 'D')
let cmd .= ' -c "set virtualedit=onemore"'
let cmd .= ' -c "call cursor(1, 14)"'
let cmd .= ' -c "startinsert"'
let cmd .= ' --servername ' . name
let cmd .= ' ' .. fname
let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitForAssert({-> assert_equal("run", job_status(job))})
" Takes a short while for the server to be active.
" When using valgrind it takes much longer.
call WaitForAssert({-> assert_match(name, serverlist())})
call remote_expr(name, 'execute("stopinsert")')
call assert_equal('n', name->remote_expr("mode(1)"))
call assert_equal('13', name->remote_expr("col('.')"))
eval name->remote_send(":qa!\<CR>")
try
call WaitForAssert({-> assert_equal("dead", job_status(job))})
finally
if job_status(job) != 'dead'
call assert_report('Server did not exit')
call job_stop(job, 'kill')
endif
endtry
endfunc
" Uncomment this line to get a debugging log
" call ch_logfile('channellog', 'w')

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1295,
/**/
1294,
/**/