mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 04:42:03 +00:00
feat(ui2): configure targets per message kind #38091
Problem: Unable to configure message targets based on message kind.
Solution: Add cfg.msg.targets mapping message kinds to "cmd/msg/pager".
Check the configured target when writing the message.
cfg.msg = { target = 'cmd', targets = { progress = 'msg', list_cmd = 'pager' } }
will for example use the 'msg' target for progress messages,
immediately open the pager for 'list_cmd' and use the cmdline
for all other message kinds.
This commit is contained in:
@@ -5285,9 +5285,11 @@ To enable the experimental UI (default opts shown): >lua
|
||||
require('vim._core.ui2').enable({
|
||||
enable = true, -- Whether to enable or disable the UI.
|
||||
msg = { -- Options related to the message module.
|
||||
---@type 'cmd'|'msg' Where to place regular messages, either in the
|
||||
---@type 'cmd'|'msg' Default message target, either in the
|
||||
---cmdline or in a separate ephemeral message window.
|
||||
target = 'cmd',
|
||||
---@type string|table<string, 'cmd'|'msg'|'pager'> Default message target
|
||||
or table mapping |ui-messages| kinds to a target.
|
||||
targets = 'cmd',
|
||||
timeout = 4000, -- Time a message is visible in the message window.
|
||||
},
|
||||
})
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
---require('vim._core.ui2').enable({
|
||||
--- enable = true, -- Whether to enable or disable the UI.
|
||||
--- msg = { -- Options related to the message module.
|
||||
--- ---@type 'cmd'|'msg' Where to place regular messages, either in the
|
||||
--- ---@type 'cmd'|'msg' Default message target, either in the
|
||||
--- ---cmdline or in a separate ephemeral message window.
|
||||
--- target = 'cmd',
|
||||
--- ---@type string|table<string, 'cmd'|'msg'|'pager'> Default message target
|
||||
--- or table mapping |ui-messages| kinds to a target.
|
||||
--- targets = 'cmd',
|
||||
--- timeout = 4000, -- Time a message is visible in the message window.
|
||||
--- },
|
||||
---})
|
||||
@@ -43,9 +45,8 @@ local M = {
|
||||
cfg = {
|
||||
enable = true,
|
||||
msg = { -- Options related to the message module.
|
||||
---@type 'cmd'|'msg' Where to place regular messages, either in the
|
||||
---cmdline or in a separate ephemeral message window.
|
||||
target = 'cmd',
|
||||
target = 'cmd', ---@type 'cmd'|'msg' Default message target if not present in targets.
|
||||
targets = {}, ---@type table<string, 'cmd'|'msg'|'pager'> Kind specific message targets.
|
||||
timeout = 4000, -- Time a message is visible in the message window.
|
||||
},
|
||||
},
|
||||
@@ -160,6 +161,8 @@ local scheduled_ui_callback = vim.schedule_wrap(ui_callback)
|
||||
function M.enable(opts)
|
||||
vim.validate('opts', opts, 'table', true)
|
||||
M.cfg = vim.tbl_deep_extend('keep', opts, M.cfg)
|
||||
M.cfg.msg.target = type(M.cfg.msg.targets) == 'string' and M.cfg.msg.targets or M.cfg.msg.target
|
||||
M.cfg.msg.targets = type(M.cfg.msg.targets) == 'table' and M.cfg.msg.targets or {}
|
||||
if #vim.api.nvim_list_uis() == 0 then
|
||||
return -- Don't prevent stdout messaging when no UIs are attached.
|
||||
end
|
||||
|
||||
@@ -216,8 +216,6 @@ local function expand_msg(src)
|
||||
|
||||
if tgt == 'cmd' and ui.cmd.highlighter then
|
||||
ui.cmd.highlighter.active[ui.bufs.cmd] = nil
|
||||
elseif tgt == 'pager' then
|
||||
api.nvim_command('norm! G')
|
||||
end
|
||||
else
|
||||
M.virt.msg[M.virt.idx.dupe][1] = nil
|
||||
@@ -329,7 +327,6 @@ function M.show_msg(tgt, kind, content, replace_last, append, id)
|
||||
if texth.all > math.ceil(o.lines * 0.5) then
|
||||
expand_msg(tgt)
|
||||
else
|
||||
M.set_pos('msg')
|
||||
M.msg.width = width
|
||||
M.msg:start_timer(buf, id)
|
||||
end
|
||||
@@ -358,6 +355,11 @@ function M.show_msg(tgt, kind, content, replace_last, append, id)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set pager/dialog/msg dimensions unless sent to expanded cmdline.
|
||||
if tgt ~= 'cmd' and (tgt ~= 'msg' or M.msg.ids[id]) then
|
||||
M.set_pos(tgt)
|
||||
end
|
||||
|
||||
if M[tgt] and (tgt == 'cmd' or row == api.nvim_buf_line_count(buf) - 1) then
|
||||
-- Place (x) indicator for repeated messages. Mainly to mitigate unnecessary
|
||||
-- resizing of the message window, but also placed in the cmdline.
|
||||
@@ -385,7 +387,12 @@ end
|
||||
---@param append boolean
|
||||
---@param id integer|string
|
||||
function M.msg_show(kind, content, replace_last, _, append, id)
|
||||
if kind == 'empty' then
|
||||
-- Set the entered search command in the cmdline (if available).
|
||||
local tgt = kind == 'search_cmd' and 'cmd' or ui.cfg.msg.targets[kind] or ui.cfg.msg.target
|
||||
if kind == 'search_cmd' and ui.cmdheight == 0 then
|
||||
-- Blocked by messaging() without ext_messages. TODO: look at other messaging() guards.
|
||||
return
|
||||
elseif kind == 'empty' then
|
||||
-- A sole empty message clears the cmdline.
|
||||
if ui.cfg.msg.target == 'cmd' and not next(M.cmd.ids) and ui.cmd.srow == 0 then
|
||||
M.msg_clear()
|
||||
@@ -398,9 +405,7 @@ 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 (ui.cmd.level > 0 and ui.cfg.msg.target == 'cmd')) and ui.cmd.srow == 0
|
||||
then
|
||||
elseif (ui.cmd.prompt or (ui.cmd.level > 0 and tgt == '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
|
||||
@@ -408,14 +413,8 @@ function M.msg_show(kind, content, replace_last, _, append, id)
|
||||
end
|
||||
ui.cmd.dialog = true -- Ensure dialog is closed when cmdline is hidden.
|
||||
M.show_msg('dialog', kind, content, replace_last, append, id)
|
||||
M.set_pos('dialog')
|
||||
else
|
||||
-- Set the entered search command in the cmdline (if available).
|
||||
local tgt = kind == 'search_cmd' and 'cmd' or ui.cfg.msg.target
|
||||
if kind == 'search_cmd' and ui.cmdheight == 0 then
|
||||
-- Blocked by messaging() without ext_messages. TODO: look at other messaging() guards.
|
||||
return
|
||||
elseif tgt == 'cmd' then
|
||||
if tgt == 'cmd' then
|
||||
-- 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.
|
||||
M.cmd.last_emsg = (kind == 'emsg' or kind == 'wmsg') and os.time() or M.cmd.last_emsg
|
||||
@@ -423,10 +422,13 @@ function M.msg_show(kind, content, replace_last, _, append, id)
|
||||
M.virt.last[M.virt.idx.search][1] = nil
|
||||
end
|
||||
|
||||
M.show_msg(tgt, kind, content, replace_last, append, id)
|
||||
local enter_pager = tgt == 'pager' and api.nvim_get_current_win() ~= ui.wins.pager
|
||||
M.show_msg(tgt, kind, content, replace_last or enter_pager, append, id)
|
||||
-- Don't remember search_cmd message as actual message.
|
||||
if kind == 'search_cmd' then
|
||||
M.cmd.ids, M.prev_msg = {}, ''
|
||||
elseif api.nvim_get_current_win() == ui.wins.pager and not enter_pager then
|
||||
api.nvim_command('norm! G')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -522,7 +524,7 @@ function M.set_pos(tgt)
|
||||
return
|
||||
end
|
||||
vim.on_key(nil, ui.ns)
|
||||
cmd_on_key, M[ui.cfg.msg.target].ids = nil, {}
|
||||
cmd_on_key, M.cmd.ids = nil, {}
|
||||
|
||||
-- Check if window was entered and reopen with original config.
|
||||
local entered = typed == '<CR>'
|
||||
@@ -581,8 +583,7 @@ function M.set_pos(tgt)
|
||||
end, M.dialog_on_key)
|
||||
elseif tgt == 'msg' then
|
||||
-- Ensure last line is visible and first line is at top of window.
|
||||
local row = (texth.all > cfg.height and texth.end_row or 0) + 1
|
||||
api.nvim_win_set_cursor(ui.wins.msg, { row, 0 })
|
||||
fn.win_execute(ui.wins.msg, 'norm! Gzb')
|
||||
elseif tgt == 'pager' and api.nvim_get_current_win() ~= ui.wins.pager then
|
||||
if fn.getcmdwintype() ~= '' then
|
||||
-- Cannot leave the cmdwin to enter the pager, so close it.
|
||||
|
||||
@@ -4,7 +4,7 @@ local t = require('test.testutil')
|
||||
local n = require('test.functional.testnvim')()
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local clear, command, exec_lua, feed = n.clear, n.command, n.exec_lua, n.feed
|
||||
local api, clear, command, exec_lua, feed = n.api, n.clear, n.command, n.exec_lua, n.feed
|
||||
|
||||
local msg_timeout = 200
|
||||
local function set_msg_target_zero_ch()
|
||||
@@ -631,18 +631,14 @@ describe('messages2', function()
|
||||
baz |
|
||||
foo |
|
||||
]])
|
||||
exec_lua(function()
|
||||
vim.api.nvim_echo({ { 'foo' } }, true, { id = 2 })
|
||||
end)
|
||||
api.nvim_echo({ { 'foo' } }, true, { id = 2 })
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*9
|
||||
{3: }|
|
||||
foo |*3
|
||||
]])
|
||||
exec_lua(function()
|
||||
vim.api.nvim_echo({ { 'bar\nbaz' } }, true, { id = 1 })
|
||||
end)
|
||||
api.nvim_echo({ { 'bar\nbaz' } }, true, { id = 1 })
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*8
|
||||
@@ -653,7 +649,7 @@ describe('messages2', function()
|
||||
]])
|
||||
-- Pressing a key immediately dismisses an expanded cmdline, and
|
||||
-- replacing a multiline, multicolored message doesn't error due
|
||||
-- to unneccesarily inserted lines #37994.
|
||||
-- to unnecessarily inserted lines #37994.
|
||||
feed('Q')
|
||||
screen:expect([[
|
||||
^ |
|
||||
@@ -664,12 +660,11 @@ describe('messages2', function()
|
||||
]])
|
||||
feed('Q')
|
||||
screen:expect_unchanged()
|
||||
feed('<C-L>') -- close expanded cmdline
|
||||
set_msg_target_zero_ch()
|
||||
exec_lua(function()
|
||||
vim.api.nvim_echo({ { 'foo' } }, true, { id = 1 })
|
||||
vim.api.nvim_echo({ { 'bar\nbaz' } }, true, { id = 2 })
|
||||
vim.api.nvim_echo({ { 'foo' } }, true, { id = 3 })
|
||||
end)
|
||||
api.nvim_echo({ { 'foo' } }, true, { id = 1 })
|
||||
api.nvim_echo({ { 'bar\nbaz' } }, true, { id = 2 })
|
||||
api.nvim_echo({ { 'foo' } }, true, { id = 3 })
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*9
|
||||
@@ -678,17 +673,13 @@ describe('messages2', function()
|
||||
{1:~ }{4:baz}|
|
||||
{1:~ }{4:foo}|
|
||||
]])
|
||||
exec_lua(function()
|
||||
vim.api.nvim_echo({ { 'foo' } }, true, { id = 2 })
|
||||
end)
|
||||
api.nvim_echo({ { 'foo' } }, true, { id = 2 })
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*10
|
||||
{1:~ }{4:foo}|*3
|
||||
]])
|
||||
exec_lua(function()
|
||||
vim.api.nvim_echo({ { 'f', 'Conceal' }, { 'oo\nbar' } }, true, { id = 3 })
|
||||
end)
|
||||
api.nvim_echo({ { 'f', 'Conceal' }, { 'oo\nbar' } }, true, { id = 3 })
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*9
|
||||
@@ -704,7 +695,7 @@ describe('messages2', function()
|
||||
{1:~ }|
|
||||
{3: }|
|
||||
foo |*2
|
||||
{14:f}oo |
|
||||
{14:f}oo [+6] |
|
||||
]])
|
||||
feed('<Esc>')
|
||||
screen:expect([[
|
||||
@@ -782,5 +773,56 @@ describe('messages2', function()
|
||||
{1:~ }|*12
|
||||
{1:~ }{4:baz}|
|
||||
]])
|
||||
-- Last message line is at bottom of window after closing it.
|
||||
screen:try_resize(screen._width, 8)
|
||||
command('mode | echo "1\n" | echo "2\n" | echo "3\n" | echo "4\n"')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*3
|
||||
{1:~ }{4:3}|
|
||||
{1:~ }{4: }|
|
||||
{1:~ }{4:4}|
|
||||
{1:~ }{4: }|
|
||||
]])
|
||||
command('fclose!')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*7
|
||||
]])
|
||||
command('echo "5\n"')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*3
|
||||
{1:~ }{4:4}|
|
||||
{1:~ }{4: }|
|
||||
{1:~ }{4:5}|
|
||||
{1:~ }{4: }|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('configured targets per kind', function()
|
||||
exec_lua(function()
|
||||
local cfg = { msg = { targets = { echo = 'msg', list_cmd = 'pager' } } }
|
||||
require('vim._core.ui2').enable(cfg)
|
||||
print('foo') -- "lua_print" kind goes to cmd
|
||||
vim.cmd.echo('"bar"') -- "echo" kind goes to msg
|
||||
vim.cmd.highlight('VisualNC') -- "list_cmd" kind goes to pager
|
||||
end)
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*10
|
||||
{3: }|
|
||||
^VisualNC xxx cleared {4:bar}|
|
||||
foo |
|
||||
]])
|
||||
command('hi VisualNC') -- cursor moved to last message in pager
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*9
|
||||
{3: }|
|
||||
VisualNC xxx cleared |
|
||||
^VisualNC xxx cleared {4:bar}|
|
||||
foo |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user