commit 7641177c5f981d90b3c080763a401496034f35c9
parent 7d8653575f2a1170f0c7651f271c45a15a185d5e
Author: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Date: Sun, 15 Feb 2026 03:21:07 +0000
fix(prompt): wrong cursor col after prompt_setprompt, no on_lines
Problem: prompt_setprompt calls coladvance with a byte column, but it expects a
screen column. on_lines buffer-updates aren't fired when fixing the prompt line.
Solution: don't use coladvance. Call changed_lines, which also simplifies the
redraw logic. (and calls changed_cline_bef_curs if needed; added test checks
this)
Unlike https://github.com/neovim/neovim/pull/37743/changes#r2775398744, this
means &modified is set by prompt_setprompt if it fixes the prompt line.
Not setting &modified is inconsistent anyway -- even init_prompt sets it if it
fixes the prompt line.
Diffstat:
3 files changed, 83 insertions(+), 10 deletions(-)
diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c
@@ -801,10 +801,9 @@ void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
if (curwin->w_buffer == buf && curwin->w_cursor.lnum == prompt_lno) {
- coladvance(curwin, cursor_col);
+ curwin->w_cursor.col = cursor_col;
}
- changed_lines_redraw_buf(buf, prompt_lno, prompt_lno + 1, 0);
- redraw_buf_later(buf, UPD_INVERTED);
+ changed_lines(buf, prompt_lno, 0, prompt_lno + 1, 0, true);
}
// Clear old prompt text and replace with the new one
diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua
@@ -62,7 +62,7 @@ describe('prompt buffer', function()
screen:expect([[
cmd: ^ |
{1:~ }|*3
- {3:[Prompt] }|
+ {3:[Prompt] [+] }|
other buffer |
{1:~ }|*3
{5:-- INSERT --} |
@@ -149,7 +149,7 @@ describe('prompt buffer', function()
screen:expect([[
cmd: |
{1:~ }|*3
- {2:[Prompt] }|
+ {2:[Prompt] [+] }|
^other buffer |
{1:~ }|*3
|
@@ -158,7 +158,7 @@ describe('prompt buffer', function()
screen:expect([[
cmd: ^ |
{1:~ }|*3
- {3:[Prompt] }|
+ {3:[Prompt] [+] }|
other buffer |
{1:~ }|*3
{5:-- INSERT --} |
@@ -167,7 +167,7 @@ describe('prompt buffer', function()
screen:expect([[
cmd:^ |
{1:~ }|*3
- {3:[Prompt] }|
+ {3:[Prompt] [+] }|
other buffer |
{1:~ }|*3
|
@@ -892,10 +892,42 @@ describe('prompt buffer', function()
{1:~ }|*7
|
]])
+ -- Correct col when prompt has multi-cell chars.
+ feed('i<Left><Left>')
+ screen:expect([[
+ new-prompt > user input |
+ <>< user inp^ut |
+ {1:~ }|*7
+ {5:-- INSERT --} |
+ ]])
+ set_prompt('\t > ')
+ screen:expect([[
+ new-prompt > user input |
+ > user inp^ut |
+ {1:~ }|*7
+ {5:-- INSERT --} |
+ ]])
+ -- Works with 'virtualedit': coladd remains sensible. Cursor is redrawn correctly.
+ -- Tab size visually changes due to multiples of 'tabstop'.
+ command('set virtualedit=all')
+ feed('<C-O>Sa<Tab>b<C-O>3h')
+ screen:expect([[
+ new-prompt > user input |
+ > a ^ b |
+ {1:~ }|*7
+ {5:-- INSERT --} |
+ ]])
+ set_prompt('😊 > ')
+ screen:expect([[
+ new-prompt > user input |
+ 😊 > a ^ b |
+ {1:~ }|*7
+ {5:-- INSERT --} |
+ ]])
-- No crash when setting shorter prompt than curbuf's in other buffer.
- feed('i<C-O>zt')
- command('new | setlocal buftype=prompt')
+ feed('<C-O>zt')
+ command('set virtualedit& | new | setlocal buftype=prompt')
set_prompt('looooooooooooooooooooooooooooooooooooooooooooong > ', '') -- curbuf
set_prompt('foo > ')
screen:expect([[
@@ -904,7 +936,7 @@ describe('prompt buffer', function()
^ |
{1:~ }|
{3:[Prompt] [+] }|
- foo > user input |
+ foo > a b |
{1:~ }|*3
{5:-- INSERT --} |
]])
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
@@ -422,6 +422,48 @@ describe('lua: nvim_buf_attach on_lines', function()
feed('<C-v>I <ESC>')
eq({ api.nvim_get_current_buf(), 0, 1, 1 }, exec_lua('return _G.res'))
end)
+
+ it('prompt buffer', function()
+ local check_events = setup_eventcheck(false, nil, {})
+ api.nvim_set_option_value('buftype', 'prompt', {})
+ feed('i')
+ check_events {
+ { 'test1', 'lines', 1, 4, 0, 1, 1, 1 },
+ }
+ fn.prompt_setprompt('', 'foo > ')
+ check_events {
+ { 'test1', 'lines', 1, 5, 0, 1, 1, 3 },
+ }
+ feed('hello')
+ check_events {
+ { 'test1', 'lines', 1, 6, 0, 1, 1, 7 },
+ }
+ fn.prompt_setprompt('', 'super-foo > ')
+ check_events {
+ { 'test1', 'lines', 1, 7, 0, 1, 1, 12 },
+ }
+ eq({ 'super-foo > hello' }, api.nvim_buf_get_lines(0, 0, -1, true))
+ -- Do this in the same event.
+ exec_lua(function()
+ vim.fn.setpos("':", { 0, 1, 999, 0 })
+ vim.fn.prompt_setprompt('', 'discard > ')
+ end)
+ check_events {
+ { 'test1', 'lines', 1, 8, 0, 1, 1, 18 },
+ }
+ eq({ 'discard > ' }, api.nvim_buf_get_lines(0, 0, -1, true))
+ feed('hello<S-CR>there')
+ check_events {
+ { 'test1', 'lines', 1, 9, 0, 1, 1, 11 },
+ { 'test1', 'lines', 1, 10, 0, 1, 2, 16 },
+ { 'test1', 'lines', 1, 11, 1, 2, 2, 1 },
+ }
+ fn.prompt_setprompt('', 'foo > ')
+ check_events {
+ { 'test1', 'lines', 1, 12, 0, 1, 1, 16 },
+ }
+ eq({ 'foo > hello', 'there' }, api.nvim_buf_get_lines(0, 0, -1, true))
+ end)
end)
describe('lua: nvim_buf_attach on_bytes', function()