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_type = "Spaces"
indent_width = 2 indent_width = 2
quote_style = "AutoPreferSingle" quote_style = "AutoPreferSingle"
call_parentheses = "Always" call_parentheses = "Input"

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
-- Generator for various vimdoc and Lua type files -- Generator for various vimdoc and Lua type files
local DEP_API_METADATA = 'build/api_metadata.mpack' local DEP_API_METADATA = 'build/api_metadata.mpack'
local DEP_API_DOC = 'runtime/doc/api.mpack' local DEP_API_DOC = 'runtime/doc/api.mpack'
--- @class vim.api.metadata --- @class vim.api.metadata
--- @field name string --- @field name string
@ -302,7 +302,7 @@ local function get_api_keysets_meta()
for _, k in ipairs(keysets) do for _, k in ipairs(keysets) do
local params = {} local params = {}
for _, key in ipairs(k.keys) do for _, key in ipairs(k.keys) do
table.insert(params, {key..'?', api_type(k.types[key] or 'any')}) table.insert(params, { key .. '?', api_type(k.types[key] or 'any') })
end end
ret[k.name] = { ret[k.name] = {
signature = 'NA', signature = 'NA',
@ -396,7 +396,7 @@ local function render_sig_and_tag(name, fun, write)
local tag = table.concat(tags, ' ') local tag = table.concat(tags, ' ')
local siglen = #fun.signature local siglen = #fun.signature
local conceal_offset = 2*(#tags - 1) local conceal_offset = 2 * (#tags - 1)
local tag_pad_len = math.max(1, 80 - #tag + conceal_offset) local tag_pad_len = math.max(1, 80 - #tag + conceal_offset)
if siglen + #tag > 80 then if siglen + #tag > 80 then
@ -473,7 +473,7 @@ local function render_option_default(d, vimdoc)
end end
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 dt = d.meta
end end
@ -481,22 +481,22 @@ local function render_option_default(d, vimdoc)
if not vimdoc then if not vimdoc then
v = vim.inspect(dt) --[[@as string]] v = vim.inspect(dt) --[[@as string]]
else else
v = type(dt) == 'string' and '"'..dt..'"' or tostring(dt) v = type(dt) == 'string' and '"' .. dt .. '"' or tostring(dt)
end end
--- @type table<string, string|false> --- @type table<string, string|false>
local envvars = { local envvars = {
TMPDIR = false, TMPDIR = false,
VIMRUNTIME = false, VIMRUNTIME = false,
XDG_CONFIG_HOME = vim.env.HOME..'/.local/config', XDG_CONFIG_HOME = vim.env.HOME .. '/.local/config',
XDG_DATA_HOME = vim.env.HOME..'/.local/share', XDG_DATA_HOME = vim.env.HOME .. '/.local/share',
XDG_STATE_HOME = vim.env.HOME..'/.local/state', XDG_STATE_HOME = vim.env.HOME .. '/.local/state',
} }
for name, default in pairs(envvars) do for name, default in pairs(envvars) do
local value = vim.env[name] or default local value = vim.env[name] or default
if value then if value then
v = v:gsub(vim.pesc(value), '$'..name) v = v:gsub(vim.pesc(value), '$' .. name)
end end
end end
@ -509,26 +509,26 @@ end
local function render_option_meta(_f, opt, write) local function render_option_meta(_f, opt, write)
write('') write('')
for _, l in ipairs(split(norm_text(opt.desc))) do for _, l in ipairs(split(norm_text(opt.desc))) do
write('--- '..l) write('--- ' .. l)
end end
write('--- @type '..OPTION_TYPES[opt.type]) write('--- @type ' .. OPTION_TYPES[opt.type])
write('vim.o.'..opt.full_name..' = '..render_option_default(opt.defaults)) write('vim.o.' .. opt.full_name .. ' = ' .. render_option_default(opt.defaults))
if opt.abbreviation then if opt.abbreviation then
write('vim.o.'..opt.abbreviation..' = vim.o.'..opt.full_name) write('vim.o.' .. opt.abbreviation .. ' = vim.o.' .. opt.full_name)
end end
for _, s in pairs { for _, s in pairs {
{'wo', 'window'}, { 'wo', 'window' },
{'bo', 'buffer'}, { 'bo', 'buffer' },
{'go', 'global'}, { 'go', 'global' },
} do } do
local id, scope = s[1], s[2] local id, scope = s[1], s[2]
if vim.list_contains(opt.scope, scope) or (id == 'go' and #opt.scope > 1) then if vim.list_contains(opt.scope, scope) or (id == 'go' and #opt.scope > 1) then
local pfx = 'vim.'..id..'.' local pfx = 'vim.' .. id .. '.'
write(pfx..opt.full_name..' = vim.o.'..opt.full_name) write(pfx .. opt.full_name .. ' = vim.o.' .. opt.full_name)
if opt.abbreviation then if opt.abbreviation then
write(pfx..opt.abbreviation..' = '..pfx..opt.full_name) write(pfx .. opt.abbreviation .. ' = ' .. pfx .. opt.full_name)
end end
end end
end end
@ -541,14 +541,14 @@ local function scope_to_doc(s)
global = 'global', global = 'global',
buffer = 'local to buffer', buffer = 'local to buffer',
window = 'local to window', window = 'local to window',
tab = 'local to tab page' tab = 'local to tab page',
} }
if #s == 1 then if #s == 1 then
return m[s[1]] return m[s[1]]
end end
assert(s[1] == 'global') assert(s[1] == 'global')
return 'global or '..m[s[2]]..' |global-local|' return 'global or ' .. m[s[2]] .. ' |global-local|'
end end
-- @param o vim.option_meta -- @param o vim.option_meta
@ -602,23 +602,23 @@ local function build_option_tags(opt)
--- @type string[] --- @type string[]
local tags = { opt.full_name } local tags = { opt.full_name }
tags[#tags+1] = opt.abbreviation tags[#tags + 1] = opt.abbreviation
if opt.type == 'bool' then if opt.type == 'bool' then
for i = 1, #tags do for i = 1, #tags do
tags[#tags+1] = 'no'..tags[i] tags[#tags + 1] = 'no' .. tags[i]
end end
end end
for i, t in ipairs(tags) do for i, t in ipairs(tags) do
tags[i] = "'"..t.."'" tags[i] = "'" .. t .. "'"
end end
for _, t in ipairs(opt.tags or {}) do for _, t in ipairs(opt.tags or {}) do
tags[#tags+1] = t tags[#tags + 1] = t
end end
for i, t in ipairs(tags) do for i, t in ipairs(tags) do
tags[i] = "*"..t.."*" tags[i] = '*' .. t .. '*'
end end
return tags return tags
@ -630,10 +630,10 @@ end
local function render_option_doc(_f, opt, write) local function render_option_doc(_f, opt, write)
local tags = build_option_tags(opt) local tags = build_option_tags(opt)
local tag_str = table.concat(tags, ' ') local tag_str = table.concat(tags, ' ')
local conceal_offset = 2*(#tags - 1) local conceal_offset = 2 * (#tags - 1)
local tag_pad = string.rep('\t', math.ceil((64 - #tag_str + conceal_offset) / 8)) local tag_pad = string.rep('\t', math.ceil((64 - #tag_str + conceal_offset) / 8))
-- local pad = string.rep(' ', 80 - #tag_str + conceal_offset) -- local pad = string.rep(' ', 80 - #tag_str + conceal_offset)
write(tag_pad..tag_str) write(tag_pad .. tag_str)
local name_str --- @type string local name_str --- @type string
if opt.abbreviation then if opt.abbreviation then
@ -649,19 +649,19 @@ local function render_option_doc(_f, opt, write)
if opt.defaults.doc then if opt.defaults.doc then
local deflen = #string.format('%s%s%s (', name_str, pad, otype) local deflen = #string.format('%s%s%s (', name_str, pad, otype)
--- @type string --- @type string
v = v:gsub('\n', '\n'..string.rep(' ', deflen - 2)) v = v:gsub('\n', '\n' .. string.rep(' ', deflen - 2))
end end
write(string.format('%s%s%s\t(default %s)', name_str, pad, otype, v)) write(string.format('%s%s%s\t(default %s)', name_str, pad, otype, v))
else else
write(string.format('%s\t%s', name_str, otype)) write(string.format('%s\t%s', name_str, otype))
end end
write('\t\t\t'..scope_to_doc(opt.scope)..scope_more_doc(opt)) write('\t\t\t' .. scope_to_doc(opt.scope) .. scope_more_doc(opt))
for _, l in ipairs(split(opt.desc)) do for _, l in ipairs(split(opt.desc)) do
if l == '<' or l:match('^<%s') then if l == '<' or l:match('^<%s') then
write(l) write(l)
else else
write('\t'..l:gsub('\\<', '<')) write('\t' .. l:gsub('\\<', '<'))
end end
end end
end end
@ -751,21 +751,21 @@ local CONFIG = {
header = { '' }, header = { '' },
from = 'A jump table for the options with a short description can be found at |Q_op|.', from = 'A jump table for the options with a short description can be found at |Q_op|.',
footer = { footer = {
' vim:tw=78:ts=8:noet:ft=help:norl:' ' vim:tw=78:ts=8:noet:ft=help:norl:',
}, },
funcs = get_option_meta, funcs = get_option_meta,
render = render_option_doc, render = render_option_doc,
} },
} }
--- @param elem nvim.gen_eval_files.elem --- @param elem nvim.gen_eval_files.elem
local function render(elem) local function render(elem)
print('Rendering '..elem.path) print('Rendering ' .. elem.path)
local from_lines = {} --- @type string[] local from_lines = {} --- @type string[]
local from = elem.from local from = elem.from
if from then if from then
for line in io.lines(elem.path) do for line in io.lines(elem.path) do
from_lines[#from_lines+1] = line from_lines[#from_lines + 1] = line
if line:match(from) then if line:match(from) then
break break
end end

View File

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

View File

@ -60,26 +60,26 @@ local new_layout = {
-- TODO: These known invalid |links| require an update to the relevant docs. -- TODO: These known invalid |links| require an update to the relevant docs.
local exclude_invalid = { local exclude_invalid = {
["'string'"] = "eval.txt", ["'string'"] = 'eval.txt',
Query = 'treesitter.txt', Query = 'treesitter.txt',
matchit = 'vim_diff.txt', matchit = 'vim_diff.txt',
["set!"] = "treesitter.txt", ['set!'] = 'treesitter.txt',
} }
-- False-positive "invalid URLs". -- False-positive "invalid URLs".
local exclude_invalid_urls = { local exclude_invalid_urls = {
["http://"] = "usr_23.txt", ['http://'] = 'usr_23.txt',
["http://."] = "usr_23.txt", ['http://.'] = 'usr_23.txt',
["http://aspell.net/man-html/Affix-Compression.html"] = "spell.txt", ['http://aspell.net/man-html/Affix-Compression.html'] = 'spell.txt',
["http://aspell.net/man-html/Phonetic-Code.html"] = "spell.txt", ['http://aspell.net/man-html/Phonetic-Code.html'] = 'spell.txt',
["http://canna.sourceforge.jp/"] = "mbyte.txt", ['http://canna.sourceforge.jp/'] = 'mbyte.txt',
["http://gnuada.sourceforge.net"] = "ft_ada.txt", ['http://gnuada.sourceforge.net'] = 'ft_ada.txt',
["http://lua-users.org/wiki/StringLibraryTutorial"] = "lua.txt", ['http://lua-users.org/wiki/StringLibraryTutorial'] = 'lua.txt',
["http://michael.toren.net/code/"] = "pi_tar.txt", ['http://michael.toren.net/code/'] = 'pi_tar.txt',
["http://papp.plan9.de"] = "syntax.txt", ['http://papp.plan9.de'] = 'syntax.txt',
["http://wiki.services.openoffice.org/wiki/Dictionaries"] = "spell.txt", ['http://wiki.services.openoffice.org/wiki/Dictionaries'] = 'spell.txt',
["http://www.adapower.com"] = "ft_ada.txt", ['http://www.adapower.com'] = 'ft_ada.txt',
["http://www.jclark.com/"] = "quickfix.txt", ['http://www.jclark.com/'] = 'quickfix.txt',
} }
-- Deprecated, brain-damaged files that I don't care about. -- Deprecated, brain-damaged files that I don't care about.
@ -98,19 +98,18 @@ local function tofile(fname, text)
end end
local function html_esc(s) local function html_esc(s)
return s:gsub( return s:gsub('&', '&amp;'):gsub('<', '&lt;'):gsub('>', '&gt;')
'&', '&amp;'):gsub(
'<', '&lt;'):gsub(
'>', '&gt;')
end end
local function url_encode(s) local function url_encode(s)
-- Credit: tpope / vim-unimpaired -- Credit: tpope / vim-unimpaired
-- NOTE: these chars intentionally *not* escaped: ' ( ) -- 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()'_.~-]]=], [=[[^A-Za-z0-9()'_.~-]]=],
[=[\="%".printf("%02X",char2nr(submatch(0)))]=], [=[\="%".printf("%02X",char2nr(submatch(0)))]=],
'g') 'g'
)
end end
local function expandtabs(s) local function expandtabs(s)
@ -131,7 +130,7 @@ local function to_heading_tag(text)
end end
local function basename_noext(f) local function basename_noext(f)
return vim.fs.basename(f:gsub('%.txt', '')) return vim.fs.basename(f:gsub('%.txt', ''))
end end
local function is_blank(s) local function is_blank(s)
@ -151,7 +150,7 @@ local function fix_url(url)
local removed_chars = '' local removed_chars = ''
local fixed_url = url local fixed_url = url
-- Remove up to one of each char from end of the URL, in this order. -- 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 if fixed_url:sub(-1) == c then
removed_chars = c .. removed_chars removed_chars = c .. removed_chars
fixed_url = fixed_url:sub(1, -2) 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. --- Checks if a given line is a "noise" line that doesn't look good in HTML form.
local function is_noise(line, noise_lines) local function is_noise(line, noise_lines)
if ( if
-- First line is always noise. -- First line is always noise.
(noise_lines ~= nil and vim.tbl_count(noise_lines) == 0) (noise_lines ~= nil and vim.tbl_count(noise_lines) == 0)
or line:find('Type .*gO.* to see the table of contents') 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?%:.*ft=help')
or line:find('^%s*vim?%:.*filetype=help') or line:find('^%s*vim?%:.*filetype=help')
or line:find('[*>]local%-additions[*<]') or line:find('[*>]local%-additions[*<]')
) then then
-- table.insert(stats.noise_lines, getbuflinestr(root, opt.buf, 0)) -- table.insert(stats.noise_lines, getbuflinestr(root, opt.buf, 0))
table.insert(noise_lines or {}, line) table.insert(noise_lines or {}, line)
return true return true
@ -188,28 +187,32 @@ 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 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 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 = (
..vim.fs.basename(fname) 'https://github.com/neovim/tree-sitter-vimdoc/issues/new?labels=bug&title=parse+error%3A+'
..'+&body=Found+%60tree-sitter-vimdoc%60+parse+error+at%3A+' .. vim.fs.basename(fname)
..this_url .. '+&body=Found+%60tree-sitter-vimdoc%60+parse+error+at%3A+'
..'%0D%0DContext%3A%0D%0D%60%60%60%0D' .. this_url
..url_encode(sample_text) .. '%0D%0DContext%3A%0D%0D%60%60%60%0D'
..'%0D%60%60%60') .. url_encode(sample_text)
.. '%0D%60%60%60'
)
return bug_url return bug_url
end 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 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 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 = (
..vim.fs.basename(fname) 'https://github.com/neovim/neovim/issues/new?labels=bug&title=user+docs+HTML%3A+'
..'+&body=%60gen_help_html.lua%60+problem+at%3A+' .. vim.fs.basename(fname)
..this_url .. '+&body=%60gen_help_html.lua%60+problem+at%3A+'
..'%0D' .. this_url
..(token_name and '+unhandled+token%3A+%60'..token_name..'%60' or '') .. '%0D'
..'%0DContext%3A%0D%0D%60%60%60%0D' .. (token_name and '+unhandled+token%3A+%60' .. token_name .. '%60' or '')
..url_encode(sample_text) .. '%0DContext%3A%0D%0D%60%60%60%0D'
..'%0D%60%60%60') .. url_encode(sample_text)
.. '%0D%60%60%60'
)
return bug_url return bug_url
end end
@ -274,9 +277,11 @@ end
local function get_tagname(node, bufnr) local function get_tagname(node, bufnr)
local text = vim.treesitter.get_node_text(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')
local helpfile = vim.fs.basename(tagmap[tag]) or nil -- "api.txt" and ("'%s'"):format(text)
local helppage = get_helppage(helpfile) -- "api.html" or text
local helpfile = vim.fs.basename(tagmap[tag]) or nil -- "api.txt"
local helppage = get_helppage(helpfile) -- "api.html"
return helppage, tag return helppage, tag
end end
@ -295,11 +300,9 @@ local function ignore_parse_error(fname, s)
if ignore_errors[vim.fs.basename(fname)] then if ignore_errors[vim.fs.basename(fname)] then
return true return true
end end
return ( -- Ignore parse errors for unclosed tag.
-- Ignore parse errors for unclosed tag. -- This is common in vimdocs and is treated as plaintext by :help.
-- This is common in vimdocs and is treated as plaintext by :help. return s:find("^[`'|*]")
s:find("^[`'|*]")
)
end end
local function has_ancestor(node, ancestor_name) local function has_ancestor(node, ancestor_name)
@ -377,10 +380,11 @@ local function visit_validate(root, level, lang_tree, opt, stats)
-- Flatten the sample text to a single, truncated line. -- Flatten the sample text to a single, truncated line.
sample_text = vim.trim(sample_text):gsub('[\t\n]', ' '):sub(1, 80) sample_text = vim.trim(sample_text):gsub('[\t\n]', ' '):sub(1, 80)
table.insert(stats.parse_errors, sample_text) table.insert(stats.parse_errors, sample_text)
elseif (node_name == 'word' or node_name == 'uppercase_name') elseif
and (not vim.tbl_contains({'codespan', 'taglink', 'tag'}, parent)) (node_name == 'word' or node_name == 'uppercase_name')
and (not vim.tbl_contains({ 'codespan', 'taglink', 'tag' }, parent))
then then
local text_nopunct = vim.fn.trim(text, '.,', 0) -- Ignore some punctuation. local text_nopunct = vim.fn.trim(text, '.,', 0) -- Ignore some punctuation.
if spell_dict[text_nopunct] then if spell_dict[text_nopunct] then
invalid_spelling[text_nopunct] = invalid_spelling[text_nopunct] or {} invalid_spelling[text_nopunct] = invalid_spelling[text_nopunct] or {}
invalid_spelling[text_nopunct][vim.fs.basename(opt.fname)] = node_text(root:parent()) invalid_spelling[text_nopunct][vim.fs.basename(opt.fname)] = node_text(root:parent())
@ -399,7 +403,7 @@ local function fix_tab_after_conceal(text, next_node_text)
-- Vim tabs take into account the two concealed characters even though they -- Vim tabs take into account the two concealed characters even though they
-- are invisible, so we need to add back in the two spaces if this is -- are invisible, so we need to add back in the two spaces if this is
-- followed by a tab to make the tab alignment to match Vim's behavior. -- followed by a tab to make the tab alignment to match Vim's behavior.
if string.sub(next_node_text,1,1) == '\t' then if string.sub(next_node_text, 1, 1) == '\t' then
text = text .. ' ' text = text .. ' '
end end
return text return text
@ -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 local node_name = (root.named and root:named()) and root:type() or nil
-- Previous sibling kind (string). -- 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). -- 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). -- Parent kind (string).
local parent = root:parent() and root:parent():type() or nil local parent = root:parent() and root:parent():type() or nil
local text = '' local text = ''
@ -450,7 +460,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
trimmed = trim(text) trimmed = trim(text)
end end
if node_name == 'help_file' then -- root node if node_name == 'help_file' then -- root node
return text return text
elseif node_name == 'url' then elseif node_name == 'url' then
local fixed_url, removed_chars = fix_url(trimmed) local fixed_url, removed_chars = fix_url(trimmed)
@ -459,18 +469,22 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
return text return text
elseif node_name == 'h1' or node_name == 'h2' or node_name == 'h3' then elseif node_name == 'h1' or node_name == 'h2' or node_name == 'h3' then
if is_noise(text, stats.noise_lines) then if is_noise(text, stats.noise_lines) then
return '' -- Discard common "noise" lines. return '' -- Discard common "noise" lines.
end end
-- Remove "===" and tags from ToC text. -- Remove "===" and tags from ToC text.
local hname = (node_text():gsub('%-%-%-%-+', ''):gsub('%=%=%=%=+', ''):gsub('%*.*%*', '')) local hname = (node_text():gsub('%-%-%-%-+', ''):gsub('%=%=%=%=+', ''):gsub('%*.*%*', ''))
-- Use the first *tag* node as the heading anchor, if any. -- Use the first *tag* node as the heading anchor, if any.
local tagnode = first(root, 'tag') local tagnode = first(root, 'tag')
-- Use the *tag* as the heading anchor id, if possible. -- 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 if node_name == 'h1' or #headings == 0 then
table.insert(headings, { name = hname, subheadings = {}, tag = tagname }) table.insert(headings, { name = hname, subheadings = {}, tag = tagname })
else else
table.insert(headings[#headings].subheadings, { name = hname, subheadings = {}, tag = tagname }) table.insert(
headings[#headings].subheadings,
{ name = hname, subheadings = {}, tag = tagname }
)
end end
local el = node_name == 'h1' and 'h2' or 'h3' local el = node_name == 'h1' and 'h2' or 'h3'
return ('<%s id="%s" class="help-heading">%s</%s>\n'):format(el, tagname, text, el) 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 end
return string.format('<div class="help-para">\n%s\n</div>\n', text) return string.format('<div class="help-para">\n%s\n</div>\n', text)
elseif node_name == 'line' then elseif node_name == 'line' then
if (parent ~= 'codeblock' or parent ~= 'code') and (is_blank(text) or is_noise(text, stats.noise_lines)) then if
return '' -- Discard common "noise" lines. (parent ~= 'codeblock' or parent ~= 'code')
and (is_blank(text) or is_noise(text, stats.noise_lines))
then
return '' -- Discard common "noise" lines.
end end
-- XXX: Avoid newlines (too much whitespace) after block elements in old (preformatted) layout. -- 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') return string.format('%s%s', div and trim(text) or text, div and '' or '\n')
elseif node_name == 'line_li' then elseif node_name == 'line_li' then
local sib = root:prev_sibling() local sib = root:prev_sibling()
@ -520,12 +539,17 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
if ignored then if ignored then
return text return text
end 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 if opt.old and node_name == 'taglink' then
s = fix_tab_after_conceal(s, node_text(root:next_sibling())) s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end end
return s return s
elseif vim.list_contains({'codespan', 'keycode'}, node_name) then elseif vim.list_contains({ 'codespan', 'keycode' }, node_name) then
if root:has_error() then if root:has_error() then
return text return text
end end
@ -541,24 +565,28 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
elseif node_name == 'language' then elseif node_name == 'language' then
language = node_text(root) language = node_text(root)
return '' return ''
elseif node_name == 'code' then -- Highlighted codeblock (child). elseif node_name == 'code' then -- Highlighted codeblock (child).
if is_blank(text) then if is_blank(text) then
return '' return ''
end end
local code local code
if language then 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 language = nil
else else
code = ('<pre>%s</pre>'):format(trim(trim_indent(text), 2)) code = ('<pre>%s</pre>'):format(trim(trim_indent(text), 2))
end end
return code return code
elseif node_name == 'tag' then -- anchor elseif node_name == 'tag' then -- anchor
if root:has_error() then if root:has_error() then
return text return text
end end
local in_heading = vim.list_contains({'h1', 'h2', 'h3'}, parent) 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) local tagname = node_text(root:child(1), false)
if vim.tbl_count(stats.first_tags) < 2 then if vim.tbl_count(stats.first_tags) < 2 then
-- Force the first 2 tags in the doc to be anchored at the main heading. -- 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 end
local el = in_heading and 'span' or 'code' local el = in_heading and 'span' or 'code'
local encoded_tagname = url_encode(tagname) 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 if opt.old then
s = fix_tab_after_conceal(s, node_text(root:next_sibling())) s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end end
if in_heading and prev ~= 'tag' then if in_heading and prev ~= 'tag' then
-- Don't set "id", let the heading use the tag as its "id" (used by search engines). -- 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. -- Start the <span> container for tags in a heading.
-- This makes "justify-content:space-between" right-align the tags. -- This makes "justify-content:space-between" right-align the tags.
-- <h2>foo bar<span>tag1 tag2</span></h2> -- <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!]' local sample_text = level > 0 and getbuflinestr(root, opt.buf, 3) or '[top level!]'
table.insert(stats.parse_errors, sample_text) table.insert(stats.parse_errors, sample_text)
return ('<a class="parse-error" target="_blank" title="Report bug... (parse error)" href="%s">%s</a>'):format( 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),
else -- Unknown token. trimmed
)
else -- Unknown token.
local sample_text = level > 0 and getbuflinestr(root, opt.buf, 3) or '[top level!]' 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( 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
end end
@ -605,9 +654,11 @@ local function get_helpfiles(include)
local dir = './build/runtime/doc' local dir = './build/runtime/doc'
local rv = {} local rv = {}
for f, type in vim.fs.dir(dir) do for f, type in vim.fs.dir(dir) do
if (vim.endswith(f, '.txt') if
and type == 'file' vim.endswith(f, '.txt')
and (not include or vim.list_contains(include, f))) then and type == 'file'
and (not include or vim.list_contains(include, f))
then
local fullpath = vim.fn.fnamemodify(('%s/%s'):format(dir, f), ':p') local fullpath = vim.fn.fnamemodify(('%s/%s'):format(dir, f), ':p')
table.insert(rv, fullpath) table.insert(rv, fullpath)
end end
@ -633,7 +684,7 @@ 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() local function ensure_runtimepath()
if not vim.o.runtimepath:find('build/lib/nvim/') then if not vim.o.runtimepath:find('build/lib/nvim/') then
vim.cmd[[set runtimepath^=./build/lib/nvim/]] vim.cmd [[set runtimepath^=./build/lib/nvim/]]
end end
end end
@ -645,11 +696,11 @@ end
local function parse_buf(fname, parser_path) local function parse_buf(fname, parser_path)
local buf local buf
if type(fname) == 'string' then if type(fname) == 'string' then
vim.cmd('split '..vim.fn.fnameescape(fname)) -- Filename. vim.cmd('split ' .. vim.fn.fnameescape(fname)) -- Filename.
buf = vim.api.nvim_get_current_buf() buf = vim.api.nvim_get_current_buf()
else else
buf = fname buf = fname
vim.cmd('sbuffer '..tostring(fname)) -- Buffer number. vim.cmd('sbuffer ' .. tostring(fname)) -- Buffer number.
end end
if parser_path then if parser_path then
vim.treesitter.language.add('vimdoc', { path = parser_path }) vim.treesitter.language.add('vimdoc', { path = parser_path })
@ -671,7 +722,7 @@ local function validate_one(fname, parser_path)
} }
local lang_tree, buf = parse_buf(fname, parser_path) local lang_tree, buf = parse_buf(fname, parser_path)
for _, tree in ipairs(lang_tree:trees()) do 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 end
lang_tree:destroy() lang_tree:destroy()
vim.cmd.close() vim.cmd.close()
@ -690,10 +741,10 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
local stats = { local stats = {
noise_lines = {}, noise_lines = {},
parse_errors = {}, parse_errors = {},
first_tags = {}, -- Track the first few tags in doc. first_tags = {}, -- Track the first few tags in doc.
} }
local lang_tree, buf = parse_buf(fname, parser_path) local lang_tree, buf = parse_buf(fname, parser_path)
local headings = {} -- Headings (for ToC). 2-dimensional: h1 contains h2/h3. local headings = {} -- Headings (for ToC). 2-dimensional: h1 contains h2/h3.
local title = to_titlecase(basename_noext(fname)) local title = to_titlecase(basename_noext(fname))
local html = ([[ local html = ([[
@ -777,9 +828,17 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
local main = '' local main = ''
for _, tree in ipairs(lang_tree:trees()) do for _, tree in ipairs(lang_tree:trees()) do
main = main .. (visit_node(tree:root(), 0, tree, headings, main = main
{ buf = buf, old = old, fname = fname, to_fname = to_fname, indent = 1, }, .. (
stats)) visit_node(
tree:root(),
0,
tree,
headings,
{ buf = buf, old = old, fname = fname, to_fname = to_fname, indent = 1 },
stats
)
)
end end
main = ([[ main = ([[
@ -809,7 +868,14 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
<hr/> <hr/>
%s %s
</div> </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 = [[ local toc = [[
<div class="col-narrow toc"> <div class="col-narrow toc">
@ -819,13 +885,16 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
<hr/> <hr/>
]] ]]
local n = 0 -- Count of all headings + subheadings. 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 for _, h1 in ipairs(headings) do
toc = toc .. ('<div class="help-toc-h1"><a href="#%s">%s</a>\n'):format(h1.tag, h1.name) 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. if n < 30 or #headings < 10 then -- Show subheadings only if there aren't too many.
for _, h2 in ipairs(h1.subheadings) do 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
end end
toc = toc .. '</div>' toc = toc .. '</div>'
@ -859,11 +928,16 @@ local function gen_one(fname, to_fname, old, commit, parser_path)
</footer> </footer>
]]):format( ]]):format(
os.date('%Y-%m-%d %H:%M'), commit, commit:sub(1, 7), #stats.parse_errors, bug_link, os.date('%Y-%m-%d %H:%M'),
html_esc(table.concat(stats.noise_lines, '\n')), #stats.noise_lines) 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 = ('%s%s%s</div>\n%s</body>\n</html>\n'):format(html, main, toc, footer)
html, main, toc, footer)
vim.cmd('q!') vim.cmd('q!')
lang_tree:destroy() lang_tree:destroy()
return html, stats return html, stats
@ -1038,9 +1112,15 @@ function M._test()
helpfiles = get_helpfiles() helpfiles = get_helpfiles()
local function ok(cond, expected, actual) 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 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 else
return assert(cond) return assert(cond)
end end
@ -1050,7 +1130,11 @@ function M._test()
end end
ok(vim.tbl_count(tagmap) > 3000, '>3000', vim.tbl_count(tagmap)) 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(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([[vim:tw=78:isk=!-~,^*,^\|,^\":ts=8:noet:ft=help:norl:]]))
ok(is_noise([[ NVIM REFERENCE MANUAL by Thiago de Arruda ]])) ok(is_noise([[ NVIM REFERENCE MANUAL by Thiago de Arruda ]]))
@ -1060,7 +1144,10 @@ function M._test()
eq(1, get_indent(' a')) eq(1, get_indent(' a'))
eq(2, get_indent(' a\n b\n c\n')) 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(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).') local fixed_url, removed_chars = fix_url('https://example.com).')
eq('https://example.com', fixed_url) eq('https://example.com', fixed_url)
@ -1093,12 +1180,24 @@ end
--- ---
--- @returns info dict --- @returns info dict
function M.gen(help_dir, to_dir, include, commit, parser_path) function M.gen(help_dir, to_dir, include, commit, parser_path)
vim.validate{ vim.validate {
help_dir={help_dir, function(d) return vim.fn.isdirectory(vim.fn.expand(d)) == 1 end, 'valid directory'}, help_dir = {
to_dir={to_dir, 's'}, help_dir,
include={include, 't', true}, function(d)
commit={commit, 's', true}, return vim.fn.isdirectory(vim.fn.expand(d)) == 1
parser_path={parser_path, function(f) return f == nil or vim.fn.filereadable(vim.fn.expand(f)) == 1 end, 'valid vimdoc.{so,dll} filepath'}, 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 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 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) local html, stats = gen_one(f, to_fname, not new_layout[helpfile], commit or '?', parser_path)
tofile(to_fname, html) 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 err_count = err_count + #stats.parse_errors
end end
print(('generated %d html pages'):format(#helpfiles)) print(('generated %d html pages'):format(#helpfiles))
@ -1139,10 +1244,22 @@ end
-- --
-- @returns results dict -- @returns results dict
function M.validate(help_dir, include, parser_path) function M.validate(help_dir, include, parser_path)
vim.validate{ vim.validate {
help_dir={help_dir, function(d) return vim.fn.isdirectory(vim.fn.expand(d)) == 1 end, 'valid directory'}, help_dir = {
include={include, 't', true}, help_dir,
parser_path={parser_path, function(f) return f == nil or vim.fn.filereadable(vim.fn.expand(f)) == 1 end, 'valid vimdoc.{so,dll} filepath'}, 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',
},
} }
local err_count = 0 local err_count = 0
local files_to_errors = {} 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)) print(('validated (%-4s errors): %s'):format(#rv.parse_errors, helpfile))
if #rv.parse_errors > 0 then if #rv.parse_errors > 0 then
files_to_errors[helpfile] = rv.parse_errors 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 end
err_count = err_count + #rv.parse_errors err_count = err_count + #rv.parse_errors
end end

View File

@ -16,7 +16,7 @@ local _trace = false
-- Print message -- Print message
local function p(s) local function p(s)
vim.cmd('set verbose=1') vim.cmd('set verbose=1')
vim.api.nvim_echo({{s, ''}}, false, {}) vim.api.nvim_echo({ { s, '' } }, false, {})
vim.cmd('set verbose=0') vim.cmd('set verbose=0')
end end
@ -25,7 +25,7 @@ end
-- Prints `cmd` if `trace` is enabled. -- Prints `cmd` if `trace` is enabled.
local function run(cmd, or_die) local function run(cmd, or_die)
if _trace then if _trace then
p('run: '..vim.inspect(cmd)) p('run: ' .. vim.inspect(cmd))
end end
local rv = vim.trim(vim.fn.system(cmd)) or '' local rv = vim.trim(vim.fn.system(cmd)) or ''
if vim.v.shell_error ~= 0 then if vim.v.shell_error ~= 0 then
@ -43,14 +43,14 @@ end
local function validate_commit(commit_message) local function validate_commit(commit_message)
-- Return nil if the commit message starts with "fixup" as it signifies it's -- Return nil if the commit message starts with "fixup" as it signifies it's
-- a work in progress and shouldn't be linted yet. -- 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 return nil
end 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 -- Return nil if the type is vim-patch since most of the normal rules don't
-- apply. -- apply.
if commit_split[1] == "vim-patch" then if commit_split[1] == 'vim-patch' then
return nil return nil
end end
@ -81,32 +81,34 @@ local function validate_commit(commit_message)
end end
-- Check if commit introduces a breaking change. -- 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) before_colon = before_colon:sub(1, -2)
end end
-- Check if type is correct -- Check if type is correct
local type = vim.split(before_colon, "(", {plain = true})[1] local type = vim.split(before_colon, '(', { plain = true })[1]
local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'vim-patch'} local allowed_types =
{ 'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'vim-patch' }
if not vim.tbl_contains(allowed_types, type) then if not vim.tbl_contains(allowed_types, type) then
return string.format( return string.format(
[[Invalid commit type "%s". Allowed types are: [[Invalid commit type "%s". Allowed types are:
%s. %s.
If none of these seem appropriate then use "fix"]], If none of these seem appropriate then use "fix"]],
type, type,
vim.inspect(allowed_types)) vim.inspect(allowed_types)
)
end end
-- Check if scope is appropriate -- Check if scope is appropriate
if before_colon:match("%(") then if before_colon:match('%(') then
local scope = vim.trim(commit_message:match("%((.-)%)")) local scope = vim.trim(commit_message:match('%((.-)%)'))
if scope == '' then if scope == '' then
return [[Scope can't be empty]] return [[Scope can't be empty]]
end end
if vim.startswith(scope, "nvim_") then if vim.startswith(scope, 'nvim_') then
return [[Scope should be "api" instead of "nvim_..."]] return [[Scope should be "api" instead of "nvim_..."]]
end end
local alternative_scope = { local alternative_scope = {
@ -123,17 +125,17 @@ local function validate_commit(commit_message)
end end
-- Check that description doesn't end with a period -- 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 (".").]] return [[Description ends with a period (".").]]
end end
-- Check that description starts with a whitespace. -- 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.]] return [[There should be a whitespace after the colon.]]
end end
-- Check that description doesn't start with multiple whitespaces. -- 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.]] return [[There should only be one whitespace after the colon.]]
end end
@ -143,7 +145,7 @@ local function validate_commit(commit_message)
end end
-- Check that description isn't just whitespaces -- 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.]] return [[Description shouldn't be empty.]]
end end
@ -154,25 +156,25 @@ end
function M.main(opt) function M.main(opt)
_trace = not opt or not not opt.trace _trace = not opt or not not opt.trace
local branch = run({'git', 'rev-parse', '--abbrev-ref', 'HEAD'}, true) local branch = run({ 'git', 'rev-parse', '--abbrev-ref', 'HEAD' }, true)
-- TODO(justinmk): check $GITHUB_REF -- TODO(justinmk): check $GITHUB_REF
local ancestor = run({'git', 'merge-base', 'origin/master', branch}) local ancestor = run({ 'git', 'merge-base', 'origin/master', branch })
if not ancestor then if not ancestor then
ancestor = run({'git', 'merge-base', 'upstream/master', branch}) ancestor = run({ 'git', 'merge-base', 'upstream/master', branch })
end end
local commits_str = run({'git', 'rev-list', ancestor..'..'..branch}, true) local commits_str = run({ 'git', 'rev-list', ancestor .. '..' .. branch }, true)
assert(commits_str) assert(commits_str)
local commits = {} --- @type string[] local commits = {} --- @type string[]
for substring in commits_str:gmatch("%S+") do for substring in commits_str:gmatch('%S+') do
table.insert(commits, substring) table.insert(commits, substring)
end end
local failed = 0 local failed = 0
for _, commit_id in ipairs(commits) do for _, commit_id in ipairs(commits) do
local msg = run({'git', 'show', '-s', '--format=%s' , commit_id}) local msg = run({ 'git', 'show', '-s', '--format=%s', commit_id })
if vim.v.shell_error ~= 0 then if vim.v.shell_error ~= 0 then
p('Invalid commit-id: '..commit_id..'"') p('Invalid commit-id: ' .. commit_id .. '"')
else else
local invalid_msg = validate_commit(msg) local invalid_msg = validate_commit(msg)
if invalid_msg then if invalid_msg then
@ -183,20 +185,22 @@ function M.main(opt)
p('\n') p('\n')
end end
p(string.format([[ p(string.format(
[[
Invalid commit message: "%s" Invalid commit message: "%s"
Commit: %s Commit: %s
%s %s
]], ]],
msg, msg,
commit_id, commit_id,
invalid_msg)) invalid_msg
))
end end
end end
end end
if failed > 0 then if failed > 0 then
p([[ p([[
See also: See also:
https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages
@ -259,7 +263,7 @@ function M._test()
['feat(:grep/:make)'] = false, ['feat(:grep/:make)'] = false,
['feat(:grep'] = false, ['feat(:grep'] = false,
['feat(:grep/:make'] = 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 local failed = 0
@ -267,14 +271,15 @@ function M._test()
local is_valid = (nil == validate_commit(message)) local is_valid = (nil == validate_commit(message))
if is_valid ~= expected then if is_valid ~= expected then
failed = failed + 1 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
end end
if failed > 0 then if failed > 0 then
os.exit(1) os.exit(1)
end end
end end
--- @class LintcommitOptions --- @class LintcommitOptions

View File

@ -59,9 +59,12 @@ local TAGGED_TYPES = { 'TSNode', 'LanguageTree' }
-- Document these as 'table' -- Document these as 'table'
local ALIAS_TYPES = { local ALIAS_TYPES = {
'Range', 'Range4', 'Range6', 'TSMetadata', 'Range',
'Range4',
'Range6',
'TSMetadata',
'vim.filetype.add.filetypes', 'vim.filetype.add.filetypes',
'vim.filetype.match.args' 'vim.filetype.match.args',
} }
local debug_outfile = nil --- @type string? local debug_outfile = nil --- @type string?
@ -103,7 +106,7 @@ function StreamRead.new(filename)
-- syphon lines to our table -- syphon lines to our table
local filecontents = {} --- @type string[] local filecontents = {} --- @type string[]
for line in io.lines(filename) do for line in io.lines(filename) do
filecontents[#filecontents+1] = line filecontents[#filecontents + 1] = line
end end
return setmetatable({ return setmetatable({
@ -176,9 +179,15 @@ local function process_magic(line, generics)
local magic_split = vim.split(magic, ' ', { plain = true }) local magic_split = vim.split(magic, ' ', { plain = true })
local directive = magic_split[1] local directive = magic_split[1]
if vim.list_contains({ if
'cast', 'diagnostic', 'overload', 'meta', 'type' vim.list_contains({
}, directive) then 'cast',
'diagnostic',
'overload',
'meta',
'type',
}, directive)
then
-- Ignore LSP directives -- Ignore LSP directives
return '// gg:"' .. line .. '"' return '// gg:"' .. line .. '"'
end end
@ -202,8 +211,7 @@ local function process_magic(line, generics)
if directive == 'param' then if directive == 'param' then
for _, type in ipairs(TYPES) do 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 .. ')%)', 'param %1 %2')
magic = magic = magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', 'param %1 %2')
magic:gsub('^param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', 'param %1 %2')
end end
magic_split = vim.split(magic, ' ', { plain = true }) magic_split = vim.split(magic, ' ', { plain = true })
type_index = 3 type_index = 3
@ -225,7 +233,7 @@ local function process_magic(line, generics)
-- fix optional parameters -- fix optional parameters
if magic_split[2]:find('%?$') then if magic_split[2]:find('%?$') then
if not ty:find('nil') then if not ty:find('nil') then
ty = ty .. '|nil' ty = ty .. '|nil'
end end
magic_split[2] = magic_split[2]:sub(1, -2) magic_split[2] = magic_split[2]:sub(1, -2)
end end
@ -240,18 +248,15 @@ local function process_magic(line, generics)
end end
for _, type in ipairs(ALIAS_TYPES) do for _, type in ipairs(ALIAS_TYPES) do
ty = ty:gsub('^'..type..'$', 'table') --- @type string ty = ty:gsub('^' .. type .. '$', 'table') --- @type string
end end
-- surround some types by () -- surround some types by ()
for _, type in ipairs(TYPES) do for _, type in ipairs(TYPES) do
ty = ty ty = ty:gsub('^(' .. type .. '|nil):?$', '(%1)'):gsub('^(' .. type .. '):?$', '(%1)')
:gsub('^(' .. type .. '|nil):?$', '(%1)')
:gsub('^(' .. type .. '):?$', '(%1)')
end end
magic_split[type_index] = ty magic_split[type_index] = ty
end end
magic = table.concat(magic_split, ' ') magic = table.concat(magic_split, ' ')
@ -281,7 +286,7 @@ local function process_block_comment(line, in_stream)
-- easier to program -- easier to program
in_stream:ungetLine(vim.trim(line:sub(closeSquare + 2))) in_stream:ungetLine(vim.trim(line:sub(closeSquare + 2)))
end end
comment_parts[#comment_parts+1] = thisComment comment_parts[#comment_parts + 1] = thisComment
end end
local comment = table.concat(comment_parts) local comment = table.concat(comment_parts)
@ -303,7 +308,7 @@ local function process_function_header(line)
if fn:sub(1, 1) == '(' then if fn:sub(1, 1) == '(' then
-- it's an anonymous function -- it's an anonymous function
return '// ZZ: '..line return '// ZZ: ' .. line
end end
-- fn has a name, so is interesting -- fn has a name, so is interesting
@ -330,10 +335,7 @@ local function process_function_header(line)
comma = ', ' comma = ', '
end end
fn = fn:sub(1, paren_start) fn = fn:sub(1, paren_start) .. 'self' .. comma .. fn:sub(paren_start + 1)
.. 'self'
.. comma
.. fn:sub(paren_start + 1)
end end
if line:match('local') then if line:match('local') then
@ -357,7 +359,7 @@ local function process_line(line, in_stream, generics)
return process_magic(line:sub(4), generics) return process_magic(line:sub(4), generics)
end end
if vim.startswith(line, '--'..'[[') then -- it's a long comment if vim.startswith(line, '--' .. '[[') then -- it's a long comment
return process_block_comment(line:sub(5), in_stream) return process_block_comment(line:sub(5), in_stream)
end end
@ -375,7 +377,7 @@ local function process_line(line, in_stream, generics)
local v = line_raw:match('^([A-Za-z][.a-zA-Z_]*)%s+%=') local v = line_raw:match('^([A-Za-z][.a-zA-Z_]*)%s+%=')
if v and v:match('%.') then if v and v:match('%.') then
-- Special: this lets gen_vimdoc.py handle tables. -- Special: this lets gen_vimdoc.py handle tables.
return 'table '..v..'() {}' return 'table ' .. v .. '() {}'
end end
end end
@ -418,7 +420,7 @@ local TApp = {
timestamp = os.date('%c %Z', os.time()), timestamp = os.date('%c %Z', os.time()),
name = 'Lua2DoX', name = 'Lua2DoX',
version = '0.2 20130128', version = '0.2 20130128',
copyright = 'Copyright (c) Simon Dales 2012-13' copyright = 'Copyright (c) Simon Dales 2012-13',
} }
setmetatable(TApp, { __index = TApp }) setmetatable(TApp, { __index = TApp })
@ -447,12 +449,15 @@ if arg[1] == '--help' then
elseif arg[1] == '--version' then elseif arg[1] == '--version' then
writeln(TApp:getVersion()) writeln(TApp:getVersion())
writeln(TApp.copyright) writeln(TApp.copyright)
else -- It's a filter. else -- It's a filter.
local filename = arg[1] local filename = arg[1]
if arg[2] == '--outdir' then if arg[2] == '--outdir' then
local outdir = arg[3] 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))) error(('invalid --outdir: "%s"'):format(tostring(outdir)))
end end
vim.fn.mkdir(outdir, 'p') vim.fn.mkdir(outdir, 'p')

View File

@ -10,13 +10,13 @@ local function systemlist(...)
local err = nvim.nvim_get_vvar('shell_error') local err = nvim.nvim_get_vvar('shell_error')
local args_str = nvim.nvim_call_function('string', ...) local args_str = nvim.nvim_call_function('string', ...)
if 0 ~= err then if 0 ~= err then
error('command failed: '..args_str) error('command failed: ' .. args_str)
end end
return rv return rv
end end
local function vimpatch_sh_list_numbers() 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 end
-- Generates the lines to be inserted into the src/version.c -- Generates the lines to be inserted into the src/version.c
@ -55,9 +55,9 @@ local function patch_version_c()
nvim.nvim_command('silent normal! j0d/};\rk') nvim.nvim_command('silent normal! j0d/};\rk')
-- Insert the lines. -- Insert the lines.
nvim.nvim_call_function('append', { nvim.nvim_call_function('append', {
nvim.nvim_eval('line(".")'), nvim.nvim_eval('line(".")'),
lines, lines,
}) })
nvim.nvim_command('silent write') nvim.nvim_command('silent write')
end end