build: enable lintlua for scripts/ dir #26391

Problem:
We don't enable stylua for many Lua scripts. Automating code-style is an
important tool for reducing time spent on accidental (non-essential)
complexity.

Solution:
- Enable lintlua for `scripts/` directory.
- Specify `call_parentheses = "Input"`, we should allow kwargs-style
  function invocations.
This commit is contained in:
Justin M. Keyes 2023-12-04 12:38:31 -08:00 committed by GitHub
parent e5d7003b02
commit 517f0cc634
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 415 additions and 292 deletions

View File

@ -3,4 +3,4 @@ line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferSingle"
call_parentheses = "Always"
call_parentheses = "Input"

View File

@ -2,6 +2,5 @@
/runtime/lua/coxpcall.lua
/runtime/lua/vim/_meta
/runtime/lua/vim/re.lua
/scripts
/src
/test

View File

@ -233,7 +233,7 @@ add_glob_target(
TARGET lintlua-stylua
COMMAND ${STYLUA_PRG}
FLAGS --color=always --check --respect-ignores
GLOB_DIRS runtime/
GLOB_DIRS runtime/ scripts/
GLOB_PAT *.lua
TOUCH_STRATEGY SINGLE)
@ -260,7 +260,7 @@ add_glob_target(
TARGET formatlua
COMMAND ${STYLUA_PRG}
FLAGS --respect-ignores
GLOB_DIRS runtime
GLOB_DIRS runtime/ scripts/
GLOB_PAT *.lua)
add_custom_target(format)

View File

@ -138,9 +138,10 @@ local function get_archive_info(repo, ref)
'Failed to download archive from GitHub'
)
local shacmd = (vim.fn.executable('sha256sum') == 1
and{ 'sha256sum', archive_path }
or { 'shasum', '-a', '256', archive_path })
local shacmd = (
vim.fn.executable('sha256sum') == 1 and { 'sha256sum', archive_path }
or { 'shasum', '-a', '256', archive_path }
)
local archive_sha = run(shacmd):gmatch('%w+')()
return { url = archive_url, sha = archive_sha }
end
@ -152,18 +153,7 @@ local function write_cmakelists_line(symbol, kind, value)
'sed',
'-i',
'-e',
's/'
.. symbol
.. '_'
.. kind
.. '.*$'
.. '/'
.. symbol
.. '_'
.. kind
.. ' '
.. value
.. '/',
's/' .. symbol .. '_' .. kind .. '.*$' .. '/' .. symbol .. '_' .. kind .. ' ' .. value .. '/',
deps_file,
}, 'Failed to write ' .. deps_file)
end
@ -203,16 +193,13 @@ local function update_cmakelists(dependency, archive, comment)
p('Updating ' .. dependency.name .. ' to ' .. archive.url .. '\n')
write_cmakelists_line(dependency.symbol, 'URL', archive.url:gsub('/', '\\/'))
write_cmakelists_line(dependency.symbol, 'SHA256', archive.sha)
run_die(
{
run_die({
'git',
'commit',
deps_file,
'-m',
commit_prefix .. 'bump ' .. dependency.name .. ' to ' .. comment,
},
'git failed to commit'
)
}, 'git failed to commit')
end
local function verify_cmakelists_committed()
@ -384,7 +371,7 @@ function M.submit_pr()
end
local function usage()
local this_script = _G.arg[0]:match("[^/]*.lua$")
local this_script = _G.arg[0]:match('[^/]*.lua$')
print(([=[
Bump Nvim dependencies

View File

@ -473,7 +473,7 @@ local function render_option_default(d, vimdoc)
end
end
if dt == "" or dt == nil or type(dt) == 'function' then
if dt == '' or dt == nil or type(dt) == 'function' then
dt = d.meta
end
@ -541,7 +541,7 @@ local function scope_to_doc(s)
global = 'global',
buffer = 'local to buffer',
window = 'local to window',
tab = 'local to tab page'
tab = 'local to tab page',
}
if #s == 1 then
@ -618,7 +618,7 @@ local function build_option_tags(opt)
end
for i, t in ipairs(tags) do
tags[i] = "*"..t.."*"
tags[i] = '*' .. t .. '*'
end
return tags
@ -751,11 +751,11 @@ local CONFIG = {
header = { '' },
from = 'A jump table for the options with a short description can be found at |Q_op|.',
footer = {
' vim:tw=78:ts=8:noet:ft=help:norl:'
' vim:tw=78:ts=8:noet:ft=help:norl:',
},
funcs = get_option_meta,
render = render_option_doc,
}
},
}
--- @param elem nvim.gen_eval_files.elem

View File

@ -8,18 +8,18 @@ if do_not_run then
return
end
local filetype_vim = "runtime/filetype.vim"
local filetype_lua = "runtime/lua/vim/filetype.lua"
local filetype_vim = 'runtime/filetype.vim'
local filetype_lua = 'runtime/lua/vim/filetype.lua'
local keywords = {
["for"] = true,
["or"] = true,
["and"] = true,
["end"] = true,
["do"] = true,
["if"] = true,
["while"] = true,
["repeat"] = true,
['for'] = true,
['or'] = true,
['and'] = true,
['end'] = true,
['do'] = true,
['if'] = true,
['while'] = true,
['repeat'] = true,
}
local sections = {
@ -28,42 +28,42 @@ local sections = {
pattern = { str = {}, func = {} },
}
local specialchars = "%*%?\\%$%[%]%{%}"
local specialchars = '%*%?\\%$%[%]%{%}'
local function add_pattern(pat, ft)
local ok = true
-- Patterns that start or end with { or } confuse splitting on commas and make parsing harder, so just skip those
if not string.find(pat, "^%{") and not string.find(pat, "%}$") then
for part in string.gmatch(pat, "[^,]+") do
if not string.find(part, "[" .. specialchars .. "]") then
if type(ft) == "string" then
if not string.find(pat, '^%{') and not string.find(pat, '%}$') then
for part in string.gmatch(pat, '[^,]+') do
if not string.find(part, '[' .. specialchars .. ']') then
if type(ft) == 'string' then
sections.filename.str[part] = ft
else
sections.filename.func[part] = ft
end
elseif string.match(part, "^%*%.[^%./" .. specialchars .. "]+$") then
if type(ft) == "string" then
elseif string.match(part, '^%*%.[^%./' .. specialchars .. ']+$') then
if type(ft) == 'string' then
sections.extension.str[part:sub(3)] = ft
else
sections.extension.func[part:sub(3)] = ft
end
else
if string.match(part, "^%*/[^" .. specialchars .. "]+$") then
if string.match(part, '^%*/[^' .. specialchars .. ']+$') then
-- For patterns matching */some/pattern we want to easily match files
-- with path /some/pattern, so include those in filename detection
if type(ft) == "string" then
if type(ft) == 'string' then
sections.filename.str[part:sub(2)] = ft
else
sections.filename.func[part:sub(2)] = ft
end
end
if string.find(part, "^[%w-_.*?%[%]/]+$") then
local p = part:gsub("%.", "%%."):gsub("%*", ".*"):gsub("%?", ".")
if string.find(part, '^[%w-_.*?%[%]/]+$') then
local p = part:gsub('%.', '%%.'):gsub('%*', '.*'):gsub('%?', '.')
-- Insert into array to maintain order rather than setting
-- key-value directly
if type(ft) == "string" then
if type(ft) == 'string' then
sections.pattern.str[p] = ft
else
sections.pattern.func[p] = ft
@ -80,14 +80,16 @@ end
local function parse_line(line)
local pat, ft
pat, ft = line:match("^%s*au%a* Buf[%a,]+%s+(%S+)%s+setf%s+(%S+)")
pat, ft = line:match('^%s*au%a* Buf[%a,]+%s+(%S+)%s+setf%s+(%S+)')
if pat then
return add_pattern(pat, ft)
else
local func
pat, func = line:match("^%s*au%a* Buf[%a,]+%s+(%S+)%s+call%s+(%S+)")
pat, func = line:match('^%s*au%a* Buf[%a,]+%s+(%S+)%s+call%s+(%S+)')
if pat then
return add_pattern(pat, function() return func end)
return add_pattern(pat, function()
return func
end)
end
end
end
@ -95,12 +97,12 @@ end
local unparsed = {}
local full_line
for line in io.lines(filetype_vim) do
local cont = string.match(line, "^%s*\\%s*(.*)$")
local cont = string.match(line, '^%s*\\%s*(.*)$')
if cont then
full_line = full_line .. " " .. cont
full_line = full_line .. ' ' .. cont
else
if full_line then
if not parse_line(full_line) and string.find(full_line, "^%s*au%a* Buf") then
if not parse_line(full_line) and string.find(full_line, '^%s*au%a* Buf') then
table.insert(unparsed, full_line)
end
end
@ -109,40 +111,46 @@ for line in io.lines(filetype_vim) do
end
if #unparsed > 0 then
print("Failed to parse the following patterns:")
print('Failed to parse the following patterns:')
for _, v in ipairs(unparsed) do
print(v)
end
end
local function add_item(indent, key, ft)
if type(ft) == "string" then
if string.find(key, "%A") or keywords[key] then
key = string.format("[\"%s\"]", key)
if type(ft) == 'string' then
if string.find(key, '%A') or keywords[key] then
key = string.format('["%s"]', key)
end
return string.format([[%s%s = "%s",]], indent, key, ft)
elseif type(ft) == "function" then
elseif type(ft) == 'function' then
local func = ft()
if string.find(key, "%A") or keywords[key] then
key = string.format("[\"%s\"]", key)
if string.find(key, '%A') or keywords[key] then
key = string.format('["%s"]', key)
end
-- Right now only a single argument is supported, which covers
-- everything in filetype.vim as of this writing
local arg = string.match(func, "%((.*)%)$")
func = string.gsub(func, "%(.*$", "")
if arg == "" then
local arg = string.match(func, '%((.*)%)$')
func = string.gsub(func, '%(.*$', '')
if arg == '' then
-- Function with no arguments, call the function directly
return string.format([[%s%s = function() vim.fn["%s"]() end,]], indent, key, func)
elseif string.match(arg, [[^(["']).*%1$]]) then
-- String argument
if func == "s:StarSetf" then
if func == 's:StarSetf' then
return string.format([[%s%s = starsetf(%s),]], indent, key, arg)
else
return string.format([[%s%s = function() vim.fn["%s"](%s) end,]], indent, key, func, arg)
end
elseif string.find(arg, "%(") then
elseif string.find(arg, '%(') then
-- Function argument
return string.format([[%s%s = function() vim.fn["%s"](vim.fn.%s) end,]], indent, key, func, arg)
return string.format(
[[%s%s = function() vim.fn["%s"](vim.fn.%s) end,]],
indent,
key,
func,
arg
)
else
assert(false, arg)
end
@ -153,7 +161,7 @@ do
local lines = {}
local start = false
for line in io.lines(filetype_lua) do
if line:match("^%s+-- END [A-Z]+$") then
if line:match('^%s+-- END [A-Z]+$') then
start = false
end
@ -161,7 +169,7 @@ do
table.insert(lines, line)
end
local indent, section = line:match("^(%s+)-- BEGIN ([A-Z]+)$")
local indent, section = line:match('^(%s+)-- BEGIN ([A-Z]+)$')
if section then
start = true
local t = sections[string.lower(section)]
@ -195,7 +203,7 @@ do
end
end
end
local f = io.open(filetype_lua, "w")
f:write(table.concat(lines, "\n") .. "\n")
local f = io.open(filetype_lua, 'w')
f:write(table.concat(lines, '\n') .. '\n')
f:close()
end

View File

@ -60,26 +60,26 @@ local new_layout = {
-- TODO: These known invalid |links| require an update to the relevant docs.
local exclude_invalid = {
["'string'"] = "eval.txt",
["'string'"] = 'eval.txt',
Query = 'treesitter.txt',
matchit = 'vim_diff.txt',
["set!"] = "treesitter.txt",
['set!'] = 'treesitter.txt',
}
-- False-positive "invalid URLs".
local exclude_invalid_urls = {
["http://"] = "usr_23.txt",
["http://."] = "usr_23.txt",
["http://aspell.net/man-html/Affix-Compression.html"] = "spell.txt",
["http://aspell.net/man-html/Phonetic-Code.html"] = "spell.txt",
["http://canna.sourceforge.jp/"] = "mbyte.txt",
["http://gnuada.sourceforge.net"] = "ft_ada.txt",
["http://lua-users.org/wiki/StringLibraryTutorial"] = "lua.txt",
["http://michael.toren.net/code/"] = "pi_tar.txt",
["http://papp.plan9.de"] = "syntax.txt",
["http://wiki.services.openoffice.org/wiki/Dictionaries"] = "spell.txt",
["http://www.adapower.com"] = "ft_ada.txt",
["http://www.jclark.com/"] = "quickfix.txt",
['http://'] = 'usr_23.txt',
['http://.'] = 'usr_23.txt',
['http://aspell.net/man-html/Affix-Compression.html'] = 'spell.txt',
['http://aspell.net/man-html/Phonetic-Code.html'] = 'spell.txt',
['http://canna.sourceforge.jp/'] = 'mbyte.txt',
['http://gnuada.sourceforge.net'] = 'ft_ada.txt',
['http://lua-users.org/wiki/StringLibraryTutorial'] = 'lua.txt',
['http://michael.toren.net/code/'] = 'pi_tar.txt',
['http://papp.plan9.de'] = 'syntax.txt',
['http://wiki.services.openoffice.org/wiki/Dictionaries'] = 'spell.txt',
['http://www.adapower.com'] = 'ft_ada.txt',
['http://www.jclark.com/'] = 'quickfix.txt',
}
-- Deprecated, brain-damaged files that I don't care about.
@ -98,19 +98,18 @@ local function tofile(fname, text)
end
local function html_esc(s)
return s:gsub(
'&', '&'):gsub(
'<', '&lt;'):gsub(
'>', '&gt;')
return s:gsub('&', '&amp;'):gsub('<', '&lt;'):gsub('>', '&gt;')
end
local function url_encode(s)
-- Credit: tpope / vim-unimpaired
-- NOTE: these chars intentionally *not* escaped: ' ( )
return vim.fn.substitute(vim.fn.iconv(s, 'latin1', 'utf-8'),
return vim.fn.substitute(
vim.fn.iconv(s, 'latin1', 'utf-8'),
[=[[^A-Za-z0-9()'_.~-]]=],
[=[\="%".printf("%02X",char2nr(submatch(0)))]=],
'g')
'g'
)
end
local function expandtabs(s)
@ -151,7 +150,7 @@ local function fix_url(url)
local removed_chars = ''
local fixed_url = url
-- Remove up to one of each char from end of the URL, in this order.
for _, c in ipairs({ '.', ')', }) do
for _, c in ipairs({ '.', ')' }) do
if fixed_url:sub(-1) == c then
removed_chars = c .. removed_chars
fixed_url = fixed_url:sub(1, -2)
@ -162,7 +161,7 @@ end
--- 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 (
if
-- First line is always noise.
(noise_lines ~= nil and vim.tbl_count(noise_lines) == 0)
or line:find('Type .*gO.* to see the table of contents')
@ -177,7 +176,7 @@ local function is_noise(line, noise_lines)
or line:find('^%s*vim?%:.*ft=help')
or line:find('^%s*vim?%:.*filetype=help')
or line:find('[*>]local%-additions[*<]')
) then
then
-- table.insert(stats.noise_lines, getbuflinestr(root, opt.buf, 0))
table.insert(noise_lines or {}, line)
return true
@ -188,20 +187,23 @@ end
--- 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+'
local bug_url = (
'https://github.com/neovim/tree-sitter-vimdoc/issues/new?labels=bug&title=parse+error%3A+'
.. vim.fs.basename(fname)
.. '+&body=Found+%60tree-sitter-vimdoc%60+parse+error+at%3A+'
.. this_url
.. '%0D%0DContext%3A%0D%0D%60%60%60%0D'
.. url_encode(sample_text)
..'%0D%60%60%60')
.. '%0D%60%60%60'
)
return bug_url
end
--- 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+'
local bug_url = (
'https://github.com/neovim/neovim/issues/new?labels=bug&title=user+docs+HTML%3A+'
.. vim.fs.basename(fname)
.. '+&body=%60gen_help_html.lua%60+problem+at%3A+'
.. this_url
@ -209,7 +211,8 @@ local function get_bug_url_nvim(fname, to_fname, sample_text, token_name)
.. (token_name and '+unhandled+token%3A+%60' .. token_name .. '%60' or '')
.. '%0DContext%3A%0D%0D%60%60%60%0D'
.. url_encode(sample_text)
..'%0D%60%60%60')
.. '%0D%60%60%60'
)
return bug_url
end
@ -274,7 +277,9 @@ end
local function get_tagname(node, bufnr)
local text = vim.treesitter.get_node_text(node, bufnr)
local tag = (node:type() == 'optionlink' or node:parent():type() == 'optionlink') and ("'%s'"):format(text) or text
local tag = (node:type() == 'optionlink' or node:parent():type() == 'optionlink')
and ("'%s'"):format(text)
or text
local helpfile = vim.fs.basename(tagmap[tag]) or nil -- "api.txt"
local helppage = get_helppage(helpfile) -- "api.html"
return helppage, tag
@ -295,11 +300,9 @@ local function ignore_parse_error(fname, s)
if ignore_errors[vim.fs.basename(fname)] then
return true
end
return (
-- Ignore parse errors for unclosed tag.
-- This is common in vimdocs and is treated as plaintext by :help.
s:find("^[`'|*]")
)
return s:find("^[`'|*]")
end
local function has_ancestor(node, ancestor_name)
@ -377,7 +380,8 @@ local function visit_validate(root, level, lang_tree, opt, stats)
-- Flatten the sample text to a single, truncated line.
sample_text = vim.trim(sample_text):gsub('[\t\n]', ' '):sub(1, 80)
table.insert(stats.parse_errors, sample_text)
elseif (node_name == 'word' or node_name == 'uppercase_name')
elseif
(node_name == 'word' or node_name == 'uppercase_name')
and (not vim.tbl_contains({ 'codespan', 'taglink', 'tag' }, parent))
then
local text_nopunct = vim.fn.trim(text, '.,', 0) -- Ignore some punctuation.
@ -411,9 +415,15 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
local node_name = (root.named and root:named()) and root:type() or nil
-- Previous sibling kind (string).
local prev = root:prev_sibling() and (root:prev_sibling().named and root:prev_sibling():named()) and root:prev_sibling():type() or nil
local prev = root:prev_sibling()
and (root:prev_sibling().named and root:prev_sibling():named())
and root:prev_sibling():type()
or nil
-- Next sibling kind (string).
local next_ = root:next_sibling() and (root:next_sibling().named and root:next_sibling():named()) and root:next_sibling():type() or nil
local next_ = root:next_sibling()
and (root:next_sibling().named and root:next_sibling():named())
and root:next_sibling():type()
or nil
-- Parent kind (string).
local parent = root:parent() and root:parent():type() or nil
local text = ''
@ -466,11 +476,15 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
-- Use the first *tag* node as the heading anchor, if any.
local tagnode = first(root, 'tag')
-- Use the *tag* as the heading anchor id, if possible.
local tagname = tagnode and url_encode(node_text(tagnode:child(1), false)) or to_heading_tag(hname)
local tagname = tagnode and url_encode(node_text(tagnode:child(1), false))
or to_heading_tag(hname)
if node_name == 'h1' or #headings == 0 then
table.insert(headings, { name = hname, subheadings = {}, tag = tagname })
else
table.insert(headings[#headings].subheadings, { name = hname, subheadings = {}, tag = tagname })
table.insert(
headings[#headings].subheadings,
{ name = hname, subheadings = {}, tag = tagname }
)
end
local el = node_name == 'h1' and 'h2' or 'h3'
return ('<%s id="%s" class="help-heading">%s</%s>\n'):format(el, tagname, text, el)
@ -490,11 +504,16 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
end
return string.format('<div class="help-para">\n%s\n</div>\n', text)
elseif node_name == 'line' then
if (parent ~= 'codeblock' or parent ~= 'code') and (is_blank(text) or is_noise(text, stats.noise_lines)) then
if
(parent ~= 'codeblock' or parent ~= 'code')
and (is_blank(text) or is_noise(text, stats.noise_lines))
then
return '' -- Discard common "noise" lines.
end
-- XXX: Avoid newlines (too much whitespace) after block elements in old (preformatted) layout.
local div = opt.old and root:child(0) and vim.list_contains({'column_heading', 'h1', 'h2', 'h3'}, root:child(0):type())
local div = opt.old
and root:child(0)
and vim.list_contains({ 'column_heading', 'h1', 'h2', 'h3' }, root:child(0):type())
return string.format('%s%s', div and trim(text) or text, div and '' or '\n')
elseif node_name == 'line_li' then
local sib = root:prev_sibling()
@ -520,7 +539,12 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
if ignored then
return text
end
local s = ('%s<a href="%s#%s">%s</a>'):format(ws(), helppage, url_encode(tagname), html_esc(tagname))
local s = ('%s<a href="%s#%s">%s</a>'):format(
ws(),
helppage,
url_encode(tagname),
html_esc(tagname)
)
if opt.old and node_name == 'taglink' then
s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end
@ -547,7 +571,10 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
end
local code
if language then
code = ('<pre><code class="language-%s">%s</code></pre>'):format(language,trim(trim_indent(text), 2))
code = ('<pre><code class="language-%s">%s</code></pre>'):format(
language,
trim(trim_indent(text), 2)
)
language = nil
else
code = ('<pre>%s</pre>'):format(trim(trim_indent(text), 2))
@ -558,7 +585,8 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
return text
end
local in_heading = vim.list_contains({ 'h1', 'h2', 'h3' }, parent)
local cssclass = (not in_heading and get_indent(node_text()) > 8) and 'help-tag-right' or 'help-tag'
local cssclass = (not in_heading and get_indent(node_text()) > 8) and 'help-tag-right'
or 'help-tag'
local tagname = node_text(root:child(1), false)
if vim.tbl_count(stats.first_tags) < 2 then
-- Force the first 2 tags in the doc to be anchored at the main heading.
@ -567,14 +595,29 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
end
local el = in_heading and 'span' or 'code'
local encoded_tagname = url_encode(tagname)
local s = ('%s<%s id="%s" class="%s"><a href="#%s">%s</a></%s>'):format(ws(), el, encoded_tagname, cssclass, encoded_tagname, trimmed, el)
local s = ('%s<%s id="%s" class="%s"><a href="#%s">%s</a></%s>'):format(
ws(),
el,
encoded_tagname,
cssclass,
encoded_tagname,
trimmed,
el
)
if opt.old then
s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end
if in_heading and prev ~= 'tag' then
-- Don't set "id", let the heading use the tag as its "id" (used by search engines).
s = ('%s<%s class="%s"><a href="#%s">%s</a></%s>'):format(ws(), el, cssclass, encoded_tagname, trimmed, el)
s = ('%s<%s class="%s"><a href="#%s">%s</a></%s>'):format(
ws(),
el,
cssclass,
encoded_tagname,
trimmed,
el
)
-- Start the <span> container for tags in a heading.
-- This makes "justify-content:space-between" right-align the tags.
-- <h2>foo bar<span>tag1 tag2</span></h2>
@ -593,11 +636,17 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
local sample_text = level > 0 and getbuflinestr(root, opt.buf, 3) or '[top level!]'
table.insert(stats.parse_errors, sample_text)
return ('<a class="parse-error" target="_blank" title="Report bug... (parse error)" href="%s">%s</a>'):format(
get_bug_url_vimdoc(opt.fname, opt.to_fname, sample_text), trimmed)
get_bug_url_vimdoc(opt.fname, opt.to_fname, sample_text),
trimmed
)
else -- Unknown token.
local sample_text = level > 0 and getbuflinestr(root, opt.buf, 3) or '[top level!]'
return ('<a class="unknown-token" target="_blank" title="Report bug... (unhandled token "%s")" href="%s">%s</a>'):format(
node_name, get_bug_url_nvim(opt.fname, opt.to_fname, sample_text, node_name), trimmed), ('unknown-token:"%s"'):format(node_name)
node_name,
get_bug_url_nvim(opt.fname, opt.to_fname, sample_text, node_name),
trimmed
),
('unknown-token:"%s"'):format(node_name)
end
end
@ -605,9 +654,11 @@ local function get_helpfiles(include)
local dir = './build/runtime/doc'
local rv = {}
for f, type in vim.fs.dir(dir) do
if (vim.endswith(f, '.txt')
if
vim.endswith(f, '.txt')
and type == 'file'
and (not include or vim.list_contains(include, f))) then
and (not include or vim.list_contains(include, f))
then
local fullpath = vim.fn.fnamemodify(('%s/%s'):format(dir, f), ':p')
table.insert(rv, fullpath)
end
@ -671,7 +722,7 @@ local function validate_one(fname, parser_path)
}
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)
visit_validate(tree:root(), 0, tree, { buf = buf, fname = fname }, stats)
end
lang_tree:destroy()
vim.cmd.close()
@ -777,9 +828,17 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
local main = ''
for _, tree in ipairs(lang_tree:trees()) do
main = main .. (visit_node(tree:root(), 0, tree, headings,
{ buf = buf, old = old, fname = fname, to_fname = to_fname, indent = 1, },
stats))
main = main
.. (
visit_node(
tree:root(),
0,
tree,
headings,
{ buf = buf, old = old, fname = fname, to_fname = to_fname, indent = 1 },
stats
)
)
end
main = ([[
@ -809,7 +868,14 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
<hr/>
%s
</div>
]]):format(logo_svg, stats.first_tags[2] or '', stats.first_tags[1] or '', title, vim.fs.basename(fname), main)
]]):format(
logo_svg,
stats.first_tags[2] or '',
stats.first_tags[1] or '',
title,
vim.fs.basename(fname),
main
)
local toc = [[
<div class="col-narrow toc">
@ -820,12 +886,15 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
]]
local n = 0 -- Count of all headings + subheadings.
for _, h1 in ipairs(headings) do n = n + 1 + #h1.subheadings end
for _, h1 in ipairs(headings) do
n = n + 1 + #h1.subheadings
end
for _, h1 in ipairs(headings) do
toc = toc .. ('<div class="help-toc-h1"><a href="#%s">%s</a>\n'):format(h1.tag, h1.name)
if n < 30 or #headings < 10 then -- Show subheadings only if there aren't too many.
for _, h2 in ipairs(h1.subheadings) do
toc = toc .. ('<div class="help-toc-h2"><a href="#%s">%s</a></div>\n'):format(h2.tag, h2.name)
toc = toc
.. ('<div class="help-toc-h2"><a href="#%s">%s</a></div>\n'):format(h2.tag, h2.name)
end
end
toc = toc .. '</div>'
@ -859,11 +928,16 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
</footer>
]]):format(
os.date('%Y-%m-%d %H:%M'), commit, commit:sub(1, 7), #stats.parse_errors, bug_link,
html_esc(table.concat(stats.noise_lines, '\n')), #stats.noise_lines)
os.date('%Y-%m-%d %H:%M'),
commit,
commit:sub(1, 7),
#stats.parse_errors,
bug_link,
html_esc(table.concat(stats.noise_lines, '\n')),
#stats.noise_lines
)
html = ('%s%s%s</div>\n%s</body>\n</html>\n'):format(
html, main, toc, footer)
html = ('%s%s%s</div>\n%s</body>\n</html>\n'):format(html, main, toc, footer)
vim.cmd('q!')
lang_tree:destroy()
return html, stats
@ -1038,9 +1112,15 @@ function M._test()
helpfiles = get_helpfiles()
local function ok(cond, expected, actual)
assert((not expected and not actual) or (expected and actual), 'if "expected" is given, "actual" is also required')
assert(
(not expected and not actual) or (expected and actual),
'if "expected" is given, "actual" is also required'
)
if expected then
return assert(cond, ('expected %s, got: %s'):format(vim.inspect(expected), vim.inspect(actual)))
return assert(
cond,
('expected %s, got: %s'):format(vim.inspect(expected), vim.inspect(actual))
)
else
return assert(cond)
end
@ -1050,7 +1130,11 @@ function M._test()
end
ok(vim.tbl_count(tagmap) > 3000, '>3000', vim.tbl_count(tagmap))
ok(vim.endswith(tagmap['vim.diagnostic.set()'], 'diagnostic.txt'), tagmap['vim.diagnostic.set()'], 'diagnostic.txt')
ok(
vim.endswith(tagmap['vim.diagnostic.set()'], 'diagnostic.txt'),
tagmap['vim.diagnostic.set()'],
'diagnostic.txt'
)
ok(vim.endswith(tagmap['%:s'], 'cmdline.txt'), tagmap['%:s'], 'cmdline.txt')
ok(is_noise([[vim:tw=78:isk=!-~,^*,^\|,^\":ts=8:noet:ft=help:norl:]]))
ok(is_noise([[ NVIM REFERENCE MANUAL by Thiago de Arruda ]]))
@ -1060,7 +1144,10 @@ function M._test()
eq(1, get_indent(' a'))
eq(2, get_indent(' a\n b\n c\n'))
eq(5, get_indent(' a\n \n b\n c\n d\n e\n'))
eq('a\n \n b\n c\n d\n e\n', trim_indent(' a\n \n b\n c\n d\n e\n'))
eq(
'a\n \n b\n c\n d\n e\n',
trim_indent(' a\n \n b\n c\n d\n e\n')
)
local fixed_url, removed_chars = fix_url('https://example.com).')
eq('https://example.com', fixed_url)
@ -1094,11 +1181,23 @@ end
--- @returns info dict
function M.gen(help_dir, to_dir, include, commit, parser_path)
vim.validate {
help_dir={help_dir, function(d) return vim.fn.isdirectory(vim.fn.expand(d)) == 1 end, 'valid directory'},
help_dir = {
help_dir,
function(d)
return vim.fn.isdirectory(vim.fn.expand(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'},
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
@ -1117,7 +1216,13 @@ function M.gen(help_dir, to_dir, include, commit, parser_path)
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 '?', parser_path)
tofile(to_fname, html)
print(('generated (%-4s errors): %-15s => %s'):format(#stats.parse_errors, helpfile, vim.fs.basename(to_fname)))
print(
('generated (%-4s errors): %-15s => %s'):format(
#stats.parse_errors,
helpfile,
vim.fs.basename(to_fname)
)
)
err_count = err_count + #stats.parse_errors
end
print(('generated %d html pages'):format(#helpfiles))
@ -1140,9 +1245,21 @@ end
-- @returns results dict
function M.validate(help_dir, include, parser_path)
vim.validate {
help_dir={help_dir, function(d) return vim.fn.isdirectory(vim.fn.expand(d)) == 1 end, 'valid directory'},
help_dir = {
help_dir,
function(d)
return vim.fn.isdirectory(vim.fn.expand(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'},
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
local files_to_errors = {}
@ -1157,7 +1274,9 @@ function M.validate(help_dir, include, parser_path)
print(('validated (%-4s errors): %s'):format(#rv.parse_errors, helpfile))
if #rv.parse_errors > 0 then
files_to_errors[helpfile] = rv.parse_errors
vim.print(('%s'):format(vim.iter(rv.parse_errors):fold('', function(s, v) return s..'\n '..v end)))
vim.print(('%s'):format(vim.iter(rv.parse_errors):fold('', function(s, v)
return s .. '\n ' .. v
end)))
end
err_count = err_count + #rv.parse_errors
end

View File

@ -43,14 +43,14 @@ end
local function validate_commit(commit_message)
-- Return nil if the commit message starts with "fixup" as it signifies it's
-- a work in progress and shouldn't be linted yet.
if vim.startswith(commit_message, "fixup") then
if vim.startswith(commit_message, 'fixup') then
return nil
end
local commit_split = vim.split(commit_message, ":", {plain = true})
local commit_split = vim.split(commit_message, ':', { plain = true })
-- Return nil if the type is vim-patch since most of the normal rules don't
-- apply.
if commit_split[1] == "vim-patch" then
if commit_split[1] == 'vim-patch' then
return nil
end
@ -81,31 +81,33 @@ local function validate_commit(commit_message)
end
-- Check if commit introduces a breaking change.
if vim.endswith(before_colon, "!") then
if vim.endswith(before_colon, '!') then
before_colon = before_colon:sub(1, -2)
end
-- Check if type is correct
local type = vim.split(before_colon, "(", {plain = true})[1]
local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'vim-patch'}
local type = vim.split(before_colon, '(', { plain = true })[1]
local allowed_types =
{ 'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'vim-patch' }
if not vim.tbl_contains(allowed_types, type) then
return string.format(
[[Invalid commit type "%s". Allowed types are:
%s.
If none of these seem appropriate then use "fix"]],
type,
vim.inspect(allowed_types))
vim.inspect(allowed_types)
)
end
-- Check if scope is appropriate
if before_colon:match("%(") then
local scope = vim.trim(commit_message:match("%((.-)%)"))
if before_colon:match('%(') then
local scope = vim.trim(commit_message:match('%((.-)%)'))
if scope == '' then
return [[Scope can't be empty]]
end
if vim.startswith(scope, "nvim_") then
if vim.startswith(scope, 'nvim_') then
return [[Scope should be "api" instead of "nvim_..."]]
end
@ -123,17 +125,17 @@ local function validate_commit(commit_message)
end
-- Check that description doesn't end with a period
if vim.endswith(after_colon, ".") then
if vim.endswith(after_colon, '.') then
return [[Description ends with a period (".").]]
end
-- Check that description starts with a whitespace.
if after_colon:sub(1,1) ~= " " then
if after_colon:sub(1, 1) ~= ' ' then
return [[There should be a whitespace after the colon.]]
end
-- Check that description doesn't start with multiple whitespaces.
if after_colon:sub(1,2) == " " then
if after_colon:sub(1, 2) == ' ' then
return [[There should only be one whitespace after the colon.]]
end
@ -143,7 +145,7 @@ local function validate_commit(commit_message)
end
-- Check that description isn't just whitespaces
if vim.trim(after_colon) == "" then
if vim.trim(after_colon) == '' then
return [[Description shouldn't be empty.]]
end
@ -164,7 +166,7 @@ function M.main(opt)
assert(commits_str)
local commits = {} --- @type string[]
for substring in commits_str:gmatch("%S+") do
for substring in commits_str:gmatch('%S+') do
table.insert(commits, substring)
end
@ -183,14 +185,16 @@ function M.main(opt)
p('\n')
end
p(string.format([[
p(string.format(
[[
Invalid commit message: "%s"
Commit: %s
%s
]],
msg,
commit_id,
invalid_msg))
invalid_msg
))
end
end
end
@ -259,7 +263,7 @@ function M._test()
['feat(:grep/:make)'] = false,
['feat(:grep'] = false,
['feat(:grep/:make'] = false,
['ci: you\'re saying this commit message just goes on and on and on and on and on and on for way too long?'] = false,
["ci: you're saying this commit message just goes on and on and on and on and on and on for way too long?"] = false,
}
local failed = 0
@ -267,14 +271,15 @@ function M._test()
local is_valid = (nil == validate_commit(message))
if is_valid ~= expected then
failed = failed + 1
p(string.format('[ FAIL ]: expected=%s, got=%s\n input: "%s"', expected, is_valid, message))
p(
string.format('[ FAIL ]: expected=%s, got=%s\n input: "%s"', expected, is_valid, message)
)
end
end
if failed > 0 then
os.exit(1)
end
end
--- @class LintcommitOptions

View File

@ -59,9 +59,12 @@ local TAGGED_TYPES = { 'TSNode', 'LanguageTree' }
-- Document these as 'table'
local ALIAS_TYPES = {
'Range', 'Range4', 'Range6', 'TSMetadata',
'Range',
'Range4',
'Range6',
'TSMetadata',
'vim.filetype.add.filetypes',
'vim.filetype.match.args'
'vim.filetype.match.args',
}
local debug_outfile = nil --- @type string?
@ -176,9 +179,15 @@ local function process_magic(line, generics)
local magic_split = vim.split(magic, ' ', { plain = true })
local directive = magic_split[1]
if vim.list_contains({
'cast', 'diagnostic', 'overload', 'meta', 'type'
}, directive) then
if
vim.list_contains({
'cast',
'diagnostic',
'overload',
'meta',
'type',
}, directive)
then
-- Ignore LSP directives
return '// gg:"' .. line .. '"'
end
@ -202,8 +211,7 @@ local function process_magic(line, generics)
if directive == 'param' then
for _, type in ipairs(TYPES) do
magic = magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. ')%)', 'param %1 %2')
magic =
magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', 'param %1 %2')
magic = magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', 'param %1 %2')
end
magic_split = vim.split(magic, ' ', { plain = true })
type_index = 3
@ -245,13 +253,10 @@ local function process_magic(line, generics)
-- surround some types by ()
for _, type in ipairs(TYPES) do
ty = ty
:gsub('^(' .. type .. '|nil):?$', '(%1)')
:gsub('^(' .. type .. '):?$', '(%1)')
ty = ty:gsub('^(' .. type .. '|nil):?$', '(%1)'):gsub('^(' .. type .. '):?$', '(%1)')
end
magic_split[type_index] = ty
end
magic = table.concat(magic_split, ' ')
@ -330,10 +335,7 @@ local function process_function_header(line)
comma = ', '
end
fn = fn:sub(1, paren_start)
.. 'self'
.. comma
.. fn:sub(paren_start + 1)
fn = fn:sub(1, paren_start) .. 'self' .. comma .. fn:sub(paren_start + 1)
end
if line:match('local') then
@ -418,7 +420,7 @@ local TApp = {
timestamp = os.date('%c %Z', os.time()),
name = 'Lua2DoX',
version = '0.2 20130128',
copyright = 'Copyright (c) Simon Dales 2012-13'
copyright = 'Copyright (c) Simon Dales 2012-13',
}
setmetatable(TApp, { __index = TApp })
@ -452,7 +454,10 @@ else -- It's a filter.
if arg[2] == '--outdir' then
local outdir = arg[3]
if type(outdir) ~= 'string' or (0 ~= vim.fn.filereadable(outdir) and 0 == vim.fn.isdirectory(outdir)) then
if
type(outdir) ~= 'string'
or (0 ~= vim.fn.filereadable(outdir) and 0 == vim.fn.isdirectory(outdir))
then
error(('invalid --outdir: "%s"'):format(tostring(outdir)))
end
vim.fn.mkdir(outdir, 'p')

View File

@ -16,7 +16,7 @@ local function systemlist(...)
end
local function vimpatch_sh_list_numbers()
return systemlist( { { 'bash', '-c', 'scripts/vim-patch.sh -M', } } )
return systemlist({ { 'bash', '-c', 'scripts/vim-patch.sh -M' } })
end
-- Generates the lines to be inserted into the src/version.c