local 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, }