mirror of
https://github.com/neovim/neovim.git
synced 2026-03-30 20:32:08 +00:00
fix(ui2): always route to dialog when cmdline is open #37730
Problem: Messages emitted while cmdline is open are not shown with
cmdline message target.
Solution: Route to dialog window when cmdline is open.
This commit is contained in:
@@ -4,10 +4,11 @@ local api, fn = vim.api, vim.fn
|
||||
local M = {
|
||||
highlighter = nil, ---@type vim.treesitter.highlighter?
|
||||
indent = 0, -- Current indent for block event.
|
||||
prompt = false, -- Whether a prompt is active; messages are placed in the 'dialog' window.
|
||||
prompt = false, -- Whether a prompt is active; route to dialog regardless of ui.cfg.msg.target.
|
||||
dialog = false, -- Whether a dialog window was opened.
|
||||
srow = 0, -- Buffer row at which the current cmdline starts; > 0 in block mode.
|
||||
erow = 0, -- Buffer row at which the current cmdline ends; messages appended here in block mode.
|
||||
level = -1, -- Current cmdline level; 0 when inactive, -1 one loop iteration after closing.
|
||||
level = 0, -- Current cmdline level; 0 when inactive.
|
||||
wmnumode = 0, -- wildmenumode() when not using the pum, dialog position adjusted when toggled.
|
||||
}
|
||||
|
||||
@@ -29,7 +30,7 @@ local function win_config(win, hide, height)
|
||||
vim.o.cmdheight = height
|
||||
end)
|
||||
ui.msg.set_pos()
|
||||
elseif M.wmnumode ~= (M.prompt and fn.pumvisible() == 0 and fn.wildmenumode() or 0) then
|
||||
elseif M.wmnumode ~= (M.dialog and fn.pumvisible() == 0 and fn.wildmenumode() or 0) then
|
||||
M.wmnumode = (M.wmnumode == 1 and 0 or 1)
|
||||
ui.msg.set_pos()
|
||||
end
|
||||
@@ -66,7 +67,7 @@ end
|
||||
---@param level integer
|
||||
---@param hl_id integer
|
||||
function M.cmdline_show(content, pos, firstc, prompt, indent, level, hl_id)
|
||||
M.level, M.indent, M.prompt = level, indent, M.prompt or #prompt > 0
|
||||
M.level, M.indent, M.prompt = level, indent, #prompt > 0
|
||||
if M.highlighter == nil or M.highlighter.bufnr ~= ui.bufs.cmd then
|
||||
local parser = assert(vim.treesitter.get_parser(ui.bufs.cmd, 'vim', {}))
|
||||
M.highlighter = vim.treesitter.highlighter.new(parser)
|
||||
@@ -130,28 +131,21 @@ function M.cmdline_hide(level, abort)
|
||||
|
||||
fn.clearmatches(ui.wins.cmd) -- Clear matchparen highlights.
|
||||
api.nvim_win_set_cursor(ui.wins.cmd, { 1, 0 })
|
||||
if abort then
|
||||
-- Clear cmd buffer for aborted command (non-abort is left visible).
|
||||
if M.prompt or abort then
|
||||
-- Clear cmd buffer prompt or aborted command (non-abort is left visible).
|
||||
api.nvim_buf_set_lines(ui.bufs.cmd, 0, -1, false, {})
|
||||
end
|
||||
|
||||
local clear = vim.schedule_wrap(function(was_prompt)
|
||||
vim.schedule(function()
|
||||
-- Avoid clearing prompt window when it is re-entered before the next event
|
||||
-- loop iteration. E.g. when a non-choice confirm button is pressed.
|
||||
if was_prompt and not M.prompt then
|
||||
api.nvim_buf_set_lines(ui.bufs.cmd, 0, -1, false, {})
|
||||
if M.dialog and M.level == 0 then
|
||||
api.nvim_buf_set_lines(ui.bufs.dialog, 0, -1, false, {})
|
||||
api.nvim_win_set_config(ui.wins.dialog, { hide = true })
|
||||
vim.on_key(nil, ui.msg.dialog_on_key)
|
||||
M.dialog = false
|
||||
end
|
||||
-- Messages emitted as a result of a typed command are treated specially:
|
||||
-- remember if the cmdline was used this event loop iteration.
|
||||
-- NOTE: Message event callbacks are themselves scheduled, so delay two iterations.
|
||||
vim.schedule(function()
|
||||
M.level = -1
|
||||
end)
|
||||
end)
|
||||
clear(M.prompt)
|
||||
|
||||
M.prompt, M.level, curpos[1], curpos[2] = false, 0, 0, 0
|
||||
win_config(ui.wins.cmd, true, ui.cmdheight)
|
||||
|
||||
@@ -286,7 +286,7 @@ function M.show_msg(tar, content, replace_last, append, id)
|
||||
local start_col = col
|
||||
|
||||
-- Accumulate to be inserted and highlighted message chunks.
|
||||
for _, chunk in ipairs(content) do
|
||||
for i, chunk in ipairs(content) do
|
||||
-- Split at newline and write to start of line after carriage return.
|
||||
for str in (chunk[2] .. '\0'):gmatch('.-[\n\r%z]') do
|
||||
local repl, pat = str:sub(1, -2), str:sub(-1)
|
||||
@@ -302,7 +302,6 @@ function M.show_msg(tar, content, replace_last, append, id)
|
||||
api.nvim_buf_set_text(buf, row, col, erow, ecol, { repl })
|
||||
end
|
||||
curline = api.nvim_buf_get_lines(buf, row, row + 1, false)[1]
|
||||
width = tar == 'msg' and math.max(width, api.nvim_strwidth(curline)) or 0
|
||||
mark[3] = nil
|
||||
|
||||
if chunk[3] > 0 then
|
||||
@@ -315,6 +314,11 @@ function M.show_msg(tar, content, replace_last, append, id)
|
||||
else
|
||||
col = pat == '\r' and 0 or end_col
|
||||
end
|
||||
if tar == 'msg' and (pat == '\n' or (i == #content and pat == '\0')) then
|
||||
width = api.nvim_win_call(ui.wins.msg, function()
|
||||
return math.max(width, fn.strdisplaywidth(curline))
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -398,21 +402,23 @@ function M.msg_show(kind, content, replace_last, _, append, id)
|
||||
M.virt.last[M.virt.idx.search] = content
|
||||
M.virt.last[M.virt.idx.cmd] = { { 0, (' '):rep(11) } }
|
||||
set_virttext('last')
|
||||
elseif (ui.cmd.prompt or kind == 'wildlist') and ui.cmd.srow == 0 then
|
||||
-- Route to dialog that stays open so long as the cmdline prompt is active.
|
||||
elseif
|
||||
(ui.cmd.prompt or (ui.cmd.level > 0 and ui.cfg.msg.target == 'cmd')) and ui.cmd.srow == 0
|
||||
then
|
||||
-- Route to dialog when a prompt is active, or message would overwrite active cmdline.
|
||||
replace_last = api.nvim_win_get_config(ui.wins.dialog).hide or kind == 'wildlist'
|
||||
if kind == 'wildlist' then
|
||||
api.nvim_buf_set_lines(ui.bufs.dialog, 0, -1, false, {})
|
||||
ui.cmd.prompt = true -- Ensure dialog is closed when cmdline is hidden.
|
||||
end
|
||||
ui.cmd.dialog = true -- Ensure dialog is closed when cmdline is hidden.
|
||||
M.show_msg('dialog', content, replace_last, append, id)
|
||||
M.set_pos('dialog')
|
||||
else
|
||||
-- Set the entered search command in the cmdline (if available).
|
||||
local tar = kind == 'search_cmd' and 'cmd' or ui.cfg.msg.target
|
||||
if tar == 'cmd' then
|
||||
if ui.cmdheight == 0 or (ui.cmd.level > 0 and ui.cmd.srow == 0) then
|
||||
return -- Do not overwrite an active cmdline unless in block mode.
|
||||
if ui.cmdheight == 0 and ui.cmd.srow == 0 then
|
||||
return
|
||||
end
|
||||
-- Store the time when an important message was emitted in order to not overwrite
|
||||
-- it with 'last' virt_text in the cmdline so that the user has a chance to read it.
|
||||
@@ -531,7 +537,7 @@ function M.set_pos(type)
|
||||
if entered then
|
||||
api.nvim_command('norm! g<') -- User entered the cmdline window: open the pager.
|
||||
end
|
||||
elseif ui.cfg.msg.target == 'cmd' and ui.cmd.level <= 0 then
|
||||
elseif ui.cfg.msg.target == 'cmd' and ui.cmd.level == 0 then
|
||||
ui.check_targets()
|
||||
set_virttext('msg')
|
||||
end
|
||||
|
||||
@@ -147,7 +147,7 @@ describe('cmdline2', function()
|
||||
end)
|
||||
|
||||
it('highlights after deleting buffer', function()
|
||||
feed(':%bw!<CR>:call foo()')
|
||||
feed(':sil %bw!<CR>:call foo()')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*12
|
||||
@@ -209,17 +209,17 @@ describe('cmdline2', function()
|
||||
{101:Foo()}{3: Fooo() }|
|
||||
{16::}{15:call} {25:Foo}{16:()}^ |
|
||||
]])
|
||||
feed('()')
|
||||
feed('<BS><BS>')
|
||||
exec('set wildoptions+=pum laststatus=2')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
{3: }|
|
||||
Foo() Fooo() |
|
||||
|
|
||||
{16::}{15:call} {25:Foo}{16:()()}^ |
|
||||
{16::}{15:call} Foo^ |
|
||||
]])
|
||||
exec('set wildoptions+=pum laststatus=2')
|
||||
feed('<C-U>call Fo<C-Z><C-Z>')
|
||||
feed('<C-Z><C-Z>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
@@ -228,15 +228,6 @@ describe('cmdline2', function()
|
||||
{4: Fooo() } |
|
||||
{16::}{15:call} {25:Foo}{16:()}^ |
|
||||
]])
|
||||
feed('()')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
{3: }|
|
||||
Foo() Fooo() |
|
||||
|
|
||||
{16::}{15:call} {25:Foo}{16:()()}^ |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
@@ -612,4 +612,47 @@ describe('messages2', function()
|
||||
{1:~ }|*5
|
||||
]])
|
||||
end)
|
||||
|
||||
it('while cmdline is open', function()
|
||||
command('cnoremap <C-A> <Cmd>lua error("foo")<CR>')
|
||||
feed(':echo "bar"<C-A>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*7
|
||||
{3: }|
|
||||
{9:E5108: Lua: [string ":lua"]:1: foo} |
|
||||
{9:stack traceback:} |
|
||||
{9: [C]: in function 'error'} |
|
||||
{9: [string ":lua"]:1: in main chunk} |
|
||||
{16::}{15:echo} {26:"bar"}^ |
|
||||
]])
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*12
|
||||
bar |
|
||||
]])
|
||||
command('set cmdheight=0')
|
||||
feed([[:call confirm("foo\nbar")<C-A>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*8
|
||||
{1:~ }{9:E5108: Lua: [string ":lua"]:1: foo}{4: }|
|
||||
{1:~ }{9:stack traceback:}{4: }|
|
||||
{1:~ }{9: [C]: in function 'error'}{4: }|
|
||||
{1:~ }{9: [string ":lua"]:1: in main chunk}|
|
||||
{16::}{15:call} {25:confirm}{16:(}{26:"foo\nbar"}{16:)}^ |
|
||||
]])
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*7
|
||||
{3: }|
|
||||
|
|
||||
{6:foo} |
|
||||
{6:bar} |
|
||||
|
|
||||
{6:[O]k: }^ |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user