mirror of
https://github.com/neovim/neovim.git
synced 2026-09-04 13:20:34 +00:00
Problem: there should be exactly one cell of padding between sections, and exactly one cell of minimum padding between the left and the right. - Spaces between sections waste space when a section is empty. According to a comment in #33036, this was the reason to avoid `%k` and implement the keymap section with a vim expression, but other sections still have this problem. - The diagnostics section wastes space because it is not entirely empty when there are diagnostics in another buffer. - The terminal exit code section can touch the right side, e.g. the ruler, even though it belongs to the left side. Solution: - Use auto-hiding item groups (`%(` without width fields) to get rid of unneeded spaces when a section shows no information. This simplifies the 'showcmd' and 'keymap' sections in particular. - As a slight simplification, `term_exitcode` is moved into the flags section since it is formatted with square brackets like a flag. - Count the diagnostics for the current buffer specifically. - Ensure at least one cell of padding between the left and the right side by adding a space next to the separator `%=`. Problem: some sections are implemented with `%{%`, even though reevaluation of the expression result is not needed. This leads to otherwise needless %-escaping in `progress_status`. Solution: use `%{` instead. Problem: `%{` and `%{%` (without items) replace spaces with fillchars. This looks out-of-place inside the terminal exit code section, and in contrast to all other sections, the 'busy' section is surrounded by fillchars, which looks inconsistent, and with some terminal-font combinations, ◐ overlaps the fillchar, e.g. Alacritty & JetBrains Mono. Solution: use non-breaking spaces U+202F to avoid fillchar substitution. Problem: sections that appear/disappear frequently can make otherwise more stable sections jump around a lot. Solution: sort the sections on the right roughly by volatility: 'showcmd' in first place, 'keymap' next to the ruler.
1545 lines
64 KiB
Lua
1545 lines
64 KiB
Lua
local t = require('test.testutil')
|
||
local n = require('test.functional.testnvim')()
|
||
local tt = require('test.functional.testterm')
|
||
local Screen = require('test.functional.ui.screen')
|
||
|
||
local describe, it, before_each = t.describe, t.it, t.before_each
|
||
local assert_alive = n.assert_alive
|
||
local clear = n.clear
|
||
local command = n.command
|
||
local feed = n.feed
|
||
local eq = t.eq
|
||
local fn = n.fn
|
||
local api = n.api
|
||
local exec = n.exec
|
||
local exec_lua = n.exec_lua
|
||
local eval = n.eval
|
||
local sleep = vim.uv.sleep
|
||
local pcall_err = t.pcall_err
|
||
local testprg = n.testprg
|
||
local expect_exitcode = tt.expect_exitcode
|
||
|
||
local mousemodels = { 'extend', 'popup', 'popup_setpos' }
|
||
|
||
for _, model in ipairs(mousemodels) do
|
||
describe('statusline clicks with mousemodel=' .. model, function()
|
||
local screen
|
||
|
||
before_each(function()
|
||
clear()
|
||
screen = Screen.new(40, 8)
|
||
screen:add_extra_attr_ids {
|
||
[100] = { bold = true, reverse = true, foreground = Screen.colors.Blue },
|
||
}
|
||
command('set laststatus=2 mousemodel=' .. model)
|
||
exec([=[
|
||
function! MyClickFunc(minwid, clicks, button, mods)
|
||
let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
|
||
if a:mods !=# ' '
|
||
let g:testvar ..= '(' .. a:mods .. ')'
|
||
endif
|
||
endfunction
|
||
let g:testvar = ''
|
||
]=])
|
||
end)
|
||
|
||
it('works', function()
|
||
api.nvim_set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 16)
|
||
eq('', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 29)
|
||
eq('', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 17)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 17)
|
||
eq('0 2 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 17)
|
||
eq('0 3 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 17)
|
||
eq('0 4 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 28)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 28)
|
||
eq('0 2 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 28)
|
||
eq('0 3 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 28)
|
||
eq('0 4 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
|
||
eq('0 1 x1', eval('g:testvar'))
|
||
api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
|
||
eq('0 2 x1', eval('g:testvar'))
|
||
api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
|
||
eq('0 3 x1', eval('g:testvar'))
|
||
api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
|
||
eq('0 4 x1', eval('g:testvar'))
|
||
api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
|
||
eq('0 1 x2', eval('g:testvar'))
|
||
api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
|
||
eq('0 2 x2', eval('g:testvar'))
|
||
api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
|
||
eq('0 3 x2', eval('g:testvar'))
|
||
api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
|
||
eq('0 4 x2', eval('g:testvar'))
|
||
end)
|
||
|
||
it('works with control characters and highlight', function()
|
||
api.nvim_set_option_value('statusline', '\t%#NonText#\1%0@MyClickFunc@\t\1%T\t%##\1', {})
|
||
screen:expect {
|
||
grid = [[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:^I}{100:^A^I^A^I}{3:^A }|
|
||
|
|
||
]],
|
||
}
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 3)
|
||
eq('', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 8)
|
||
eq('', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 4)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 7)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
end)
|
||
|
||
it('works with combined highlight attributes', function()
|
||
screen:add_extra_attr_ids({
|
||
[131] = { reverse = true, bold = true, background = Screen.colors.LightMagenta },
|
||
[132] = {
|
||
reverse = true,
|
||
foreground = Screen.colors.Magenta,
|
||
bold = true,
|
||
background = Screen.colors.LightMagenta,
|
||
},
|
||
[133] = { reverse = true, bold = true, foreground = Screen.colors.Magenta1 },
|
||
[134] = {
|
||
bold = true,
|
||
background = Screen.colors.LightMagenta,
|
||
reverse = true,
|
||
undercurl = true,
|
||
special = Screen.colors.Red,
|
||
},
|
||
[135] = {
|
||
bold = true,
|
||
background = Screen.colors.LightMagenta,
|
||
reverse = true,
|
||
undercurl = true,
|
||
foreground = Screen.colors.Fuchsia,
|
||
special = Screen.colors.Red,
|
||
},
|
||
})
|
||
|
||
api.nvim_set_option_value(
|
||
'statusline',
|
||
'\t%#Pmenu#foo%$SpellBad$bar%$String$baz%#Constant#qux',
|
||
{}
|
||
)
|
||
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:^I}{131:foo}{134:bar}{135:baz}{133:qux }|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('works for winbar', function()
|
||
api.nvim_set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
|
||
api.nvim_input_mouse('left', 'press', '', 0, 0, 17)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 0, 17)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
end)
|
||
|
||
it('works for winbar in floating window', function()
|
||
api.nvim_open_win(
|
||
0,
|
||
true,
|
||
{ width = 30, height = 4, relative = 'editor', row = 1, col = 5, border = 'single' }
|
||
)
|
||
api.nvim_set_option_value(
|
||
'winbar',
|
||
'Not clicky stuff %0@MyClickFunc@Clicky stuff%T',
|
||
{ scope = 'local' }
|
||
)
|
||
api.nvim_input_mouse('left', 'press', '', 0, 2, 23)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
end)
|
||
|
||
it('works when there are multiple windows', function()
|
||
command('split')
|
||
api.nvim_set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
|
||
api.nvim_set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
|
||
api.nvim_input_mouse('left', 'press', '', 0, 0, 17)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 4, 17)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('middle', 'press', '', 0, 3, 17)
|
||
eq('0 1 m', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 17)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
end)
|
||
|
||
it('works with Lua function', function()
|
||
exec_lua([[
|
||
function clicky_func(minwid, clicks, button, mods)
|
||
vim.g.testvar = string.format("%d %d %s", minwid, clicks, button)
|
||
end
|
||
]])
|
||
api.nvim_set_option_value(
|
||
'statusline',
|
||
'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T',
|
||
{}
|
||
)
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 17)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
end)
|
||
|
||
it('ignores unsupported click items', function()
|
||
command('tabnew | tabprevious')
|
||
api.nvim_set_option_value('statusline', '%2TNot clicky stuff%T', {})
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 0)
|
||
eq(1, api.nvim_get_current_tabpage())
|
||
api.nvim_set_option_value('statusline', '%2XNot clicky stuff%X', {})
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 0)
|
||
eq(2, #api.nvim_list_tabpages())
|
||
end)
|
||
|
||
it("right click works when statusline isn't focused #18994", function()
|
||
api.nvim_set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 17)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 17)
|
||
eq('0 2 r', eval('g:testvar'))
|
||
end)
|
||
|
||
it('works with modifiers #18994', function()
|
||
api.nvim_set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
|
||
-- Note: alternate between left and right mouse buttons to avoid triggering multiclicks
|
||
api.nvim_input_mouse('left', 'press', 'S', 0, 6, 17)
|
||
eq('0 1 l(s )', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', 'S', 0, 6, 17)
|
||
eq('0 1 r(s )', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', 'A', 0, 6, 17)
|
||
eq('0 1 l( a )', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', 'A', 0, 6, 17)
|
||
eq('0 1 r( a )', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', 'AS', 0, 6, 17)
|
||
eq('0 1 l(s a )', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', 'AS', 0, 6, 17)
|
||
eq('0 1 r(s a )', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', 'T', 0, 6, 17)
|
||
eq('0 1 l( m)', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', 'T', 0, 6, 17)
|
||
eq('0 1 r( m)', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', 'TS', 0, 6, 17)
|
||
eq('0 1 l(s m)', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', 'TS', 0, 6, 17)
|
||
eq('0 1 r(s m)', eval('g:testvar'))
|
||
api.nvim_input_mouse('left', 'press', 'C', 0, 6, 17)
|
||
eq('0 1 l( c )', eval('g:testvar'))
|
||
-- <C-RightMouse> is for tag jump
|
||
end)
|
||
|
||
it('works for global statusline with vertical splits #19186', function()
|
||
command('set laststatus=3')
|
||
api.nvim_set_option_value(
|
||
'statusline',
|
||
'%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T',
|
||
{}
|
||
)
|
||
command('vsplit')
|
||
screen:expect {
|
||
grid = [[
|
||
^ │ |
|
||
{1:~ }│{1:~ }|*5
|
||
{3:Clicky stuff Clicky stuff}|
|
||
|
|
||
]],
|
||
}
|
||
|
||
-- clickable area on the right
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 35)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 35)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
|
||
-- clickable area on the left
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 5)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 5)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
end)
|
||
|
||
it('no memory leak with zero-width click labels', function()
|
||
command([[
|
||
let &stl = '%@Test@%T%@MyClickFunc@%=%T%@Test@'
|
||
]])
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 0)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
api.nvim_input_mouse('right', 'press', '', 0, 6, 39)
|
||
eq('0 1 r', eval('g:testvar'))
|
||
end)
|
||
|
||
it('no memory leak with truncated click labels', function()
|
||
command([[
|
||
let &stl = '%@MyClickFunc@foo%X' .. repeat('a', 40) .. '%<t%@Test@bar%X%@Test@baz'
|
||
]])
|
||
api.nvim_input_mouse('left', 'press', '', 0, 6, 2)
|
||
eq('0 1 l', eval('g:testvar'))
|
||
end)
|
||
end)
|
||
end
|
||
|
||
describe('global statusline', function()
|
||
local screen
|
||
|
||
before_each(function()
|
||
clear()
|
||
screen = Screen.new(60, 16)
|
||
screen:add_extra_attr_ids {
|
||
[100] = { foreground = Screen.colors.Magenta1, bold = true },
|
||
}
|
||
command('set laststatus=3')
|
||
command('set ruler')
|
||
end)
|
||
|
||
it('works', function()
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
feed('i<CR><CR>')
|
||
screen:expect([[
|
||
|*2
|
||
^ |
|
||
{1:~ }|*11
|
||
{3:[No Name] [+] 3,1 All}|
|
||
{5:-- INSERT --} |
|
||
]])
|
||
end)
|
||
|
||
it('works with splits', function()
|
||
command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
|
||
screen:expect([[
|
||
│ │ │^ |
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
|
||
{1:~ }├────────────────┤{1:~}│{1:~ }|
|
||
{1:~ }│ │{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}├────────────────────|
|
||
{1:~ }│{1:~ }│{1:~}│ |
|
||
────────────────────┴────────────────┴─┤{1:~ }|
|
||
│{1:~ }|
|
||
{1:~ }│{1:~ }|*3
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('works when switching between values of laststatus', function()
|
||
command('set laststatus=1')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*14
|
||
0,0-1 All|
|
||
]])
|
||
|
||
command('set laststatus=3')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
|
||
command('set laststatus=2')
|
||
screen:expect([[
|
||
│ │ │^ |
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
|
||
{1:~ }│{2:<-1 All}│{1:~}│{1:~ }|
|
||
{1:~ }│ │{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{3:< 0,0-1 All}|
|
||
{1:~ }│{1:~ }│{1:~}│ |
|
||
{2:< 0,0-1 All <-1 All <}│{1:~ }|
|
||
│{1:~ }|
|
||
{1:~ }│{1:~ }|*3
|
||
{2:[No Name] 0,0-1 All < 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
command('set laststatus=3')
|
||
screen:expect([[
|
||
│ │ │^ |
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
|
||
{1:~ }├────────────────┤{1:~}│{1:~ }|
|
||
{1:~ }│ │{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}├────────────────────|
|
||
{1:~ }│{1:~ }│{1:~}│ |
|
||
────────────────────┴────────────────┴─┤{1:~ }|
|
||
│{1:~ }|
|
||
{1:~ }│{1:~ }|*3
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
command('set laststatus=0')
|
||
screen:expect([[
|
||
│ │ │^ |
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
|
||
{1:~ }│{2:<-1 All}│{1:~}│{1:~ }|
|
||
{1:~ }│ │{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{3:< 0,0-1 All}|
|
||
{1:~ }│{1:~ }│{1:~}│ |
|
||
{2:< 0,0-1 All <-1 All <}│{1:~ }|
|
||
│{1:~ }|
|
||
{1:~ }│{1:~ }|*4
|
||
0,0-1 All|
|
||
]])
|
||
|
||
command('set laststatus=3')
|
||
screen:expect([[
|
||
│ │ │^ |
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|*3
|
||
{1:~ }├────────────────┤{1:~}│{1:~ }|
|
||
{1:~ }│ │{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}│{1:~ }|
|
||
{1:~ }│{1:~ }│{1:~}├────────────────────|
|
||
{1:~ }│{1:~ }│{1:~}│ |
|
||
────────────────────┴────────────────┴─┤{1:~ }|
|
||
│{1:~ }|
|
||
{1:~ }│{1:~ }|*3
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('leaving laststatus=3 does not push a window past the last row', function()
|
||
command('split | wincmd j | vsplit | split')
|
||
command('wincmd t')
|
||
command('resize 1000')
|
||
command('set laststatus=2')
|
||
command('resize 1000')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*9
|
||
{3:[No Name] 0,0-1 All}|
|
||
│ |
|
||
{2:[No Name] 0,0-1 All}│{1:~ }|
|
||
│{1:~ }|
|
||
{2:[No Name] 0,0-1 All [No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('win_move_statusline() can reduce cmdheight to 1', function()
|
||
eq(1, api.nvim_get_option_value('cmdheight', {}))
|
||
fn.win_move_statusline(0, -1)
|
||
eq(2, api.nvim_get_option_value('cmdheight', {}))
|
||
fn.win_move_statusline(0, -1)
|
||
eq(3, api.nvim_get_option_value('cmdheight', {}))
|
||
fn.win_move_statusline(0, 1)
|
||
eq(2, api.nvim_get_option_value('cmdheight', {}))
|
||
fn.win_move_statusline(0, 1)
|
||
eq(1, api.nvim_get_option_value('cmdheight', {}))
|
||
end)
|
||
|
||
it('mouse dragging can reduce cmdheight to 1', function()
|
||
command('set mouse=a')
|
||
api.nvim_input_mouse('left', 'press', '', 0, 14, 10)
|
||
eq(1, api.nvim_get_option_value('cmdheight', {}))
|
||
api.nvim_input_mouse('left', 'drag', '', 0, 13, 10)
|
||
eq(2, api.nvim_get_option_value('cmdheight', {}))
|
||
api.nvim_input_mouse('left', 'drag', '', 0, 12, 10)
|
||
eq(3, api.nvim_get_option_value('cmdheight', {}))
|
||
api.nvim_input_mouse('left', 'drag', '', 0, 13, 10)
|
||
eq(2, api.nvim_get_option_value('cmdheight', {}))
|
||
api.nvim_input_mouse('left', 'drag', '', 0, 14, 10)
|
||
eq(1, api.nvim_get_option_value('cmdheight', {}))
|
||
api.nvim_input_mouse('left', 'drag', '', 0, 15, 10)
|
||
eq(1, api.nvim_get_option_value('cmdheight', {}))
|
||
api.nvim_input_mouse('left', 'drag', '', 0, 14, 10)
|
||
eq(1, api.nvim_get_option_value('cmdheight', {}))
|
||
end)
|
||
|
||
it('cmdline row is correct after setting cmdheight #20514', function()
|
||
command('botright split test/functional/fixtures/bigfile.txt')
|
||
api.nvim_set_option_value('cmdheight', 1, {})
|
||
feed('L')
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*5
|
||
────────────────────────────────────────────────────────────|
|
||
0000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
|
||
0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
|
||
0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
|
||
0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
|
||
0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
|
||
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
|
||
^0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
|
||
{3:test/functional/fixtures/bigfile.txt 7,1 Top}|
|
||
|
|
||
]])
|
||
feed('j')
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*5
|
||
────────────────────────────────────────────────────────────|
|
||
0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
|
||
0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
|
||
0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
|
||
0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
|
||
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
|
||
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
|
||
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
|
||
{3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
||
|
|
||
]])
|
||
api.nvim_set_option_value('showtabline', 2, {})
|
||
screen:expect([[
|
||
{5: }{100:2}{5: t/f/f/bigfile.txt }{2: }|
|
||
|
|
||
{1:~ }|*5
|
||
────────────────────────────────────────────────────────────|
|
||
0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
|
||
0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
|
||
0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
|
||
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
|
||
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
|
||
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
|
||
{3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
||
|
|
||
]])
|
||
api.nvim_set_option_value('cmdheight', 0, {})
|
||
screen:expect([[
|
||
{5: }{100:2}{5: t/f/f/bigfile.txt }{2: }|
|
||
|
|
||
{1:~ }|*5
|
||
────────────────────────────────────────────────────────────|
|
||
0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
|
||
0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
|
||
0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
|
||
0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
|
||
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
|
||
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
|
||
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
|
||
{3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
||
]])
|
||
api.nvim_set_option_value('cmdheight', 1, {})
|
||
screen:expect([[
|
||
{5: }{100:2}{5: t/f/f/bigfile.txt }{2: }|
|
||
|
|
||
{1:~ }|*5
|
||
────────────────────────────────────────────────────────────|
|
||
0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
|
||
0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
|
||
0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
|
||
0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
|
||
0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
|
||
^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
|
||
{3:test/functional/fixtures/bigfile.txt 8,1 0%}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('vertical separator connector is not lost when switching window', function()
|
||
screen:add_extra_attr_ids {
|
||
[101] = { background = tonumber('0x282828') },
|
||
[102] = { bold = true, background = tonumber('0x282828'), foreground = Screen.colors.Blue1 },
|
||
}
|
||
command('hi NormalNC guibg=#282828')
|
||
command('vsplit | wincmd l | split')
|
||
-- Cursor is in top-right. Move to bottom-right.
|
||
feed('<C-w>j')
|
||
-- Verify the ├ connector is present.
|
||
screen:expect([[
|
||
{101: }│{101: }|
|
||
{102:~ }│{102:~ }|*6
|
||
{102:~ }├─────────────────────────────|
|
||
{102:~ }│^ |
|
||
{102:~ }│{1:~ }|*5
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
-- Navigate from bottom-right to left.
|
||
feed('<C-w>h')
|
||
-- The ├ connector must still be present.
|
||
screen:expect([[
|
||
^ │{101: }|
|
||
{1:~ }│{102:~ }|*6
|
||
{1:~ }├─────────────────────────────|
|
||
{1:~ }│{101: }|
|
||
{1:~ }│{102:~ }|*5
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('horizontal separator connector is not lost when switching window', function()
|
||
screen:add_extra_attr_ids {
|
||
[101] = { background = tonumber('0x282828') },
|
||
[102] = { bold = true, background = tonumber('0x282828'), foreground = Screen.colors.Blue1 },
|
||
}
|
||
command('hi NormalNC guibg=#282828')
|
||
command('split | wincmd j | vsplit')
|
||
-- Cursor is in bottom-left. Move to bottom-right.
|
||
feed('<C-w>l')
|
||
-- Verify the ┬ connector is present.
|
||
screen:expect([[
|
||
{101: }|
|
||
{102:~ }|*6
|
||
──────────────────────────────┬─────────────────────────────|
|
||
{101: }│^ |
|
||
{102:~ }│{1:~ }|*5
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
-- Navigate from bottom-right to top.
|
||
feed('<C-w>k')
|
||
-- The ┬ connector must still be present.
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*6
|
||
──────────────────────────────┬─────────────────────────────|
|
||
{101: }│{101: }|
|
||
{102:~ }│{102:~ }|*5
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('horizontal separators unchanged when failing to split-move window', function()
|
||
exec([[
|
||
botright split
|
||
let &winwidth = &columns
|
||
let &winminwidth = &columns
|
||
]])
|
||
eq('Vim(wincmd):E36: Not enough room', pcall_err(command, 'wincmd L'))
|
||
command('mode')
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*5
|
||
────────────────────────────────────────────────────────────|
|
||
^ |
|
||
{1:~ }|*6
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
-- Shouldn't gain a hsep if the global statusline is turned off.
|
||
command('set laststatus=2')
|
||
eq('Vim(wincmd):E36: Not enough room', pcall_err(command, 'wincmd L'))
|
||
command('mode')
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*5
|
||
{2:[No Name] 0,0-1 All}|
|
||
^ |
|
||
{1:~ }|*6
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
end)
|
||
|
||
describe('statusline', function()
|
||
local screen
|
||
before_each(function()
|
||
clear()
|
||
screen = Screen.new(40, 8)
|
||
screen:add_extra_attr_ids {
|
||
[100] = { bold = true, reverse = true, foreground = Screen.colors.Blue },
|
||
[101] = { reverse = true, bold = true, foreground = Screen.colors.SlateBlue },
|
||
}
|
||
end)
|
||
|
||
it('does not crash if it has Arabic characters #19447', function()
|
||
api.nvim_set_option_value('statusline', 'غً', {})
|
||
api.nvim_set_option_value('laststatus', 2, {})
|
||
command('redraw!')
|
||
assert_alive()
|
||
end)
|
||
|
||
it('is redrawn with :resize from <Cmd> mapping #19629', function()
|
||
exec([[
|
||
set laststatus=2
|
||
nnoremap <Up> <cmd>resize -1<CR>
|
||
nnoremap <Down> <cmd>resize +1<CR>
|
||
]])
|
||
feed('<Up>')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*4
|
||
{3:[No Name] }|
|
||
|*2
|
||
]])
|
||
feed('<Down>')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:[No Name] }|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('does not contain showmcd with showcmdloc=statusline when too narrow', function()
|
||
command('set showcmd')
|
||
command('set showcmdloc=statusline')
|
||
command('1vsplit')
|
||
screen:expect([[
|
||
^ │ |
|
||
{1:~}│{1:~ }|*5
|
||
{3:< }{2:[No Name] }|
|
||
|
|
||
]])
|
||
feed('1234')
|
||
screen:expect_unchanged()
|
||
end)
|
||
|
||
it('does not redraw unnecessarily after K_EVENT', function()
|
||
-- does not redraw on vim.schedule (#17937)
|
||
command([[
|
||
set laststatus=2
|
||
let g:counter = 0
|
||
func Status()
|
||
let g:counter += 1
|
||
lua vim.schedule(function() end)
|
||
return g:counter
|
||
endfunc
|
||
set statusline=%!Status()
|
||
]])
|
||
sleep(50)
|
||
eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
|
||
-- also in insert mode
|
||
feed('i')
|
||
sleep(50)
|
||
eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
|
||
-- does not redraw on timer call (#14303)
|
||
command([[
|
||
let g:counter = 0
|
||
func Timer(timer)
|
||
endfunc
|
||
call timer_start(1, 'Timer', {'repeat': 100})
|
||
]])
|
||
sleep(50)
|
||
eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
|
||
end)
|
||
|
||
it('is redrawn on various state changes', function()
|
||
-- recording state change #22683
|
||
command('set ls=2 stl=%{repeat(reg_recording(),5)}')
|
||
local s1 = [[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3: }|
|
||
|
|
||
]]
|
||
screen:expect(s1)
|
||
feed('qQ')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:QQQQQ }|
|
||
{5:recording @Q} |
|
||
]])
|
||
feed('q')
|
||
screen:expect(s1)
|
||
|
||
-- Visual mode change #23932
|
||
command('set ls=2 stl=%{mode(1)}')
|
||
local s2 = [[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:n }|
|
||
|
|
||
]]
|
||
screen:expect(s2)
|
||
feed('v')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:v }|
|
||
{5:-- VISUAL --} |
|
||
]])
|
||
feed('V')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:V }|
|
||
{5:-- VISUAL LINE --} |
|
||
]])
|
||
feed('<C-V>')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:^V }|
|
||
{5:-- VISUAL BLOCK --} |
|
||
]])
|
||
feed('<Esc>')
|
||
screen:expect(s2)
|
||
|
||
-- Visual selection other end change #36280
|
||
exec([[
|
||
function! DebugVisualSelection()
|
||
return printf("v %s %s", col("v"), col("."))
|
||
endfunction
|
||
set statusline=%!DebugVisualSelection()
|
||
]])
|
||
feed('iabc<Esc>v')
|
||
screen:expect([[
|
||
ab^c |
|
||
{1:~ }|*5
|
||
{3:v 3 3 }|
|
||
{5:-- VISUAL --} |
|
||
]])
|
||
feed('iw')
|
||
screen:expect([[
|
||
{17:ab}^c |
|
||
{1:~ }|*5
|
||
{3:v 1 3 }|
|
||
{5:-- VISUAL --} |
|
||
]])
|
||
end)
|
||
|
||
it('ruler is redrawn in cmdline with redrawstatus #22804', function()
|
||
command([[
|
||
let g:n = 'initial value'
|
||
set ls=1 ru ruf=%{g:n}
|
||
redraw
|
||
let g:n = 'other value'
|
||
redrawstatus
|
||
]])
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*6
|
||
other value |
|
||
]])
|
||
end)
|
||
|
||
it('ruler is cleared when window without statusline is closed', function()
|
||
local cfg = { relative = 'editor', row = 1, col = 1, height = 1, width = 1 }
|
||
local win = api.nvim_open_win(0, true, cfg)
|
||
-- Last line ruler does not take on window-local highlights #38777
|
||
command('hi link MsgArea Normal | setlocal winhl=Normal:Statement | set ruler laststatus=2')
|
||
screen:expect([[
|
||
|
|
||
{1:~}{15:^ }{1: }|
|
||
{1:~ }|*4
|
||
{2:[No Name] 0,0-1 All}|
|
||
0,0-1 All|
|
||
]])
|
||
api.nvim_win_close(win, true)
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('hidden moves ruler to cmdline', function()
|
||
-- Use long ruler to check 'ruler' with 'rulerformat' set has correct width.
|
||
command [[
|
||
set ruler rulerformat=%{winnr()}longlonglong ls=0 winwidth=10
|
||
split
|
||
wincmd b
|
||
vsplit
|
||
wincmd t
|
||
wincmd |
|
||
mode
|
||
]]
|
||
-- Window 1 is current. It has a statusline, so cmdline should show the
|
||
-- last window's ruler, which has no statusline.
|
||
command '1wincmd w'
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*2
|
||
{3:[No Name] 1longlonglong}|
|
||
│ |
|
||
{1:~ }│{1:~ }|*2
|
||
3longlonglong |
|
||
]])
|
||
-- Window 2 is current. It has no statusline, so cmdline should show its
|
||
-- ruler instead.
|
||
command '2wincmd w'
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*2
|
||
{2:[No Name] 1longlonglong}|
|
||
^ │ |
|
||
{1:~ }│{1:~ }|*2
|
||
2longlonglong |
|
||
]])
|
||
-- Window 3 is current. Cmdline should again show its ruler.
|
||
command '3wincmd w'
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*2
|
||
{2:[No Name] 1longlonglong}|
|
||
│^ |
|
||
{1:~ }│{1:~ }|*2
|
||
3longlonglong |
|
||
]])
|
||
end)
|
||
|
||
it('uses "stl" and "stlnc" fillchars even if they are the same #19803', function()
|
||
command('hi clear StatusLine')
|
||
command('hi clear StatusLineNC')
|
||
command('vsplit')
|
||
screen:expect([[
|
||
^ │ |
|
||
{1:~ }│{1:~ }|*5
|
||
[No Name] [No Name] |
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('showcmdloc=statusline works with vertical splits', function()
|
||
command('rightbelow vsplit')
|
||
command('set showcmd showcmdloc=statusline')
|
||
feed('1234')
|
||
screen:expect([[
|
||
│^ |
|
||
{1:~ }│{1:~ }|*5
|
||
{2:[No Name] }{3:<o Name] 1234 }|
|
||
|
|
||
]])
|
||
feed('<Esc>')
|
||
command('set laststatus=3')
|
||
feed('1234')
|
||
screen:expect([[
|
||
│^ |
|
||
{1:~ }│{1:~ }|*5
|
||
{3:[No Name] 1234 }|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('keymap is shown with vertical splits #27269', function()
|
||
command('setlocal keymap=dvorak')
|
||
command('rightbelow vsplit')
|
||
screen:expect([[
|
||
│^ |
|
||
{1:~ }│{1:~ }|*5
|
||
{2:[No Name] <en-dv> }{3:[No Name] <en-dv> }|
|
||
|
|
||
]])
|
||
|
||
command('set laststatus=3')
|
||
screen:expect([[
|
||
│^ |
|
||
{1:~ }│{1:~ }|*5
|
||
{3:[No Name] <en-dv> }|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it("nested call from nvim_eval_statusline() doesn't overwrite items #32259", function()
|
||
exec_lua('vim.o.laststatus = 2')
|
||
exec_lua([[vim.o.statusline = '%#Special#B:%{nvim_eval_statusline("%f", []).str}']])
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{101:B:[No Name] }|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('truncation inside nested nvim_eval_statusline does not crash #36616', function()
|
||
exec_lua(function()
|
||
function _G.statusline_truncating()
|
||
local win = vim.api.nvim_get_current_win()
|
||
local res = vim.api.nvim_eval_statusline('%f', { winid = win, maxwidth = 5 })
|
||
return res.str
|
||
end
|
||
vim.o.laststatus = 2
|
||
vim.o.statusline = '%#Special#B:%{%v:lua.statusline_truncating()%}'
|
||
end)
|
||
local truncated = exec_lua(function()
|
||
return vim.api.nvim_eval_statusline('%f', { maxwidth = 5 }).str
|
||
end)
|
||
local rendered = exec_lua(function()
|
||
return vim.api.nvim_eval_statusline(
|
||
vim.o.statusline,
|
||
{ winid = vim.api.nvim_get_current_win() }
|
||
).str
|
||
end)
|
||
eq('B:' .. truncated, rendered)
|
||
end)
|
||
|
||
it('truncation inside nested nvim_eval_statusline correctly adjusts highlights', function()
|
||
exec_lua('vim.o.laststatus = 2')
|
||
exec_lua([[vim.o.statusline = "%{%repeat('%#Error#',20)%}"]])
|
||
exec_lua([[
|
||
vim.o.statusline = "%l%l%l%l%{%nvim_eval_statusline('test%#Error#%l%<',{'maxwidth':4,'highlights':1}).highlights%}"
|
||
]])
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:< 'groups': ['StatusLine'], 'start': 0}]}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('no cmdline ruler for autocmd window #39938', function()
|
||
command('set ruler laststatus=2')
|
||
api.nvim_create_autocmd('BufDelete', { command = 'redrawstatus' })
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
api.nvim_exec_autocmds('BufDelete', { buf = api.nvim_create_buf(true, true) })
|
||
screen:expect_unchanged(true)
|
||
end)
|
||
|
||
it('active window is correct after nvim_exec_autocmds({buf}) #40153', function()
|
||
command('set laststatus=2')
|
||
local caller_win = api.nvim_get_current_win()
|
||
command('split')
|
||
local target = api.nvim_create_buf(true, false)
|
||
api.nvim_set_current_buf(target)
|
||
api.nvim_set_current_win(caller_win)
|
||
exec_lua(function(buf)
|
||
_G.in_aucmd_statusline = false
|
||
_G.statusline_contexts = {}
|
||
_G.Status = function()
|
||
local current = vim.api.nvim_get_current_win()
|
||
local statusline = vim.g.statusline_winid
|
||
local focus = current == statusline
|
||
table.insert(_G.statusline_contexts, {
|
||
current = current,
|
||
focus = focus,
|
||
in_aucmd = _G.in_aucmd_statusline,
|
||
statusline = statusline,
|
||
})
|
||
return focus and 'CUR' or 'nc'
|
||
end
|
||
vim.o.statusline = '%!v:lua.Status()'
|
||
vim.api.nvim_create_autocmd('User', {
|
||
buffer = buf,
|
||
callback = function(ev)
|
||
_G.in_aucmd_statusline = true
|
||
vim.api.nvim__redraw({ buf = ev.buf, statusline = true })
|
||
_G.in_aucmd_statusline = false
|
||
end,
|
||
})
|
||
end, target)
|
||
-- Ignore statusline evaluations from setup; only the autocmd redraw matters.
|
||
exec_lua('_G.statusline_contexts = {}')
|
||
api.nvim_exec_autocmds('User', { buf = target })
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*2
|
||
{2:nc }|
|
||
^ |
|
||
{1:~ }|
|
||
{3:CUR }|
|
||
|
|
||
]])
|
||
-- `%!` may evaluate during the callback, but must not see the target as focused.
|
||
eq(
|
||
{},
|
||
exec_lua(function(win)
|
||
return vim
|
||
.iter(_G.statusline_contexts)
|
||
:filter(function(context)
|
||
return context.in_aucmd and context.focus and context.current ~= win
|
||
end)
|
||
:totable()
|
||
end, caller_win)
|
||
)
|
||
end)
|
||
|
||
it('statusline evaluation during nvim_exec_autocmds({buf}) #40153', function()
|
||
command('set laststatus=2')
|
||
local caller_win = api.nvim_get_current_win()
|
||
command('split')
|
||
local target = api.nvim_create_buf(true, false)
|
||
api.nvim_set_current_buf(target)
|
||
api.nvim_set_current_win(caller_win)
|
||
exec_lua(function(buf)
|
||
_G.in_aucmd_statusline = false
|
||
_G.statusline_contexts = {}
|
||
_G.Status = function()
|
||
table.insert(_G.statusline_contexts, {
|
||
in_aucmd = _G.in_aucmd_statusline,
|
||
current = vim.api.nvim_get_current_win(),
|
||
actual = tonumber(vim.g.actual_curwin or -1),
|
||
})
|
||
return vim.api.nvim_get_current_win() == tonumber(vim.g.actual_curwin or -1) and 'CUR'
|
||
or 'nc'
|
||
end
|
||
-- `%{%...%}` sets g:actual_curwin while evaluating the statusline.
|
||
vim.o.statusline = '%{%v:lua.Status()%}'
|
||
vim.api.nvim_create_autocmd('User', {
|
||
buffer = buf,
|
||
callback = function(ev)
|
||
_G.in_aucmd_statusline = true
|
||
vim.api.nvim__redraw({ buf = ev.buf, statusline = true })
|
||
_G.in_aucmd_statusline = false
|
||
end,
|
||
})
|
||
end, target)
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*2
|
||
{2:nc }|
|
||
^ |
|
||
{1:~ }|
|
||
{3:CUR }|
|
||
|
|
||
]])
|
||
-- Ignore statusline evaluations from setup; only the autocmd redraw matters.
|
||
exec_lua('_G.statusline_contexts = {}')
|
||
api.nvim_exec_autocmds('User', { buf = target })
|
||
screen:expect({ unchanged = true })
|
||
local contexts = exec_lua(function()
|
||
return _G.statusline_contexts
|
||
end)
|
||
eq(true, #contexts > 0)
|
||
eq(caller_win, contexts[#contexts].actual)
|
||
end)
|
||
|
||
it('%P %L updates in other windows', function()
|
||
screen:try_resize(40, 14)
|
||
command('set laststatus=2 statusline=%P\\ %L | split')
|
||
feed(':put=range(10)<cr>dgg')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:All 1 }|
|
||
|
|
||
{1:~ }|*4
|
||
{2:All 1 }|
|
||
--No lines in buffer-- |
|
||
]])
|
||
end)
|
||
end)
|
||
|
||
describe('default statusline', function()
|
||
local screen
|
||
|
||
before_each(function()
|
||
clear()
|
||
screen = Screen.new(60, 16)
|
||
screen:add_extra_attr_ids {
|
||
[100] = { foreground = Screen.colors.Magenta1, bold = true },
|
||
[131] = { foreground = Screen.colors.NvimDarkGreen },
|
||
}
|
||
command('set laststatus=2')
|
||
command('set ruler')
|
||
end)
|
||
|
||
it('setting statusline to empty string sets default statusline', function()
|
||
exec_lua("vim.o.statusline = 'asdf'")
|
||
eq('asdf', eval('&statusline'))
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:asdf }|
|
||
|
|
||
]])
|
||
|
||
local default_statusline = table.concat({
|
||
'%<',
|
||
'%f',
|
||
"%( %h%w%m%r%{ v:lua.require('vim._core.util').term_exitcode() }%)",
|
||
'%= ',
|
||
'%(%-10S %)',
|
||
"%{ &busy > 0 ? '◐\226\128\175' : '' }",
|
||
"%(%{ luaeval('(package.loaded[''vim.ui''] and vim.api.nvim_get_current_win() == tonumber(vim.g.actual_curwin or -1) and vim.ui.progress_status()) or '''' ')} %)",
|
||
"%{% luaeval('(package.loaded[''vim.diagnostic''] and next(vim.diagnostic.count(0)) and vim.diagnostic.status() .. '' '') or '''' ') %}",
|
||
'%(%k %)',
|
||
"%{% &ruler ? &rulerformat : '' %}",
|
||
})
|
||
|
||
exec_lua("vim.o.statusline = ''")
|
||
eq(default_statusline, eval('&statusline'))
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
-- Reset to default (via the correct scope) if there's an error.
|
||
command('setglobal statusline=%{a%}')
|
||
eq(default_statusline, eval('&statusline'))
|
||
eq(default_statusline, eval('&g:statusline'))
|
||
eq('', eval('&l:statusline'))
|
||
command('redrawstatus') -- like Vim, statusline isn't immediately redrawn after an error
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
{9:E121: Undefined variable: a} |
|
||
]])
|
||
command('setlocal statusline=%{b%}')
|
||
eq(default_statusline, eval('&statusline'))
|
||
eq(default_statusline, eval('&g:statusline'))
|
||
eq('', eval('&l:statusline'))
|
||
command('redrawstatus') -- like Vim, statusline isn't immediately redrawn after an error
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
{9:E121: Undefined variable: b} |
|
||
]])
|
||
end)
|
||
|
||
it('shows busy status when buffer is set to be busy', function()
|
||
exec_lua("vim.o.statusline = ''")
|
||
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
exec_lua('vim.o.busy = 1')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] ◐ 0,0-1 All}|
|
||
|
|
||
]])
|
||
|
||
exec_lua('vim.o.busy = 0')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 0,0-1 All}|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it('shows exit code when terminal exits #14986', function()
|
||
exec_lua("vim.o.statusline = ''")
|
||
api.nvim_set_option_value('shell', testprg('shell-test'), {})
|
||
api.nvim_set_option_value('shellcmdflag', 'EXIT', {})
|
||
api.nvim_set_option_value('shellxquote', '', {}) -- win: avoid extra quotes
|
||
command('terminal 9')
|
||
screen:expect({ any = '%[Exit:\226\128\1759%]' })
|
||
expect_exitcode(9)
|
||
end)
|
||
|
||
it('shows and updates progress status', function()
|
||
exec_lua("vim.o.statusline = ''")
|
||
local function get_progress()
|
||
return exec_lua(function()
|
||
return vim.ui.progress_status()
|
||
end)
|
||
end
|
||
|
||
eq('', get_progress())
|
||
---@type integer|string
|
||
local id1 = api.nvim_echo(
|
||
{ { 'searching...' } },
|
||
true,
|
||
{ kind = 'progress', source = 'tests', title = 'test', status = 'running', percent = 10 }
|
||
)
|
||
eq('10%(1)', get_progress())
|
||
|
||
api.nvim_echo({ { 'searching' } }, true, {
|
||
id = id1,
|
||
kind = 'progress',
|
||
source = 'tests',
|
||
percent = 50,
|
||
status = 'running',
|
||
title = 'terminal(ripgrep)',
|
||
})
|
||
eq('50%(1)', get_progress())
|
||
|
||
api.nvim_echo({ { 'searching...' } }, true, {
|
||
kind = 'progress',
|
||
source = 'tests',
|
||
title = 'second-item',
|
||
status = 'running',
|
||
percent = 20,
|
||
})
|
||
eq('35%(2)', get_progress())
|
||
|
||
api.nvim_echo({ { 'searching' } }, true, {
|
||
id = id1,
|
||
kind = 'progress',
|
||
source = 'tests',
|
||
percent = 100,
|
||
status = 'success',
|
||
title = 'terminal(ripgrep)',
|
||
})
|
||
eq('20%(1)', get_progress())
|
||
|
||
exec('redrawstatus')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*13
|
||
{3:[No Name] 20%(1) 0,0-1 All}|
|
||
{131:terminal(ripgrep)}: {19:100% }searching |
|
||
]])
|
||
|
||
-- Progress_status only shown on active window
|
||
exec('split')
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*6
|
||
{3:[No Name] 20%(1) 0,0-1 All}|
|
||
|
|
||
{1:~ }|*5
|
||
{2:[No Name] 0,0-1 All}|
|
||
{131:terminal(ripgrep)}: {19:100% }searching |
|
||
]])
|
||
|
||
exec('wincmd w')
|
||
screen:expect([[
|
||
|
|
||
{1:~ }|*6
|
||
{2:[No Name] 0,0-1 All}|
|
||
^ |
|
||
{1:~ }|*5
|
||
{3:[No Name] 20%(1) 0,0-1 All}|
|
||
{131:terminal(ripgrep)}: {19:100% }searching |
|
||
]])
|
||
end)
|
||
end)
|
||
|
||
describe('default rulerformat', function()
|
||
local screen
|
||
|
||
before_each(function()
|
||
clear()
|
||
screen = Screen.new(60, 16)
|
||
command('set ruler')
|
||
end)
|
||
|
||
it('setting rulerformat to empty string sets default rulerformat', function()
|
||
exec_lua("vim.o.rulerformat = 'hjkl'")
|
||
eq('hjkl', eval('&rulerformat'))
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*14
|
||
hjkl |
|
||
]])
|
||
|
||
local default_rulerformat = '%18(%l,%c%V%= %P%)%<'
|
||
|
||
exec_lua("vim.o.rulerformat = ''")
|
||
eq(default_rulerformat, eval('&rulerformat'))
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*14
|
||
0,0-1 All|
|
||
]])
|
||
|
||
-- Reset to default if there's an error.
|
||
command('set rulerformat=%{a%}')
|
||
eq(default_rulerformat, eval('&rulerformat'))
|
||
eq(default_rulerformat, eval('&g:rulerformat'))
|
||
eq(default_rulerformat, eval('&l:rulerformat'))
|
||
command('redrawstatus') -- like Vim, rulerformat isn't immediately redrawn after an error
|
||
screen:expect([[
|
||
^ |
|
||
{1:~ }|*14
|
||
{9:E121: Undefined variable: a} 0,0-1 All|
|
||
]])
|
||
end)
|
||
end)
|
||
|
||
describe("'statusline' in floatwin", function()
|
||
local screen
|
||
before_each(function()
|
||
clear()
|
||
screen = Screen.new(30, 20)
|
||
screen:add_extra_attr_ids({
|
||
[101] = { foreground = Screen.colors.Magenta1, bold = true },
|
||
[102] = {
|
||
foreground = Screen.colors.Magenta1,
|
||
underline = true,
|
||
background = Screen.colors.LightGray,
|
||
bold = true,
|
||
},
|
||
})
|
||
end)
|
||
|
||
it('controlled by ":setlocal statusline" and "style" and "laststatus"', function()
|
||
local buf = api.nvim_create_buf(false, false)
|
||
api.nvim_buf_set_lines(buf, 0, -1, false, { '1', '2', '3', '4' })
|
||
local cfg = {
|
||
relative = 'editor',
|
||
row = 1,
|
||
col = 1,
|
||
height = 4,
|
||
width = 10,
|
||
border = 'single',
|
||
}
|
||
local win = api.nvim_open_win(buf, true, cfg)
|
||
local set_stl = [[setlocal stl=%f\ %m]]
|
||
command('set laststatus=2')
|
||
command(set_stl)
|
||
local has_stl = [[
|
||
|
|
||
{1:~}{4:┌──────────┐}{1: }|
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:│}{3:<Name] [+]}{4:│}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*10
|
||
{2:[No Name] }|
|
||
|
|
||
]]
|
||
screen:expect(has_stl)
|
||
|
||
-- setting the style will clear the statusline expression for floating windows
|
||
api.nvim_win_set_config(win, { style = 'minimal' })
|
||
local without_stl = [[
|
||
|
|
||
{1:~}{4:┌──────────┐}{1: }|
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*11
|
||
{2:[No Name] }|
|
||
|
|
||
]]
|
||
screen:expect(without_stl)
|
||
|
||
-- no statusline is displayed because the statusline option was cleared
|
||
api.nvim_win_set_config(win, cfg)
|
||
screen:expect_unchanged()
|
||
|
||
-- displayed after the option is reset
|
||
command(set_stl)
|
||
screen:expect(has_stl)
|
||
|
||
-- Show in a new window in a new tab, then return to the previous tab;
|
||
-- remove the statusline of the new window, When re-entering this new tab,
|
||
-- the statusline of the new window is cleared
|
||
command('tabnew')
|
||
local win2 = api.nvim_open_win(buf, false, cfg)
|
||
command(set_stl)
|
||
screen:expect([[
|
||
{24: }{102:2}{24:+ [No Name] }{5: }{101:2}{5:+ [No Name] }{2: }{24:X}|
|
||
^ {4:┌──────────┐} |
|
||
{1:~}{4:│1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*11
|
||
{3:[No Name] }|
|
||
|
|
||
]])
|
||
command('tabfirst')
|
||
api.nvim_win_set_config(win2, { style = 'minimal' })
|
||
screen:expect([[
|
||
{5: }{101:2}{5:+ [No Name] }{24: }{102:2}{24:+ [No Name] }{2: }{24:X}|
|
||
{4:┌──────────┐} |
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:│}{3:<Name] [+]}{4:│}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*10
|
||
{2:[No Name] }|
|
||
|
|
||
]])
|
||
command('tabnext')
|
||
screen:expect([[
|
||
{24: }{102:2}{24:+ [No Name] }{5: }{101:2}{5:+ [No Name] }{2: }{24:X}|
|
||
^ {4:┌──────────┐} |
|
||
{1:~}{4:│1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*11
|
||
{3:[No Name] }|
|
||
|
|
||
]])
|
||
-- clear statusline when laststatus is 3
|
||
command('tabclose | set laststatus=2')
|
||
screen:expect([[
|
||
|
|
||
{1:~}{4:┌──────────┐}{1: }|
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:│}{3:<Name] [+]}{4:│}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*10
|
||
{2:[No Name] }|
|
||
|
|
||
]])
|
||
command('set laststatus=0')
|
||
screen:expect([[
|
||
|
|
||
{1:~}{4:┌──────────┐}{1: }|
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*12
|
||
|
|
||
]])
|
||
|
||
command('set laststatus=3')
|
||
screen:expect([[
|
||
|
|
||
{1:~}{4:┌──────────┐}{1: }|
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*11
|
||
{3:[No Name] [+] }|
|
||
|
|
||
]])
|
||
api.nvim_buf_set_name(buf, 'stl_test')
|
||
screen:expect([[
|
||
|
|
||
{1:~}{4:┌──────────┐}{1: }|
|
||
{1:~}{4:│^1 │}{1: }|
|
||
{1:~}{4:│2 │}{1: }|
|
||
{1:~}{4:│3 │}{1: }|
|
||
{1:~}{4:│4 │}{1: }|
|
||
{1:~}{4:└──────────┘}{1: }|
|
||
{1:~ }|*11
|
||
{3:stl_test [+] }|
|
||
|
|
||
]])
|
||
end)
|
||
|
||
it("clears inherited window-local 'statusline' on creation", function()
|
||
command('set laststatus=2')
|
||
api.nvim_set_option_value('statusline', 'global', {})
|
||
local curwin = api.nvim_get_current_win()
|
||
api.nvim_set_option_value('statusline', 'split-local', { win = curwin })
|
||
api.nvim_open_win(0, true, { relative = 'editor', row = 1, col = 1, height = 2, width = 4 })
|
||
screen:expect([[
|
||
|
|
||
{1:~}{4:^ }{1: }|
|
||
{1:~}{11:~ }{1: }|
|
||
{1:~ }|*15
|
||
{2:split-local }|
|
||
|
|
||
]])
|
||
end)
|
||
end)
|