mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
feat(extui): support paging in the dialog window (#35310)
Problem: Unable to see e.g. `inputlist()` prompts that exceed the dialog window height. Multi-line prompts are not handled properly, and tracking is insufficient for messages in cmdline_block mode. Solution: Add vim.on_key handler while the dialog window is open that forwards paging keys to the window. Properly render multi-line prompts. Keep track of both the start and end of the current cmdline prompt. Append messages after the current prompt in cmdline_block mode.
This commit is contained in:
@@ -5,8 +5,9 @@ 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 'dialog' 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.
|
srow = 0, -- Buffer row at which the current cmdline starts; > 0 in block mode.
|
||||||
level = -1, -- Current cmdline level, 0 when inactive, -1 one loop iteration after closing.
|
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.
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Set the 'cmdheight' and cmdline window height. Reposition message windows.
|
--- Set the 'cmdheight' and cmdline window height. Reposition message windows.
|
||||||
@@ -31,7 +32,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"
|
local promptlen = 0 -- Current length of the last line in the prompt.
|
||||||
--- Concatenate content chunks and set the text for the current row in the cmdline buffer.
|
--- Concatenate content chunks and set the text for the current row in the cmdline buffer.
|
||||||
---
|
---
|
||||||
---@alias CmdChunk [integer, string]
|
---@alias CmdChunk [integer, string]
|
||||||
@@ -39,11 +40,16 @@ local promptlen = 0 -- Current length of the prompt, stored for use in "cmdline_
|
|||||||
---@param content CmdContent
|
---@param content CmdContent
|
||||||
---@param prompt string
|
---@param prompt string
|
||||||
local function set_text(content, prompt)
|
local function set_text(content, prompt)
|
||||||
promptlen, cmdbuff = #prompt, ''
|
local lines = {} ---@type string[]
|
||||||
|
for line in prompt:gmatch('[^\n]+') do
|
||||||
|
lines[#lines + 1] = fn.strtrans(line)
|
||||||
|
end
|
||||||
|
cmdbuff, promptlen, M.erow = '', #lines[#lines], M.srow + #lines - 1
|
||||||
for _, chunk in ipairs(content) do
|
for _, chunk in ipairs(content) do
|
||||||
cmdbuff = cmdbuff .. chunk[2]
|
cmdbuff = cmdbuff .. chunk[2]
|
||||||
end
|
end
|
||||||
api.nvim_buf_set_lines(ext.bufs.cmd, M.row, -1, false, { prompt .. fn.strtrans(cmdbuff) .. ' ' })
|
lines[#lines] = ('%s%s '):format(lines[#lines], fn.strtrans(cmdbuff))
|
||||||
|
api.nvim_buf_set_lines(ext.bufs.cmd, M.srow, -1, false, lines)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the cmdline buffer text and cursor position.
|
--- Set the cmdline buffer text and cursor position.
|
||||||
@@ -96,8 +102,8 @@ local curpos = { 0, 0 } -- Last drawn cursor position.
|
|||||||
--@param level integer
|
--@param level integer
|
||||||
function M.cmdline_pos(pos)
|
function M.cmdline_pos(pos)
|
||||||
pos = #fn.strtrans(cmdbuff:sub(1, pos))
|
pos = #fn.strtrans(cmdbuff:sub(1, pos))
|
||||||
if curpos[1] ~= M.row + 1 or curpos[2] ~= promptlen + pos then
|
if curpos[1] ~= M.erow + 1 or curpos[2] ~= promptlen + pos then
|
||||||
curpos[1], curpos[2] = M.row + 1, promptlen + pos
|
curpos[1], curpos[2] = M.erow + 1, promptlen + pos
|
||||||
-- Add matchparen highlighting to non-prompt part of cmdline.
|
-- Add matchparen highlighting to non-prompt part of cmdline.
|
||||||
if pos > 0 and fn.exists('#matchparen#CursorMoved') == 1 then
|
if pos > 0 and fn.exists('#matchparen#CursorMoved') == 1 then
|
||||||
api.nvim_win_set_cursor(ext.wins.cmd, { curpos[1], curpos[2] - 1 })
|
api.nvim_win_set_cursor(ext.wins.cmd, { curpos[1], curpos[2] - 1 })
|
||||||
@@ -114,7 +120,7 @@ end
|
|||||||
---@param level integer
|
---@param level integer
|
||||||
---@param abort boolean
|
---@param abort boolean
|
||||||
function M.cmdline_hide(level, abort)
|
function M.cmdline_hide(level, abort)
|
||||||
if M.row > 0 or level > (fn.getcmdwintype() == '' and 1 or 2) then
|
if M.srow > 0 or level > (fn.getcmdwintype() == '' and 1 or 2) then
|
||||||
return -- No need to hide when still in nested cmdline or cmdline_block.
|
return -- No need to hide when still in nested cmdline or cmdline_block.
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -132,6 +138,7 @@ function M.cmdline_hide(level, abort)
|
|||||||
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
||||||
api.nvim_buf_set_lines(ext.bufs.dialog, 0, -1, false, {})
|
api.nvim_buf_set_lines(ext.bufs.dialog, 0, -1, false, {})
|
||||||
api.nvim_win_set_config(ext.wins.dialog, { hide = true })
|
api.nvim_win_set_config(ext.wins.dialog, { hide = true })
|
||||||
|
vim.on_key(nil, ext.msg.dialog_on_key)
|
||||||
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.
|
||||||
@@ -152,7 +159,7 @@ end
|
|||||||
function M.cmdline_block_show(lines)
|
function M.cmdline_block_show(lines)
|
||||||
for _, content in ipairs(lines) do
|
for _, content in ipairs(lines) do
|
||||||
set_text(content, ':')
|
set_text(content, ':')
|
||||||
M.row = M.row + 1
|
M.srow = M.srow + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -161,12 +168,12 @@ end
|
|||||||
---@param line CmdContent
|
---@param line CmdContent
|
||||||
function M.cmdline_block_append(line)
|
function M.cmdline_block_append(line)
|
||||||
set_text(line, ':')
|
set_text(line, ':')
|
||||||
M.row = M.row + 1
|
M.srow = M.srow + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Clear cmdline buffer and leave the cmdline.
|
--- Clear cmdline buffer and leave the cmdline.
|
||||||
function M.cmdline_block_hide()
|
function M.cmdline_block_hide()
|
||||||
M.row = 0
|
M.srow = 0
|
||||||
M.cmdline_hide(M.level, true)
|
M.cmdline_hide(M.level, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -27,11 +27,14 @@ local M = {
|
|||||||
prev_msg = '', -- Concatenated content of the previous message.
|
prev_msg = '', -- Concatenated content of the previous message.
|
||||||
virt = { -- Stored virt_text state.
|
virt = { -- Stored virt_text state.
|
||||||
last = { {}, {}, {}, {} }, ---@type MsgContent[] status in last cmdline row.
|
last = { {}, {}, {}, {} }, ---@type MsgContent[] status in last cmdline row.
|
||||||
msg = { {}, {} }, ---@type MsgContent[] [(x)] indicators in message window.
|
msg = { {}, {} }, ---@type MsgContent[] [(x)] indicators in msg window.
|
||||||
|
top = { {} }, ---@type MsgContent[] [+x] top indicator in dialog window.
|
||||||
|
bot = { {} }, ---@type MsgContent[] [+x] bottom indicator in dialog window.
|
||||||
idx = { mode = 1, search = 2, cmd = 3, ruler = 4, spill = 1, dupe = 2 },
|
idx = { mode = 1, search = 2, cmd = 3, ruler = 4, spill = 1, dupe = 2 },
|
||||||
ids = {}, ---@type { ['last'|'msg']: integer? } Table of mark IDs.
|
ids = {}, ---@type { ['last'|'msg'|'top'|'bot']: integer? } Table of mark IDs.
|
||||||
delayed = false, -- Whether placement of 'last' virt_text is delayed.
|
delayed = false, -- Whether placement of 'last' virt_text is delayed.
|
||||||
},
|
},
|
||||||
|
on_dialog_key = 0, -- vim.on_key namespace for paging in the dialog window.
|
||||||
}
|
}
|
||||||
|
|
||||||
function M.msg:close()
|
function M.msg:close()
|
||||||
@@ -66,8 +69,8 @@ end
|
|||||||
local cmd_on_key = nil
|
local cmd_on_key = nil
|
||||||
--- 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.
|
||||||
---
|
---
|
||||||
---@param type 'last'|'msg'
|
---@param type 'last'|'msg'|'top'|'bot'
|
||||||
---@param tar? 'cmd'|'msg'
|
---@param tar? 'cmd'|'msg'|'dialog'
|
||||||
local function set_virttext(type, tar)
|
local function set_virttext(type, tar)
|
||||||
if (type == 'last' and (ext.cmdheight == 0 or M.virt.delayed)) or cmd_on_key then
|
if (type == 'last' and (ext.cmdheight == 0 or M.virt.delayed)) or cmd_on_key then
|
||||||
return -- Don't show virtual text while cmdline, error or full message in cmdline is shown.
|
return -- Don't show virtual text while cmdline, error or full message in cmdline is shown.
|
||||||
@@ -75,32 +78,34 @@ local function set_virttext(type, tar)
|
|||||||
|
|
||||||
-- Concatenate the components of M.virt[type] and calculate the concatenated width.
|
-- Concatenate the components of M.virt[type] and calculate the concatenated width.
|
||||||
local width, chunks = 0, {} ---@type integer, [string, integer|string][]
|
local width, chunks = 0, {} ---@type integer, [string, integer|string][]
|
||||||
local contents = type == 'last' and M.virt.last or M.virt.msg
|
local contents = M.virt[type] ---@type MsgContent[]
|
||||||
for _, content in ipairs(contents) do
|
for _, content in ipairs(contents) do
|
||||||
for _, chunk in ipairs(content) do
|
for _, chunk in ipairs(content) do
|
||||||
chunks[#chunks + 1] = { chunk[2], chunk[3] }
|
chunks[#chunks + 1] = { chunk[2], chunk[3] }
|
||||||
width = width + api.nvim_strwidth(chunk[2])
|
width = width + api.nvim_strwidth(chunk[2])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
tar = tar or type == 'msg' and ext.cfg.msg.target or 'cmd'
|
||||||
|
|
||||||
if M.virt.ids[type] and #chunks == 0 then
|
if M.virt.ids[type] and #chunks == 0 then
|
||||||
api.nvim_buf_del_extmark(ext.bufs.cmd, ext.ns, M.virt.ids[type])
|
api.nvim_buf_del_extmark(ext.bufs[tar], ext.ns, M.virt.ids[type])
|
||||||
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
|
||||||
|
M.virt.ids[type] = nil
|
||||||
elseif #chunks > 0 then
|
elseif #chunks > 0 then
|
||||||
tar = tar or type == 'msg' and ext.cfg.msg.target or 'cmd'
|
|
||||||
local win = ext.wins[tar]
|
local win = ext.wins[tar]
|
||||||
|
local line = (tar == 'msg' or type == 'top') and 'w0' or type == 'bot' and 'w$'
|
||||||
|
local srow = line and fn.line(line, ext.wins.dialog) - 1
|
||||||
local erow = tar == 'cmd' and math.min(M.cmd.msg_row, api.nvim_buf_line_count(ext.bufs.cmd) - 1)
|
local erow = tar == 'cmd' and math.min(M.cmd.msg_row, api.nvim_buf_line_count(ext.bufs.cmd) - 1)
|
||||||
local texth = api.nvim_win_text_height(win, {
|
local texth = api.nvim_win_text_height(win, {
|
||||||
max_height = api.nvim_win_get_height(win),
|
max_height = (type == 'top' or type == 'bot') and 1 or api.nvim_win_get_height(win),
|
||||||
start_row = tar == 'msg' and fn.line('w0', ext.wins.msg) - 1 or nil,
|
start_row = srow or nil,
|
||||||
end_row = erow or nil,
|
end_row = erow or nil,
|
||||||
})
|
})
|
||||||
local row = texth.end_row
|
local row = texth.end_row
|
||||||
local col = fn.virtcol2col(win, row + 1, texth.end_vcol)
|
local col = fn.virtcol2col(win, row + 1, texth.end_vcol)
|
||||||
local scol = fn.screenpos(win, row + 1, col).col ---@type integer
|
local scol = fn.screenpos(win, row + 1, col).col ---@type integer
|
||||||
|
|
||||||
if type == 'msg' then
|
if type ~= 'last' then
|
||||||
-- 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.
|
||||||
@@ -115,7 +120,7 @@ local function set_virttext(type, tar)
|
|||||||
M.msg.width = maxwidth
|
M.msg.width = maxwidth
|
||||||
end
|
end
|
||||||
|
|
||||||
local mwidth = tar == 'msg' and M.msg.width or M.cmd.last_col
|
local mwidth = tar == 'msg' and M.msg.width or tar == 'dialog' and o.columns or M.cmd.last_col
|
||||||
if scol - offset + width > mwidth then
|
if scol - offset + width > mwidth then
|
||||||
col = fn.virtcol2col(win, row + 1, texth.end_vcol - (scol - offset + width - mwidth))
|
col = fn.virtcol2col(win, row + 1, texth.end_vcol - (scol - offset + width - mwidth))
|
||||||
end
|
end
|
||||||
@@ -231,7 +236,7 @@ function M.show_msg(tar, content, replace_last, append)
|
|||||||
for _, chunk in ipairs(content) do
|
for _, chunk in ipairs(content) do
|
||||||
msg = msg .. chunk[2]
|
msg = msg .. chunk[2]
|
||||||
end
|
end
|
||||||
dupe = (msg == M.prev_msg and ext.cmd.row == 0 and M.dupe + 1 or 0)
|
dupe = (msg == M.prev_msg and ext.cmd.srow == 0 and M.dupe + 1 or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
cr = M[tar].count > 0 and msg:sub(1, 1) == '\r'
|
cr = M[tar].count > 0 and msg:sub(1, 1) == '\r'
|
||||||
@@ -239,7 +244,7 @@ function M.show_msg(tar, content, replace_last, append)
|
|||||||
count = M[tar].count + ((restart or msg == '\n') and 0 or 1)
|
count = M[tar].count + ((restart or msg == '\n') and 0 or 1)
|
||||||
|
|
||||||
-- Ensure cmdline is clear when writing the first message.
|
-- Ensure cmdline is clear when writing the first message.
|
||||||
if tar == 'cmd' and not will_full and dupe == 0 and M.cmd.count == 0 and ext.cmd.row == 0 then
|
if tar == 'cmd' and not will_full and dupe == 0 and M.cmd.count == 0 and ext.cmd.srow == 0 then
|
||||||
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
api.nvim_buf_set_lines(ext.bufs.cmd, 0, -1, false, {})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -252,7 +257,7 @@ function M.show_msg(tar, content, replace_last, append)
|
|||||||
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_full and (tar == 'cmd' and ext.cmd.row or 0)
|
local row = M[tar] and count <= 1 and not will_full and (tar == 'cmd' and ext.cmd.erow 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.msg.width
|
local start_row, width = row, M.msg.width
|
||||||
@@ -307,10 +312,10 @@ function M.show_msg(tar, content, replace_last, append)
|
|||||||
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.
|
||||||
if ext.cmd.row > 0 then
|
if ext.cmd.srow > 0 then
|
||||||
-- In block mode the cmdheight is already dynamic, so just print the full message
|
-- In block mode the cmdheight is already dynamic, so just print the full message
|
||||||
-- regardless of height. Spoof cmdline_show to put cmdline below message.
|
-- regardless of height. Spoof cmdline_show to put cmdline below message.
|
||||||
ext.cmd.row = ext.cmd.row + 1 + row - start_row
|
ext.cmd.srow = ext.cmd.srow + 1 + row - start_row
|
||||||
ext.cmd.cmdline_show({}, 0, ':', '', ext.cmd.indent, 0, 0)
|
ext.cmd.cmdline_show({}, 0, ':', '', ext.cmd.indent, 0, 0)
|
||||||
api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd })
|
api.nvim__redraw({ flush = true, cursor = true, win = ext.wins.cmd })
|
||||||
else
|
else
|
||||||
@@ -340,7 +345,7 @@ function M.show_msg(tar, content, replace_last, append)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Reset message state the next event loop iteration.
|
-- Reset message state the next event loop iteration.
|
||||||
if start_row == 0 or ext.cmd.row > 0 then
|
if start_row == 0 or ext.cmd.srow > 0 then
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
col, M.cmd.count = 0, 0
|
col, M.cmd.count = 0, 0
|
||||||
end)
|
end)
|
||||||
@@ -359,7 +364,7 @@ end
|
|||||||
function M.msg_show(kind, content, replace_last, _, append)
|
function M.msg_show(kind, content, replace_last, _, append)
|
||||||
if kind == 'empty' then
|
if kind == 'empty' then
|
||||||
-- A sole empty message clears the cmdline.
|
-- A sole empty message clears the cmdline.
|
||||||
if ext.cfg.msg.target == 'cmd' and M.cmd.count == 0 then
|
if ext.cfg.msg.target == 'cmd' and M.cmd.count == 0 and ext.cmd.srow == 0 then
|
||||||
M.msg_clear()
|
M.msg_clear()
|
||||||
end
|
end
|
||||||
elseif kind == 'search_count' then
|
elseif kind == 'search_count' then
|
||||||
@@ -370,7 +375,7 @@ function M.msg_show(kind, content, replace_last, _, append)
|
|||||||
M.virt.last[M.virt.idx.search] = content
|
M.virt.last[M.virt.idx.search] = content
|
||||||
M.virt.last[M.virt.idx.cmd] = { { 0, (' '):rep(11) } }
|
M.virt.last[M.virt.idx.cmd] = { { 0, (' '):rep(11) } }
|
||||||
set_virttext('last')
|
set_virttext('last')
|
||||||
elseif ext.cmd.prompt or kind == 'wildlist' then
|
elseif (ext.cmd.prompt or kind == 'wildlist') and ext.cmd.srow == 0 then
|
||||||
-- Route to dialog 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.
|
||||||
replace_last = api.nvim_win_get_config(ext.wins.dialog).hide or kind == 'wildlist'
|
replace_last = api.nvim_win_get_config(ext.wins.dialog).hide or kind == 'wildlist'
|
||||||
if kind == 'wildlist' then
|
if kind == 'wildlist' then
|
||||||
@@ -383,7 +388,7 @@ function M.msg_show(kind, content, replace_last, _, append)
|
|||||||
-- 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.target
|
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.srow == 0) then
|
||||||
return -- Do not overwrite an active cmdline unless in block mode.
|
return -- Do not overwrite an active cmdline unless in block mode.
|
||||||
end
|
end
|
||||||
-- Store the time when an important message was emitted in order to not overwrite
|
-- Store the time when an important message was emitted in order to not overwrite
|
||||||
@@ -458,7 +463,7 @@ function M.msg_history_show(entries, prev_cmd)
|
|||||||
M.set_pos('pager')
|
M.set_pos('pager')
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Adjust dimensions of the message windows after certain events.
|
--- Adjust visibility and dimensions of the message windows after certain events.
|
||||||
---
|
---
|
||||||
---@param type? 'cmd'|'dialog'|'msg'|'pager' 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)
|
||||||
@@ -469,10 +474,10 @@ function M.set_pos(type)
|
|||||||
local border = win ~= ext.wins.msg and { '', top, '', '', '', '', '', '' } or nil
|
local border = win ~= ext.wins.msg and { '', top, '', '', '', '', '', '' } or nil
|
||||||
local config = {
|
local config = {
|
||||||
hide = false,
|
hide = false,
|
||||||
relative = 'laststatus',
|
relative = (win == ext.wins.pager or win == ext.wins.dialog) and 'editor' or 'laststatus',
|
||||||
border = border,
|
border = border,
|
||||||
height = height,
|
height = height,
|
||||||
row = win == ext.wins.msg and 0 or 1,
|
row = (win == ext.wins.pager or win == ext.wins.dialog) and o.lines - o.cmdheight or 0,
|
||||||
col = 10000,
|
col = 10000,
|
||||||
focusable = type == 'cmd' or nil, -- Allow entering the cmdline window.
|
focusable = type == 'cmd' or nil, -- Allow entering the cmdline window.
|
||||||
}
|
}
|
||||||
@@ -511,6 +516,41 @@ function M.set_pos(type)
|
|||||||
end)
|
end)
|
||||||
vim.on_key(nil, ext.ns)
|
vim.on_key(nil, ext.ns)
|
||||||
end, ext.ns)
|
end, ext.ns)
|
||||||
|
elseif type == 'dialog' then
|
||||||
|
-- Add virtual [+x] text to indicate scrolling is possible.
|
||||||
|
local function set_top_bot_spill()
|
||||||
|
local topspill = fn.line('w0', ext.wins.dialog) - 1
|
||||||
|
local botspill = api.nvim_buf_line_count(ext.bufs.dialog) - fn.line('w$', ext.wins.dialog)
|
||||||
|
M.virt.top[1][1] = topspill > 0 and { 0, (' [+%d]'):format(topspill) } or nil
|
||||||
|
set_virttext('top', 'dialog')
|
||||||
|
M.virt.bot[1][1] = botspill > 0 and { 0, (' [+%d]'):format(botspill) } or nil
|
||||||
|
set_virttext('bot', 'dialog')
|
||||||
|
api.nvim__redraw({ flush = true })
|
||||||
|
end
|
||||||
|
set_top_bot_spill()
|
||||||
|
|
||||||
|
-- Allow paging in the dialog window, consume the key if the topline changes.
|
||||||
|
M.dialog_on_key = vim.on_key(function(key, typed)
|
||||||
|
if not typed then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local page_keys = {
|
||||||
|
g = 'gg',
|
||||||
|
G = 'G',
|
||||||
|
j = 'Lj',
|
||||||
|
k = 'Hk',
|
||||||
|
d = [[\<C-D>]],
|
||||||
|
u = [[\<C-U>]],
|
||||||
|
f = [[\<C-F>]],
|
||||||
|
b = [[\<C-B>]],
|
||||||
|
}
|
||||||
|
if page_keys[key] then
|
||||||
|
local topline = fn.getwininfo(ext.wins.dialog)[1].topline
|
||||||
|
fn.win_execute(ext.wins.dialog, ('exe "norm! %s"'):format(page_keys[key]))
|
||||||
|
set_top_bot_spill()
|
||||||
|
return fn.getwininfo(ext.wins.dialog)[1].topline ~= topline and '' or nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
elseif type == 'msg' then
|
elseif 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
|
||||||
|
@@ -49,7 +49,7 @@ function M.check_targets()
|
|||||||
hide = type ~= 'cmd' or M.cmdheight == 0 or nil,
|
hide = type ~= 'cmd' or M.cmdheight == 0 or nil,
|
||||||
border = type ~= 'msg' and 'none' or nil,
|
border = type ~= 'msg' and 'none' or nil,
|
||||||
-- kZIndexMessages < zindex < kZIndexCmdlinePopupMenu (grid_defs.h), pager below others.
|
-- kZIndexMessages < zindex < kZIndexCmdlinePopupMenu (grid_defs.h), pager below others.
|
||||||
zindex = 200 - (type == 'pager' and 1 or 0),
|
zindex = 200 + (type == 'cmd' and 1 or 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
|
||||||
|
@@ -253,4 +253,142 @@ describe('messages2', function()
|
|||||||
{16::}^ |
|
{16::}^ |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('paging prompt dialog #35191', function()
|
||||||
|
screen:try_resize(71, screen._height)
|
||||||
|
local top = [[
|
||||||
|
|
|
||||||
|
{1:~ }|*4
|
||||||
|
{3:───────────────────────────────────────────────────────────────────────}|
|
||||||
|
0 |
|
||||||
|
1 |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
6 [+93] |
|
||||||
|
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
|
||||||
|
]]
|
||||||
|
feed(':call inputlist(range(100))<CR>')
|
||||||
|
screen:expect(top)
|
||||||
|
feed('j')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*4
|
||||||
|
{3:───────────────────────────────────────────────────────────────────────}|
|
||||||
|
1 [+1] |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
6 |
|
||||||
|
7 [+92] |
|
||||||
|
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
|
||||||
|
]])
|
||||||
|
feed('k')
|
||||||
|
screen:expect(top)
|
||||||
|
feed('d')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*4
|
||||||
|
{3:───────────────────────────────────────────────────────────────────────}|
|
||||||
|
3 [+3] |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
6 |
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
9 [+90] |
|
||||||
|
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
|
||||||
|
]])
|
||||||
|
feed('u')
|
||||||
|
screen:expect(top)
|
||||||
|
feed('f')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*4
|
||||||
|
{3:───────────────────────────────────────────────────────────────────────}|
|
||||||
|
5 [+5] |
|
||||||
|
6 |
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
11 [+88] |
|
||||||
|
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
|
||||||
|
]])
|
||||||
|
feed('b')
|
||||||
|
screen:expect(top)
|
||||||
|
feed('G')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*4
|
||||||
|
{3:───────────────────────────────────────────────────────────────────────}|
|
||||||
|
93 [+93] |
|
||||||
|
94 |
|
||||||
|
95 |
|
||||||
|
96 |
|
||||||
|
97 |
|
||||||
|
98 |
|
||||||
|
99 |
|
||||||
|
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
|
||||||
|
]])
|
||||||
|
feed('g')
|
||||||
|
screen:expect(top)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('in cmdline_block mode', function()
|
||||||
|
feed(':if 1<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*11
|
||||||
|
{16::}{15:if} {26:1} |
|
||||||
|
{16::} ^ |
|
||||||
|
]])
|
||||||
|
feed([[echo input("foo\nbar:")<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*9
|
||||||
|
:if 1 |
|
||||||
|
: echo input("foo\nbar:") |
|
||||||
|
foo |
|
||||||
|
bar:^ |
|
||||||
|
]])
|
||||||
|
feed('baz<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*9
|
||||||
|
{16::}{15:if} {26:1} |
|
||||||
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||||
|
{15:baz} |
|
||||||
|
{16::} ^ |
|
||||||
|
]])
|
||||||
|
feed([[echo input("foo\nbar:")<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*7
|
||||||
|
:if 1 |
|
||||||
|
: echo input("foo\nbar:") |
|
||||||
|
baz |
|
||||||
|
: echo input("foo\nbar:") |
|
||||||
|
foo |
|
||||||
|
bar:^ |
|
||||||
|
]])
|
||||||
|
feed('<Esc>:endif')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*8
|
||||||
|
{16::}{15:if} {26:1} |
|
||||||
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||||
|
{15:baz} |
|
||||||
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
||||||
|
{16::} {16::}{15:endif}^ |
|
||||||
|
]])
|
||||||
|
feed('<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{1:~ }|*12
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user