refactor(help): move local-additions to Lua #37831

Problem:
- ~200 line function of hard-to-maintain C code.
- Local Addition section looks messy because of the varying description
  formats.

Solution:
- Move code to Lua.
- Have a best-effort approach where short descriptions are right
  aligned, giving a cleaner look. Long descriptions are untouched.
This commit is contained in:
Yochem van Rosmalen
2026-02-14 11:30:18 +01:00
committed by GitHub
parent 29c81ba27e
commit b5ce7e74dc
4 changed files with 84 additions and 167 deletions

View File

@@ -143,7 +143,7 @@ Standard plugins ~
See |standard-plugin-list|.
Local additions ~
*local-additions*
*local-additions*
------------------------------------------------------------------------------
Bars example *bars*

View File

@@ -122,10 +122,77 @@ function M.escape_subject(word)
-- E.g. '`command`,' --> 'command' (backticks are removed too, but '``' stays '``')
word = word:gsub([[^'([^']*)'.*]], [['%1']])
word = word:gsub([[^{([^}]*)}.*]], '{%1}')
word = word:gsub([[^`([^`]+)`.*]], '%1')
word = word:gsub([[.*`([^`]+)`.*]], '%1')
end
return word
end
---Populates the |local-additions| section of a help buffer with references to locally-installed
---help files. These are help files outside of $VIMRUNTIME (typically from plugins) whose first
---line contains a tag (e.g. *plugin-name.txt*) and a short description.
---
---For each help file found in 'runtimepath', the first line is extracted and added to the buffer
---as a reference (converting '*tag*' to '|tag|'). If a translated version of a help file exists
---in the same language as the current buffer (e.g. 'plugin.nlx' alongside 'plugin.txt'), the
---translated version is preferred over the '.txt' file.
function M.local_additions()
local buf = vim.api.nvim_get_current_buf()
local bufname = vim.fs.basename(vim.api.nvim_buf_get_name(buf))
-- "help.txt" or "help.??x" where ?? is a language code, see |help-translated|.
local lang = bufname:match('^help%.(%a%a)x$')
if bufname ~= 'help.txt' and not lang then
return
end
-- Find local help files
---@type table<string, string>
local plugins = {}
local pattern = lang and ('doc/*.{txt,%sx}'):format(lang) or 'doc/*.txt'
for _, docpath in ipairs(vim.api.nvim_get_runtime_file(pattern, true)) do
if not vim.fs.relpath(vim.env.VIMRUNTIME, docpath) then
-- '/path/to/doc/plugin.txt' --> 'plugin'
local plugname = vim.fs.basename(docpath):sub(1, -5)
-- prefer language-specific files over .txt
if not plugins[plugname] or vim.endswith(plugins[plugname], '.txt') then
plugins[plugname] = docpath
end
end
end
-- Format plugin list lines
-- Default to 78 if 'textwidth' is not set (e.g. in sandbox)
local textwidth = math.max(vim.bo[buf].textwidth, 78)
local lines = {}
for _, path in vim.spairs(plugins) do
local fp = io.open(path, 'r')
if fp then
local tagline = fp:read('*l') or ''
fp:close()
---@type string, string
local plugname, desc = tagline:match('^%*([^*]+)%*%s*(.*)$')
if plugname and desc then
-- left-align taglink and right-align description by inserting spaces in between
local plug_width = vim.fn.strdisplaywidth(plugname)
local desc_width = vim.fn.strdisplaywidth(desc)
-- max(l, 1) forces at least one space for if the description is too long
local spaces = string.rep(' ', math.max(textwidth - desc_width - plug_width - 2, 1))
local fmt = string.format('|%s|%s%s', plugname, spaces, desc)
table.insert(lines, fmt)
end
end
end
-- Add plugin list to local-additions section
for linenr, line in ipairs(vim.api.nvim_buf_get_lines(buf, 0, -1, false)) do
if line:find('*local-additions*', 1, true) then
vim._with({ buf = buf, bo = { modifiable = true, readonly = false } }, function()
vim.api.nvim_buf_set_lines(buf, linenr, linenr, true, lines)
end)
break
end
end
end
return M