neovim/test/functional/plugin/man_spec.lua

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

271 lines
9.2 KiB
Lua
Raw Normal View History

local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local command, feed = n.command, n.feed
local clear = n.clear
local exec_lua = n.exec_lua
local fn = n.fn
local nvim_prog = n.nvim_prog
local matches = t.matches
local write_file = t.write_file
local tmpname = t.tmpname
local eq = t.eq
local pesc = vim.pesc
local skip = t.skip
local is_ci = t.is_ci
2023-03-07 07:13:09 -07:00
-- Collects all names passed to find_path() after attempting ":Man foo".
local function get_search_history(name)
2023-03-07 07:13:09 -07:00
local args = vim.split(name, ' ')
local code = [[
local args = ...
local man = require('runtime.lua.man')
local res = {}
2023-03-07 07:13:09 -07:00
man.find_path = function(sect, name)
table.insert(res, {sect, name})
return nil
end
local ok, rv = pcall(man.open_page, -1, {tab = 0}, args)
2023-03-07 07:13:09 -07:00
assert(not ok)
assert(rv and rv:match('no manual entry'))
return res
2023-03-07 07:13:09 -07:00
]]
return exec_lua(code, args)
end
clear()
if fn.executable('man') == 0 then
pending('missing "man" command', function() end)
return
end
describe(':Man', function()
before_each(function()
clear()
end)
describe('man.lua: highlight_line()', function()
2024-03-25 12:06:28 -07:00
local screen --- @type test.functional.ui.screen
before_each(function()
command('syntax on')
command('set filetype=man')
command('syntax off') -- Ignore syntax groups
screen = Screen.new(52, 5)
2017-12-24 10:16:58 -07:00
screen:set_default_attr_ids({
b = { bold = true },
i = { italic = true },
u = { underline = true },
bi = { bold = true, italic = true },
biu = { bold = true, italic = true, underline = true },
c = { foreground = Screen.colors.Blue }, -- control chars
eob = { bold = true, foreground = Screen.colors.Blue }, -- empty line '~'s
2017-12-24 10:16:58 -07:00
})
screen:attach()
end)
2017-12-24 10:16:58 -07:00
it('clears backspaces from text and adds highlights', function()
2024-03-25 12:06:28 -07:00
feed(
2017-12-24 10:16:58 -07:00
[[
ithis i<C-v><C-h>is<C-v><C-h>s a<C-v><C-h>a test
with _<C-v><C-h>o_<C-v><C-h>v_<C-v><C-h>e_<C-v><C-h>r_<C-v><C-h>s_<C-v><C-h>t_<C-v><C-h>r_<C-v><C-h>u_<C-v><C-h>c_<C-v><C-h>k text<ESC>]]
)
screen:expect {
grid = [[
this i{c:^H}is{c:^H}s a{c:^H}a test |
with _{c:^H}o_{c:^H}v_{c:^H}e_{c:^H}r_{c:^H}s_{c:^H}t_{c:^H}r_{c:^H}u_{c:^H}c_{c:^H}k tex^t |
{eob:~ }|*2
|
]],
}
exec_lua [[require'man'.init_pager()]]
2017-12-24 10:16:58 -07:00
screen:expect([[
^this {b:is} {b:a} test |
with {i:overstruck} text |
{eob:~ }|*2
|
]])
end)
2017-12-24 10:16:58 -07:00
it('clears escape sequences from text and adds highlights', function()
2024-03-25 12:06:28 -07:00
feed(
2017-12-24 10:16:58 -07:00
[[
ithis <C-v><ESC>[1mis <C-v><ESC>[3ma <C-v><ESC>[4mtest<C-v><ESC>[0m
<C-v><ESC>[4mwith<C-v><ESC>[24m <C-v><ESC>[4mescaped<C-v><ESC>[24m <C-v><ESC>[4mtext<C-v><ESC>[24m<ESC>]]
)
screen:expect {
grid = [=[
this {c:^[}[1mis {c:^[}[3ma {c:^[}[4mtest{c:^[}[0m |
{c:^[}[4mwith{c:^[}[24m {c:^[}[4mescaped{c:^[}[24m {c:^[}[4mtext{c:^[}[24^m |
{eob:~ }|*2
|
]=],
}
exec_lua [[require'man'.init_pager()]]
2017-12-24 10:16:58 -07:00
screen:expect([[
^this {b:is }{bi:a }{biu:test} |
{u:with} {u:escaped} {u:text} |
{eob:~ }|*2
|
]])
end)
it('clears OSC 8 hyperlink markup from text', function()
feed(
[[
ithis <C-v><ESC>]8;;http://example.com<C-v><ESC>\Link Title<C-v><ESC>]8;;<C-v><ESC>\<ESC>]]
)
screen:expect {
grid = [=[
this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ |
{eob:~ }|*3
|
]=],
}
exec_lua [[require'man'.init_pager()]]
screen:expect([[
^this Link Title |
{eob:~ }|*3
|
]])
end)
it('highlights multibyte text', function()
2024-03-25 12:06:28 -07:00
feed(
2017-12-24 10:16:58 -07:00
[[
ithis i<C-v><C-h>is<C-v><C-h>s <C-v><C-h> test
with _<C-v><C-h>ö_<C-v><C-h>v_<C-v><C-h>e_<C-v><C-h>r_<C-v><C-h>s_<C-v><C-h>t_<C-v><C-h>r_<C-v><C-h>u_<C-v><C-h>̃_<C-v><C-h>c_<C-v><C-h>k te<C-v><ESC>[3mxt<C-v><ESC>[0m<ESC>]]
)
exec_lua [[require'man'.init_pager()]]
2017-12-24 10:16:58 -07:00
screen:expect([[
^this {b:is} {b:} test |
with {i:överstrũck} te{i:xt} |
{eob:~ }|*2
|
]])
end)
it('highlights underscores based on context', function()
2024-03-25 12:06:28 -07:00
feed(
2017-12-24 10:16:58 -07:00
[[
i_<C-v><C-h>_b<C-v><C-h>be<C-v><C-h>eg<C-v><C-h>gi<C-v><C-h>in<C-v><C-h>ns<C-v><C-h>s
m<C-v><C-h>mi<C-v><C-h>id<C-v><C-h>d_<C-v><C-h>_d<C-v><C-h>dl<C-v><C-h>le<C-v><C-h>e
_<C-v><C-h>m_<C-v><C-h>i_<C-v><C-h>d_<C-v><C-h>__<C-v><C-h>d_<C-v><C-h>l_<C-v><C-h>e<ESC>]]
)
exec_lua [[require'man'.init_pager()]]
2017-12-24 10:16:58 -07:00
screen:expect([[
{b:^_begins} |
{b:mid_dle} |
{i:mid_dle} |
{eob:~ }|
|
]])
end)
it('highlights various bullet formats', function()
2024-03-25 12:06:28 -07:00
feed([[
2017-12-24 10:16:58 -07:00
i· ·<C-v><C-h>·
+<C-v><C-h>o
+<C-v><C-h>+<C-v><C-h>o<C-v><C-h>o double<ESC>]])
exec_lua [[require'man'.init_pager()]]
2017-12-24 10:16:58 -07:00
screen:expect([[
^· {b:·} |
{b:·} |
{b:·} double |
{eob:~ }|
|
]])
end)
it('handles : characters in input', function()
2024-03-25 12:06:28 -07:00
feed([[
i<C-v><C-[>[40m 0 <C-v><C-[>[41m 1 <C-v><C-[>[42m 2 <C-v><C-[>[43m 3
<C-v><C-[>[44m 4 <C-v><C-[>[45m 5 <C-v><C-[>[46m 6 <C-v><C-[>[47m 7 <C-v><C-[>[100m 8 <C-v><C-[>[101m 9
<C-v><C-[>[102m 10 <C-v><C-[>[103m 11 <C-v><C-[>[104m 12 <C-v><C-[>[105m 13 <C-v><C-[>[106m 14 <C-v><C-[>[107m 15
<C-v><C-[>[48:5:16m 16 <ESC>]])
exec_lua [[require'man'.init_pager()]]
screen:expect([[
^ 0 1 2 3 |
4 5 6 7 8 9 |
10 11 12 13 14 15 |
16 |
|
]])
end)
end)
it('q quits in "$MANPAGER mode" (:Man!) #18281', function()
-- This will hang if #18281 regresses.
local args = {
nvim_prog,
'--headless',
'+autocmd VimLeave * echo "quit works!!"',
'+Man!',
'+tag ls',
'+call nvim_input("q")',
}
matches('quit works!!', fn.system(args, { 'manpage contents' }))
end)
fix(man): handle absolute paths as `:Man` targets (#20624) * fix(man): handle absolute paths as :Man targets Previously, attempting to provide `:Man` with an absolute path as the name would cause neovim to return the following error: ``` Error detected while processing command line: /usr/local/share/nvim/runtime/lua/man.lua:690: /usr/local/share/nvim/runtime/lua/man.lua:683: Vim:E426: tag not found: nil(nil) Press ENTER or type command to continue ``` ..because it would try to validate the existence of a man page for the provided name by executing `man -w /some/path` which (on at least some Linux machines [0]) returns `/some/path` instead of the path to the nroff files that would be formatted to satisfy the man(1) lookup. While man pages are not normally named after absolute paths, users shouldn't be blamed for trying. Given such a name/path, neovim would **not** complain that the path didn't have a corresponding man file but would error out when trying to call the tag function for the null-propagated name-and-section `nil(nil)`. (The same underlying error existed before this function was ported to lua, but did not exhibit the lua-specific `nil(nil)` name; instead a tag lookup for `()` would fail and error out.) With this patch, we detect the case where `man -w ...` returns the same value as the provided name to not only prevent invoking the tag function for a non-existent/malformed name+sect but also to properly report the non-existence of a man page for the provided lookup (the absolute path). While man(1) can be used to directly read an nroff-formatted document via `man /path/to/nroff.doc`, `:Man /path/to/nroff.doc` never supported this behavior so no functionality is lost in case the provided path _was_ an nroff file. [0]: `man -w /absolute/path` returning `/absolute/path` observed on an Ubuntu 18.04 installation. * test: add regression test for #20624 Add a functional test to `man_spec.lua` to check for a regression for #20624 by first obtaining an absolute path to a random file and materializing it to disk, then attempting to query `:Man` for an entry by that same name/path. The test passes if nvim correctly reports that there is no man page correspending to the provided name/path and fails if any other error (or no error) is shown.
2022-10-17 02:37:44 -07:00
it('reports non-existent man pages for absolute paths', function()
skip(is_ci('cirrus'))
fix(man): handle absolute paths as `:Man` targets (#20624) * fix(man): handle absolute paths as :Man targets Previously, attempting to provide `:Man` with an absolute path as the name would cause neovim to return the following error: ``` Error detected while processing command line: /usr/local/share/nvim/runtime/lua/man.lua:690: /usr/local/share/nvim/runtime/lua/man.lua:683: Vim:E426: tag not found: nil(nil) Press ENTER or type command to continue ``` ..because it would try to validate the existence of a man page for the provided name by executing `man -w /some/path` which (on at least some Linux machines [0]) returns `/some/path` instead of the path to the nroff files that would be formatted to satisfy the man(1) lookup. While man pages are not normally named after absolute paths, users shouldn't be blamed for trying. Given such a name/path, neovim would **not** complain that the path didn't have a corresponding man file but would error out when trying to call the tag function for the null-propagated name-and-section `nil(nil)`. (The same underlying error existed before this function was ported to lua, but did not exhibit the lua-specific `nil(nil)` name; instead a tag lookup for `()` would fail and error out.) With this patch, we detect the case where `man -w ...` returns the same value as the provided name to not only prevent invoking the tag function for a non-existent/malformed name+sect but also to properly report the non-existence of a man page for the provided lookup (the absolute path). While man(1) can be used to directly read an nroff-formatted document via `man /path/to/nroff.doc`, `:Man /path/to/nroff.doc` never supported this behavior so no functionality is lost in case the provided path _was_ an nroff file. [0]: `man -w /absolute/path` returning `/absolute/path` observed on an Ubuntu 18.04 installation. * test: add regression test for #20624 Add a functional test to `man_spec.lua` to check for a regression for #20624 by first obtaining an absolute path to a random file and materializing it to disk, then attempting to query `:Man` for an entry by that same name/path. The test passes if nvim correctly reports that there is no man page correspending to the provided name/path and fails if any other error (or no error) is shown.
2022-10-17 02:37:44 -07:00
local actual_file = tmpname()
-- actual_file must be an absolute path to an existent file for us to test against it
matches('^/.+', actual_file)
write_file(actual_file, '')
local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' }
matches(
('Error detected while processing command line:\r\n' .. 'man.lua: "no manual entry for %s"'):format(
pesc(actual_file)
),
fn.system(args, { '' })
2024-01-02 18:09:18 -07:00
)
fix(man): handle absolute paths as `:Man` targets (#20624) * fix(man): handle absolute paths as :Man targets Previously, attempting to provide `:Man` with an absolute path as the name would cause neovim to return the following error: ``` Error detected while processing command line: /usr/local/share/nvim/runtime/lua/man.lua:690: /usr/local/share/nvim/runtime/lua/man.lua:683: Vim:E426: tag not found: nil(nil) Press ENTER or type command to continue ``` ..because it would try to validate the existence of a man page for the provided name by executing `man -w /some/path` which (on at least some Linux machines [0]) returns `/some/path` instead of the path to the nroff files that would be formatted to satisfy the man(1) lookup. While man pages are not normally named after absolute paths, users shouldn't be blamed for trying. Given such a name/path, neovim would **not** complain that the path didn't have a corresponding man file but would error out when trying to call the tag function for the null-propagated name-and-section `nil(nil)`. (The same underlying error existed before this function was ported to lua, but did not exhibit the lua-specific `nil(nil)` name; instead a tag lookup for `()` would fail and error out.) With this patch, we detect the case where `man -w ...` returns the same value as the provided name to not only prevent invoking the tag function for a non-existent/malformed name+sect but also to properly report the non-existence of a man page for the provided lookup (the absolute path). While man(1) can be used to directly read an nroff-formatted document via `man /path/to/nroff.doc`, `:Man /path/to/nroff.doc` never supported this behavior so no functionality is lost in case the provided path _was_ an nroff file. [0]: `man -w /absolute/path` returning `/absolute/path` observed on an Ubuntu 18.04 installation. * test: add regression test for #20624 Add a functional test to `man_spec.lua` to check for a regression for #20624 by first obtaining an absolute path to a random file and materializing it to disk, then attempting to query `:Man` for an entry by that same name/path. The test passes if nvim correctly reports that there is no man page correspending to the provided name/path and fails if any other error (or no error) is shown.
2022-10-17 02:37:44 -07:00
os.remove(actual_file)
end)
2023-03-07 07:13:09 -07:00
it('tries variants with spaces, underscores #22503', function()
eq({
{ '', 'NAME WITH SPACES' },
{ '', 'NAME_WITH_SPACES' },
2023-03-07 07:13:09 -07:00
}, get_search_history('NAME WITH SPACES'))
eq({
{ '3', 'some other man' },
{ '3', 'some_other_man' },
2023-03-07 07:13:09 -07:00
}, get_search_history('3 some other man'))
eq({
{ '3x', 'some other man' },
{ '3x', 'some_other_man' },
}, get_search_history('3X some other man'))
eq({
{ '3tcl', 'some other man' },
{ '3tcl', 'some_other_man' },
}, get_search_history('3tcl some other man'))
eq({
{ 'n', 'some other man' },
{ 'n', 'some_other_man' },
}, get_search_history('n some other man'))
eq({
{ '', '123some other man' },
{ '', '123some_other_man' },
}, get_search_history('123some other man'))
eq({
{ '1', 'other_man' },
{ '1', 'other_man' },
2023-03-07 07:13:09 -07:00
}, get_search_history('other_man(1)'))
end)
end)