mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
docs(extui): rename box->msg, more->pager, prompt->dialog
Includes breaking changes to the `opts` layout. "box" doesn't really describe anything other than a floating window so was an unwanted synonym.
This commit is contained in:
@@ -2683,12 +2683,10 @@ To enable the experimental UI (default opts shown): >lua
|
|||||||
require('vim._extui').enable({
|
require('vim._extui').enable({
|
||||||
enable = true, -- Whether to enable or disable the UI.
|
enable = true, -- Whether to enable or disable the UI.
|
||||||
msg = { -- Options related to the message module.
|
msg = { -- Options related to the message module.
|
||||||
---@type 'box'|'cmd' Type of window used to place messages, either in the
|
---@type 'cmd'|'msg' Where to place regular messages, either in the
|
||||||
---cmdline or in a separate message box window with ephemeral messages.
|
---cmdline or in a separate ephemeral message window.
|
||||||
pos = 'cmd',
|
target = 'cmd',
|
||||||
box = { -- Options related to the message box window.
|
timeout = 4000, -- Time a message is visible in the message window.
|
||||||
timeout = 4000, -- Time a message is visible.
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
<
|
<
|
||||||
@@ -2696,15 +2694,15 @@ To enable the experimental UI (default opts shown): >lua
|
|||||||
There are four separate window types used by this interface:
|
There are four separate window types used by this interface:
|
||||||
• "cmd": The cmdline window; also used for 'showcmd', 'showmode', 'ruler', and
|
• "cmd": The cmdline window; also used for 'showcmd', 'showmode', 'ruler', and
|
||||||
messages if 'cmdheight' > 0.
|
messages if 'cmdheight' > 0.
|
||||||
• "box": The message box window; used for messages when 'cmdheight' == 0.
|
• "msg": The message window; used for messages when 'cmdheight' == 0.
|
||||||
• "more": The more-prompt window; used for |:messages| and certain messages
|
• "pager": The pager window; used for |:messages| and certain messages that
|
||||||
that should be shown in full.
|
should be shown in full.
|
||||||
• "prompt": The cmdline prompt window; used for prompt messages that expect
|
• "dialog": The dialog window; used for prompt messages that expect user
|
||||||
user input.
|
input.
|
||||||
|
|
||||||
These four windows are assigned the "cmdline", "msgbox", "msgmore" and
|
These four windows are assigned the "cmd", "msg", "pager" and "dialog"
|
||||||
"msgprompt" 'filetype' respectively. Use a |FileType| autocommand to configure
|
'filetype' respectively. Use a |FileType| autocommand to configure any local
|
||||||
any local options for these windows and their respective buffers.
|
options for these windows and their respective buffers.
|
||||||
|
|
||||||
Rather than a |hit-enter-prompt|, messages shown in the cmdline area that do
|
Rather than a |hit-enter-prompt|, messages shown in the cmdline area that do
|
||||||
not fit are appended with a `[+x]` "spill" indicator, where `x` indicates the
|
not fit are appended with a `[+x]` "spill" indicator, where `x` indicates the
|
||||||
|
@@ -8,12 +8,10 @@
|
|||||||
---require('vim._extui').enable({
|
---require('vim._extui').enable({
|
||||||
--- enable = true, -- Whether to enable or disable the UI.
|
--- enable = true, -- Whether to enable or disable the UI.
|
||||||
--- msg = { -- Options related to the message module.
|
--- msg = { -- Options related to the message module.
|
||||||
--- ---@type 'box'|'cmd' Type of window used to place messages, either in the
|
--- ---@type 'cmd'|'msg' Where to place regular messages, either in the
|
||||||
--- ---cmdline or in a separate message box window with ephemeral messages.
|
--- ---cmdline or in a separate ephemeral message window.
|
||||||
--- pos = 'cmd',
|
--- target = 'cmd',
|
||||||
--- box = { -- Options related to the message box window.
|
--- timeout = 4000, -- Time a message is visible in the message window.
|
||||||
--- timeout = 4000, -- Time a message is visible.
|
|
||||||
--- },
|
|
||||||
--- },
|
--- },
|
||||||
---})
|
---})
|
||||||
---```
|
---```
|
||||||
@@ -21,15 +19,14 @@
|
|||||||
---There are four separate window types used by this interface:
|
---There are four separate window types used by this interface:
|
||||||
---- "cmd": The cmdline window; also used for 'showcmd', 'showmode', 'ruler', and
|
---- "cmd": The cmdline window; also used for 'showcmd', 'showmode', 'ruler', and
|
||||||
--- messages if 'cmdheight' > 0.
|
--- messages if 'cmdheight' > 0.
|
||||||
---- "box": The message box window; used for messages when 'cmdheight' == 0.
|
---- "msg": The message window; used for messages when 'cmdheight' == 0.
|
||||||
---- "more": The more-prompt window; used for |:messages| and certain messages
|
---- "pager": The pager window; used for |:messages| and certain messages
|
||||||
--- that should be shown in full.
|
--- that should be shown in full.
|
||||||
---- "prompt": The cmdline prompt window; used for prompt messages that expect
|
---- "dialog": The dialog window; used for prompt messages that expect user input.
|
||||||
--- user input.
|
|
||||||
---
|
---
|
||||||
---These four windows are assigned the "cmdline", "msgbox", "msgmore" and
|
---These four windows are assigned the "cmd", "msg", "pager" and "dialog"
|
||||||
---"msgprompt" 'filetype' respectively. Use a |FileType| autocommand to configure
|
---'filetype' respectively. Use a |FileType| autocommand to configure any local
|
||||||
---any local options for these windows and their respective buffers.
|
---options for these windows and their respective buffers.
|
||||||
---
|
---
|
||||||
---Rather than a |hit-enter-prompt|, messages shown in the cmdline area that do
|
---Rather than a |hit-enter-prompt|, messages shown in the cmdline area that do
|
||||||
---not fit are appended with a `[+x]` "spill" indicator, where `x` indicates the
|
---not fit are appended with a `[+x]` "spill" indicator, where `x` indicates the
|
||||||
@@ -59,6 +56,10 @@ local scheduled_ui_callback = vim.schedule_wrap(ui_callback)
|
|||||||
---@nodoc
|
---@nodoc
|
||||||
function M.enable(opts)
|
function M.enable(opts)
|
||||||
vim.validate('opts', opts, 'table', true)
|
vim.validate('opts', opts, 'table', true)
|
||||||
|
if opts.msg then
|
||||||
|
vim.validate('opts.msg.pos', opts.msg.pos, 'nil', true, 'nil: "pos" moved to opts.target')
|
||||||
|
vim.validate('opts.msg.box', opts.msg.box, 'nil', true, 'nil: "timeout" moved to opts.msg')
|
||||||
|
end
|
||||||
ext.cfg = vim.tbl_deep_extend('keep', opts, ext.cfg)
|
ext.cfg = vim.tbl_deep_extend('keep', opts, ext.cfg)
|
||||||
|
|
||||||
if ext.cfg.enable == false then
|
if ext.cfg.enable == false then
|
||||||
@@ -84,13 +85,13 @@ function M.enable(opts)
|
|||||||
|
|
||||||
-- Use MsgArea and hide search highlighting in the cmdline window.
|
-- Use MsgArea and hide search highlighting in the cmdline window.
|
||||||
-- TODO: Add new highlight group/namespaces for other windows? It is
|
-- TODO: Add new highlight group/namespaces for other windows? It is
|
||||||
-- not clear if MsgArea is wanted in the box, more and prompt windows.
|
-- not clear if MsgArea is wanted in the msg, pager and dialog windows.
|
||||||
api.nvim_set_hl(ext.ns, 'Normal', { link = 'MsgArea' })
|
api.nvim_set_hl(ext.ns, 'Normal', { link = 'MsgArea' })
|
||||||
api.nvim_set_hl(ext.ns, 'Search', { link = 'MsgArea' })
|
api.nvim_set_hl(ext.ns, 'Search', { link = 'MsgArea' })
|
||||||
api.nvim_set_hl(ext.ns, 'CurSearch', { link = 'MsgArea' })
|
api.nvim_set_hl(ext.ns, 'CurSearch', { link = 'MsgArea' })
|
||||||
api.nvim_set_hl(ext.ns, 'IncSearch', { link = 'MsgArea' })
|
api.nvim_set_hl(ext.ns, 'IncSearch', { link = 'MsgArea' })
|
||||||
|
|
||||||
-- The visibility and appearance of the cmdline and message box window is
|
-- The visibility and appearance of the cmdline and message window is
|
||||||
-- dependent on some option values. Reconfigure windows when option value
|
-- dependent on some option values. Reconfigure windows when option value
|
||||||
-- has changed and after VimEnter when the user configured value is known.
|
-- has changed and after VimEnter when the user configured value is known.
|
||||||
-- TODO: Reconsider what is needed when this module is enabled by default early in startup.
|
-- TODO: Reconsider what is needed when this module is enabled by default early in startup.
|
||||||
@@ -101,7 +102,7 @@ function M.enable(opts)
|
|||||||
api.nvim_win_set_config(ext.wins.cmd, cfg)
|
api.nvim_win_set_config(ext.wins.cmd, cfg)
|
||||||
-- Change message position when 'cmdheight' was or becomes 0.
|
-- Change message position when 'cmdheight' was or becomes 0.
|
||||||
if value == 0 or ext.cmdheight == 0 then
|
if value == 0 or ext.cmdheight == 0 then
|
||||||
ext.cfg.msg.pos = value == 0 and 'box' or ext.cmdheight == 0 and 'cmd'
|
ext.cfg.msg.target = value == 0 and 'msg' or 'cmd'
|
||||||
ext.msg.prev_msg = ''
|
ext.msg.prev_msg = ''
|
||||||
end
|
end
|
||||||
ext.cmdheight = value
|
ext.cmdheight = value
|
||||||
|
@@ -4,7 +4,7 @@ local api, fn = vim.api, vim.fn
|
|||||||
local M = {
|
local M = {
|
||||||
highlighter = nil, ---@type vim.treesitter.highlighter?
|
highlighter = nil, ---@type vim.treesitter.highlighter?
|
||||||
indent = 0, -- Current indent for block event.
|
indent = 0, -- Current indent for block event.
|
||||||
prompt = false, -- Whether a prompt is active; messages are placed in the 'prompt' window.
|
prompt = false, -- Whether a prompt is active; messages are placed in the 'dialog' window.
|
||||||
row = 0, -- Current row in the cmdline buffer, > 0 for block events.
|
row = 0, -- Current row in the cmdline buffer, > 0 for block events.
|
||||||
level = -1, -- Current cmdline level, 0 when inactive, -1 one loop iteration after closing.
|
level = -1, -- Current cmdline level, 0 when inactive, -1 one loop iteration after closing.
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ function M.cmdline_show(content, pos, firstc, prompt, indent, level, hl_id)
|
|||||||
M.cmdline_pos(pos)
|
M.cmdline_pos(pos)
|
||||||
|
|
||||||
-- Clear message cmdline state; should not be shown during, and reset after cmdline.
|
-- Clear message cmdline state; should not be shown during, and reset after cmdline.
|
||||||
if ext.cfg.msg.pos == 'cmd' and ext.msg.cmd.msg_row ~= -1 then
|
if ext.cfg.msg.target == 'cmd' and ext.msg.cmd.msg_row ~= -1 then
|
||||||
ext.msg.prev_msg, ext.msg.dupe, ext.msg.cmd.msg_row = '', 0, -1
|
ext.msg.prev_msg, ext.msg.dupe, ext.msg.cmd.msg_row = '', 0, -1
|
||||||
api.nvim_buf_clear_namespace(ext.bufs.cmd, ext.ns, 0, -1)
|
api.nvim_buf_clear_namespace(ext.bufs.cmd, ext.ns, 0, -1)
|
||||||
ext.msg.virt.msg = { {}, {} }
|
ext.msg.virt.msg = { {}, {} }
|
||||||
@@ -129,7 +129,8 @@ function M.cmdline_hide(_, abort)
|
|||||||
-- loop iteration. E.g. when a non-choice confirm button is pressed.
|
-- loop iteration. E.g. when a non-choice confirm button is pressed.
|
||||||
if was_prompt and not M.prompt then
|
if was_prompt and not M.prompt then
|
||||||
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
||||||
api.nvim_win_set_config(ext.wins.prompt, { hide = true })
|
api.nvim_buf_set_lines(ext.bufs.dialog, 0, -1, false, {})
|
||||||
|
api.nvim_win_set_config(ext.wins.dialog, { hide = true })
|
||||||
end
|
end
|
||||||
-- Messages emitted as a result of a typed command are treated specially:
|
-- Messages emitted as a result of a typed command are treated specially:
|
||||||
-- remember if the cmdline was used this event loop iteration.
|
-- remember if the cmdline was used this event loop iteration.
|
||||||
|
@@ -3,13 +3,13 @@ local ext = require('vim._extui.shared')
|
|||||||
|
|
||||||
---@class vim._extui.messages
|
---@class vim._extui.messages
|
||||||
local M = {
|
local M = {
|
||||||
-- Message box window. Used for regular messages with 'cmdheight' == 0 or,
|
-- Message window. Used for regular messages with 'cmdheight' == 0 or,
|
||||||
-- cfg.msg.pos == 'box'. Also used for verbose messages regardless of
|
-- cfg.msg.target == 'msg'. Also used for verbose messages regardless of
|
||||||
-- cfg.msg.pos. Automatically resizes to the text dimensions up to a point,
|
-- cfg.msg.target. Automatically resizes to the text dimensions up to a point,
|
||||||
-- at which point only the most recent messages will fit and be shown.
|
-- at which point only the most recent messages will fit and be shown.
|
||||||
-- A timer is started for each message whose callback will remove the message
|
-- A timer is started for each message whose callback will remove the message
|
||||||
-- from the window again.
|
-- from the window again.
|
||||||
box = {
|
msg = {
|
||||||
count = 0, -- Number of messages currently in the message window.
|
count = 0, -- Number of messages currently in the message window.
|
||||||
width = 1, -- Current width of the message window.
|
width = 1, -- Current width of the message window.
|
||||||
timer = nil, ---@type uv.uv_timer_t Timer that removes the most recent message.
|
timer = nil, ---@type uv.uv_timer_t Timer that removes the most recent message.
|
||||||
@@ -36,12 +36,12 @@ local M = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function M.box:close()
|
function M.msg:close()
|
||||||
self.width, M.virt.msg = 1, { {}, {} }
|
self.width, M.virt.msg = 1, { {}, {} }
|
||||||
M.prev_msg = ext.cfg.msg.pos == 'box' and '' or M.prev_msg
|
M.prev_msg = ext.cfg.msg.target == 'msg' and '' or M.prev_msg
|
||||||
api.nvim_buf_clear_namespace(ext.bufs.box, -1, 0, -1)
|
api.nvim_buf_clear_namespace(ext.bufs.msg, -1, 0, -1)
|
||||||
if api.nvim_win_is_valid(ext.wins.box) then
|
if api.nvim_win_is_valid(ext.wins.msg) then
|
||||||
api.nvim_win_set_config(ext.wins.box, { hide = true })
|
api.nvim_win_set_config(ext.wins.msg, { hide = true })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -49,20 +49,20 @@ end
|
|||||||
---
|
---
|
||||||
---@param buf integer Buffer the message was written to.
|
---@param buf integer Buffer the message was written to.
|
||||||
---@param len integer Number of rows that should be removed.
|
---@param len integer Number of rows that should be removed.
|
||||||
function M.box:start_timer(buf, len)
|
function M.msg:start_timer(buf, len)
|
||||||
self.timer = vim.defer_fn(function()
|
self.timer = vim.defer_fn(function()
|
||||||
if self.count == 0 or not api.nvim_buf_is_valid(buf) then
|
if self.count == 0 or not api.nvim_buf_is_valid(buf) then
|
||||||
return -- Messages moved to more or buffer was closed.
|
return -- Messages moved to pager or buffer was closed.
|
||||||
end
|
end
|
||||||
api.nvim_buf_set_lines(buf, 0, len, false, {})
|
api.nvim_buf_set_lines(buf, 0, len, false, {})
|
||||||
self.count = self.count - 1
|
self.count = self.count - 1
|
||||||
-- Resize or hide message box for removed message.
|
-- Resize or hide message window for removed message.
|
||||||
if self.count > 0 then
|
if self.count > 0 then
|
||||||
M.set_pos('box')
|
M.set_pos('msg')
|
||||||
else
|
else
|
||||||
self:close()
|
self:close()
|
||||||
end
|
end
|
||||||
end, ext.cfg.msg.box.timeout)
|
end, ext.cfg.msg.timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Place or delete a virtual text mark in the cmdline or message window.
|
--- Place or delete a virtual text mark in the cmdline or message window.
|
||||||
@@ -88,11 +88,11 @@ local function set_virttext(type)
|
|||||||
M.virt.ids[type] = nil
|
M.virt.ids[type] = nil
|
||||||
M.cmd.last_col = type == 'last' and o.columns or M.cmd.last_col
|
M.cmd.last_col = type == 'last' and o.columns or M.cmd.last_col
|
||||||
elseif #chunks > 0 then
|
elseif #chunks > 0 then
|
||||||
local tar = type == 'msg' and ext.cfg.msg.pos or 'cmd'
|
local tar = type == 'msg' and ext.cfg.msg.target or 'cmd'
|
||||||
local win = ext.wins[tar]
|
local win = ext.wins[tar]
|
||||||
local max = api.nvim_win_get_height(win)
|
local max = api.nvim_win_get_height(win)
|
||||||
local erow = tar == 'cmd' and M.cmd.msg_row or nil
|
local erow = tar == 'cmd' and M.cmd.msg_row or nil
|
||||||
local srow = tar == 'box' and fn.line('w0', ext.wins.box) - 1 or nil
|
local srow = tar == 'msg' and fn.line('w0', ext.wins.msg) - 1 or nil
|
||||||
local h = api.nvim_win_text_height(win, { start_row = srow, end_row = erow, max_height = max })
|
local h = api.nvim_win_text_height(win, { start_row = srow, end_row = erow, max_height = max })
|
||||||
local row = h.end_row ---@type integer
|
local row = h.end_row ---@type integer
|
||||||
local col = fn.virtcol2col(win, row + 1, h.end_vcol)
|
local col = fn.virtcol2col(win, row + 1, h.end_vcol)
|
||||||
@@ -102,17 +102,17 @@ local function set_virttext(type)
|
|||||||
-- Calculate at which column to place the virt_text such that it is at the end
|
-- Calculate at which column to place the virt_text such that it is at the end
|
||||||
-- of the last visible message line, overlapping the message text if necessary,
|
-- of the last visible message line, overlapping the message text if necessary,
|
||||||
-- but not overlapping the 'last' virt_text.
|
-- but not overlapping the 'last' virt_text.
|
||||||
local offset = tar ~= 'box' and 0
|
local offset = tar ~= 'msg' and 0
|
||||||
or api.nvim_win_get_position(win)[2] + (api.nvim_win_get_config(win).border and 1 or 0)
|
or api.nvim_win_get_position(win)[2] + (api.nvim_win_get_config(win).border and 1 or 0)
|
||||||
|
|
||||||
-- Check if adding the virt_text on this line will exceed the current 'box' width.
|
-- Check if adding the virt_text on this line will exceed the current window width.
|
||||||
local boxwidth = math.max(M.box.width, math.min(o.columns, scol - offset + width))
|
local maxwidth = math.max(M.msg.width, math.min(o.columns, scol - offset + width))
|
||||||
if tar == 'box' and api.nvim_win_get_width(win) < boxwidth then
|
if tar == 'msg' and api.nvim_win_get_width(win) < maxwidth then
|
||||||
api.nvim_win_set_width(win, boxwidth)
|
api.nvim_win_set_width(win, maxwidth)
|
||||||
M.box.width = boxwidth
|
M.msg.width = maxwidth
|
||||||
end
|
end
|
||||||
|
|
||||||
local mwidth = tar == 'box' and M.box.width or M.cmd.last_col
|
local mwidth = tar == 'msg' and M.msg.width or M.cmd.last_col
|
||||||
if scol - offset + width > mwidth then
|
if scol - offset + width > mwidth then
|
||||||
col = fn.virtcol2col(win, row + 1, h.end_vcol - (scol - offset + width - mwidth))
|
col = fn.virtcol2col(win, row + 1, h.end_vcol - (scol - offset + width - mwidth))
|
||||||
end
|
end
|
||||||
@@ -174,45 +174,45 @@ end
|
|||||||
|
|
||||||
-- We need to keep track of the current message column to be able to
|
-- We need to keep track of the current message column to be able to
|
||||||
-- append or overwrite messages for :echon or carriage returns.
|
-- append or overwrite messages for :echon or carriage returns.
|
||||||
local col, will_more, hlopts = 0, false, { undo_restore = false, invalidate = true, priority = 1 }
|
local col, will_pager, hlopts = 0, false, { undo_restore = false, invalidate = true, priority = 1 }
|
||||||
--- Move message to more buffer, appending if window was already open.
|
--- Move message to pager, appending if window was already open.
|
||||||
local function msg_to_more(tar)
|
local function msg_to_pager(tar)
|
||||||
if will_more then
|
if will_pager then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
will_more, M.prev_msg = true, ''
|
will_pager, M.prev_msg = true, ''
|
||||||
|
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
local hidden = api.nvim_win_get_config(ext.wins.more).hide
|
local hidden = api.nvim_win_get_config(ext.wins.pager).hide
|
||||||
local marks = api.nvim_buf_get_extmarks(ext.bufs[tar], -1, 0, -1, { details = true })
|
local marks = api.nvim_buf_get_extmarks(ext.bufs[tar], -1, 0, -1, { details = true })
|
||||||
local lines = api.nvim_buf_get_lines(ext.bufs[tar], 0, -1, false)
|
local lines = api.nvim_buf_get_lines(ext.bufs[tar], 0, -1, false)
|
||||||
api.nvim_buf_set_lines(ext.bufs.more, hidden and 0 or -1, -1, false, lines)
|
api.nvim_buf_set_lines(ext.bufs.pager, hidden and 0 or -1, -1, false, lines)
|
||||||
local rows = api.nvim_buf_line_count(ext.bufs.more) - #lines
|
local rows = api.nvim_buf_line_count(ext.bufs.pager) - #lines
|
||||||
api.nvim_buf_set_lines(ext.bufs[tar], 0, -1, false, {})
|
api.nvim_buf_set_lines(ext.bufs[tar], 0, -1, false, {})
|
||||||
for _, mark in ipairs(marks) do
|
for _, mark in ipairs(marks) do
|
||||||
hlopts.end_col, hlopts.hl_group = mark[4].end_col, mark[4].hl_group
|
hlopts.end_col, hlopts.hl_group = mark[4].end_col, mark[4].hl_group
|
||||||
api.nvim_buf_set_extmark(ext.bufs.more, ext.ns, mark[2] + rows, mark[3], hlopts)
|
api.nvim_buf_set_extmark(ext.bufs.pager, ext.ns, mark[2] + rows, mark[3], hlopts)
|
||||||
end
|
end
|
||||||
M.box:close()
|
M.msg:close()
|
||||||
M.set_pos('more')
|
M.set_pos('pager')
|
||||||
if not hidden then
|
if not hidden then
|
||||||
api.nvim_command('norm! G')
|
api.nvim_command('norm! G')
|
||||||
end
|
end
|
||||||
M[tar].count, col, will_more = 0, 0, false
|
M[tar].count, col, will_pager = 0, 0, false
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param tar 'box'|'cmd'|'more'|'prompt'
|
---@param tar 'cmd'|'dialog'|'msg'|'pager'
|
||||||
---@param content MsgContent
|
---@param content MsgContent
|
||||||
---@param replace_last boolean
|
---@param replace_last boolean
|
||||||
---@param append boolean
|
---@param append boolean
|
||||||
---@param more boolean? If true, route messages that exceed the target window to more window.
|
---@param pager boolean? If true, route messages that exceed the target window to the pager.
|
||||||
function M.show_msg(tar, content, replace_last, append, more)
|
function M.show_msg(tar, content, replace_last, append, pager)
|
||||||
local msg, restart, cr, dupe, count = '', false, false, 0, 0
|
local msg, restart, cr, dupe, count = '', false, false, 0, 0
|
||||||
append = append and col > 0
|
append = append and col > 0
|
||||||
|
|
||||||
if M[tar] then -- tar == 'box'|'cmd'
|
if M[tar] then -- tar == 'cmd'|'msg'
|
||||||
if tar == ext.cfg.msg.pos then
|
if tar == ext.cfg.msg.target then
|
||||||
-- Save the concatenated message to identify repeated messages.
|
-- Save the concatenated message to identify repeated messages.
|
||||||
for _, chunk in ipairs(content) do
|
for _, chunk in ipairs(content) do
|
||||||
msg = msg .. chunk[2]
|
msg = msg .. chunk[2]
|
||||||
@@ -233,10 +233,10 @@ function M.show_msg(tar, content, replace_last, append, more)
|
|||||||
local line_count = api.nvim_buf_line_count(ext.bufs[tar])
|
local line_count = api.nvim_buf_line_count(ext.bufs[tar])
|
||||||
---@type integer Start row after last line in the target buffer, unless
|
---@type integer Start row after last line in the target buffer, unless
|
||||||
---this is the first message, or in case of a repeated or replaced message.
|
---this is the first message, or in case of a repeated or replaced message.
|
||||||
local row = M[tar] and count <= 1 and not will_more and (tar == 'cmd' and ext.cmd.row or 0)
|
local row = M[tar] and count <= 1 and not will_pager and (tar == 'cmd' and ext.cmd.row or 0)
|
||||||
or line_count - ((replace_last or restart or cr or append) and 1 or 0)
|
or line_count - ((replace_last or restart or cr or append) and 1 or 0)
|
||||||
local curline = (cr or append) and api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1]
|
local curline = (cr or append) and api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1]
|
||||||
local start_row, width = row, M.box.width
|
local start_row, width = row, M.msg.width
|
||||||
col = append and not cr and math.min(col, #curline) or 0
|
col = append and not cr and math.min(col, #curline) or 0
|
||||||
|
|
||||||
-- Accumulate to be inserted and highlighted message chunks for a non-repeated message.
|
-- Accumulate to be inserted and highlighted message chunks for a non-repeated message.
|
||||||
@@ -254,7 +254,7 @@ function M.show_msg(tar, content, replace_last, append, more)
|
|||||||
api.nvim_buf_set_text(ext.bufs[tar], row, col, row, ecol, { repl })
|
api.nvim_buf_set_text(ext.bufs[tar], row, col, row, ecol, { repl })
|
||||||
end
|
end
|
||||||
curline = api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1]
|
curline = api.nvim_buf_get_lines(ext.bufs[tar], row, row + 1, false)[1]
|
||||||
width = tar == 'box' and math.max(width, api.nvim_strwidth(curline)) or 0
|
width = tar == 'msg' and math.max(width, api.nvim_strwidth(curline)) or 0
|
||||||
|
|
||||||
if chunk[3] > 0 then
|
if chunk[3] > 0 then
|
||||||
hlopts.end_col, hlopts.hl_group = end_col, chunk[3]
|
hlopts.end_col, hlopts.hl_group = end_col, chunk[3]
|
||||||
@@ -269,22 +269,22 @@ function M.show_msg(tar, content, replace_last, append, more)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if tar == 'box' then
|
if tar == 'msg' then
|
||||||
api.nvim_win_set_width(ext.wins.box, width)
|
api.nvim_win_set_width(ext.wins.msg, width)
|
||||||
local h = api.nvim_win_text_height(ext.wins.box, { start_row = start_row })
|
local h = api.nvim_win_text_height(ext.wins.msg, { start_row = start_row })
|
||||||
if more and h.all > 1 then
|
if pager and h.all > 1 then
|
||||||
msg_to_more(tar)
|
msg_to_pager(tar)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
M.set_pos('box')
|
M.set_pos('msg')
|
||||||
M.box.width = width
|
M.msg.width = width
|
||||||
if restart then
|
if restart then
|
||||||
M.box.timer:stop()
|
M.msg.timer:stop()
|
||||||
M.box.timer:set_repeat(4000)
|
M.msg.timer:set_repeat(4000)
|
||||||
M.box.timer:again()
|
M.msg.timer:again()
|
||||||
else
|
else
|
||||||
M.box:start_timer(ext.bufs.box, row - start_row + 1)
|
M.msg:start_timer(ext.bufs.msg, row - start_row + 1)
|
||||||
end
|
end
|
||||||
elseif tar == 'cmd' and dupe == 0 then
|
elseif tar == 'cmd' and dupe == 0 then
|
||||||
fn.clearmatches(ext.wins.cmd) -- Clear matchparen highlights.
|
fn.clearmatches(ext.wins.cmd) -- Clear matchparen highlights.
|
||||||
@@ -296,8 +296,9 @@ function M.show_msg(tar, content, replace_last, append, more)
|
|||||||
api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd })
|
api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd })
|
||||||
else
|
else
|
||||||
local h = api.nvim_win_text_height(ext.wins.cmd, {})
|
local h = api.nvim_win_text_height(ext.wins.cmd, {})
|
||||||
if (more or not api.nvim_win_get_config(ext.wins.cmd).hide) and h.all > ext.cmdheight then
|
local want_pager = pager or will_pager or not api.nvim_win_get_config(ext.wins.pager).hide
|
||||||
msg_to_more(tar)
|
if want_pager and h.all > ext.cmdheight then
|
||||||
|
msg_to_pager(tar)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -312,7 +313,7 @@ function M.show_msg(tar, content, replace_last, append, more)
|
|||||||
|
|
||||||
if M[tar] then
|
if M[tar] then
|
||||||
-- Place (x) indicator for repeated messages. Mainly to mitigate unnecessary
|
-- Place (x) indicator for repeated messages. Mainly to mitigate unnecessary
|
||||||
-- resizing of the message box window, but also placed in the cmdline.
|
-- resizing of the message window, but also placed in the cmdline.
|
||||||
M.virt.msg[M.virt.idx.dupe][1] = dupe > 0 and { 0, ('(%d)'):format(dupe) } or nil
|
M.virt.msg[M.virt.idx.dupe][1] = dupe > 0 and { 0, ('(%d)'):format(dupe) } or nil
|
||||||
M.prev_msg, M.dupe, M[tar].count = msg, dupe, count
|
M.prev_msg, M.dupe, M[tar].count = msg, dupe, count
|
||||||
set_virttext('msg')
|
set_virttext('msg')
|
||||||
@@ -350,16 +351,15 @@ function M.msg_show(kind, content, _, _, append)
|
|||||||
vim.api.nvim_feedkeys(vim.keycode('<CR>'), 'n', false)
|
vim.api.nvim_feedkeys(vim.keycode('<CR>'), 'n', false)
|
||||||
elseif kind == 'verbose' then
|
elseif kind == 'verbose' then
|
||||||
-- Verbose messages are sent too often to be meaningful in the cmdline:
|
-- Verbose messages are sent too often to be meaningful in the cmdline:
|
||||||
-- always route to box regardless of cfg.msg.pos.
|
-- always route to message window regardless of cfg.msg.target.
|
||||||
M.show_msg('box', content, false, append)
|
M.show_msg('msg', content, false, append)
|
||||||
elseif ext.cmd.prompt then
|
elseif ext.cmd.prompt then
|
||||||
-- Route to prompt that stays open so long as the cmdline prompt is active.
|
-- Route to dialog that stays open so long as the cmdline prompt is active.
|
||||||
api.nvim_buf_set_lines(ext.bufs.prompt, 0, -1, false, { '' })
|
M.show_msg('dialog', content, api.nvim_win_get_config(ext.wins.dialog).hide, append)
|
||||||
M.show_msg('prompt', content, true, append)
|
M.set_pos('dialog')
|
||||||
M.set_pos('prompt')
|
|
||||||
else
|
else
|
||||||
-- Set the entered search command in the cmdline (if available).
|
-- Set the entered search command in the cmdline (if available).
|
||||||
local tar = kind == 'search_cmd' and 'cmd' or ext.cfg.msg.pos
|
local tar = kind == 'search_cmd' and 'cmd' or ext.cfg.msg.target
|
||||||
if tar == 'cmd' then
|
if tar == 'cmd' then
|
||||||
if ext.cmdheight == 0 or (ext.cmd.level > 0 and ext.cmd.row == 0) then
|
if ext.cmdheight == 0 or (ext.cmd.level > 0 and ext.cmd.row == 0) then
|
||||||
return -- Do not overwrite an active cmdline unless in block mode.
|
return -- Do not overwrite an active cmdline unless in block mode.
|
||||||
@@ -372,10 +372,10 @@ function M.msg_show(kind, content, _, _, append)
|
|||||||
M.msg_showcmd({})
|
M.msg_showcmd({})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Typed "inspection" messages should be routed to the more window.
|
-- Typed "inspection" messages should be routed to the pager.
|
||||||
local typed_more = { 'echo', 'echomsg', 'lua_print' }
|
local inspect = { 'echo', 'echomsg', 'lua_print' }
|
||||||
local more = kind == 'list_cmd' or (ext.cmd.level >= 0 and vim.tbl_contains(typed_more, kind))
|
local pager = kind == 'list_cmd' or (ext.cmd.level >= 0 and vim.tbl_contains(inspect, kind))
|
||||||
M.show_msg(tar, content, replace_bufwrite, append, more)
|
M.show_msg(tar, content, replace_bufwrite, append, pager)
|
||||||
-- Replace message for every second bufwrite message.
|
-- Replace message for every second bufwrite message.
|
||||||
replace_bufwrite = not replace_bufwrite and kind == 'bufwrite'
|
replace_bufwrite = not replace_bufwrite and kind == 'bufwrite'
|
||||||
-- Don't remember search_cmd message as actual message.
|
-- Don't remember search_cmd message as actual message.
|
||||||
@@ -415,7 +415,7 @@ function M.msg_ruler(content)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@alias MsgHistory [string, MsgContent]
|
---@alias MsgHistory [string, MsgContent]
|
||||||
--- Open the message history in the more window.
|
--- Open the message history in the pager.
|
||||||
---
|
---
|
||||||
---@param entries MsgHistory[]
|
---@param entries MsgHistory[]
|
||||||
function M.msg_history_show(entries)
|
function M.msg_history_show(entries)
|
||||||
@@ -423,19 +423,19 @@ function M.msg_history_show(entries)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
api.nvim_buf_set_lines(ext.bufs.more, 0, -1, false, {})
|
api.nvim_buf_set_lines(ext.bufs.pager, 0, -1, false, {})
|
||||||
for i, entry in ipairs(entries) do
|
for i, entry in ipairs(entries) do
|
||||||
M.show_msg('more', entry[2], i == 1, false)
|
M.show_msg('pager', entry[2], i == 1, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
M.set_pos('more')
|
M.set_pos('pager')
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.msg_history_clear() end
|
function M.msg_history_clear() end
|
||||||
|
|
||||||
--- Adjust dimensions of the message windows after certain events.
|
--- Adjust dimensions of the message windows after certain events.
|
||||||
---
|
---
|
||||||
---@param type? 'box'|'cmd'|'more'|'prompt' Type of to be positioned window (nil for all).
|
---@param type? 'cmd'|'dialog'|'msg'|'pager' Type of to be positioned window (nil for all).
|
||||||
function M.set_pos(type)
|
function M.set_pos(type)
|
||||||
local function win_set_pos(win)
|
local function win_set_pos(win)
|
||||||
local texth = type and api.nvim_win_text_height(win, {}) or 0
|
local texth = type and api.nvim_win_text_height(win, {}) or 0
|
||||||
@@ -444,18 +444,18 @@ function M.set_pos(type)
|
|||||||
hide = false,
|
hide = false,
|
||||||
relative = 'laststatus',
|
relative = 'laststatus',
|
||||||
height = height,
|
height = height,
|
||||||
row = win == ext.wins.box and 0 or 1,
|
row = win == ext.wins.msg and 0 or 1,
|
||||||
col = 10000,
|
col = 10000,
|
||||||
}
|
}
|
||||||
|
|
||||||
if type == 'box' then
|
if type == 'msg' then
|
||||||
-- Ensure last line is visible and first line is at top of window.
|
-- Ensure last line is visible and first line is at top of window.
|
||||||
local row = (texth.all > height and texth.end_row or 0) + 1
|
local row = (texth.all > height and texth.end_row or 0) + 1
|
||||||
api.nvim_win_set_cursor(ext.wins.box, { row, 0 })
|
api.nvim_win_set_cursor(ext.wins.msg, { row, 0 })
|
||||||
elseif type == 'more' and api.nvim_win_get_config(win).hide then
|
elseif type == 'pager' and api.nvim_win_get_config(win).hide then
|
||||||
-- Cannot leave the cmdwin to enter the "more" window, so close it.
|
-- Cannot leave the cmdwin to enter the pager, so close it.
|
||||||
-- NOTE: regression w.r.t. the message grid, which allowed this. Resolving
|
-- NOTE: regression w.r.t. the message grid, which allowed this. Resolving
|
||||||
-- that would require somehow bypassing textlock for the "more" window.
|
-- that would require somehow bypassing textlock for the pager.
|
||||||
if fn.getcmdwintype() ~= '' then
|
if fn.getcmdwintype() ~= '' then
|
||||||
api.nvim_command('quit')
|
api.nvim_command('quit')
|
||||||
end
|
end
|
||||||
@@ -465,18 +465,17 @@ function M.set_pos(type)
|
|||||||
api.nvim_set_current_win(win)
|
api.nvim_set_current_win(win)
|
||||||
api.nvim_create_autocmd({ 'WinEnter', 'CmdwinEnter', 'CmdwinLeave' }, {
|
api.nvim_create_autocmd({ 'WinEnter', 'CmdwinEnter', 'CmdwinLeave' }, {
|
||||||
callback = function(ev)
|
callback = function(ev)
|
||||||
if ev.event == 'CmdwinEnter' then
|
-- Make pager relative to cmdwin when it is opened, restore when it is closed.
|
||||||
api.nvim_win_set_config(win, { relative = 'win', win = 0, row = 0, col = 0 })
|
config = ev.event == 'CmdwinLeave' and config
|
||||||
elseif ev.event == 'CmdwinLeave' then
|
or ev.event == 'WinEnter' and { hide = true }
|
||||||
|
or { relative = 'win', win = 0, row = 0, col = 0 }
|
||||||
|
if api.nvim_win_is_valid(win) then
|
||||||
api.nvim_win_set_config(win, config)
|
api.nvim_win_set_config(win, config)
|
||||||
else
|
|
||||||
if api.nvim_win_is_valid(win) then
|
|
||||||
api.nvim_win_set_config(win, { hide = true })
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
-- Delete autocmd when a window other than the cmdwin is entered.
|
||||||
|
return ev.event == 'WinEnter'
|
||||||
end,
|
end,
|
||||||
desc = 'Hide inactive "more" window.',
|
desc = 'Hide inactive pager window.',
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@@ -5,17 +5,15 @@ local M = {
|
|||||||
ns = api.nvim_create_namespace('nvim._ext_ui'),
|
ns = api.nvim_create_namespace('nvim._ext_ui'),
|
||||||
augroup = api.nvim_create_augroup('nvim._ext_ui', {}),
|
augroup = api.nvim_create_augroup('nvim._ext_ui', {}),
|
||||||
cmdheight = -1, -- 'cmdheight' option value set by user.
|
cmdheight = -1, -- 'cmdheight' option value set by user.
|
||||||
wins = { box = -1, cmd = -1, more = -1, prompt = -1 },
|
wins = { cmd = -1, dialog = -1, msg = -1, pager = -1 },
|
||||||
bufs = { box = -1, cmd = -1, more = -1, prompt = -1 },
|
bufs = { cmd = -1, dialog = -1, msg = -1, pager = -1 },
|
||||||
cfg = {
|
cfg = {
|
||||||
enable = true,
|
enable = true,
|
||||||
msg = { -- Options related to the message module.
|
msg = { -- Options related to the message module.
|
||||||
---@type 'box'|'cmd' Type of window used to place messages, either in the
|
---@type 'cmd'|'msg' Where to place regular messages, either in the
|
||||||
---cmdline or in a separate ephemeral message box window.
|
---cmdline or in a separate ephemeral message window.
|
||||||
pos = 'cmd',
|
target = 'cmd',
|
||||||
box = { -- Options related to the message box window.
|
timeout = 4000, -- Time a message is visible in the message window.
|
||||||
timeout = 4000, -- Time a message is visible.
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -33,7 +31,7 @@ local tab = 0
|
|||||||
--- Ensure the various buffers and windows have not been deleted.
|
--- Ensure the various buffers and windows have not been deleted.
|
||||||
function M.tab_check_wins()
|
function M.tab_check_wins()
|
||||||
local curtab = api.nvim_get_current_tabpage()
|
local curtab = api.nvim_get_current_tabpage()
|
||||||
for _, type in ipairs({ 'box', 'cmd', 'more', 'prompt' }) do
|
for _, type in ipairs({ 'cmd', 'dialog', 'msg', 'pager' }) do
|
||||||
local setopt = not api.nvim_buf_is_valid(M.bufs[type])
|
local setopt = not api.nvim_buf_is_valid(M.bufs[type])
|
||||||
if setopt then
|
if setopt then
|
||||||
M.bufs[type] = api.nvim_create_buf(false, true)
|
M.bufs[type] = api.nvim_create_buf(false, true)
|
||||||
@@ -50,16 +48,16 @@ function M.tab_check_wins()
|
|||||||
or not api.nvim_win_get_config(M.wins[type]).zindex -- no longer floating
|
or not api.nvim_win_get_config(M.wins[type]).zindex -- no longer floating
|
||||||
then
|
then
|
||||||
local top = { vim.opt.fcs:get().horiz or o.ambw == 'single' and '─' or '-', 'WinSeparator' }
|
local top = { vim.opt.fcs:get().horiz or o.ambw == 'single' and '─' or '-', 'WinSeparator' }
|
||||||
local border = (type == 'more' or type == 'prompt') and { '', top, '', '', '', '', '', '' }
|
local border = (type == 'pager' or type == 'dialog') and { '', top, '', '', '', '', '', '' }
|
||||||
local cfg = vim.tbl_deep_extend('force', wincfg, {
|
local cfg = vim.tbl_deep_extend('force', wincfg, {
|
||||||
focusable = type == 'more',
|
focusable = type == 'pager',
|
||||||
mouse = type ~= 'cmd' and true or nil,
|
mouse = type ~= 'cmd' and true or nil,
|
||||||
anchor = type ~= 'cmd' and 'SE' or nil,
|
anchor = type ~= 'cmd' and 'SE' or nil,
|
||||||
hide = type ~= 'cmd' or M.cmdheight == 0 or nil,
|
hide = type ~= 'cmd' or M.cmdheight == 0 or nil,
|
||||||
title = type == 'more' and 'Messages' or nil,
|
title = type == 'pager' and 'Pager' or nil,
|
||||||
border = type == 'box' and 'single' or border or 'none',
|
border = type == 'msg' and 'single' or border or 'none',
|
||||||
-- kZIndexMessages < zindex < kZIndexCmdlinePopupMenu (grid_defs.h), 'more' below others.
|
-- kZIndexMessages < zindex < kZIndexCmdlinePopupMenu (grid_defs.h), pager below others.
|
||||||
zindex = 200 - (type == 'more' and 1 or 0),
|
zindex = 200 - (type == 'pager' and 1 or 0),
|
||||||
_cmdline_offset = type == 'cmd' and 0 or nil,
|
_cmdline_offset = type == 'cmd' and 0 or nil,
|
||||||
})
|
})
|
||||||
if tab ~= curtab and api.nvim_win_is_valid(M.wins[type]) then
|
if tab ~= curtab and api.nvim_win_is_valid(M.wins[type]) then
|
||||||
@@ -77,10 +75,11 @@ function M.tab_check_wins()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if setopt then
|
if setopt then
|
||||||
api.nvim_buf_set_name(M.bufs[type], 'nvim.' .. type)
|
local name = { cmd = 'Cmd', dialog = 'Dialog', msg = 'Msg', pager = 'Pager' }
|
||||||
if type == 'more' then
|
api.nvim_buf_set_name(M.bufs[type], ('[%s]'):format(name[type]))
|
||||||
-- Close more window with `q`, same as `checkhealth`
|
if type == 'pager' then
|
||||||
api.nvim_buf_set_keymap(M.bufs.more, 'n', 'q', '<Cmd>wincmd c<CR>', {})
|
-- Close pager with `q`, same as `checkhealth`
|
||||||
|
api.nvim_buf_set_keymap(M.bufs.pager, 'n', 'q', '<Cmd>wincmd c<CR>', {})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Fire a FileType autocommand with window context to let the user reconfigure local options.
|
-- Fire a FileType autocommand with window context to let the user reconfigure local options.
|
||||||
@@ -88,9 +87,9 @@ function M.tab_check_wins()
|
|||||||
api.nvim_set_option_value('wrap', true, { scope = 'local' })
|
api.nvim_set_option_value('wrap', true, { scope = 'local' })
|
||||||
api.nvim_set_option_value('linebreak', false, { scope = 'local' })
|
api.nvim_set_option_value('linebreak', false, { scope = 'local' })
|
||||||
api.nvim_set_option_value('smoothscroll', true, { scope = 'local' })
|
api.nvim_set_option_value('smoothscroll', true, { scope = 'local' })
|
||||||
local ft = type == 'cmd' and 'cmdline' or ('msg' .. type)
|
local ft = name[type]:sub(1, 1):lower() .. name[type]:sub(2)
|
||||||
api.nvim_set_option_value('filetype', ft, { scope = 'local' })
|
api.nvim_set_option_value('filetype', ft, { scope = 'local' })
|
||||||
local ignore = 'all' .. (type == 'more' and ',-TextYankPost' or '')
|
local ignore = 'all' .. (type == 'pager' and ',-TextYankPost' or '')
|
||||||
api.nvim_set_option_value('eventignorewin', ignore, { scope = 'local' })
|
api.nvim_set_option_value('eventignorewin', ignore, { scope = 'local' })
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user