diff --git a/runtime/lua/vim/_extui.lua b/runtime/lua/vim/_extui.lua index 1b9d81b091..9132d1fa64 100644 --- a/runtime/lua/vim/_extui.lua +++ b/runtime/lua/vim/_extui.lua @@ -40,7 +40,7 @@ local M = {} local function ui_callback(event, ...) local handler = ext.msg[event] or ext.cmd[event] - ext.tab_check_wins() + ext.check_targets() handler(...) api.nvim__redraw({ flush = handler ~= ext.cmd.cmdline_hide or nil, @@ -99,44 +99,37 @@ function M.enable(opts) -- dependent on some option values. Reconfigure windows when option value -- 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. - local function check_opt(name, value) - if name == 'cmdheight' then - -- 'cmdheight' set; (un)hide cmdline window and set its height. - local cfg = { height = math.max(value, 1), hide = value == 0 } - api.nvim_win_set_config(ext.wins.cmd, cfg) - -- Change message position when 'cmdheight' was or becomes 0. - if value == 0 or ext.cmdheight == 0 then - ext.cfg.msg.target = value == 0 and 'msg' or 'cmd' - ext.msg.prev_msg = '' - end - ext.cmdheight = value + local function check_cmdheight(value) + ext.check_targets() + -- 'cmdheight' set; (un)hide cmdline window and set its height. + local cfg = { height = math.max(value, 1), hide = value == 0 } + api.nvim_win_set_config(ext.wins.cmd, cfg) + -- Change message position when 'cmdheight' was or becomes 0. + if value == 0 or ext.cmdheight == 0 then + ext.cfg.msg.target = value == 0 and 'msg' or 'cmd' + ext.msg.prev_msg = '' end + ext.cmdheight = value end - ext.tab_check_wins() - check_opt('cmdheight', vim.o.cmdheight) + vim.schedule(function() + check_cmdheight(vim.o.cmdheight) + end) api.nvim_create_autocmd('OptionSet', { group = ext.augroup, pattern = { 'cmdheight' }, - callback = function(ev) - ext.tab_check_wins() - check_opt(ev.match, vim.v.option_new) + callback = function() + check_cmdheight(vim.v.option_new) ext.msg.set_pos() end, desc = 'Set cmdline and message window dimensions for changed option values.', }) - api.nvim_create_autocmd({ 'VimEnter', 'VimResized', 'TabEnter' }, { + api.nvim_create_autocmd({ 'VimResized', 'TabEnter' }, { group = ext.augroup, - callback = function(ev) - ext.tab_check_wins() - if ev.event == 'VimEnter' then - check_opt('cmdheight', vim.o.cmdheight) - end - ext.msg.set_pos() - end, - desc = 'Set extui window dimensions after startup, shell resize or tabpage change.', + callback = ext.msg.set_pos, + desc = 'Set cmdline and message window dimensions after shell resize or tabpage change.', }) api.nvim_create_autocmd('WinEnter', { diff --git a/runtime/lua/vim/_extui/cmdline.lua b/runtime/lua/vim/_extui/cmdline.lua index 38050eb74f..c257d07ebb 100644 --- a/runtime/lua/vim/_extui/cmdline.lua +++ b/runtime/lua/vim/_extui/cmdline.lua @@ -30,7 +30,7 @@ local function win_config(win, hide, height) end end -local cmdbuff ---@type string Stored cmdline used to calculate translation offset. +local cmdbuff = '' ---@type string Stored cmdline used to calculate translation offset. local promptlen = 0 -- Current length of the prompt, stored for use in "cmdline_pos" --- Concatenate content chunks and set the text for the current row in the cmdline buffer. --- @@ -57,6 +57,10 @@ end ---@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 + if M.highlighter == nil then + local parser = assert(vim.treesitter.get_parser(ext.bufs.cmd, 'vim', {})) + M.highlighter = vim.treesitter.highlighter.new(parser) + end -- Only enable TS highlighter for Ex commands (not search or filter commands). M.highlighter.active[ext.bufs.cmd] = firstc == ':' and M.highlighter or nil if ext.msg.cmd.msg_row ~= -1 then diff --git a/runtime/lua/vim/_extui/messages.lua b/runtime/lua/vim/_extui/messages.lua index 5e9e1cde58..312a2a2a0e 100644 --- a/runtime/lua/vim/_extui/messages.lua +++ b/runtime/lua/vim/_extui/messages.lua @@ -310,7 +310,9 @@ function M.show_msg(tar, content, replace_last, append, pager) end api.nvim_win_set_cursor(ext.wins[tar], { 1, 0 }) - ext.cmd.highlighter.active[ext.bufs.cmd] = nil + if ext.cmd.highlighter then + ext.cmd.highlighter.active[ext.bufs.cmd] = nil + end -- Place [+x] indicator for lines that spill over 'cmdheight'. M.cmd.lines, M.cmd.msg_row = h.all, h.end_row local spill = M.cmd.lines > ext.cmdheight and ('[+%d]'):format(M.cmd.lines - ext.cmdheight) @@ -455,9 +457,12 @@ function M.set_pos(type) local function win_set_pos(win) local texth = type and api.nvim_win_text_height(win, {}) or 0 local height = type and math.min(texth.all, math.ceil(o.lines * 0.5)) + local top = { vim.opt.fcs:get().horiz or o.ambw == 'single' and '─' or '-', 'WinSeparator' } + local border = (type == 'pager' or type == 'dialog') and { '', top, '', '', '', '', '', '' } local config = { hide = false, relative = 'laststatus', + border = border or nil, height = height, row = win == ext.wins.msg and 0 or 1, col = 10000, diff --git a/runtime/lua/vim/_extui/shared.lua b/runtime/lua/vim/_extui/shared.lua index 0045748039..9454653c58 100644 --- a/runtime/lua/vim/_extui/shared.lua +++ b/runtime/lua/vim/_extui/shared.lua @@ -1,10 +1,10 @@ -local api, o = vim.api, vim.o +local api = vim.api local M = { msg = nil, ---@type vim._extui.messages cmd = nil, ---@type vim._extui.cmdline ns = api.nvim_create_namespace('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 = { cmd = -1, dialog = -1, msg = -1, pager = -1 }, bufs = { cmd = -1, dialog = -1, msg = -1, pager = -1 }, cfg = { @@ -28,18 +28,13 @@ local wincfg = { -- Default cfg for nvim_open_win(). } local tab = 0 ---- Ensure the various buffers and windows have not been deleted. -function M.tab_check_wins() +---Ensure target buffers and windows are still valid. +function M.check_targets() local curtab = api.nvim_get_current_tabpage() for _, type in ipairs({ 'cmd', 'dialog', 'msg', 'pager' }) do local setopt = not api.nvim_buf_is_valid(M.bufs[type]) if setopt then M.bufs[type] = api.nvim_create_buf(false, true) - if type == 'cmd' then - -- Attach highlighter to the cmdline buffer. - local parser = assert(vim.treesitter.get_parser(M.bufs.cmd, 'vim', {})) - M.cmd.highlighter = vim.treesitter.highlighter.new(parser) - end end if @@ -47,15 +42,12 @@ function M.tab_check_wins() or not api.nvim_win_is_valid(M.wins[type]) or not api.nvim_win_get_config(M.wins[type]).zindex -- no longer floating then - local top = { vim.opt.fcs:get().horiz or o.ambw == 'single' and '─' or '-', 'WinSeparator' } - local border = (type == 'pager' or type == 'dialog') and { '', top, '', '', '', '', '', '' } local cfg = vim.tbl_deep_extend('force', wincfg, { focusable = type == 'pager', mouse = type ~= 'cmd' and true or nil, anchor = type ~= 'cmd' and 'SE' or nil, hide = type ~= 'cmd' or M.cmdheight == 0 or nil, - title = type == 'pager' and 'Pager' or nil, - border = type == 'msg' and 'single' or border or 'none', + border = type == 'msg' and 'single' or 'none', -- kZIndexMessages < zindex < kZIndexCmdlinePopupMenu (grid_defs.h), pager below others. zindex = 200 - (type == 'pager' and 1 or 0), _cmdline_offset = type == 'cmd' and 0 or nil, diff --git a/test/functional/ui/messages2_spec.lua b/test/functional/ui/messages2_spec.lua index 496c8821d2..29e632b6ca 100644 --- a/test/functional/ui/messages2_spec.lua +++ b/test/functional/ui/messages2_spec.lua @@ -30,7 +30,7 @@ describe('messages2', function() screen:expect([[ | {1:~ }|*9 - ─{100:Pager}───────────────────────────────────────────────| + ─────────────────────────────────────────────────────| {4:fo^o }| {4:bar }| foo[+1] 1,3 All| @@ -40,7 +40,7 @@ describe('messages2', function() screen:expect([[ | {1:~ }|*9 - ─{100:Pager}───────────────────────────────────────────────| + ─────────────────────────────────────────────────────| {4:fo^o }| {4:bar }| {9:E354: Invalid register name: '^@'} 1,3 All| @@ -50,7 +50,7 @@ describe('messages2', function() screen:expect([[ | {1:~ }|*8 - ─{100:Pager}───────────────────────────────────────────────| + ─────────────────────────────────────────────────────| {4:^foo }| {4:bar }| {4:baz }| @@ -62,7 +62,7 @@ describe('messages2', function() screen:expect([[ | {1:~ }|*7 - ─{100:Pager}───────────────────────────────────────────────| + ─────────────────────────────────────────────────────| {4:^foo }| {4:bar }| {4: }| @@ -89,7 +89,7 @@ describe('messages2', function() screen:expect([[ | {1:~ }|*10 - ─{100:Pager}───────────────────────────────────────────────| + ─────────────────────────────────────────────────────| {4:fo^o }| foo | ]])