diff --git a/runtime/lua/vim/_core/ui2/messages.lua b/runtime/lua/vim/_core/ui2/messages.lua index 5c4356d995..33e25aa4f4 100644 --- a/runtime/lua/vim/_core/ui2/messages.lua +++ b/runtime/lua/vim/_core/ui2/messages.lua @@ -527,6 +527,7 @@ local cmd_on_key = function(key, typed) or (typed:find('LeftMouse') and fn.getmousepos().winid == ui.wins.cmd) if entered then M.expand_msg('cmd', 'pager') + api.nvim_win_set_cursor(ui.wins.pager, { 1, 0 }) end pcall(api.nvim_win_close, ui.wins.cmd, true) ui.check_targets() @@ -554,28 +555,19 @@ local dialog_on_key = function(_, typed) typed = typed and fn.keytrans(typed) if not typed then return - elseif typed == '' 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) - M.dialog_on_key = nil - return '' end - local page_keys = { - g = 'gg', - G = 'G', - j = 'Lj', - k = 'Hk', - d = [[\]], - u = [[\]], - f = [[\]], - b = [[\]], - } - local info = page_keys[typed] and fn.getwininfo(ui.wins.dialog)[1] - 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[typed])) + -- TODO: no hint anymore, so should at least be documented at some point. + local map, eob = {}, typed:match('PageDown') + map[''], map[''] = 'gg', 'G' + map[''], map[''] = 'Hk', 'Hk' + map[''], map[''] = 'Lj', 'Lj' + map[''], map[''] = [[\]], [[\]] + map[''], map[''] = [[\]], [[\]] + + local info = map[typed] and fn.getwininfo(ui.wins.dialog)[1] + if info and (not eob or info.botline < api.nvim_buf_line_count(ui.bufs.dialog)) then + fn.win_execute(ui.wins.dialog, ('exe "norm! %s"'):format(map[typed])) set_top_bot_spill() return fn.getwininfo(ui.wins.dialog)[1].topline ~= info.topline and '' or nil end @@ -583,16 +575,17 @@ end local was_cmdwin = '' ---@param min integer Minimum window height. -local function win_row_height(tgt, min) +local function win_row_height_border(tgt, min) local cfgmin = ui.cfg.msg[tgt].height --[[@as number]] - cfgmin = cfgmin > 1 and cfgmin or math.ceil(o.lines * cfgmin) + min = math.min(min, cfgmin > 1 and cfgmin or math.ceil(o.lines * cfgmin)) if tgt ~= 'pager' then - return (tgt == 'msg' and 0 or 1) - ui.cmd.wmnumode, math.min(min, cfgmin) + return (tgt == 'msg' and 0 or 1) - ui.cmd.wmnumode, min, min < o.lines - ui.cmdheight end local cmdwin = fn.getcmdwintype() ~= was_cmdwin and api.nvim_win_get_height(0) or 0 local global_stl = (cmdwin > 0 or o.laststatus == 3) and 1 or 0 local row = 1 - cmdwin - global_stl - return row, math.min(math.min(cfgmin, min), o.lines - 1 - ui.cmdheight - global_stl - cmdwin) + local top = min < o.lines - ui.cmdheight - global_stl - cmdwin + return row, math.min(min, o.lines - (top and 1 or 0) - ui.cmdheight - global_stl - cmdwin), top end local function enter_pager() @@ -624,7 +617,7 @@ local function enter_pager() in_pager = in_pager and api.nvim_win_is_valid(ui.wins.pager) local cfg = in_pager and { relative = 'laststatus', col = 0 } or { hide = true } if in_pager then - cfg.row, cfg.height = win_row_height('pager', height) + cfg.row, cfg.height, cfg.border = win_row_height_border('pager', height) else pcall(api.nvim_set_option_value, 'eiw', 'all', { scope = 'local', win = ui.wins.pager }) api.nvim_del_autocmd(id) @@ -651,14 +644,10 @@ function M.set_pos(tgt) if cfg and (tgt or not cfg.hide) then local texth = api.nvim_win_text_height(win, {}) local top = { vim.opt.fcs:get().msgsep or ' ', 'MsgSeparator' } - local hint = 'f/d/j: screen/page/line down, b/u/k: up, : stop paging' cfg = { hide = false, relative = 'laststatus', col = 10000 } ---@type table - cfg.row, cfg.height = win_row_height(t, texth.all) - cfg.border = t ~= 'msg' and { '', top, '', '', '', '', '', '' } or nil + cfg.row, cfg.height, cfg.border = win_row_height_border(t, texth.all) + cfg.border = cfg.border and t ~= 'msg' and { '', top, '', '', '', '', '', '' } or nil cfg.mouse = tgt == 'cmd' or nil - cfg.title = tgt == 'dialog' - and { { ui.cmd.expand == 0 and cfg.height < texth.all and hint or '', 'MsgMore' } } - or nil api.nvim_win_set_config(win, cfg) if tgt == 'cmd' then @@ -668,7 +657,7 @@ function M.set_pos(tgt) set_virttext('msg', 'cmd') M.virt.msg[M.virt.idx.spill][1] = { 0, (' [+%d]'):format(texth.all - ui.cmdheight) } M.cmd_on_key = vim.on_key(cmd_on_key, ui.ns) - elseif tgt == 'dialog' and set_top_bot_spill() and #cfg.title[1][1] > 0 then + elseif tgt == 'dialog' and set_top_bot_spill() then M.dialog_on_key = vim.on_key(dialog_on_key, M.dialog_on_key) elseif tgt == 'msg' then -- Ensure last line is visible and first line is at top of window. diff --git a/test/functional/ui/messages2_spec.lua b/test/functional/ui/messages2_spec.lua index 9350b877e4..c3cf060bc9 100644 --- a/test/functional/ui/messages2_spec.lua +++ b/test/functional/ui/messages2_spec.lua @@ -182,25 +182,22 @@ describe('messages2', function() -- Do enter the pager in normal mode. feed('') screen:expect([[ - {3: }| ^foo | - foo |*11 + foo |*12 1,1 Top| ]]) -- Changing 'laststatus' reveals the global statusline with a pager height -- exceeding the available lines: #38008. command('set laststatus=3') screen:expect([[ - {3: }| ^foo | - foo |*10 + foo |*11 {3:[Pager] 1,1 Top}| | ]]) feed(':') screen:expect([[ - {3: }| - foo |*4 + foo |*5 {1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) | {1::}^ | {1:~ }|*5 @@ -209,8 +206,7 @@ describe('messages2', function() ]]) command('wincmd +') screen:expect([[ - {3: }| - foo |*3 + foo |*4 {1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) | {1::}^ | {1:~ }|*6 @@ -219,8 +215,7 @@ describe('messages2', function() ]]) command('echo "foo"') screen:expect([[ - {3: }| - foo |*3 + foo |*4 {1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) | {1::}^ | {1:~ }|*6 @@ -229,8 +224,7 @@ describe('messages2', function() ]]) feed('') screen:expect([[ - {3: }| - foo |*11 + foo |*12 {3:[Pager] 1,1 Top}| {16::}^ | ]]) @@ -248,9 +242,8 @@ describe('messages2', function() ]]) feed(':messages') screen:expect([[ - {3: }| ^foo | - foo |*10 + foo |*11 {3:[Pager] 1,1 Top}| | ]]) @@ -527,7 +520,7 @@ describe('messages2', function() local top = [[ | {1:~ }|*4 - {3: }f/d/j: screen/page/line down, b/u/k: up, : stop paging{3: }| + {3: }| 0 | 1 | 2 | @@ -539,11 +532,11 @@ describe('messages2', function() ]] feed(':call inputlist(range(100))') screen:expect(top) - feed('j') + feed('') screen:expect([[ | {1:~ }|*4 - {3: }f/d/j: screen/page/line down, b/u/k: up, : stop paging{3: }| + {3: }| 1 [+1] | 2 | 3 | @@ -553,29 +546,13 @@ describe('messages2', function() 7 [+92] | Type number and or click with the mouse (q or empty cancels): ^ | ]]) - feed('k') + feed('') screen:expect(top) - feed('d') + feed('') screen:expect([[ | {1:~ }|*4 - {3: }f/d/j: screen/page/line down, b/u/k: up, : stop paging{3: }| - 3 [+3] | - 4 | - 5 | - 6 | - 7 | - 8 | - 9 [+90] | - Type number and or click with the mouse (q or empty cancels): ^ | - ]]) - feed('u') - screen:expect(top) - feed('f') - screen:expect([[ - | - {1:~ }|*4 - {3: }f/d/j: screen/page/line down, b/u/k: up, : stop paging{3: }| + {3: }| 5 [+5] | 6 | 7 | @@ -585,13 +562,13 @@ describe('messages2', function() 11 [+88] | Type number and or click with the mouse (q or empty cancels): ^ | ]]) - feed('b') + feed('') screen:expect(top) - feed('G') + feed('') screen:expect([[ | {1:~ }|*4 - {3: }f/d/j: screen/page/line down, b/u/k: up, : stop paging{3: }| + {3: }| 93 [+93] | 94 | 95 | @@ -602,38 +579,10 @@ describe('messages2', function() Type number and or click with the mouse (q or empty cancels): ^ | ]]) -- No scrolling beyond end of buffer #36114 - feed('f') - screen:expect([[ - | - {1:~ }|*3 - {3: }f/d/j: screen/page/line down, b/u/k: up, : stop paging{3: }| - 93 [+93] | - 94 | - 95 | - 96 | - 97 | - 98 | - 99 | - Type number and or click with the mouse (q or empty cancels): f| - ^ | - ]]) - feed('g') + feed('') + screen:expect_unchanged() + feed('') screen:expect(top) - feed('f') - screen:expect([[ - | - {1:~ }|*3 - {3: }| - 0 | - 1 | - 2 | - 3 | - 4 | - 5 | - 6 [+93] | - Type number and or click with the mouse (q or empty cancels): f| - ^ | - ]]) end) it('FileType is fired after default options are set', function()