diff --git a/runtime/lua/vim/_core/ui2/cmdline.lua b/runtime/lua/vim/_core/ui2/cmdline.lua index 2260d85819..aa9d48538f 100644 --- a/runtime/lua/vim/_core/ui2/cmdline.lua +++ b/runtime/lua/vim/_core/ui2/cmdline.lua @@ -96,7 +96,7 @@ function M.cmdline_show(content, pos, firstc, prompt, indent, level, hl_id) if M.level == 0 and ui.msg.cmd_on_key then M.expand, M.dialog, ui.msg.cmd_on_key = 1, true, nil api.nvim_win_set_config(ui.wins.cmd, { border = 'none' }) - ui.msg.expand_msg('cmd') + ui.msg.expand_msg('cmd', 'dialog') elseif ui.msg.cmd.msg_row ~= -1 and M.expand == 0 then ui.msg.msg_clear() end diff --git a/runtime/lua/vim/_core/ui2/messages.lua b/runtime/lua/vim/_core/ui2/messages.lua index 1cc64afc22..9fc01aaa42 100644 --- a/runtime/lua/vim/_core/ui2/messages.lua +++ b/runtime/lua/vim/_core/ui2/messages.lua @@ -86,7 +86,12 @@ end ---@param type 'last'|'msg'|'top'|'bot' ---@param tgt? 'cmd'|'msg'|'dialog' local function set_virttext(type, tgt) - if (type == 'last' and (ui.cmdheight == 0 or M.virt.delayed)) or M.cmd_on_key then + if + -- Cannot show with 0 'cmdheight' and delay for error. + (type == 'last' and (ui.cmdheight == 0 or M.virt.delayed)) + -- Do not overwrite temporary spill indicator during expanded cmdline. + or (M.cmd_on_key and type == 'msg') + then return -- Don't show virtual text while cmdline is expanded or delaying for error. end @@ -192,12 +197,12 @@ end local hlopts = { undo_restore = false, invalidate = true, priority = 1 } --- Move messages to expanded cmdline, dialog or pager to show in full. -function M.expand_msg(src) +function M.expand_msg(src, tgt) -- Copy and clear message from src to enlarged cmdline that is dismissed by any -- key press. Append to pager instead if it isn't hidden or we want to enter it -- after cmdline was entered during expanded cmdline. local hidden = api.nvim_win_get_config(ui.wins.pager).hide - local tgt = (src == 'dialog' or not hidden) and 'pager' or ui.cmd.expand > 0 and 'dialog' or 'cmd' + tgt = tgt or not hidden and 'pager' or 'cmd' if tgt ~= src then local srow = hidden and 0 or api.nvim_buf_line_count(ui.bufs.pager) local opts = { details = true, type = 'highlight' } @@ -428,7 +433,7 @@ function M.msg_show(kind, content, replace_last, _, append, id, trigger) -- When message was emitted below an already expanded cmdline, move and route to pager. tgt = ui.cmd.expand > 0 and 'pager' or tgt if ui.cmd.expand == 1 then - M.expand_msg('dialog') + M.expand_msg('dialog', 'pager') end ui.cmd.expand = ui.cmd.expand + (ui.cmd.expand > 0 and 1 or 0) @@ -476,7 +481,7 @@ end --- ---@param content MsgContent function M.msg_ruler(content) - M.virt.last[M.virt.idx.ruler] = ui.cmd.level > 0 and {} or content + M.virt.last[M.virt.idx.ruler] = (ui.cmd.level > 0 or M.cmd_on_key) and {} or content set_virttext('last') end @@ -493,7 +498,6 @@ function M.msg_history_show(entries, prev_cmd) -- Showing output of previous command, clear in case still visible. if M.cmd_on_key or prev_cmd then M.msg_clear() - api.nvim_feedkeys(vim.keycode(''), 'n', false) end api.nvim_buf_set_lines(ui.bufs.pager, 0, -1, false, {}) @@ -505,28 +509,33 @@ function M.msg_history_show(entries, prev_cmd) M.set_pos('pager') end -local cmd_on_key = function(_, typed) +local typed_g = false +local cmd_on_key = function(key, typed) typed = typed and fn.keytrans(typed) - if not typed or typed == '' or typed == ':' then - if typed == ':' then - vim.on_key(nil, ui.ns) - end + -- Don't dismiss for non-typed keys and mouse movement. When 'g' is passed (typed + -- or mapped), wait until the next key to avoid flickering when the pager is opened. + if not typed_g and (not typed or typed == '' or typed == 'g' or key == 'g') then + typed_g = typed == 'g' or key == 'g' return end vim.on_key(nil, ui.ns) - M.cmd_on_key, M.cmd.ids = nil, {} + if typed == ':' then + return -- Keep expanded messages open until cmdline closes. + end -- Check if window was entered and reopen with original config. - local entered = typed == '' and not api.nvim_get_mode().mode:match('[it]') - or typed:find('LeftMouse') and fn.getmousepos().winid == ui.wins.cmd + local mode = not api.nvim_get_mode().mode:match('[it]') + local entered = mode and (typed == '' or typed_g and (typed == '' or key == '<')) + or (typed:find('LeftMouse') and fn.getmousepos().winid == ui.wins.cmd) + if entered then + M.expand_msg('cmd', 'pager') + end pcall(api.nvim_win_close, ui.wins.cmd, true) ui.check_targets() - - -- Show or clear the message depending on if the pager was opened. - if entered then - api.nvim_command('norm! g<') - end set_virttext('msg') + api.nvim__redraw({ flush = true }) + + typed_g, M.cmd_on_key, M.cmd.ids = false, nil, {} return entered and '' end @@ -593,6 +602,8 @@ local function enter_pager() in_pager, was_cmdwin = true, fn.getcmdwintype() if was_cmdwin ~= '' then api.nvim_command('quit') + elseif M.cmd_on_key then + api.nvim_feedkeys(vim.keycode(''), 'n', false) end -- Cmdwin is closed one event iteration later so schedule in case it was open. vim.schedule(function() diff --git a/test/functional/ui/messages2_spec.lua b/test/functional/ui/messages2_spec.lua index 4bc5ae186f..179cd4b008 100644 --- a/test/functional/ui/messages2_spec.lua +++ b/test/functional/ui/messages2_spec.lua @@ -39,7 +39,7 @@ describe('messages2', function() end) it('multiline messages and pager', function() - command('echo "foo\nbar"') + command('set ruler showcmd noshowmode | echo "foo\nbar"') screen:expect([[ ^ | {1:~ }|*10 @@ -47,8 +47,15 @@ describe('messages2', function() foo | bar | ]]) - command('set ruler showcmd noshowmode') - feed('g') + feed('g') + screen:expect([[ + ^ | + {1:~ }|*10 + {3: }| + foo | + bar g | + ]]) + feed('') screen:expect([[ | {1:~ }|*9 @@ -76,7 +83,7 @@ describe('messages2', function() screen:expect([[ ^ | {1:~ }|*12 - foo [+29] 0,0-1 All| + foo [+29] | ]]) command('echo "foo"') -- New message clears spill indicator. @@ -835,7 +842,7 @@ describe('messages2', function() - cCommentL | ]]) feed('Q') - screen:expect_unchanged() + screen:expect_unchanged(true) feed('') -- close expanded cmdline set_msg_target_zero_ch() api.nvim_echo({ { 'foo' } }, true, { id = 1 })