mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(man.lua): support spaces in manpage names
Problem: :Man command errors if given more than two arguments. Thus, it is impossible to open man pages that contain spaces in their names. Solution: Adjust :Man so that it tries variants with spaces and underscores, and uses the first found.
This commit is contained in:
parent
7a462c10d5
commit
160a019ffa
@ -328,7 +328,8 @@ local function get_path(sect, name, silent)
|
|||||||
-- find any that match the specified name
|
-- find any that match the specified name
|
||||||
---@param v string
|
---@param v string
|
||||||
local namematches = vim.tbl_filter(function(v)
|
local namematches = vim.tbl_filter(function(v)
|
||||||
return fn.fnamemodify(v, ':t'):match(name)
|
local tail = fn.fnamemodify(v, ':t')
|
||||||
|
return string.find(tail, name, 1, true)
|
||||||
end, results) or {}
|
end, results) or {}
|
||||||
local sectmatches = {}
|
local sectmatches = {}
|
||||||
|
|
||||||
@ -372,18 +373,18 @@ local function extract_sect_and_name_ref(ref)
|
|||||||
if not name then
|
if not name then
|
||||||
man_error('manpage reference cannot contain only parentheses: ' .. ref)
|
man_error('manpage reference cannot contain only parentheses: ' .. ref)
|
||||||
end
|
end
|
||||||
return '', spaces_to_underscores(name)
|
return '', name
|
||||||
end
|
end
|
||||||
local parts = vim.split(ref1, '(', { plain = true })
|
local parts = vim.split(ref1, '(', { plain = true })
|
||||||
-- see ':Man 3X curses' on why tolower.
|
-- see ':Man 3X curses' on why tolower.
|
||||||
-- TODO(nhooyr) Not sure if this is portable across OSs
|
-- TODO(nhooyr) Not sure if this is portable across OSs
|
||||||
-- but I have not seen a single uppercase section.
|
-- but I have not seen a single uppercase section.
|
||||||
local sect = vim.split(parts[2] or '', ')', { plain = true })[1]:lower()
|
local sect = vim.split(parts[2] or '', ')', { plain = true })[1]:lower()
|
||||||
local name = spaces_to_underscores(parts[1])
|
local name = parts[1]
|
||||||
return sect, name
|
return sect, name
|
||||||
end
|
end
|
||||||
|
|
||||||
-- verify_exists attempts to find the path to a manpage
|
-- search_for_path attempts to find the path to a manpage
|
||||||
-- based on the passed section and name.
|
-- based on the passed section and name.
|
||||||
--
|
--
|
||||||
-- 1. If manpage could not be found with the given sect and name,
|
-- 1. If manpage could not be found with the given sect and name,
|
||||||
@ -391,10 +392,10 @@ end
|
|||||||
-- 2. If it still could not be found, then we try again without a section.
|
-- 2. If it still could not be found, then we try again without a section.
|
||||||
-- 3. If still not found but $MANSECT is set, then we try again with $MANSECT
|
-- 3. If still not found but $MANSECT is set, then we try again with $MANSECT
|
||||||
-- unset.
|
-- unset.
|
||||||
|
-- 4. If a path still wasn't found, return nil.
|
||||||
---@param sect string?
|
---@param sect string?
|
||||||
---@param name string
|
---@param name string
|
||||||
---@param silent boolean?
|
function M.search_for_path(sect, name)
|
||||||
local function verify_exists(sect, name, silent)
|
|
||||||
if sect and sect ~= '' then
|
if sect and sect ~= '' then
|
||||||
local ret = get_path(sect, name, true)
|
local ret = get_path(sect, name, true)
|
||||||
if ret then
|
if ret then
|
||||||
@ -430,10 +431,8 @@ local function verify_exists(sect, name, silent)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not silent then
|
-- finally, if that didn't work, there is no hope
|
||||||
-- finally, if that didn't work, there is no hope
|
return nil
|
||||||
man_error('no manual entry for ' .. name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local EXT_RE = vim.regex([[\.\%([glx]z\|bz2\|lzma\|Z\)$]])
|
local EXT_RE = vim.regex([[\.\%([glx]z\|bz2\|lzma\|Z\)$]])
|
||||||
@ -585,8 +584,8 @@ local function get_paths(sect, name)
|
|||||||
---@type string[]
|
---@type string[]
|
||||||
local paths = fn.globpath(mandirs, 'man?/' .. name .. '*.' .. sect .. '*', false, true)
|
local paths = fn.globpath(mandirs, 'man?/' .. name .. '*.' .. sect .. '*', false, true)
|
||||||
|
|
||||||
-- Prioritize the result from verify_exists as it obeys b:man_default_sects.
|
-- Prioritize the result from search_for_path as it obeys b:man_default_sects.
|
||||||
local first = verify_exists(sect, name, true)
|
local first = M.search_for_path(sect, name)
|
||||||
if first then
|
if first then
|
||||||
paths = move_elem_to_head(paths, first)
|
paths = move_elem_to_head(paths, first)
|
||||||
end
|
end
|
||||||
@ -728,10 +727,6 @@ end
|
|||||||
---@param count integer
|
---@param count integer
|
||||||
---@param args string[]
|
---@param args string[]
|
||||||
function M.open_page(count, smods, args)
|
function M.open_page(count, smods, args)
|
||||||
if #args > 2 then
|
|
||||||
man_error('too many arguments')
|
|
||||||
end
|
|
||||||
|
|
||||||
local ref ---@type string
|
local ref ---@type string
|
||||||
if #args == 0 then
|
if #args == 0 then
|
||||||
ref = vim.bo.filetype == 'man' and fn.expand('<cWORD>') or fn.expand('<cword>')
|
ref = vim.bo.filetype == 'man' and fn.expand('<cWORD>') or fn.expand('<cword>')
|
||||||
@ -743,9 +738,14 @@ function M.open_page(count, smods, args)
|
|||||||
else
|
else
|
||||||
-- Combine the name and sect into a manpage reference so that all
|
-- Combine the name and sect into a manpage reference so that all
|
||||||
-- verification/extraction can be kept in a single function.
|
-- verification/extraction can be kept in a single function.
|
||||||
-- If args[2] is a reference as well, that is fine because it is the only
|
if tonumber(args[1]) then
|
||||||
-- reference that will match.
|
local sect = args[1]
|
||||||
ref = ('%s(%s)'):format(args[2], args[1])
|
table.remove(args, 1)
|
||||||
|
local name = table.concat(args, ' ')
|
||||||
|
ref = ('%s(%s)'):format(name, sect)
|
||||||
|
else
|
||||||
|
ref = table.concat(args, ' ')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local sect, name = extract_sect_and_name_ref(ref)
|
local sect, name = extract_sect_and_name_ref(ref)
|
||||||
@ -753,9 +753,16 @@ function M.open_page(count, smods, args)
|
|||||||
sect = tostring(count)
|
sect = tostring(count)
|
||||||
end
|
end
|
||||||
|
|
||||||
local path = verify_exists(sect, name)
|
-- Try both spaces and underscores, use the first that exists.
|
||||||
sect, name = extract_sect_and_name_path(path)
|
local path = M.search_for_path(sect, name)
|
||||||
|
if path == nil then
|
||||||
|
path = M.search_for_path(sect, spaces_to_underscores(name))
|
||||||
|
if path == nil then
|
||||||
|
man_error('no manual entry for ' .. name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sect, name = extract_sect_and_name_path(path)
|
||||||
local buf = fn.bufnr()
|
local buf = fn.bufnr()
|
||||||
local save_tfu = vim.bo[buf].tagfunc
|
local save_tfu = vim.bo[buf].tagfunc
|
||||||
vim.bo[buf].tagfunc = "v:lua.require'man'.goto_tag"
|
vim.bo[buf].tagfunc = "v:lua.require'man'.goto_tag"
|
||||||
@ -786,7 +793,10 @@ end
|
|||||||
-- Called when a man:// buffer is opened.
|
-- Called when a man:// buffer is opened.
|
||||||
function M.read_page(ref)
|
function M.read_page(ref)
|
||||||
local sect, name = extract_sect_and_name_ref(ref)
|
local sect, name = extract_sect_and_name_ref(ref)
|
||||||
local path = verify_exists(sect, name)
|
local path = M.search_for_path(sect, name)
|
||||||
|
if path == nil then
|
||||||
|
man_error('no manual entry for ' .. name)
|
||||||
|
end
|
||||||
sect = extract_sect_and_name_path(path)
|
sect = extract_sect_and_name_path(path)
|
||||||
local page = get_page(path)
|
local page = get_page(path)
|
||||||
vim.b.man_sect = sect
|
vim.b.man_sect = sect
|
||||||
|
@ -10,6 +10,26 @@ local write_file = helpers.write_file
|
|||||||
local tmpname = helpers.tmpname
|
local tmpname = helpers.tmpname
|
||||||
local skip = helpers.skip
|
local skip = helpers.skip
|
||||||
local is_ci = helpers.is_ci
|
local is_ci = helpers.is_ci
|
||||||
|
local table_contains = vim.tbl_contains
|
||||||
|
|
||||||
|
-- Returns a table composed of all man page name arguments
|
||||||
|
-- that were passed to search_for_path after attempting to
|
||||||
|
-- open 'name'.
|
||||||
|
local function get_search_history(name)
|
||||||
|
local as_table = string.gsub(name, ' ', '\', \'')
|
||||||
|
as_table = '\'' .. as_table .. '\''
|
||||||
|
local code = ([[
|
||||||
|
local man = require('runtime.lua.man')
|
||||||
|
local res = {}
|
||||||
|
man.attempt_to_get_path = function(sect, name, silent)
|
||||||
|
table.insert(res, name)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
pcall(man.open_page, 0, {tab = 0}, {%s})
|
||||||
|
return res
|
||||||
|
]]):format(as_table)
|
||||||
|
return exec_lua(code)
|
||||||
|
end
|
||||||
|
|
||||||
clear()
|
clear()
|
||||||
if funcs.executable('man') == 0 then
|
if funcs.executable('man') == 0 then
|
||||||
@ -173,4 +193,10 @@ describe(':Man', function()
|
|||||||
funcs.system(args, {''}))
|
funcs.system(args, {''}))
|
||||||
os.remove(actual_file)
|
os.remove(actual_file)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('searches for manpage name with variants with spaces, underscores', function()
|
||||||
|
local tried = get_search_history('NAME WITH SPACES')
|
||||||
|
table_contains(tried, 'NAME WITH SPACES')
|
||||||
|
table_contains(tried, 'NAME_WITH_SPACES')
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user