From a09ddd7ce55037edc9747a682810fba6a26bc201 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 9 Mar 2024 12:21:01 +0000 Subject: [PATCH] docs(editorconfig): move to source --- runtime/doc/editorconfig.txt | 106 ++++++++-------- runtime/doc/lua.txt | 13 ++ runtime/lua/editorconfig.lua | 197 +++++++++++++++++++----------- runtime/lua/vim/_editor.lua | 1 - runtime/lua/vim/_meta/builtin.lua | 1 - scripts/gen_vimdoc.lua | 70 +++++++---- scripts/text_utils.lua | 8 +- 7 files changed, 243 insertions(+), 153 deletions(-) diff --git a/runtime/doc/editorconfig.txt b/runtime/doc/editorconfig.txt index a2281a7b7c..c7011cfbba 100644 --- a/runtime/doc/editorconfig.txt +++ b/runtime/doc/editorconfig.txt @@ -3,7 +3,7 @@ NVIM REFERENCE MANUAL - +============================================================================== EditorConfig integration *editorconfig* Nvim supports EditorConfig. When a file is opened, Nvim searches all parent @@ -13,69 +13,23 @@ entire (recursive) directory. For more information see https://editorconfig.org/. *g:editorconfig* *b:editorconfig* -EditorConfig is enabled by default. To disable it, add to your config: >lua +EditorConfig is enabled by default. To disable it, add to your config: >lua vim.g.editorconfig = false < + (Vimscript: `let g:editorconfig = v:false`). It can also be disabled per-buffer by setting the |b:editorconfig| buffer-local variable to `false`. Nvim stores the applied properties in |b:editorconfig| if it is not `false`. - *editorconfig-properties* -The following properties are supported by default: - - *editorconfig_root* -root If "true", then stop searching for .editorconfig files - in parent directories. This property must be at the - top-level of the .editorconfig file (i.e. it must not - be within a glob section). - - *editorconfig_charset* -charset One of "utf-8", "utf-8-bom", "latin1", "utf-16be", or - "utf-16le". Sets the 'fileencoding' and 'bomb' - options. - - *editorconfig_end_of_line* -end_of_line One of "lf", "crlf", or "cr". These correspond to - setting 'fileformat' to "unix", "dos", or "mac", - respectively. - - *editorconfig_indent_style* -indent_style One of "tab" or "space". Sets the 'expandtab' option. - - *editorconfig_indent_size* -indent_size A number indicating the size of a single indent. - Alternatively, use the value "tab" to use the value of - the tab_width property. Sets the 'shiftwidth' and - 'softtabstop' options. - If this value is not "tab" and the tab_width property - is not set, 'tabstop' is also set to this value. - - *editorconfig_insert_final_newline* -insert_final_newline "true" or "false" to ensure the file always has a - trailing newline as its last byte. Sets the - 'fixendofline' and 'endofline' options. - - *editorconfig_max_line_length* -max_line_length A number indicating the maximum length of a single - line. Sets the 'textwidth' option. - - *editorconfig_tab_width* -tab_width The display size of a single tab character. Sets the - 'tabstop' option. - - *editorconfig_trim_trailing_whitespace* -trim_trailing_whitespace - When "true", trailing whitespace is automatically - removed when the buffer is written. - *editorconfig-custom-properties* + New properties can be added by adding a new entry to the "properties" table. The table key is a property name and the value is a callback function which -accepts the number of the buffer to be modified, the value of the property -in the .editorconfig file, and (optionally) a table containing all of the -other properties and their values (useful for properties which depend on other +accepts the number of the buffer to be modified, the value of the property in +the `.editorconfig` file, and (optionally) a table containing all of the other +properties and their values (useful for properties which depend on other properties). The value is always a string and must be coerced if necessary. Example: >lua @@ -86,4 +40,48 @@ Example: >lua vim.b[bufnr].foo = val end < - vim:tw=78:ts=8:et:sw=4:ft=help:norl: + + *editorconfig-properties* + +The following properties are supported by default: + + +charset *editorconfig.charset* + One of `"utf-8"`, `"utf-8-bom"`, `"latin1"`, `"utf-16be"`, or + `"utf-16le"`. Sets the 'fileencoding' and 'bomb' options. + +end_of_line *editorconfig.end_of_line* + One of `"lf"`, `"crlf"`, or `"cr"`. These correspond to setting + 'fileformat' to "unix", "dos", or "mac", respectively. + +indent_size *editorconfig.indent_size* + A number indicating the size of a single indent. Alternatively, use the + value "tab" to use the value of the tab_width property. Sets the + 'shiftwidth' and 'softtabstop' options. If this value is not "tab" and the + tab_width property is not set, 'tabstop' is also set to this value. + +indent_style *editorconfig.indent_style* + One of `"tab"` or `"space"`. Sets the 'expandtab' option. + +insert_final_newline *editorconfig.insert_final_newline* + `"true"` or `"false"` to ensure the file always has a trailing newline as + its last byte. Sets the 'fixendofline' and 'endofline' options. + +max_line_length *editorconfig.max_line_length* + A number indicating the maximum length of a single line. Sets the + 'textwidth' option. + +root *editorconfig.root* + If "true", then stop searching for `.editorconfig` files in parent + directories. This property must be at the top-level of the `.editorconfig` + file (i.e. it must not be within a glob section). + +tab_width *editorconfig.tab_width* + The display size of a single tab character. Sets the 'tabstop' option. + +trim_trailing_whitespace *editorconfig.trim_trailing_whitespace* + When `"true"`, trailing whitespace is automatically removed when the + buffer is written. + + + vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 89f62126bb..e1e3f88a1d 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1161,6 +1161,7 @@ Lua list copies the list object to Vimscript and does NOT modify the Lua list: > vim.print(list) --> "{ 1, 2, 3 }" < + vim.call({func}, {...}) *vim.call()* Invokes |vim-function| or |user-function| {func} with arguments {...}. See also |vim.fn|. @@ -1239,6 +1240,7 @@ vim.v *vim.v* |v:| variables. Invalid or unset key returns `nil`. + *lua-options* *lua-vim-options* *lua-vim-set* @@ -1262,6 +1264,7 @@ window-scoped options. Note that this must NOT be confused with |local-options| and |:setlocal|. There is also |vim.go| that only accesses the global value of a |global-local| option, see |:setglobal|. + *vim.opt_local* *vim.opt_global* *vim.opt* @@ -3897,6 +3900,7 @@ Iter:enumerate() *Iter:enumerate()* < Example: >lua + local it = vim.iter(vim.gsplit('abc', '')):enumerate() it:next() -- 1 'a' @@ -3931,6 +3935,7 @@ Iter:find({f}) *Iter:find()* found. Examples: >lua + local it = vim.iter({ 3, 6, 9, 12 }) it:find(12) -- 12 @@ -4011,6 +4016,7 @@ Iter:last() *Iter:last()* Drains the iterator and returns the last item. Example: >lua + local it = vim.iter(vim.gsplit('abcdefg', '')) it:last() -- 'g' @@ -4051,6 +4057,7 @@ Iter:next() *Iter:next()* Gets the next value from the iterator. Example: >lua + local it = vim.iter(string.gmatch('1 2 3', '%d+')):map(tonumber) it:next() -- 1 @@ -4082,6 +4089,7 @@ Iter:nth({n}) *Iter:nth()* Gets the nth value of an iterator (and advances to it). Example: >lua + local it = vim.iter({ 3, 6, 9, 12 }) it:nth(2) -- 6 @@ -4099,6 +4107,7 @@ Iter:nthback({n}) *Iter:nthback()* Gets the nth value from the end of a |list-iterator| (and advances to it). Example: >lua + local it = vim.iter({ 3, 6, 9, 12 }) it:nthback(2) -- 9 @@ -4116,6 +4125,7 @@ Iter:peek() *Iter:peek()* Gets the next value in a |list-iterator| without consuming it. Example: >lua + local it = vim.iter({ 3, 6, 9, 12 }) it:peek() -- 3 @@ -4150,6 +4160,7 @@ Iter:rev() *Iter:rev()* Reverses a |list-iterator| pipeline. Example: >lua + local it = vim.iter({ 3, 6, 9, 12 }):rev() it:totable() -- { 12, 9, 6, 3 } @@ -4166,6 +4177,7 @@ Iter:rfind({f}) *Iter:rfind()* found. Examples: >lua + local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate() it:rfind(1) -- 5 1 @@ -4186,6 +4198,7 @@ Iter:skip({n}) *Iter:skip()* Skips `n` values of an iterator pipeline. Example: >lua + local it = vim.iter({ 3, 6, 9, 12 }):skip(2) it:next() -- 9 diff --git a/runtime/lua/editorconfig.lua b/runtime/lua/editorconfig.lua index 49d63807a6..6c5c820b0c 100644 --- a/runtime/lua/editorconfig.lua +++ b/runtime/lua/editorconfig.lua @@ -1,31 +1,80 @@ -local M = {} +--- @brief +--- Nvim supports EditorConfig. When a file is opened, Nvim searches all parent +--- directories of that file for ".editorconfig" files, parses them, and applies +--- any properties that match the opened file. Think of it like 'modeline' for an +--- entire (recursive) directory. For more information see +--- https://editorconfig.org/. +--- + +--- @brief [g:editorconfig]() [b:editorconfig]() +--- +--- EditorConfig is enabled by default. To disable it, add to your config: +--- ```lua +--- vim.g.editorconfig = false +--- ``` +--- +--- (Vimscript: `let g:editorconfig = v:false`). It can also be disabled +--- per-buffer by setting the [b:editorconfig] buffer-local variable to `false`. +--- +--- Nvim stores the applied properties in [b:editorconfig] if it is not `false`. + +--- @brief [editorconfig-custom-properties]() +--- +--- New properties can be added by adding a new entry to the "properties" table. +--- The table key is a property name and the value is a callback function which +--- accepts the number of the buffer to be modified, the value of the property +--- in the `.editorconfig` file, and (optionally) a table containing all of the +--- other properties and their values (useful for properties which depend on other +--- properties). The value is always a string and must be coerced if necessary. +--- Example: +--- +--- ```lua +--- +--- require('editorconfig').properties.foo = function(bufnr, val, opts) +--- if opts.charset and opts.charset ~= "utf-8" then +--- error("foo can only be set when charset is utf-8", 0) +--- end +--- vim.b[bufnr].foo = val +--- end +--- +--- ``` + +--- @brief [editorconfig-properties]() +--- +--- The following properties are supported by default: --- @type table -M.properties = {} +local properties = {} +--- @private --- Modified version of the builtin assert that does not include error position information --- ----@param v any Condition ----@param message string Error message to display if condition is false or nil ----@return any v if not false or nil, otherwise an error is displayed ---- ----@private +--- @param v any Condition +--- @param message string Error message to display if condition is false or nil +--- @return any v if not false or nil, otherwise an error is displayed local function assert(v, message) return v or error(message, 0) end +--- @private --- Show a warning message ---- ----@param msg string Message to show ---- ----@private +--- @param msg string Message to show local function warn(msg, ...) - vim.notify_once(string.format(msg, ...), vim.log.levels.WARN, { + vim.notify_once(msg:format(...), vim.log.levels.WARN, { title = 'editorconfig', }) end -function M.properties.charset(bufnr, val) +--- If "true", then stop searching for `.editorconfig` files in parent +--- directories. This property must be at the top-level of the +--- `.editorconfig` file (i.e. it must not be within a glob section). +function properties.root() + -- Unused +end + +--- One of `"utf-8"`, `"utf-8-bom"`, `"latin1"`, `"utf-16be"`, or `"utf-16le"`. +--- Sets the 'fileencoding' and 'bomb' options. +function properties.charset(bufnr, val) assert( vim.list_contains({ 'utf-8', 'utf-8-bom', 'latin1', 'utf-16be', 'utf-16le' }, val), 'charset must be one of "utf-8", "utf-8-bom", "latin1", "utf-16be", or "utf-16le"' @@ -40,14 +89,18 @@ function M.properties.charset(bufnr, val) end end -function M.properties.end_of_line(bufnr, val) +--- One of `"lf"`, `"crlf"`, or `"cr"`. +--- These correspond to setting 'fileformat' to "unix", "dos", or "mac", +--- respectively. +function properties.end_of_line(bufnr, val) vim.bo[bufnr].fileformat = assert( ({ lf = 'unix', crlf = 'dos', cr = 'mac' })[val], 'end_of_line must be one of "lf", "crlf", or "cr"' ) end -function M.properties.indent_style(bufnr, val, opts) +--- One of `"tab"` or `"space"`. Sets the 'expandtab' option. +function properties.indent_style(bufnr, val, opts) assert(val == 'tab' or val == 'space', 'indent_style must be either "tab" or "space"') vim.bo[bufnr].expandtab = val == 'space' if val == 'tab' and not opts.indent_size then @@ -56,7 +109,11 @@ function M.properties.indent_style(bufnr, val, opts) end end -function M.properties.indent_size(bufnr, val, opts) +--- A number indicating the size of a single indent. Alternatively, use the +--- value "tab" to use the value of the tab_width property. Sets the +--- 'shiftwidth' and 'softtabstop' options. If this value is not "tab" and +--- the tab_width property is not set, 'tabstop' is also set to this value. +function properties.indent_size(bufnr, val, opts) if val == 'tab' then vim.bo[bufnr].shiftwidth = 0 vim.bo[bufnr].softtabstop = 0 @@ -70,11 +127,14 @@ function M.properties.indent_size(bufnr, val, opts) end end -function M.properties.tab_width(bufnr, val) +--- The display size of a single tab character. Sets the 'tabstop' option. +function properties.tab_width(bufnr, val) vim.bo[bufnr].tabstop = assert(tonumber(val), 'tab_width must be a number') end -function M.properties.max_line_length(bufnr, val) +--- A number indicating the maximum length of a single +--- line. Sets the 'textwidth' option. +function properties.max_line_length(bufnr, val) local n = tonumber(val) if n then vim.bo[bufnr].textwidth = n @@ -84,7 +144,8 @@ function M.properties.max_line_length(bufnr, val) end end -function M.properties.trim_trailing_whitespace(bufnr, val) +--- When `"true"`, trailing whitespace is automatically removed when the buffer is written. +function properties.trim_trailing_whitespace(bufnr, val) assert( val == 'true' or val == 'false', 'trim_trailing_whitespace must be either "true" or "false"' @@ -109,7 +170,9 @@ function M.properties.trim_trailing_whitespace(bufnr, val) end end -function M.properties.insert_final_newline(bufnr, val) +--- `"true"` or `"false"` to ensure the file always has a trailing newline as its last byte. +--- Sets the 'fixendofline' and 'endofline' options. +function properties.insert_final_newline(bufnr, val) assert(val == 'true' or val == 'false', 'insert_final_newline must be either "true" or "false"') vim.bo[bufnr].fixendofline = val == 'true' @@ -128,63 +191,56 @@ function M.properties.insert_final_newline(bufnr, val) end end ---- Modified version of |glob2regpat()| that does not match path separators on *. +--- @private +--- Modified version of [glob2regpat()] that does not match path separators on `*`. --- ---- This function replaces single instances of * with the regex pattern [^/]*. However, the star in ---- the replacement pattern also gets interpreted by glob2regpat, so we insert a placeholder, pass ---- it through glob2regpat, then replace the placeholder with the actual regex pattern. +--- This function replaces single instances of `*` with the regex pattern `[^/]*`. +--- However, the star in the replacement pattern also gets interpreted by glob2regpat, +--- so we insert a placeholder, pass it through glob2regpat, then replace the +--- placeholder with the actual regex pattern. --- ----@param glob string Glob to convert into a regular expression ----@return string Regular expression ---- ----@private +--- @param glob string Glob to convert into a regular expression +--- @return string regex Regular expression local function glob2regpat(glob) local placeholder = '@@PLACEHOLDER@@' - return ( - string.gsub( - vim.fn.glob2regpat( - vim.fn.substitute( - string.gsub(glob, '{(%d+)%.%.(%d+)}', '[%1-%2]'), - '\\*\\@ Table of options to apply to the given file ---- ----@private +--- @private +--- Parse options from an `.editorconfig` file +--- @param filepath string File path of the file to apply EditorConfig settings to +--- @param dir string Current directory +--- @return table Table of options to apply to the given file local function parse(filepath, dir) local pat --- @type vim.regex? local opts = {} --- @type table @@ -215,11 +271,11 @@ local function parse(filepath, dir) return opts end ---- Configure the given buffer with options from an .editorconfig file ---- ----@param bufnr integer Buffer number to configure ---- ----@private +local M = {} + +--- @private +--- Configure the given buffer with options from an `.editorconfig` file +--- @param bufnr integer Buffer number to configure function M.config(bufnr) bufnr = bufnr or vim.api.nvim_get_current_buf() if not vim.api.nvim_buf_is_valid(bufnr) then @@ -247,8 +303,9 @@ function M.config(bufnr) local applied = {} --- @type table for opt, val in pairs(opts) do if val ~= 'unset' then - local func = M.properties[opt] + local func = properties[opt] if func then + --- @type boolean, string? local ok, err = pcall(func, bufnr, val, opts) if ok then applied[opt] = val diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 6cf77b4648..f527fc194c 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -74,7 +74,6 @@ vim.log = { --- Examples: --- --- ```lua ---- --- local on_exit = function(obj) --- print(obj.code) --- print(obj.signal) diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua index 9a67667f02..ef9821fa32 100644 --- a/runtime/lua/vim/_meta/builtin.lua +++ b/runtime/lua/vim/_meta/builtin.lua @@ -215,7 +215,6 @@ function vim.schedule(fn) end --- Examples: --- --- ```lua ---- --- --- --- -- Wait for 100 ms, allowing other events to process --- vim.wait(100, function() end) diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua index 22df411a35..b3b211d5a6 100755 --- a/scripts/gen_vimdoc.lua +++ b/scripts/gen_vimdoc.lua @@ -94,12 +94,12 @@ end local function fn_helptag_fmt_common(fun) local fn_sfx = fun.table and '' or '()' if fun.classvar then - return fmt('*%s:%s%s*', fun.classvar, fun.name, fn_sfx) + return fmt('%s:%s%s', fun.classvar, fun.name, fn_sfx) end if fun.module then - return fmt('*%s.%s%s*', fun.module, fun.name, fn_sfx) + return fmt('%s.%s%s', fun.module, fun.name, fn_sfx) end - return fmt('*%s%s*', fun.name, fn_sfx) + return fun.name .. fn_sfx end --- @type table @@ -129,7 +129,7 @@ local config = { return name .. ' Functions' end, helptag_fmt = function(name) - return fmt('*api-%s*', name:lower()) + return fmt('api-%s', name:lower()) end, }, lua = { @@ -241,22 +241,22 @@ local config = { end, helptag_fmt = function(name) if name == '_editor' then - return '*lua-vim*' + return 'lua-vim' elseif name == '_options' then - return '*lua-vimscript*' + return 'lua-vimscript' elseif name == 'tohtml' then - return '*tohtml*' + return 'tohtml' end - return '*vim.' .. name:lower() .. '*' + return 'vim.' .. name:lower() end, fn_helptag_fmt = function(fun) local name = fun.name if vim.startswith(name, 'vim.') then local fn_sfx = fun.table and '' or '()' - return fmt('*%s%s*', name, fn_sfx) + return name .. fn_sfx elseif fun.classvar == 'Option' then - return fmt('*vim.opt:%s()*', name) + return fmt('vim.opt:%s()', name) end return fn_helptag_fmt_common(fun) @@ -297,9 +297,9 @@ local config = { end, helptag_fmt = function(name) if name:lower() == 'lsp' then - return '*lsp-core*' + return 'lsp-core' end - return fmt('*lsp-%s*', name:lower()) + return fmt('lsp-%s', name:lower()) end, }, diagnostic = { @@ -312,7 +312,7 @@ local config = { return 'Lua module: vim.diagnostic' end, helptag_fmt = function() - return '*diagnostic-api*' + return 'diagnostic-api' end, }, treesitter = { @@ -337,9 +337,28 @@ local config = { end, helptag_fmt = function(name) if name:lower() == 'treesitter' then - return '*lua-treesitter-core*' + return 'lua-treesitter-core' end - return '*lua-treesitter-' .. name:lower() .. '*' + return 'lua-treesitter-' .. name:lower() + end, + }, + editorconfig = { + filename = 'editorconfig.txt', + files = { + 'runtime/lua/editorconfig.lua', + }, + section_order = { + 'editorconfig.lua', + }, + section_fmt = function(_name) + return 'EditorConfig integration' + end, + helptag_fmt = function(name) + return name:lower() + end, + fn_xform = function(fun) + fun.table = true + fun.name = vim.split(fun.name, '.', { plain = true })[2] end, }, } @@ -600,7 +619,7 @@ local function render_fun_header(fun, cfg) cfg.fn_helptag_fmt = fn_helptag_fmt_common end - local tag = cfg.fn_helptag_fmt(fun) + local tag = '*' .. cfg.fn_helptag_fmt(fun) .. '*' if #proto + #tag > TEXT_WIDTH - 8 then table.insert(ret, fmt('%78s\n', tag)) @@ -816,7 +835,7 @@ local function make_section(filename, cfg, section_docs, funs_txt) local sectname = cfg.section_name and cfg.section_name[filename] or mktitle(name) -- section tag: e.g., "*api-autocmd*" - local help_tag = cfg.helptag_fmt(sectname) + local help_tag = '*' .. cfg.helptag_fmt(sectname) .. '*' if funs_txt == '' and #section_docs == 0 then return @@ -845,9 +864,9 @@ local function render_section(section, add_header) }) end - if section.doc and #section.doc > 0 then - table.insert(doc, '\n\n') - vim.list_extend(doc, section.doc) + local sdoc = '\n\n' .. table.concat(section.doc or {}, '\n') + if sdoc:find('[^%s]') then + doc[#doc + 1] = sdoc end if section.funs_txt then @@ -880,6 +899,7 @@ end --- @param cfg nvim.gen_vimdoc.Config local function gen_target(cfg) + print('Target:', cfg.filename) local sections = {} --- @type table expand_files(cfg.files) @@ -891,7 +911,7 @@ local function gen_target(cfg) local all_classes = {} --- First pass so we can collect all classes - for _, f in pairs(cfg.files) do + for _, f in vim.spairs(cfg.files) do local ext = assert(f:match('%.([^.]+)$')) --[[@as 'h'|'c'|'lua']] local parser = assert(parsers[ext]) local classes, funs, briefs = parser(f) @@ -899,13 +919,14 @@ local function gen_target(cfg) all_classes = vim.tbl_extend('error', all_classes, classes) end - for f, r in pairs(file_results) do + for f, r in vim.spairs(file_results) do local classes, funs, briefs = r[1], r[2], r[3] local briefs_txt = {} --- @type string[] for _, b in ipairs(briefs) do briefs_txt[#briefs_txt + 1] = md_to_vimdoc(b, 0, 0, TEXT_WIDTH) end + print(' Processing file:', f) local funs_txt = render_funs(funs, all_classes, cfg) if next(classes) then local classes_txt = render_classes(classes) @@ -923,8 +944,9 @@ local function gen_target(cfg) for _, f in ipairs(cfg.section_order) do local section = sections[f] if section then + print(string.format(" Rendering section: '%s'", section.title)) local add_sep_and_header = not vim.tbl_contains(cfg.append_only or {}, f) - table.insert(docs, render_section(section, add_sep_and_header)) + docs[#docs + 1] = render_section(section, add_sep_and_header) end end @@ -945,7 +967,7 @@ local function gen_target(cfg) end local function run() - for _, cfg in pairs(config) do + for _, cfg in vim.spairs(config) do gen_target(cfg) end end diff --git a/scripts/text_utils.lua b/scripts/text_utils.lua index 937408c546..75b3bfedd5 100644 --- a/scripts/text_utils.lua +++ b/scripts/text_utils.lua @@ -318,7 +318,7 @@ local function align_tags(text_width) --- @param line string --- @return string return function(line) - local tag_pat = '%s+(%*[^ ]+%*)%s*$' + local tag_pat = '%s*(%*.+%*)%s*$' local tags = {} for m in line:gmatch(tag_pat) do table.insert(tags, m) @@ -327,7 +327,9 @@ local function align_tags(text_width) if #tags > 0 then line = line:gsub(tag_pat, '') local tags_str = ' ' .. table.concat(tags, ' ') - local pad = string.rep(' ', text_width - #line - #tags_str) + --- @type integer + local conceal_offset = select(2, tags_str:gsub('%*', '')) - 2 + local pad = string.rep(' ', text_width - #line - #tags_str + conceal_offset) return line .. pad .. tags_str end @@ -352,7 +354,7 @@ function M.md_to_vimdoc(text, start_indent, indent, text_width, is_list) local s = table.concat(lines, '\n') -- Reduce whitespace in code-blocks - s = s:gsub('\n+%s*>([a-z]+)\n?\n', ' >%1\n') + s = s:gsub('\n+%s*>([a-z]+)\n', ' >%1\n') s = s:gsub('\n+%s*>\n?\n', ' >\n') return s