mirror of
https://github.com/neovim/neovim.git
synced 2026-11-06 05:16:52 +00:00
feat(docs): table rendering
Render tables in both `:help` and generated HTML. Use NBSP (nonbreaking space) char in empty table cells.
This commit is contained in:
1 parent
2accbdfd42
commit
6e4ab11798
6 files changed
+161
-69
No files matched your search
+15
-18
@@ -109,18 +109,17 @@ The Nvim C API defines custom types for all function parameters. Some are just
|
||||
typedefs around C99 standard types, others are Nvim-defined data structures.
|
||||
|
||||
Basic types ~
|
||||
>
|
||||
API Type C type
|
||||
------------------------------------------------------------------------
|
||||
|
||||
API Type C type ~
|
||||
Nil
|
||||
Boolean bool
|
||||
Integer (signed 64-bit integer) int64_t
|
||||
Float (IEEE 754 double precision) double
|
||||
String {char* data, size_t size} struct
|
||||
Array kvec
|
||||
Dict (msgpack: map) kvec
|
||||
Object any of the above
|
||||
<
|
||||
Boolean bool
|
||||
Integer (signed 64-bit integer) int64_t
|
||||
Float (IEEE 754 double precision) double
|
||||
String {char* data, size_t size} struct
|
||||
Array kvec
|
||||
Dict (msgpack: map) kvec
|
||||
Object any of the above
|
||||
|
||||
Note:
|
||||
- Empty Array is accepted as a valid Dictionary parameter.
|
||||
- Functions cannot cross RPC boundaries. But API functions (e.g.
|
||||
@@ -136,13 +135,11 @@ Special types (msgpack EXT) ~
|
||||
The EXT object data is the (integer) object handle. The EXT type codes given
|
||||
in the |api-metadata| `types` key are stable: they will not change and are
|
||||
thus forward-compatible.
|
||||
>
|
||||
EXT Type C type Data
|
||||
------------------------------------------------------------------------
|
||||
Buffer enum value kObjectTypeBuffer |bufnr()|
|
||||
Window enum value kObjectTypeWindow |window-ID|
|
||||
Tabpage enum value kObjectTypeTabpage internal handle
|
||||
<
|
||||
|
||||
EXT Type C type Data ~
|
||||
Buffer enum value kObjectTypeBuffer |bufnr()|
|
||||
Window enum value kObjectTypeWindow |window-ID|
|
||||
Tabpage enum value kObjectTypeTabpage internal handle
|
||||
|
||||
*api-indexing*
|
||||
Most of the API uses 0-based indices, and ranges are end-exclusive. For the
|
||||
|
||||
+45
-46
@@ -29,7 +29,7 @@ Tag Char Insert-mode action ~
|
||||
|i_CTRL-D| CTRL-D delete one shiftwidth of indent in the current
|
||||
line
|
||||
|i_CTRL-E| CTRL-E insert the character which is below the cursor
|
||||
CTRL-F not used (but by default it's in 'cinkeys' to
|
||||
CTRL-F not used (but by default it's in 'cinkeys' to
|
||||
re-indent the current line)
|
||||
|i_CTRL-G_j| CTRL-G CTRL-J line down, to column where inserting started
|
||||
|i_CTRL-G_j| CTRL-G j line down, to column where inserting started
|
||||
@@ -71,7 +71,7 @@ Tag Char Insert-mode action ~
|
||||
|i_CTRL-R_CTRL-P| CTRL-R CTRL-P {register}
|
||||
insert the contents of a register literally
|
||||
and fix indent.
|
||||
CTRL-S not used or used for terminal control flow
|
||||
CTRL-S not used or used for terminal control flow
|
||||
|i_CTRL-T| CTRL-T insert one shiftwidth of indent in current
|
||||
line
|
||||
|i_CTRL-U| CTRL-U delete all entered characters in the current
|
||||
@@ -88,24 +88,18 @@ Tag Char Insert-mode action ~
|
||||
|i_CTRL-[| CTRL-[ same as <Esc>
|
||||
|i_CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode
|
||||
|i_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode
|
||||
CTRL-\ a - z reserved for extensions
|
||||
CTRL-\ others not used
|
||||
CTRL-\ a - z reserved for extensions
|
||||
CTRL-\ others not used
|
||||
|i_CTRL-]| CTRL-] trigger abbreviation
|
||||
|i_CTRL-^| CTRL-^ toggle use of |:lmap| mappings
|
||||
|i_CTRL-_| CTRL-_ When 'allowrevins' set: toggle 'revins'
|
||||
|
||||
<Space> to '~' not used, except '0' and '^' followed by
|
||||
<Space> to '~' not used, except '0' and '^' followed by
|
||||
CTRL-D
|
||||
|
||||
|i_0_CTRL-D| 0 CTRL-D delete all indent in the current line
|
||||
|i_^_CTRL-D| ^ CTRL-D delete all indent in the current line, restore
|
||||
it in the next line
|
||||
|
||||
|i_<Del>| <Del> delete character under the cursor
|
||||
|
||||
Meta characters (0x80 to 0xff, 128 to 255)
|
||||
not used
|
||||
|
||||
Meta characters (0x80 to 0xff, 128 to 255) not used
|
||||
|i_<Left>| <Left> cursor one character left
|
||||
|i_<S-Left>| <S-Left> cursor one word left
|
||||
|i_<C-Left>| <C-Left> cursor one word left
|
||||
@@ -137,6 +131,8 @@ Tag Char Insert-mode action ~
|
||||
|
||||
commands in CTRL-X submode *i_CTRL-X_index*
|
||||
|
||||
Tag Char CTRL-X submode action ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
|i_CTRL-X_CTRL-D| CTRL-X CTRL-D complete defined identifiers
|
||||
|i_CTRL-X_CTRL-E| CTRL-X CTRL-E scroll up
|
||||
|i_CTRL-X_CTRL-F| CTRL-X CTRL-F complete file names
|
||||
@@ -158,17 +154,19 @@ commands in CTRL-X submode *i_CTRL-X_index*
|
||||
|
||||
commands in completion mode (see |popupmenu-keys|)
|
||||
|
||||
|complete_CTRL-E| CTRL-E stop completion and go back to original text
|
||||
|complete_CTRL-Y| CTRL-Y accept selected match and stop completion
|
||||
CTRL-L insert one character from the current match
|
||||
<CR> insert currently selected match
|
||||
<BS> delete one character and redo search
|
||||
CTRL-H same as <BS>
|
||||
<Up> select the previous match
|
||||
<Down> select the next match
|
||||
<PageUp> select a match several entries back
|
||||
<PageDown> select a match several entries forward
|
||||
other stop completion and insert the typed character
|
||||
Tag Char Completion-mode action ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
|complete_CTRL-E| CTRL-E stop completion and go back to original text
|
||||
|complete_CTRL-Y| CTRL-Y accept selected match and stop completion
|
||||
CTRL-L insert one character from the current match
|
||||
<CR> insert currently selected match
|
||||
<BS> delete one character and redo search
|
||||
CTRL-H same as <BS>
|
||||
<Up> select the previous match
|
||||
<Down> select the next match
|
||||
<PageUp> select a match several entries back
|
||||
<PageDown> select a match several entries forward
|
||||
other stop completion and insert the typed character
|
||||
|
||||
==============================================================================
|
||||
2. Normal mode *normal-index*
|
||||
@@ -184,7 +182,7 @@ note: 1 = cursor movement command; 2 = can be undone/redone
|
||||
|
||||
Tag Char Note Normal-mode action ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
CTRL-@ not used
|
||||
CTRL-@ not used
|
||||
|CTRL-A| CTRL-A 2 add N to number at/after cursor
|
||||
|CTRL-B| CTRL-B 1 scroll N screens Backwards
|
||||
|CTRL-C| CTRL-C interrupt current (search) command
|
||||
@@ -199,7 +197,7 @@ Tag Char Note Normal-mode action ~
|
||||
|<NL>| <NL> 1 same as "j"
|
||||
|<S-NL>| <S-NL> 1 same as CTRL-F
|
||||
|CTRL-J| CTRL-J 1 same as "j"
|
||||
CTRL-K not used
|
||||
CTRL-K not used
|
||||
|CTRL-L| CTRL-L redraw screen
|
||||
|<CR>| <CR> 1 cursor to the first CHAR N lines lower
|
||||
|<S-CR>| <S-CR> 1 same as CTRL-F
|
||||
@@ -207,9 +205,9 @@ Tag Char Note Normal-mode action ~
|
||||
|CTRL-N| CTRL-N 1 same as "j"
|
||||
|CTRL-O| CTRL-O 1 go to N older entry in jump list
|
||||
|CTRL-P| CTRL-P 1 same as "k"
|
||||
CTRL-Q not used, or used for terminal control flow
|
||||
CTRL-Q not used, or used for terminal control flow
|
||||
|CTRL-R| CTRL-R 2 redo changes which were undone with 'u'
|
||||
CTRL-S not used, or used for terminal control flow
|
||||
CTRL-S not used, or used for terminal control flow
|
||||
|CTRL-T| CTRL-T jump to N older Tag in tag list
|
||||
|CTRL-U| CTRL-U scroll N lines Upwards (default: half a
|
||||
screen)
|
||||
@@ -218,18 +216,17 @@ Tag Char Note Normal-mode action ~
|
||||
|CTRL-X| CTRL-X 2 subtract N from number at/after cursor
|
||||
|CTRL-Y| CTRL-Y scroll N lines downwards
|
||||
|CTRL-Z| CTRL-Z suspend program (or start new shell)
|
||||
CTRL-[ <Esc> not used
|
||||
CTRL-[ <Esc> not used
|
||||
|CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode (no-op)
|
||||
|CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode (no-op)
|
||||
CTRL-\ a - z reserved for extensions
|
||||
CTRL-\ others not used
|
||||
CTRL-\ a - z reserved for extensions
|
||||
CTRL-\ others not used
|
||||
|CTRL-]| CTRL-] :ta to ident under cursor
|
||||
|CTRL-^| CTRL-^ edit Nth alternate file (equivalent to
|
||||
":e #N")
|
||||
|CTRL-<Tab>| CTRL-<Tab> same as `g<Tab>` : go to last accessed tab
|
||||
page
|
||||
CTRL-_ not used
|
||||
|
||||
CTRL-_ not used
|
||||
|<Space>| <Space> 1 same as "l"
|
||||
|!| !{motion}{filter}
|
||||
2 filter Nmove text through the {filter}
|
||||
@@ -358,7 +355,7 @@ Tag Char Note Normal-mode action ~
|
||||
|ZZ| ZZ write if buffer changed and close window
|
||||
|ZQ| ZQ close window without writing
|
||||
|[| [{char} square bracket command (see |[| below)
|
||||
\ not used
|
||||
\ not used
|
||||
|]| ]{char} square bracket command (see |]| below)
|
||||
|^| ^ 1 cursor to the first CHAR of the line
|
||||
|_| _ 1 cursor to the first CHAR N - 1 lines lower
|
||||
@@ -523,7 +520,7 @@ Tag Command Normal-mode action ~
|
||||
|CTRL-W_CTRL-C| CTRL-W CTRL-C no-op
|
||||
|CTRL-W_CTRL-D| CTRL-W CTRL-D same as "CTRL-W d"
|
||||
|CTRL-W_CTRL-F| CTRL-W CTRL-F same as "CTRL-W f"
|
||||
CTRL-W CTRL-G same as "CTRL-W g .."
|
||||
CTRL-W CTRL-G same as "CTRL-W g .."
|
||||
|CTRL-W_CTRL-H| CTRL-W CTRL-H same as "CTRL-W h"
|
||||
|CTRL-W_CTRL-I| CTRL-W CTRL-I same as "CTRL-W i"
|
||||
|CTRL-W_CTRL-J| CTRL-W CTRL-J same as "CTRL-W j"
|
||||
@@ -662,7 +659,6 @@ Tag Char Note Normal-mode action ~
|
||||
|[z| [z 1 move to start of open fold
|
||||
|[{| [{ 1 cursor N times back to unmatched '{'
|
||||
|[<MiddleMouse>| [<MiddleMouse> 2 same as "[p"
|
||||
|
||||
|]_CTRL-D| ] CTRL-D jump to first #define found in current and
|
||||
included files matching the word under the
|
||||
cursor, start searching at cursor position
|
||||
@@ -802,7 +798,7 @@ Tag Char Note Normal-mode action ~
|
||||
non-blank character instead
|
||||
|g<Home>| g<Home> 1 same as "g0"
|
||||
|g<LeftMouse>| g<LeftMouse> ":tag" on the keyword at mouse-click
|
||||
g<MiddleMouse> same as <C-MiddleMouse>
|
||||
g<MiddleMouse> same as <C-MiddleMouse>
|
||||
|g<RightMouse>| g<RightMouse> same as <C-RightMouse>
|
||||
|g<Tab>| g<Tab> go to last accessed tabpage
|
||||
|g<Up>| g<Up> 1 same as "gk"
|
||||
@@ -1019,7 +1015,7 @@ file names, tags, commands etc. as appropriate.
|
||||
|
||||
Tag Command Command-line editing-mode action ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
CTRL-@ not used
|
||||
CTRL-@ not used
|
||||
|c_CTRL-A| CTRL-A do completion on the pattern in front of the
|
||||
cursor and insert all matches
|
||||
|c_CTRL-B| CTRL-B cursor to begin of command-line
|
||||
@@ -1051,7 +1047,7 @@ Tag Command Command-line editing-mode action ~
|
||||
|c_CTRL-N| CTRL-N after using 'wildchar' with multiple matches:
|
||||
go to next match, otherwise: recall older
|
||||
command-line from history.
|
||||
CTRL-O not used
|
||||
CTRL-O not used
|
||||
|c_CTRL-P| CTRL-P after using 'wildchar' with multiple matches:
|
||||
go to previous match, otherwise: recall older
|
||||
command-line from history.
|
||||
@@ -1064,29 +1060,28 @@ Tag Command Command-line editing-mode action ~
|
||||
|c_CTRL-R_CTRL-O| CTRL-R CTRL-O {regname}
|
||||
insert the contents of a register or object
|
||||
under the cursor literally
|
||||
CTRL-S not used, or used for terminal control flow
|
||||
CTRL-S not used, or used for terminal control flow
|
||||
|c_CTRL-T| CTRL-T previous match when 'incsearch' is active
|
||||
|c_CTRL-U| CTRL-U remove all characters between the cursor
|
||||
and beginning of command-line
|
||||
|c_CTRL-V| CTRL-V insert next non-digit literally, insert three
|
||||
digit decimal number as a single byte.
|
||||
|c_CTRL-W| CTRL-W delete the word in front of the cursor
|
||||
CTRL-X not used (reserved for completion)
|
||||
CTRL-Y copy (yank) modeless selection
|
||||
CTRL-Z not used (reserved for suspend)
|
||||
CTRL-X not used (reserved for completion)
|
||||
CTRL-Y copy (yank) modeless selection
|
||||
CTRL-Z not used (reserved for suspend)
|
||||
|c_<Esc>| <Esc> abandon command-line without executing it
|
||||
|c_CTRL-[| CTRL-[ same as <Esc>
|
||||
|c_CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode, abandon command-line
|
||||
|c_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode, abandon command-line
|
||||
CTRL-\ a - d reserved for extensions
|
||||
CTRL-\ a - d reserved for extensions
|
||||
|c_CTRL-\_e| CTRL-\ e {expr} replace the command line with the result of
|
||||
{expr}
|
||||
CTRL-\ f - z reserved for extensions
|
||||
CTRL-\ others not used
|
||||
CTRL-\ f - z reserved for extensions
|
||||
CTRL-\ others not used
|
||||
|c_CTRL-]| CTRL-] trigger abbreviation
|
||||
|c_CTRL-^| CTRL-^ toggle use of |:lmap| mappings
|
||||
|c_<Del>| <Del> delete the character under the cursor
|
||||
|
||||
|c_<Left>| <Left> cursor left
|
||||
|c_<S-Left>| <S-Left> cursor one word left
|
||||
|c_<C-Left>| <C-Left> cursor one word left
|
||||
@@ -1108,6 +1103,8 @@ Tag Command Command-line editing-mode action ~
|
||||
|
||||
commands in wildmenu mode (see 'wildmenu')
|
||||
|
||||
Char Wildmenu action ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
<Up> move up to parent
|
||||
<Down> move down to submenu
|
||||
<Left> select the previous match
|
||||
@@ -1119,6 +1116,8 @@ commands in wildmenu mode (see 'wildmenu')
|
||||
|
||||
commands in wildmenu mode with 'wildoptions' set to "pum"
|
||||
|
||||
Char Wildmenu action ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
<PageUp> select a match several entries back
|
||||
<PageDown> select a match several entries forward
|
||||
|
||||
|
||||
@@ -1199,7 +1199,7 @@ Context-sensitive completion on the command-line:
|
||||
file
|
||||
|:wN| :wN[ext][!] [file] write file and edit previous file
|
||||
|
||||
in current window in new window ~
|
||||
in current window in new window action ~
|
||||
|:argument| :argu[ment] N :sar[gument] N edit file N
|
||||
|:next| :n[ext] :sn[ext] edit next file
|
||||
|:next_f| :n[ext] {arglist} :sn[ext] {arglist} define new arg list
|
||||
|
||||
@@ -18,8 +18,6 @@ clientserver option.
|
||||
|
||||
The following command line arguments are available:
|
||||
|
||||
argument meaning ~
|
||||
|
||||
--remote [+{cmd}] {file} ... *--remote*
|
||||
Open the file list in a remote Vim. When
|
||||
there is no Vim server, execute locally.
|
||||
@@ -93,8 +91,6 @@ Vim supports additional functionality in clientserver that's not yet
|
||||
implemented in Nvim. In particular, none of the "wait" variants are supported
|
||||
yet. The following command line arguments are not yet available:
|
||||
|
||||
argument meaning ~
|
||||
|
||||
--remote-wait [+{cmd}] {file} ... *--remote-wait*
|
||||
Not yet supported by Nvim.
|
||||
As --remote, but wait for files to complete
|
||||
|
||||
@@ -12,6 +12,16 @@
|
||||
(column_heading
|
||||
(heading) @markup.heading.4)
|
||||
|
||||
; Table header: block starting with a tab-separated column_heading (see tree-sitter-vimdoc README).
|
||||
(block
|
||||
.
|
||||
(line
|
||||
(column_heading
|
||||
(heading) @markup.underline
|
||||
(#match? @markup.underline "\\S\\t")))
|
||||
.
|
||||
(line))
|
||||
|
||||
(column_heading
|
||||
(delimiter) @markup.heading.4
|
||||
(#set! conceal ""))
|
||||
|
||||
@@ -339,6 +339,52 @@ local function trim_indent(s)
|
||||
return (vim.text.indent(0, s, { expandtab = 8 }))
|
||||
end
|
||||
|
||||
--- Splits the named children of `node` into cells (tab-delimited).
|
||||
---@param node TSNode
|
||||
---@param bufnr integer
|
||||
---@return TSNode[][]
|
||||
local function get_table_cells(node, bufnr)
|
||||
local cells = { {} } ---@type TSNode[][]
|
||||
local prev ---@type TSNode?
|
||||
for child in node:iter_children() do
|
||||
if child:named() then
|
||||
local sr, sc = child:range()
|
||||
local _, _, pr, pc = (prev or child):range()
|
||||
if prev and table.concat(vim.api.nvim_buf_get_text(bufnr, pr, pc, sr, sc, {})):find('\t') then
|
||||
cells[#cells + 1] = {}
|
||||
end
|
||||
table.insert(cells[#cells], child)
|
||||
prev = child
|
||||
end
|
||||
end
|
||||
return cells
|
||||
end
|
||||
|
||||
--- Gets the rows (header first) of `block` if it is a table, else nil. Each row is a list of cells,
|
||||
--- each cell a list of nodes. See "Tables" in the tree-sitter-vimdoc README.
|
||||
---@param block TSNode
|
||||
---@param bufnr integer
|
||||
---@return TSNode[][][]?
|
||||
local function get_table(block, bufnr)
|
||||
local hdr = block:named_child(0) and block:named_child(0):named_child(0)
|
||||
if not hdr or hdr:type() ~= 'column_heading' then
|
||||
return nil
|
||||
end
|
||||
-- (column_heading (heading …) (delimiter))
|
||||
local rows = { get_table_cells(assert(hdr:named_child(0)), bufnr) } ---@type TSNode[][][]
|
||||
for i = 1, block:named_child_count() - 1 do
|
||||
local line = assert(block:named_child(i))
|
||||
local is_sep = vim.treesitter.get_node_text(line, bufnr):match('^[%s%-=~]+$')
|
||||
local row = not is_sep and get_table_cells(line, bufnr)
|
||||
if row and #row == 1 and #rows > 1 then
|
||||
vim.list_extend(rows[#rows][#rows[#rows]], row[1]) -- Wrapped line continues last cell.
|
||||
elseif row then
|
||||
rows[#rows + 1] = row
|
||||
end
|
||||
end
|
||||
return #rows[1] > 1 and #rows > 1 and rows or nil
|
||||
end
|
||||
|
||||
--- Gets raw buffer text in the node's range (+/- an offset), as a newline-delimited string.
|
||||
---@param node TSNode
|
||||
---@param bufnr integer
|
||||
@@ -596,6 +642,27 @@ local function ts_node_to_html(root, level, lang_tree, headings, opt, stats)
|
||||
-- Parent kind (string).
|
||||
local parent = root:parent() and root:parent():type() or nil
|
||||
|
||||
local table_rows = node_name == 'block' and get_table(root, opt.buf)
|
||||
if table_rows then
|
||||
local trs = {} ---@type string[]
|
||||
for i, row in ipairs(table_rows) do
|
||||
local tag = i == 1 and 'th' or 'td'
|
||||
local cells = {} ---@type string[]
|
||||
for _, cell in ipairs(row) do
|
||||
local s = ''
|
||||
for _, node in ipairs(cell) do
|
||||
s = s .. ts_node_to_html(node, level + 1, lang_tree, headings, opt, stats)
|
||||
end
|
||||
cells[#cells + 1] = ('<%s>%s</%s>'):format(tag, trim(s), tag)
|
||||
end
|
||||
trs[#trs + 1] = ('<tr>%s</tr>'):format(table.concat(cells))
|
||||
end
|
||||
return ('<table class="help-table">\n<thead>%s</thead>\n<tbody>\n%s\n</tbody>\n</table>\n'):format(
|
||||
trs[1],
|
||||
table.concat(trs, '\n', 2)
|
||||
)
|
||||
end
|
||||
|
||||
local text = ''
|
||||
local trimmed ---@type string
|
||||
if root:named_child_count() == 0 or node_name == 'ERROR' then
|
||||
@@ -899,6 +966,29 @@ local function ts_node_to_typ(root, level, lang_tree, opt, stats)
|
||||
-- Parent kind (string).
|
||||
local parent = root:parent() and root:parent():type() or nil
|
||||
|
||||
local table_rows = node_name == 'block' and get_table(root, opt.buf)
|
||||
if table_rows then
|
||||
-- Typst fills a flat cell list row by row, so pad every row to the widest row.
|
||||
local ncols = 0
|
||||
for _, row in ipairs(table_rows) do
|
||||
ncols = math.max(ncols, #row)
|
||||
end
|
||||
local trs = {} ---@type string[]
|
||||
for i, row in ipairs(table_rows) do
|
||||
local cells = {} ---@type string[]
|
||||
for j = 1, ncols do
|
||||
local s = ''
|
||||
for _, node in ipairs(row[j] or {}) do
|
||||
s = s .. ts_node_to_typ(node, level + 1, lang_tree, opt, stats)
|
||||
end
|
||||
cells[#cells + 1] = ('[%s]'):format(trim(s))
|
||||
end
|
||||
local tr = table.concat(cells, ', ')
|
||||
trs[#trs + 1] = i == 1 and ('table.header(%s),'):format(tr) or ('%s,'):format(tr)
|
||||
end
|
||||
return ('#table(columns: %d,\n %s\n)\n'):format(ncols, table.concat(trs, '\n '))
|
||||
end
|
||||
|
||||
local text = ''
|
||||
local trimmed ---@type string
|
||||
if root:named_child_count() == 0 or node_name == 'ERROR' then
|
||||
|
||||
Reference in new issue
Block a user