mirror of
https://github.com/neovim/neovim.git
synced 2026-08-27 01:21:48 +00:00
feat(ui2): show active paging keys in dialog float title #37919
Problem: Paging keys being consumed without obvious indicator
in the dialog window can be surprising.
Solution: Display a hint with paging keys in the dialog window title
when paging is active. Recognize <Esc> as mapping to stop
paging.
This commit is contained in:
@@ -501,21 +501,22 @@ end
|
|||||||
|
|
||||||
--- Adjust visibility and 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 tar? 'cmd'|'dialog'|'msg'|'pager' To be positioned window (nil for all).
|
||||||
function M.set_pos(type)
|
function M.set_pos(tar)
|
||||||
local function win_set_pos(win)
|
local function win_set_pos(win)
|
||||||
local cfg = { hide = false, relative = 'laststatus', col = 10000 }
|
local cfg = { hide = false, relative = 'laststatus', col = 10000 }
|
||||||
local texth = type and api.nvim_win_text_height(win, {}) or {}
|
local texth = tar and api.nvim_win_text_height(win, {}) or {}
|
||||||
local top = { vim.opt.fcs:get().msgsep or ' ', 'MsgSeparator' }
|
local top = { vim.opt.fcs:get().msgsep or ' ', 'MsgSeparator' }
|
||||||
cfg.height = type == 'pager' and texth.all
|
cfg.height = tar and math.min(texth.all, tar == 'pager' and 10000 or math.ceil(o.lines * 0.5))
|
||||||
or type and math.min(texth.all, math.ceil(o.lines * 0.5))
|
|
||||||
cfg.border = win ~= ui.wins.msg and { '', top, '', '', '', '', '', '' } or nil
|
cfg.border = win ~= ui.wins.msg and { '', top, '', '', '', '', '', '' } or nil
|
||||||
cfg.focusable = type == 'cmd' or nil
|
cfg.focusable = tar == 'cmd' or nil
|
||||||
cfg.row = (win == ui.wins.msg and 0 or 1) - ui.cmd.wmnumode
|
cfg.row = (win == ui.wins.msg and 0 or 1) - ui.cmd.wmnumode
|
||||||
cfg.row = cfg.row - ((win == ui.wins.pager and o.laststatus == 3) and 1 or 0)
|
cfg.row = cfg.row - ((win == ui.wins.pager and o.laststatus == 3) and 1 or 0)
|
||||||
|
local title = { 'f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging', 'MsgSeparator' }
|
||||||
|
cfg.title = tar == 'dialog' and cfg.height < texth.all and { title } or nil
|
||||||
api.nvim_win_set_config(win, cfg)
|
api.nvim_win_set_config(win, cfg)
|
||||||
|
|
||||||
if type == 'cmd' and not cmd_on_key then
|
if tar == 'cmd' and not cmd_on_key then
|
||||||
-- Temporarily expand the cmdline, until next key press.
|
-- Temporarily expand the cmdline, until next key press.
|
||||||
local save_spill = M.virt.msg[M.virt.idx.spill][1]
|
local save_spill = M.virt.msg[M.virt.idx.spill][1]
|
||||||
local spill = texth.all > cfg.height and (' [+%d]'):format(texth.all - cfg.height)
|
local spill = texth.all > cfg.height and (' [+%d]'):format(texth.all - cfg.height)
|
||||||
@@ -551,7 +552,7 @@ function M.set_pos(type)
|
|||||||
end)
|
end)
|
||||||
vim.on_key(nil, ui.ns)
|
vim.on_key(nil, ui.ns)
|
||||||
end, ui.ns)
|
end, ui.ns)
|
||||||
elseif type == 'dialog' then
|
elseif tar == 'dialog' then
|
||||||
-- Add virtual [+x] text to indicate scrolling is possible.
|
-- Add virtual [+x] text to indicate scrolling is possible.
|
||||||
local function set_top_bot_spill()
|
local function set_top_bot_spill()
|
||||||
local topspill = fn.line('w0', ui.wins.dialog) - 1
|
local topspill = fn.line('w0', ui.wins.dialog) - 1
|
||||||
@@ -565,10 +566,18 @@ function M.set_pos(type)
|
|||||||
set_top_bot_spill()
|
set_top_bot_spill()
|
||||||
|
|
||||||
-- Allow paging in the dialog window, consume the key if the topline changes.
|
-- Allow paging in the dialog window, consume the key if the topline changes.
|
||||||
M.dialog_on_key = vim.on_key(function(key, typed)
|
M.dialog_on_key = vim.on_key(function(_, typed)
|
||||||
|
typed = typed and fn.keytrans(typed)
|
||||||
if not typed then
|
if not typed then
|
||||||
return
|
return
|
||||||
|
elseif typed == '<Esc>' then
|
||||||
|
-- Stop paging, redraw empty title to reflect paging is no longer active.
|
||||||
|
api.nvim_win_set_config(ui.wins.dialog, { title = '' })
|
||||||
|
api.nvim__redraw({ flush = true })
|
||||||
|
vim.on_key(nil, M.dialog_on_key)
|
||||||
|
return ''
|
||||||
end
|
end
|
||||||
|
|
||||||
local page_keys = {
|
local page_keys = {
|
||||||
g = 'gg',
|
g = 'gg',
|
||||||
G = 'G',
|
G = 'G',
|
||||||
@@ -579,18 +588,18 @@ function M.set_pos(type)
|
|||||||
f = [[\<C-F>]],
|
f = [[\<C-F>]],
|
||||||
b = [[\<C-B>]],
|
b = [[\<C-B>]],
|
||||||
}
|
}
|
||||||
local info = page_keys[key] and fn.getwininfo(ui.wins.dialog)[1]
|
local info = page_keys[typed] and fn.getwininfo(ui.wins.dialog)[1]
|
||||||
if info and (key ~= 'f' or info.botline < api.nvim_buf_line_count(ui.bufs.dialog)) then
|
if info and (typed ~= 'f' or info.botline < api.nvim_buf_line_count(ui.bufs.dialog)) then
|
||||||
fn.win_execute(ui.wins.dialog, ('exe "norm! %s"'):format(page_keys[key]))
|
fn.win_execute(ui.wins.dialog, ('exe "norm! %s"'):format(page_keys[typed]))
|
||||||
set_top_bot_spill()
|
set_top_bot_spill()
|
||||||
return fn.getwininfo(ui.wins.dialog)[1].topline ~= info.topline and '' or nil
|
return fn.getwininfo(ui.wins.dialog)[1].topline ~= info.topline and '' or nil
|
||||||
end
|
end
|
||||||
end, M.dialog_on_key)
|
end, M.dialog_on_key)
|
||||||
elseif type == 'msg' then
|
elseif tar == '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 > cfg.height and texth.end_row or 0) + 1
|
local row = (texth.all > cfg.height and texth.end_row or 0) + 1
|
||||||
api.nvim_win_set_cursor(ui.wins.msg, { row, 0 })
|
api.nvim_win_set_cursor(ui.wins.msg, { row, 0 })
|
||||||
elseif type == 'pager' then
|
elseif tar == 'pager' then
|
||||||
if fn.getcmdwintype() ~= '' then
|
if fn.getcmdwintype() ~= '' then
|
||||||
-- Cannot leave the cmdwin to enter the pager, 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.
|
-- NOTE: regression w.r.t. the message grid, which allowed this.
|
||||||
@@ -621,10 +630,10 @@ function M.set_pos(type)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for t, win in pairs(ui.wins) do
|
for t, win in pairs(ui.wins) do
|
||||||
local cfg = (t == type or (type == nil and t ~= 'cmd'))
|
local cfg = (t == tar or (tar == nil and t ~= 'cmd'))
|
||||||
and api.nvim_win_is_valid(win)
|
and api.nvim_win_is_valid(win)
|
||||||
and api.nvim_win_get_config(win)
|
and api.nvim_win_get_config(win)
|
||||||
if cfg and (type or not cfg.hide) then
|
if cfg and (tar or not cfg.hide) then
|
||||||
win_set_pos(win)
|
win_set_pos(win)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ describe('messages2', function()
|
|||||||
local top = [[
|
local top = [[
|
||||||
|
|
|
|
||||||
{1:~ }|*4
|
{1:~ }|*4
|
||||||
{3: }|
|
{3: f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging }|
|
||||||
0 |
|
0 |
|
||||||
1 |
|
1 |
|
||||||
2 |
|
2 |
|
||||||
@@ -327,7 +327,7 @@ describe('messages2', function()
|
|||||||
screen:expect([[
|
screen:expect([[
|
||||||
|
|
|
|
||||||
{1:~ }|*4
|
{1:~ }|*4
|
||||||
{3: }|
|
{3: f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging }|
|
||||||
1 [+1] |
|
1 [+1] |
|
||||||
2 |
|
2 |
|
||||||
3 |
|
3 |
|
||||||
@@ -343,7 +343,7 @@ describe('messages2', function()
|
|||||||
screen:expect([[
|
screen:expect([[
|
||||||
|
|
|
|
||||||
{1:~ }|*4
|
{1:~ }|*4
|
||||||
{3: }|
|
{3: f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging }|
|
||||||
3 [+3] |
|
3 [+3] |
|
||||||
4 |
|
4 |
|
||||||
5 |
|
5 |
|
||||||
@@ -359,7 +359,7 @@ describe('messages2', function()
|
|||||||
screen:expect([[
|
screen:expect([[
|
||||||
|
|
|
|
||||||
{1:~ }|*4
|
{1:~ }|*4
|
||||||
{3: }|
|
{3: f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging }|
|
||||||
5 [+5] |
|
5 [+5] |
|
||||||
6 |
|
6 |
|
||||||
7 |
|
7 |
|
||||||
@@ -375,7 +375,7 @@ describe('messages2', function()
|
|||||||
screen:expect([[
|
screen:expect([[
|
||||||
|
|
|
|
||||||
{1:~ }|*4
|
{1:~ }|*4
|
||||||
{3: }|
|
{3: f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging }|
|
||||||
93 [+93] |
|
93 [+93] |
|
||||||
94 |
|
94 |
|
||||||
95 |
|
95 |
|
||||||
@@ -390,7 +390,7 @@ describe('messages2', function()
|
|||||||
screen:expect([[
|
screen:expect([[
|
||||||
|
|
|
|
||||||
{1:~ }|*3
|
{1:~ }|*3
|
||||||
{3: }|
|
{3: f/d/j: screen/page/line down, b/u/k: up, <Esc>: stop paging }|
|
||||||
93 [+93] |
|
93 [+93] |
|
||||||
94 |
|
94 |
|
||||||
95 |
|
95 |
|
||||||
@@ -403,6 +403,21 @@ describe('messages2', function()
|
|||||||
]])
|
]])
|
||||||
feed('<Backspace>g')
|
feed('<Backspace>g')
|
||||||
screen:expect(top)
|
screen:expect(top)
|
||||||
|
feed('<Esc>f')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{1:~ }|*3
|
||||||
|
{3: }|
|
||||||
|
0 |
|
||||||
|
1 |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
6 [+93] |
|
||||||
|
Type number and <Enter> or click with the mouse (q or empty cancels): f|
|
||||||
|
^ |
|
||||||
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('FileType is fired after default options are set', function()
|
it('FileType is fired after default options are set', function()
|
||||||
|
|||||||
Reference in New Issue
Block a user