mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 12:45:17 -07:00
feat(gen_help_html): non-default vimdoc.so parser
Callers can specify a non-default vimdoc.so file path.
This commit is contained in:
parent
d931b829e9
commit
81d8fce8f9
@ -144,11 +144,11 @@ local function trim(s, dir)
|
||||
return vim.fn.trim(s, '\r\t\n ', dir or 0)
|
||||
end
|
||||
|
||||
-- Remove common punctuation from URLs.
|
||||
--
|
||||
-- TODO: fix this in the parser instead... https://github.com/neovim/tree-sitter-vimdoc
|
||||
--
|
||||
-- @returns (fixed_url, removed_chars) where `removed_chars` is in the order found in the input.
|
||||
--- Removes common punctuation from URLs.
|
||||
---
|
||||
--- TODO: fix this in the parser instead... https://github.com/neovim/tree-sitter-vimdoc
|
||||
---
|
||||
--- @returns (fixed_url, removed_chars) where `removed_chars` is in the order found in the input.
|
||||
local function fix_url(url)
|
||||
local removed_chars = ''
|
||||
local fixed_url = url
|
||||
@ -162,7 +162,7 @@ local function fix_url(url)
|
||||
return fixed_url, removed_chars
|
||||
end
|
||||
|
||||
-- Checks if a given line is a "noise" line that doesn't look good in HTML form.
|
||||
--- Checks if a given line is a "noise" line that doesn't look good in HTML form.
|
||||
local function is_noise(line, noise_lines)
|
||||
if (
|
||||
-- First line is always noise.
|
||||
@ -187,7 +187,7 @@ local function is_noise(line, noise_lines)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Creates a github issue URL at neovim/tree-sitter-vimdoc with prefilled content.
|
||||
--- Creates a github issue URL at neovim/tree-sitter-vimdoc with prefilled content.
|
||||
local function get_bug_url_vimdoc(fname, to_fname, sample_text)
|
||||
local this_url = string.format('https://neovim.io/doc/user/%s', vim.fs.basename(to_fname))
|
||||
local bug_url = ('https://github.com/neovim/tree-sitter-vimdoc/issues/new?labels=bug&title=parse+error%3A+'
|
||||
@ -200,7 +200,7 @@ local function get_bug_url_vimdoc(fname, to_fname, sample_text)
|
||||
return bug_url
|
||||
end
|
||||
|
||||
-- Creates a github issue URL at neovim/neovim with prefilled content.
|
||||
--- Creates a github issue URL at neovim/neovim with prefilled content.
|
||||
local function get_bug_url_nvim(fname, to_fname, sample_text, token_name)
|
||||
local this_url = string.format('https://neovim.io/doc/user/%s', vim.fs.basename(to_fname))
|
||||
local bug_url = ('https://github.com/neovim/neovim/issues/new?labels=bug&title=user+docs+HTML%3A+'
|
||||
@ -215,7 +215,7 @@ local function get_bug_url_nvim(fname, to_fname, sample_text, token_name)
|
||||
return bug_url
|
||||
end
|
||||
|
||||
-- Gets a "foo.html" name from a "foo.txt" helpfile name.
|
||||
--- Gets a "foo.html" name from a "foo.txt" helpfile name.
|
||||
local function get_helppage(f)
|
||||
if not f then
|
||||
return nil
|
||||
@ -230,9 +230,9 @@ local function get_helppage(f)
|
||||
return (f:gsub('%.txt$', '.html'))
|
||||
end
|
||||
|
||||
-- Counts leading spaces (tab=8) to decide the indent size of multiline text.
|
||||
--
|
||||
-- Blank lines (empty or whitespace-only) are ignored.
|
||||
--- Counts leading spaces (tab=8) to decide the indent size of multiline text.
|
||||
---
|
||||
--- Blank lines (empty or whitespace-only) are ignored.
|
||||
local function get_indent(s)
|
||||
local min_indent = nil
|
||||
for line in vim.gsplit(s, '\n') do
|
||||
@ -244,7 +244,7 @@ local function get_indent(s)
|
||||
return min_indent or 0
|
||||
end
|
||||
|
||||
-- Removes the common indent level, after expanding tabs to 8 spaces.
|
||||
--- Removes the common indent level, after expanding tabs to 8 spaces.
|
||||
local function trim_indent(s)
|
||||
local indent_size = get_indent(s)
|
||||
local trimmed = ''
|
||||
@ -255,7 +255,7 @@ local function trim_indent(s)
|
||||
return trimmed:sub(1, -2)
|
||||
end
|
||||
|
||||
-- Gets raw buffer text in the node's range (+/- an offset), as a newline-delimited string.
|
||||
--- Gets raw buffer text in the node's range (+/- an offset), as a newline-delimited string.
|
||||
local function getbuflinestr(node, bufnr, offset)
|
||||
local line1, _, line2, _ = node:range()
|
||||
line1 = line1 - offset
|
||||
@ -264,8 +264,8 @@ local function getbuflinestr(node, bufnr, offset)
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
-- Gets the whitespace just before `node` from the raw buffer text.
|
||||
-- Needed for preformatted `old` lines.
|
||||
--- Gets the whitespace just before `node` from the raw buffer text.
|
||||
--- Needed for preformatted `old` lines.
|
||||
local function getws(node, bufnr)
|
||||
local line1, c1, line2, _ = node:range()
|
||||
local raw = vim.fn.getbufline(bufnr, line1 + 1, line2 + 1)[1]
|
||||
@ -282,7 +282,7 @@ local function get_tagname(node, bufnr)
|
||||
return helppage, tag
|
||||
end
|
||||
|
||||
-- Returns true if the given invalid tagname is a false positive.
|
||||
--- Returns true if the given invalid tagname is a false positive.
|
||||
local function ignore_invalid(s)
|
||||
return not not (
|
||||
exclude_invalid[s]
|
||||
@ -314,7 +314,7 @@ local function has_ancestor(node, ancestor_name)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Gets the first matching child node matching `name`.
|
||||
--- Gets the first matching child node matching `name`.
|
||||
local function first(node, name)
|
||||
for c, _ in node:iter_children() do
|
||||
if c:named() and c:type() == name then
|
||||
@ -336,7 +336,7 @@ local function validate_link(node, bufnr, fname)
|
||||
return helppage, tagname, ignored
|
||||
end
|
||||
|
||||
-- TODO: port the logic from scripts/check_urls.vim
|
||||
--- TODO: port the logic from scripts/check_urls.vim
|
||||
local function validate_url(text, fname)
|
||||
local ignored = false
|
||||
if vim.fs.basename(fname) == 'pi_netrw.txt' then
|
||||
@ -347,7 +347,7 @@ local function validate_url(text, fname)
|
||||
return ignored
|
||||
end
|
||||
|
||||
-- Traverses the tree at `root` and checks that |tag| links point to valid helptags.
|
||||
--- Traverses the tree at `root` and checks that |tag| links point to valid helptags.
|
||||
local function visit_validate(root, level, lang_tree, opt, stats)
|
||||
level = level or 0
|
||||
local node_name = (root.named and root:named()) and root:type() or nil
|
||||
@ -609,7 +609,7 @@ local function get_helpfiles(include)
|
||||
return rv
|
||||
end
|
||||
|
||||
-- Populates the helptags map.
|
||||
--- Populates the helptags map.
|
||||
local function get_helptags(help_dir)
|
||||
local m = {}
|
||||
-- Load a random help file to convince taglist() to do its job.
|
||||
@ -624,17 +624,19 @@ local function get_helptags(help_dir)
|
||||
return m
|
||||
end
|
||||
|
||||
-- Use the vimdoc parser defined in the build, not whatever happens to be installed on the system.
|
||||
--- Use the vimdoc parser defined in the build, not whatever happens to be installed on the system.
|
||||
local function ensure_runtimepath()
|
||||
if not vim.o.runtimepath:find('build/lib/nvim/') then
|
||||
vim.cmd[[set runtimepath^=./build/lib/nvim/]]
|
||||
end
|
||||
end
|
||||
|
||||
-- Opens `fname` in a buffer and gets a treesitter parser for the buffer contents.
|
||||
--
|
||||
-- @returns lang_tree, bufnr
|
||||
local function parse_buf(fname)
|
||||
--- Opens `fname` in a buffer and gets a treesitter parser for the buffer contents.
|
||||
---
|
||||
--- @param fname string help file to parse
|
||||
--- @param parser_path string? path to non-default vimdoc.so
|
||||
--- @returns lang_tree, bufnr
|
||||
local function parse_buf(fname, parser_path)
|
||||
local buf
|
||||
if type(fname) == 'string' then
|
||||
vim.cmd('split '..vim.fn.fnameescape(fname)) -- Filename.
|
||||
@ -643,21 +645,25 @@ local function parse_buf(fname)
|
||||
buf = fname
|
||||
vim.cmd('sbuffer '..tostring(fname)) -- Buffer number.
|
||||
end
|
||||
-- vim.treesitter.language.add('vimdoc', { path = vim.fn.expand('~/Library/Caches/tree-sitter/lib/vimdoc.so') })
|
||||
if parser_path then
|
||||
vim.treesitter.language.add('vimdoc', { path = parser_path })
|
||||
end
|
||||
local lang_tree = vim.treesitter.get_parser(buf)
|
||||
return lang_tree, buf
|
||||
end
|
||||
|
||||
-- Validates one :help file `fname`:
|
||||
-- - checks that |tag| links point to valid helptags.
|
||||
-- - recursively counts parse errors ("ERROR" nodes)
|
||||
--
|
||||
-- @returns { invalid_links: number, parse_errors: number }
|
||||
local function validate_one(fname)
|
||||
--- Validates one :help file `fname`:
|
||||
--- - checks that |tag| links point to valid helptags.
|
||||
--- - recursively counts parse errors ("ERROR" nodes)
|
||||
---
|
||||
--- @param fname string help file to validate
|
||||
--- @param parser_path string? path to non-default vimdoc.so
|
||||
--- @returns { invalid_links: number, parse_errors: number }
|
||||
local function validate_one(fname, parser_path)
|
||||
local stats = {
|
||||
parse_errors = {},
|
||||
}
|
||||
local lang_tree, buf = parse_buf(fname)
|
||||
local lang_tree, buf = parse_buf(fname, parser_path)
|
||||
for _, tree in ipairs(lang_tree:trees()) do
|
||||
visit_validate(tree:root(), 0, tree, { buf = buf, fname = fname, }, stats)
|
||||
end
|
||||
@ -666,20 +672,21 @@ local function validate_one(fname)
|
||||
return stats
|
||||
end
|
||||
|
||||
-- Generates HTML from one :help file `fname` and writes the result to `to_fname`.
|
||||
--
|
||||
-- @param fname Source :help file
|
||||
-- @param to_fname Destination .html file
|
||||
-- @param old boolean Preformat paragraphs (for old :help files which are full of arbitrary whitespace)
|
||||
--
|
||||
-- @returns html, stats
|
||||
local function gen_one(fname, to_fname, old, commit)
|
||||
--- Generates HTML from one :help file `fname` and writes the result to `to_fname`.
|
||||
---
|
||||
--- @param fname string Source :help file
|
||||
--- @param to_fname string Destination .html file
|
||||
--- @param old boolean Preformat paragraphs (for old :help files which are full of arbitrary whitespace)
|
||||
--- @param parser_path string? path to non-default vimdoc.so
|
||||
---
|
||||
--- @returns html, stats
|
||||
local function gen_one(fname, to_fname, old, commit, parser_path)
|
||||
local stats = {
|
||||
noise_lines = {},
|
||||
parse_errors = {},
|
||||
first_tags = {}, -- Track the first few tags in doc.
|
||||
}
|
||||
local lang_tree, buf = parse_buf(fname)
|
||||
local lang_tree, buf = parse_buf(fname, parser_path)
|
||||
local headings = {} -- Headings (for ToC). 2-dimensional: h1 contains h2/h3.
|
||||
local title = to_titlecase(basename_noext(fname))
|
||||
|
||||
@ -1059,18 +1066,20 @@ end
|
||||
--- @param include table|nil Process only these filenames. Example: {'api.txt', 'autocmd.txt', 'channel.txt'}
|
||||
---
|
||||
--- @returns info dict
|
||||
function M.gen(help_dir, to_dir, include, commit)
|
||||
function M.gen(help_dir, to_dir, include, commit, parser_path)
|
||||
vim.validate{
|
||||
help_dir={help_dir, function(d) return vim.fn.isdirectory(d) == 1 end, 'valid directory'},
|
||||
to_dir={to_dir, 's'},
|
||||
include={include, 't', true},
|
||||
commit={commit, 's', true},
|
||||
parser_path={parser_path, function(f) return f == nil or vim.fn.filereadable(vim.fn.expand(f)) == 1 end, 'valid vimdoc.{so,dll} filepath'},
|
||||
}
|
||||
|
||||
local err_count = 0
|
||||
ensure_runtimepath()
|
||||
tagmap = get_helptags(help_dir)
|
||||
helpfiles = get_helpfiles(include)
|
||||
parser_path = parser_path and vim.fn.expand(parser_path) or nil
|
||||
|
||||
print(('output dir: %s'):format(to_dir))
|
||||
vim.fn.mkdir(to_dir, 'p')
|
||||
@ -1079,7 +1088,7 @@ function M.gen(help_dir, to_dir, include, commit)
|
||||
for _, f in ipairs(helpfiles) do
|
||||
local helpfile = vim.fs.basename(f)
|
||||
local to_fname = ('%s/%s'):format(to_dir, get_helppage(helpfile))
|
||||
local html, stats = gen_one(f, to_fname, not new_layout[helpfile], commit or '?')
|
||||
local html, stats = gen_one(f, to_fname, not new_layout[helpfile], commit or '?', parser_path)
|
||||
tofile(to_fname, html)
|
||||
print(('generated (%-4s errors): %-15s => %s'):format(#stats.parse_errors, helpfile, vim.fs.basename(to_fname)))
|
||||
err_count = err_count + #stats.parse_errors
|
||||
@ -1102,19 +1111,21 @@ end
|
||||
-- This is 10x faster than gen(), for use in CI.
|
||||
--
|
||||
-- @returns results dict
|
||||
function M.validate(help_dir, include)
|
||||
function M.validate(help_dir, include, parser_path)
|
||||
vim.validate{
|
||||
help_dir={help_dir, function(d) return vim.fn.isdirectory(d) == 1 end, 'valid directory'},
|
||||
include={include, 't', true},
|
||||
parser_path={parser_path, function(f) return f == nil or vim.fn.filereadable(vim.fn.expand(f)) == 1 end, 'valid vimdoc.{so,dll} filepath'},
|
||||
}
|
||||
local err_count = 0
|
||||
ensure_runtimepath()
|
||||
tagmap = get_helptags(help_dir)
|
||||
helpfiles = get_helpfiles(include)
|
||||
parser_path = parser_path and vim.fn.expand(parser_path) or nil
|
||||
|
||||
for _, f in ipairs(helpfiles) do
|
||||
local helpfile = vim.fs.basename(f)
|
||||
local rv = validate_one(f)
|
||||
local rv = validate_one(f, parser_path)
|
||||
print(('validated (%-4s errors): %s'):format(#rv.parse_errors, helpfile))
|
||||
err_count = err_count + #rv.parse_errors
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user