repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/pivi/docs.lua
Rawlocal MAX_LINES = 80
local MAX_CANDIDATES = 24
local SEPARATOR = '^=====+'
local tag_files = function()
return vim.api.nvim_get_runtime_file( 'doc/tags', true )
end
--- Resolves a help tag against the tag files of the whole runtime path,
--- so plugin documentation answers exactly like `:help` does here.
--- @param tag string
--- @return table? location file and tag
local locate = function( tag )
vim.validate( 'tag', tag, 'string' )
for _, tags_path in ipairs( tag_files() ) do
local directory = vim.fs.dirname( tags_path )
local ok, lines = pcall( vim.fn.readfile, tags_path )
if ok then
for _, line in ipairs( lines ) do
local found, file = line:match '^(%S+)\t(%S+)\t'
if found == tag then
return { tag = found, path = vim.fs.normalize( directory .. '/' .. file ), }
end
end
end
end
return nil
end
local candidates = function( prefix )
local ok, found = pcall( vim.fn.getcompletion, prefix, 'help' )
if not ok then return {} end
return vim.list_slice( found, 1, math.min( #found, MAX_CANDIDATES ) )
end
local section = function( lines, first )
local collected = {}
for index = first, math.min( #lines, first + MAX_LINES - 1 ) do
local line = lines[index]
if index > first + 4 and line:match( SEPARATOR ) then break end
table.insert( collected, line )
end
while #collected > 0 and collected[#collected] == '' do
table.remove( collected )
end
return collected
end
--- Reads the help text for a tag.
--- @param tag string
--- @return table result found flag, text, source file, or candidate tags
local read = function( tag )
vim.validate( 'tag', tag, 'string' )
local location = locate( tag )
if not location then
return { found = false, tag = tag, candidates = candidates( tag ), }
end
local ok, lines = pcall( vim.fn.readfile, location.path )
if not ok then
return { found = false, tag = tag, candidates = candidates( tag ), }
end
local needle = '*' .. tag .. '*'
local first
for index, line in ipairs( lines ) do
if line:find( needle, 1, true ) then
first = index
break
end
end
if not first then first = 1 end
return {
found = true,
tag = tag,
path = location.path,
file = vim.fs.basename( location.path ),
line = first,
text = table.concat( section( lines, first ), '\n' ),
}
end
return {
max_lines = MAX_LINES,
locate = locate,
candidates = candidates,
read = read,
}