mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
fix(treesitter): fix most diagnostics
This commit is contained in:
parent
69bb145cea
commit
9a5678463c
@ -41,4 +41,5 @@ globals = {
|
||||
|
||||
exclude_files = {
|
||||
'test/functional/fixtures/lua/syntax_error.lua',
|
||||
'runtime/lua/vim/treesitter/_meta.lua'
|
||||
}
|
||||
|
@ -1362,7 +1362,8 @@ defer_fn({fn}, {timeout}) *vim.defer_fn()*
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (function) Callback to call once `timeout` expires
|
||||
• {timeout} integer Number of milliseconds to wait before calling `fn`
|
||||
• {timeout} (integer) Number of milliseconds to wait before calling
|
||||
`fn`
|
||||
|
||||
Return: ~
|
||||
(table) timer luv timer object
|
||||
|
@ -66,102 +66,102 @@ See |lua-treesitter-languagetree| for the list of available methods.
|
||||
|
||||
==============================================================================
|
||||
TREESITTER TREES *treesitter-tree*
|
||||
*tstree*
|
||||
*TSTree*
|
||||
|
||||
A "treesitter tree" represents the parsed contents of a buffer, which can be
|
||||
used to perform further analysis. It is a |luaref-userdata| reference to an
|
||||
object held by the tree-sitter library.
|
||||
|
||||
An instance `tstree` of a treesitter tree supports the following methods.
|
||||
An instance `TSTree` of a treesitter tree supports the following methods.
|
||||
|
||||
tstree:root() *tstree:root()*
|
||||
TSTree:root() *TSTree:root()*
|
||||
Return the root node of this tree.
|
||||
|
||||
tstree:copy() *tstree:copy()*
|
||||
Returns a copy of the `tstree`.
|
||||
TSTree:copy() *TSTree:copy()*
|
||||
Returns a copy of the `TSTree`.
|
||||
|
||||
==============================================================================
|
||||
TREESITTER NODES *treesitter-node*
|
||||
*tsnode*
|
||||
*TSNode*
|
||||
|
||||
A "treesitter node" represents one specific element of the parsed contents of
|
||||
a buffer, which can be captured by a |Query| for, e.g., highlighting. It is a
|
||||
|luaref-userdata| reference to an object held by the tree-sitter library.
|
||||
|
||||
An instance `tsnode` of a treesitter node supports the following methods.
|
||||
An instance `TSNode` of a treesitter node supports the following methods.
|
||||
|
||||
tsnode:parent() *tsnode:parent()*
|
||||
TSNode:parent() *TSNode:parent()*
|
||||
Get the node's immediate parent.
|
||||
|
||||
tsnode:next_sibling() *tsnode:next_sibling()*
|
||||
TSNode:next_sibling() *TSNode:next_sibling()*
|
||||
Get the node's next sibling.
|
||||
|
||||
tsnode:prev_sibling() *tsnode:prev_sibling()*
|
||||
TSNode:prev_sibling() *TSNode:prev_sibling()*
|
||||
Get the node's previous sibling.
|
||||
|
||||
tsnode:next_named_sibling() *tsnode:next_named_sibling()*
|
||||
TSNode:next_named_sibling() *TSNode:next_named_sibling()*
|
||||
Get the node's next named sibling.
|
||||
|
||||
tsnode:prev_named_sibling() *tsnode:prev_named_sibling()*
|
||||
TSNode:prev_named_sibling() *TSNode:prev_named_sibling()*
|
||||
Get the node's previous named sibling.
|
||||
|
||||
tsnode:iter_children() *tsnode:iter_children()*
|
||||
Iterates over all the direct children of {tsnode}, regardless of whether
|
||||
TSNode:iter_children() *TSNode:iter_children()*
|
||||
Iterates over all the direct children of {TSNode}, regardless of whether
|
||||
they are named or not.
|
||||
Returns the child node plus the eventual field name corresponding to this
|
||||
child node.
|
||||
|
||||
tsnode:field({name}) *tsnode:field()*
|
||||
TSNode:field({name}) *TSNode:field()*
|
||||
Returns a table of the nodes corresponding to the {name} field.
|
||||
|
||||
tsnode:child_count() *tsnode:child_count()*
|
||||
TSNode:child_count() *TSNode:child_count()*
|
||||
Get the node's number of children.
|
||||
|
||||
tsnode:child({index}) *tsnode:child()*
|
||||
TSNode:child({index}) *TSNode:child()*
|
||||
Get the node's child at the given {index}, where zero represents the first
|
||||
child.
|
||||
|
||||
tsnode:named_child_count() *tsnode:named_child_count()*
|
||||
TSNode:named_child_count() *TSNode:named_child_count()*
|
||||
Get the node's number of named children.
|
||||
|
||||
tsnode:named_child({index}) *tsnode:named_child()*
|
||||
TSNode:named_child({index}) *TSNode:named_child()*
|
||||
Get the node's named child at the given {index}, where zero represents the
|
||||
first named child.
|
||||
|
||||
tsnode:start() *tsnode:start()*
|
||||
TSNode:start() *TSNode:start()*
|
||||
Get the node's start position. Return three values: the row, column and
|
||||
total byte count (all zero-based).
|
||||
|
||||
tsnode:end_() *tsnode:end_()*
|
||||
TSNode:end_() *TSNode:end_()*
|
||||
Get the node's end position. Return three values: the row, column and
|
||||
total byte count (all zero-based).
|
||||
|
||||
tsnode:range() *tsnode:range()*
|
||||
TSNode:range() *TSNode:range()*
|
||||
Get the range of the node. Return four values: the row, column of the
|
||||
start position, then the row, column of the end position.
|
||||
|
||||
tsnode:type() *tsnode:type()*
|
||||
TSNode:type() *TSNode:type()*
|
||||
Get the node's type as a string.
|
||||
|
||||
tsnode:symbol() *tsnode:symbol()*
|
||||
TSNode:symbol() *TSNode:symbol()*
|
||||
Get the node's type as a numerical id.
|
||||
|
||||
tsnode:named() *tsnode:named()*
|
||||
TSNode:named() *TSNode:named()*
|
||||
Check if the node is named. Named nodes correspond to named rules in the
|
||||
grammar, whereas anonymous nodes correspond to string literals in the
|
||||
grammar.
|
||||
|
||||
tsnode:missing() *tsnode:missing()*
|
||||
TSNode:missing() *TSNode:missing()*
|
||||
Check if the node is missing. Missing nodes are inserted by the parser in
|
||||
order to recover from certain kinds of syntax errors.
|
||||
|
||||
tsnode:has_error() *tsnode:has_error()*
|
||||
TSNode:has_error() *TSNode:has_error()*
|
||||
Check if the node is a syntax error or contains any syntax errors.
|
||||
|
||||
tsnode:sexpr() *tsnode:sexpr()*
|
||||
TSNode:sexpr() *TSNode:sexpr()*
|
||||
Get an S-expression representing the node as a string.
|
||||
|
||||
tsnode:id() *tsnode:id()*
|
||||
TSNode:id() *TSNode:id()*
|
||||
Get an unique identifier for the node inside its own tree.
|
||||
|
||||
No guarantees are made about this identifier's internal representation,
|
||||
@ -171,20 +171,20 @@ tsnode:id() *tsnode:id()*
|
||||
Note: The `id` is not guaranteed to be unique for nodes from different
|
||||
trees.
|
||||
|
||||
*tsnode:descendant_for_range()*
|
||||
tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
|
||||
*TSNode:descendant_for_range()*
|
||||
TSNode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
|
||||
Get the smallest node within this node that spans the given range of (row,
|
||||
column) positions
|
||||
|
||||
*tsnode:named_descendant_for_range()*
|
||||
tsnode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
|
||||
*TSNode:named_descendant_for_range()*
|
||||
TSNode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
|
||||
Get the smallest named node within this node that spans the given range of
|
||||
(row, column) positions
|
||||
|
||||
==============================================================================
|
||||
TREESITTER QUERIES *treesitter-query*
|
||||
|
||||
Treesitter queries are a way to extract information about a parsed |tstree|,
|
||||
Treesitter queries are a way to extract information about a parsed |TSTree|,
|
||||
e.g., for the purpose of highlighting. Briefly, a `query` consists of one or
|
||||
more patterns. A `pattern` is defined over node types in the syntax tree. A
|
||||
`match` corresponds to specific elements of the syntax tree which match a
|
||||
@ -336,7 +336,7 @@ repeated, for example, the following two modeline blocks are both valid: >
|
||||
TREESITTER SYNTAX HIGHLIGHTING *treesitter-highlight*
|
||||
|
||||
Syntax highlighting is specified through queries named `highlights.scm`,
|
||||
which match a |tsnode| in the parsed |tstree| to a `capture` that can be
|
||||
which match a |TSNode| in the parsed |TSTree| to a `capture` that can be
|
||||
assigned a highlight group. For example, the query >
|
||||
|
||||
(parameters (identifier) @parameter)
|
||||
@ -486,7 +486,7 @@ get_captures_at_cursor({winnr})
|
||||
Returns a list of highlight capture names under the cursor
|
||||
|
||||
Parameters: ~
|
||||
• {winnr} (number|nil) Window handle or 0 for current window (default)
|
||||
• {winnr} (integer|nil) Window handle or 0 for current window (default)
|
||||
|
||||
Return: ~
|
||||
string[] List of capture names
|
||||
@ -500,9 +500,9 @@ get_captures_at_pos({bufnr}, {row}, {col})
|
||||
if none are defined).
|
||||
|
||||
Parameters: ~
|
||||
• {bufnr} (number) Buffer number (0 for current buffer)
|
||||
• {row} (number) Position row
|
||||
• {col} (number) Position column
|
||||
• {bufnr} (integer) Buffer number (0 for current buffer)
|
||||
• {row} (integer) Position row
|
||||
• {col} (integer) Position column
|
||||
|
||||
Return: ~
|
||||
table[] List of captures `{ capture = "capture name", metadata = { ...
|
||||
@ -512,7 +512,7 @@ get_node_at_cursor({winnr}) *vim.treesitter.get_node_at_cursor()*
|
||||
Returns the smallest named node under the cursor
|
||||
|
||||
Parameters: ~
|
||||
• {winnr} (number|nil) Window handle or 0 for current window (default)
|
||||
• {winnr} (integer|nil) Window handle or 0 for current window (default)
|
||||
|
||||
Return: ~
|
||||
(string) Name of node under the cursor
|
||||
@ -522,25 +522,28 @@ get_node_at_pos({bufnr}, {row}, {col}, {opts})
|
||||
Returns the smallest named node at the given position
|
||||
|
||||
Parameters: ~
|
||||
• {bufnr} (number) Buffer number (0 for current buffer)
|
||||
• {row} (number) Position row
|
||||
• {col} (number) Position column
|
||||
• {bufnr} (integer) Buffer number (0 for current buffer)
|
||||
• {row} (integer) Position row
|
||||
• {col} (integer) Position column
|
||||
• {opts} (table) Optional keyword arguments:
|
||||
• lang string|nil Parser language
|
||||
• ignore_injections boolean Ignore injected languages
|
||||
(default true)
|
||||
|
||||
Return: ~
|
||||
userdata|nil |tsnode| under the cursor
|
||||
|TSNode||nil under the cursor
|
||||
|
||||
get_node_range({node_or_range}) *vim.treesitter.get_node_range()*
|
||||
Returns the node's range or an unpacked range table
|
||||
|
||||
Parameters: ~
|
||||
• {node_or_range} (userdata|table) |tsnode| or table of positions
|
||||
• {node_or_range} (|TSNode||table) Node or table of positions
|
||||
|
||||
Return: ~
|
||||
(table) `{ start_row, start_col, end_row, end_col }`
|
||||
(integer) start_row
|
||||
(integer) start_col
|
||||
(integer) end_row
|
||||
(integer) end_col
|
||||
|
||||
get_parser({bufnr}, {lang}, {opts}) *vim.treesitter.get_parser()*
|
||||
Returns the parser for a specific buffer and filetype and attaches it to
|
||||
@ -549,14 +552,14 @@ get_parser({bufnr}, {lang}, {opts}) *vim.treesitter.get_parser()*
|
||||
If needed, this will create the parser.
|
||||
|
||||
Parameters: ~
|
||||
• {bufnr} (number|nil) Buffer the parser should be tied to (default:
|
||||
• {bufnr} (integer|nil) Buffer the parser should be tied to (default:
|
||||
current buffer)
|
||||
• {lang} (string|nil) Filetype of this parser (default: buffer
|
||||
filetype)
|
||||
• {opts} (table|nil) Options to pass to the created language tree
|
||||
|
||||
Return: ~
|
||||
LanguageTree |LanguageTree| object to use for parsing
|
||||
|LanguageTree| object to use for parsing
|
||||
|
||||
*vim.treesitter.get_string_parser()*
|
||||
get_string_parser({str}, {lang}, {opts})
|
||||
@ -568,14 +571,14 @@ get_string_parser({str}, {lang}, {opts})
|
||||
• {opts} (table|nil) Options to pass to the created language tree
|
||||
|
||||
Return: ~
|
||||
LanguageTree |LanguageTree| object to use for parsing
|
||||
|LanguageTree| object to use for parsing
|
||||
|
||||
is_ancestor({dest}, {source}) *vim.treesitter.is_ancestor()*
|
||||
Determines whether a node is the ancestor of another
|
||||
|
||||
Parameters: ~
|
||||
• {dest} userdata Possible ancestor |tsnode|
|
||||
• {source} userdata Possible descendant |tsnode|
|
||||
• {dest} |TSNode| Possible ancestor
|
||||
• {source} |TSNode| Possible descendant
|
||||
|
||||
Return: ~
|
||||
(boolean) True if {dest} is an ancestor of {source}
|
||||
@ -585,9 +588,9 @@ is_in_node_range({node}, {line}, {col})
|
||||
Determines whether (line, col) position is in node range
|
||||
|
||||
Parameters: ~
|
||||
• {node} userdata |tsnode| defining the range
|
||||
• {line} (number) Line (0-based)
|
||||
• {col} (number) Column (0-based)
|
||||
• {node} |TSNode| defining the range
|
||||
• {line} (integer) Line (0-based)
|
||||
• {col} (integer) Column (0-based)
|
||||
|
||||
Return: ~
|
||||
(boolean) True if the position is in node range
|
||||
@ -596,7 +599,7 @@ node_contains({node}, {range}) *vim.treesitter.node_contains()*
|
||||
Determines if a node contains a range
|
||||
|
||||
Parameters: ~
|
||||
• {node} userdata |tsnode|
|
||||
• {node} |TSNode|
|
||||
• {range} (table)
|
||||
|
||||
Return: ~
|
||||
@ -615,14 +618,14 @@ show_tree({opts}) *vim.treesitter.show_tree()*
|
||||
keys:
|
||||
• lang (string|nil): The language of the source buffer. If
|
||||
omitted, the filetype of the source buffer is used.
|
||||
• bufnr (number|nil): Buffer to draw the tree into. If
|
||||
• bufnr (integer|nil): Buffer to draw the tree into. If
|
||||
omitted, a new buffer is created.
|
||||
• winid (number|nil): Window id to display the tree buffer in.
|
||||
If omitted, a new window is created with {command}.
|
||||
• winid (integer|nil): Window id to display the tree buffer
|
||||
in. If omitted, a new window is created with {command}.
|
||||
• command (string|nil): Vimscript command to create the
|
||||
window. Default value is "topleft 60vnew". Only used when
|
||||
{winid} is nil.
|
||||
• title (string|fun(bufnr:number):string|nil): Title of the
|
||||
• title (string|fun(bufnr:integer):string|nil): Title of the
|
||||
window. If a function, it accepts the buffer number of the
|
||||
source buffer as its only argument and should return a
|
||||
string.
|
||||
@ -647,7 +650,7 @@ start({bufnr}, {lang}) *vim.treesitter.start()*
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {bufnr} (number|nil) Buffer to be highlighted (default: current
|
||||
• {bufnr} (integer|nil) Buffer to be highlighted (default: current
|
||||
buffer)
|
||||
• {lang} (string|nil) Language of the parser (default: buffer
|
||||
filetype)
|
||||
@ -656,7 +659,7 @@ stop({bufnr}) *vim.treesitter.stop()*
|
||||
Stops treesitter highlighting for a buffer
|
||||
|
||||
Parameters: ~
|
||||
• {bufnr} (number|nil) Buffer to stop highlighting (default: current
|
||||
• {bufnr} (integer|nil) Buffer to stop highlighting (default: current
|
||||
buffer)
|
||||
|
||||
|
||||
@ -709,8 +712,8 @@ add_directive({name}, {handler}, {force})
|
||||
|
||||
Parameters: ~
|
||||
• {name} (string) Name of the directive, without leading #
|
||||
• {handler} function(match:table, pattern:string, bufnr:number,
|
||||
predicate:string[], metadata:table)
|
||||
• {handler} function(match:table<string,|TSNode|>, pattern:string,
|
||||
bufnr:number, predicate:string[], metadata:table)
|
||||
• match: see |treesitter-query|
|
||||
• node-level data are accessible via `match[capture_id]`
|
||||
|
||||
@ -718,6 +721,7 @@ add_directive({name}, {handler}, {force})
|
||||
• predicate: list of strings containing the full directive
|
||||
being called, e.g. `(node (#set! conceal "-"))` would get
|
||||
the predicate `{ "#set!", "conceal", "-" }`
|
||||
• {force} (boolean)
|
||||
|
||||
*vim.treesitter.query.add_predicate()*
|
||||
add_predicate({name}, {handler}, {force})
|
||||
@ -725,17 +729,18 @@ add_predicate({name}, {handler}, {force})
|
||||
|
||||
Parameters: ~
|
||||
• {name} (string) Name of the predicate, without leading #
|
||||
• {handler} function(match:table, pattern:string, bufnr:number,
|
||||
predicate:string[])
|
||||
• {handler} function(match:table<string,|TSNode|>, pattern:string,
|
||||
bufnr:number, predicate:string[])
|
||||
• see |vim.treesitter.query.add_directive()| for argument
|
||||
meanings
|
||||
• {force} (boolean)
|
||||
|
||||
*vim.treesitter.query.get_node_text()*
|
||||
get_node_text({node}, {source}, {opts})
|
||||
Gets the text corresponding to a given node
|
||||
|
||||
Parameters: ~
|
||||
• {node} userdata |tsnode|
|
||||
• {node} |TSNode|
|
||||
• {source} (number|string) Buffer or string from which the {node} is
|
||||
extracted
|
||||
• {opts} (table|nil) Optional parameters.
|
||||
@ -743,7 +748,7 @@ get_node_text({node}, {source}, {opts})
|
||||
true)
|
||||
|
||||
Return: ~
|
||||
(string[]|string)
|
||||
(string[]|string|nil)
|
||||
|
||||
get_query({lang}, {query_name}) *vim.treesitter.query.get_query()*
|
||||
Returns the runtime query {query_name} for {lang}.
|
||||
@ -753,7 +758,7 @@ get_query({lang}, {query_name}) *vim.treesitter.query.get_query()*
|
||||
• {query_name} (string) Name of the query (e.g. "highlights")
|
||||
|
||||
Return: ~
|
||||
Query Parsed query
|
||||
Query|nil Parsed query
|
||||
|
||||
*vim.treesitter.query.get_query_files()*
|
||||
get_query_files({lang}, {query_name}, {is_included})
|
||||
@ -826,16 +831,15 @@ Query:iter_captures({self}, {node}, {source}, {start}, {stop})
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {node} userdata |tsnode| under which the search will occur
|
||||
• {source} (number|string) Source buffer or string to extract text from
|
||||
• {node} |TSNode| under which the search will occur
|
||||
• {source} (integer|string) Source buffer or string to extract text
|
||||
from
|
||||
• {start} (number) Starting line for the search
|
||||
• {stop} (number) Stopping line for the search (end-exclusive)
|
||||
• {self}
|
||||
|
||||
Return: ~
|
||||
(number) capture Matching capture id
|
||||
(table) capture_node Capture for {node}
|
||||
(table) metadata for the {capture}
|
||||
(fun(): integer, TSNode, TSMetadata ): capture id, capture node, metadata
|
||||
|
||||
*Query:iter_matches()*
|
||||
Query:iter_matches({self}, {node}, {source}, {start}, {stop})
|
||||
@ -861,16 +865,15 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop})
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {node} userdata |tsnode| under which the search will occur
|
||||
• {source} (number|string) Source buffer or string to search
|
||||
• {start} (number) Starting line for the search
|
||||
• {stop} (number) Stopping line for the search (end-exclusive)
|
||||
• {node} |TSNode| under which the search will occur
|
||||
• {source} (integer|string) Source buffer or string to search
|
||||
• {start} (integer) Starting line for the search
|
||||
• {stop} (integer) Stopping line for the search (end-exclusive)
|
||||
• {self}
|
||||
|
||||
Return: ~
|
||||
(number) pattern id
|
||||
(table) match
|
||||
(table) metadata
|
||||
(fun(): integer, table<integer,TSNode>, table): pattern id, match,
|
||||
metadata
|
||||
|
||||
*vim.treesitter.query.set_query()*
|
||||
set_query({lang}, {query_name}, {text})
|
||||
@ -892,7 +895,7 @@ new({tree}, {opts}) *vim.treesitter.highlighter.new()*
|
||||
Creates a new highlighter using
|
||||
|
||||
Parameters: ~
|
||||
• {tree} LanguageTree |LanguageTree| parser object to use for highlighting
|
||||
• {tree} |LanguageTree| parser object to use for highlighting
|
||||
• {opts} (table|nil) Configuration of the highlighter:
|
||||
• queries table overwrite queries used by the highlighter
|
||||
|
||||
@ -940,9 +943,9 @@ LanguageTree:for_each_child({self}, {fn}, {include_self})
|
||||
Invokes the callback for each |LanguageTree| and its children recursively
|
||||
|
||||
Parameters: ~
|
||||
• {fn} function(tree: LanguageTree, lang: string)
|
||||
• {include_self} (boolean) Whether to include the invoking tree in the
|
||||
results
|
||||
• {fn} fun(tree: LanguageTree, lang: string)
|
||||
• {include_self} (boolean|nil) Whether to include the invoking tree in
|
||||
the results
|
||||
• {self}
|
||||
|
||||
LanguageTree:for_each_tree({self}, {fn}) *LanguageTree:for_each_tree()*
|
||||
@ -951,7 +954,7 @@ LanguageTree:for_each_tree({self}, {fn}) *LanguageTree:for_each_tree()*
|
||||
Note: This includes the invoking tree's child trees as well.
|
||||
|
||||
Parameters: ~
|
||||
• {fn} function(tree: TSTree, languageTree: LanguageTree)
|
||||
• {fn} fun(tree: TSTree, ltree: LanguageTree)
|
||||
• {self}
|
||||
|
||||
LanguageTree:included_regions({self}) *LanguageTree:included_regions()*
|
||||
@ -964,6 +967,7 @@ LanguageTree:invalidate({self}, {reload}) *LanguageTree:invalidate()*
|
||||
Invalidates this parser and all its children
|
||||
|
||||
Parameters: ~
|
||||
• {reload} (boolean|nil)
|
||||
• {self}
|
||||
|
||||
LanguageTree:is_valid({self}) *LanguageTree:is_valid()*
|
||||
@ -987,7 +991,7 @@ LanguageTree:language_for_range({self}, {range})
|
||||
• {self}
|
||||
|
||||
Return: ~
|
||||
LanguageTree Managing {range}
|
||||
|LanguageTree| Managing {range}
|
||||
|
||||
*LanguageTree:named_node_for_range()*
|
||||
LanguageTree:named_node_for_range({self}, {range}, {opts})
|
||||
@ -1001,7 +1005,7 @@ LanguageTree:named_node_for_range({self}, {range}, {opts})
|
||||
• {self}
|
||||
|
||||
Return: ~
|
||||
userdata|nil Found |tsnode|
|
||||
|TSNode||nil Found node
|
||||
|
||||
LanguageTree:parse({self}) *LanguageTree:parse()*
|
||||
Parses all defined regions using a treesitter parser for the language this
|
||||
@ -1012,8 +1016,8 @@ LanguageTree:parse({self}) *LanguageTree:parse()*
|
||||
• {self}
|
||||
|
||||
Return: ~
|
||||
userdata[] Table of parsed |tstree|
|
||||
(table) Change list
|
||||
TSTree[]
|
||||
(table|nil) Change list
|
||||
|
||||
LanguageTree:register_cbs({self}, {cbs}) *LanguageTree:register_cbs()*
|
||||
Registers callbacks for the |LanguageTree|.
|
||||
@ -1050,7 +1054,7 @@ LanguageTree:tree_for_range({self}, {range}, {opts})
|
||||
• {self}
|
||||
|
||||
Return: ~
|
||||
userdata|nil Contained |tstree|
|
||||
TSTree|nil
|
||||
|
||||
LanguageTree:trees({self}) *LanguageTree:trees()*
|
||||
Returns all trees this language tree contains. Does not include child
|
||||
@ -1065,7 +1069,7 @@ new({source}, {lang}, {opts}) *vim.treesitter.languagetree.new()*
|
||||
may contain child languages themselves, hence the name).
|
||||
|
||||
Parameters: ~
|
||||
• {source} (number|string) Buffer or a string of text to parse
|
||||
• {source} (integer|string) Buffer or a string of text to parse
|
||||
• {lang} (string) Root language this tree represents
|
||||
• {opts} (table|nil) Optional keyword arguments:
|
||||
• injections table Mapping language to injection query
|
||||
@ -1074,6 +1078,6 @@ new({source}, {lang}, {opts}) *vim.treesitter.languagetree.new()*
|
||||
per language.
|
||||
|
||||
Return: ~
|
||||
LanguageTree |LanguageTree| parser object
|
||||
|LanguageTree| parser object
|
||||
|
||||
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
|
||||
|
@ -3,8 +3,11 @@ local query = require('vim.treesitter.query')
|
||||
local language = require('vim.treesitter.language')
|
||||
local LanguageTree = require('vim.treesitter.languagetree')
|
||||
|
||||
---@type table<integer,LanguageTree>
|
||||
local parsers = setmetatable({}, { __mode = 'v' })
|
||||
|
||||
---@class TreesitterModule
|
||||
---@field highlighter TSHighlighter
|
||||
local M = vim.tbl_extend('error', query, language)
|
||||
|
||||
M.language_version = vim._ts_get_language_version()
|
||||
@ -12,6 +15,7 @@ M.minimum_language_version = vim._ts_get_minimum_language_version()
|
||||
|
||||
setmetatable(M, {
|
||||
__index = function(t, k)
|
||||
---@diagnostic disable:no-unknown
|
||||
if k == 'highlighter' then
|
||||
t[k] = require('vim.treesitter.highlighter')
|
||||
return t[k]
|
||||
@ -29,21 +33,23 @@ setmetatable(M, {
|
||||
---
|
||||
--- It is not recommended to use this; use |get_parser()| instead.
|
||||
---
|
||||
---@param bufnr string Buffer the parser will be tied to (0 for current buffer)
|
||||
---@param bufnr integer Buffer the parser will be tied to (0 for current buffer)
|
||||
---@param lang string Language of the parser
|
||||
---@param opts (table|nil) Options to pass to the created language tree
|
||||
---
|
||||
---@return LanguageTree |LanguageTree| object to use for parsing
|
||||
---@return LanguageTree object to use for parsing
|
||||
function M._create_parser(bufnr, lang, opts)
|
||||
language.require_language(lang)
|
||||
if bufnr == 0 then
|
||||
bufnr = a.nvim_get_current_buf()
|
||||
bufnr = vim.api.nvim_get_current_buf()
|
||||
end
|
||||
|
||||
vim.fn.bufload(bufnr)
|
||||
|
||||
local self = LanguageTree.new(bufnr, lang, opts)
|
||||
|
||||
---@diagnostic disable:invisible
|
||||
|
||||
---@private
|
||||
local function bytes_cb(_, ...)
|
||||
self:_on_bytes(...)
|
||||
@ -58,12 +64,14 @@ function M._create_parser(bufnr, lang, opts)
|
||||
end
|
||||
|
||||
---@private
|
||||
local function reload_cb(_, ...)
|
||||
self:_on_reload(...)
|
||||
local function reload_cb(_)
|
||||
self:_on_reload()
|
||||
end
|
||||
|
||||
local source = self:source() --[[@as integer]]
|
||||
|
||||
a.nvim_buf_attach(
|
||||
self:source(),
|
||||
source,
|
||||
false,
|
||||
{ on_bytes = bytes_cb, on_detach = detach_cb, on_reload = reload_cb, preview = true }
|
||||
)
|
||||
@ -77,11 +85,11 @@ end
|
||||
---
|
||||
--- If needed, this will create the parser.
|
||||
---
|
||||
---@param bufnr (number|nil) Buffer the parser should be tied to (default: current buffer)
|
||||
---@param bufnr (integer|nil) Buffer the parser should be tied to (default: current buffer)
|
||||
---@param lang (string|nil) Filetype of this parser (default: buffer filetype)
|
||||
---@param opts (table|nil) Options to pass to the created language tree
|
||||
---
|
||||
---@return LanguageTree |LanguageTree| object to use for parsing
|
||||
---@return LanguageTree object to use for parsing
|
||||
function M.get_parser(bufnr, lang, opts)
|
||||
opts = opts or {}
|
||||
|
||||
@ -107,7 +115,7 @@ end
|
||||
---@param lang string Language of this string
|
||||
---@param opts (table|nil) Options to pass to the created language tree
|
||||
---
|
||||
---@return LanguageTree |LanguageTree| object to use for parsing
|
||||
---@return LanguageTree object to use for parsing
|
||||
function M.get_string_parser(str, lang, opts)
|
||||
vim.validate({
|
||||
str = { str, 'string' },
|
||||
@ -120,8 +128,8 @@ end
|
||||
|
||||
--- Determines whether a node is the ancestor of another
|
||||
---
|
||||
---@param dest userdata Possible ancestor |tsnode|
|
||||
---@param source userdata Possible descendant |tsnode|
|
||||
---@param dest TSNode Possible ancestor
|
||||
---@param source TSNode Possible descendant
|
||||
---
|
||||
---@return boolean True if {dest} is an ancestor of {source}
|
||||
function M.is_ancestor(dest, source)
|
||||
@ -143,9 +151,12 @@ end
|
||||
|
||||
--- Returns the node's range or an unpacked range table
|
||||
---
|
||||
---@param node_or_range (userdata|table) |tsnode| or table of positions
|
||||
---@param node_or_range (TSNode|table) Node or table of positions
|
||||
---
|
||||
---@return table `{ start_row, start_col, end_row, end_col }`
|
||||
---@return integer start_row
|
||||
---@return integer start_col
|
||||
---@return integer end_row
|
||||
---@return integer end_col
|
||||
function M.get_node_range(node_or_range)
|
||||
if type(node_or_range) == 'table' then
|
||||
return unpack(node_or_range)
|
||||
@ -156,9 +167,9 @@ end
|
||||
|
||||
--- Determines whether (line, col) position is in node range
|
||||
---
|
||||
---@param node userdata |tsnode| defining the range
|
||||
---@param line number Line (0-based)
|
||||
---@param col number Column (0-based)
|
||||
---@param node TSNode defining the range
|
||||
---@param line integer Line (0-based)
|
||||
---@param col integer Column (0-based)
|
||||
---
|
||||
---@return boolean True if the position is in node range
|
||||
function M.is_in_node_range(node, line, col)
|
||||
@ -180,7 +191,7 @@ end
|
||||
|
||||
--- Determines if a node contains a range
|
||||
---
|
||||
---@param node userdata |tsnode|
|
||||
---@param node TSNode
|
||||
---@param range table
|
||||
---
|
||||
---@return boolean True if the {node} contains the {range}
|
||||
@ -197,9 +208,9 @@ end
|
||||
--- Each capture is represented by a table containing the capture name as a string as
|
||||
--- well as a table of metadata (`priority`, `conceal`, ...; empty if none are defined).
|
||||
---
|
||||
---@param bufnr number Buffer number (0 for current buffer)
|
||||
---@param row number Position row
|
||||
---@param col number Position column
|
||||
---@param bufnr integer Buffer number (0 for current buffer)
|
||||
---@param row integer Position row
|
||||
---@param col integer Position column
|
||||
---
|
||||
---@return table[] List of captures `{ capture = "capture name", metadata = { ... } }`
|
||||
function M.get_captures_at_pos(bufnr, row, col)
|
||||
@ -250,7 +261,7 @@ end
|
||||
|
||||
--- Returns a list of highlight capture names under the cursor
|
||||
---
|
||||
---@param winnr (number|nil) Window handle or 0 for current window (default)
|
||||
---@param winnr (integer|nil) Window handle or 0 for current window (default)
|
||||
---
|
||||
---@return string[] List of capture names
|
||||
function M.get_captures_at_cursor(winnr)
|
||||
@ -271,14 +282,14 @@ end
|
||||
|
||||
--- Returns the smallest named node at the given position
|
||||
---
|
||||
---@param bufnr number Buffer number (0 for current buffer)
|
||||
---@param row number Position row
|
||||
---@param col number Position column
|
||||
---@param bufnr integer Buffer number (0 for current buffer)
|
||||
---@param row integer Position row
|
||||
---@param col integer Position column
|
||||
---@param opts table Optional keyword arguments:
|
||||
--- - lang string|nil Parser language
|
||||
--- - ignore_injections boolean Ignore injected languages (default true)
|
||||
---
|
||||
---@return userdata|nil |tsnode| under the cursor
|
||||
---@return TSNode|nil under the cursor
|
||||
function M.get_node_at_pos(bufnr, row, col, opts)
|
||||
if bufnr == 0 then
|
||||
bufnr = a.nvim_get_current_buf()
|
||||
@ -295,7 +306,7 @@ end
|
||||
|
||||
--- Returns the smallest named node under the cursor
|
||||
---
|
||||
---@param winnr (number|nil) Window handle or 0 for current window (default)
|
||||
---@param winnr (integer|nil) Window handle or 0 for current window (default)
|
||||
---
|
||||
---@return string Name of node under the cursor
|
||||
function M.get_node_at_cursor(winnr)
|
||||
@ -323,7 +334,7 @@ end
|
||||
--- })
|
||||
--- </pre>
|
||||
---
|
||||
---@param bufnr (number|nil) Buffer to be highlighted (default: current buffer)
|
||||
---@param bufnr (integer|nil) Buffer to be highlighted (default: current buffer)
|
||||
---@param lang (string|nil) Language of the parser (default: buffer filetype)
|
||||
function M.start(bufnr, lang)
|
||||
bufnr = bufnr or a.nvim_get_current_buf()
|
||||
@ -333,7 +344,7 @@ end
|
||||
|
||||
--- Stops treesitter highlighting for a buffer
|
||||
---
|
||||
---@param bufnr (number|nil) Buffer to stop highlighting (default: current buffer)
|
||||
---@param bufnr (integer|nil) Buffer to stop highlighting (default: current buffer)
|
||||
function M.stop(bufnr)
|
||||
bufnr = bufnr or a.nvim_get_current_buf()
|
||||
|
||||
@ -351,13 +362,13 @@ end
|
||||
---@param opts table|nil Optional options table with the following possible keys:
|
||||
--- - lang (string|nil): The language of the source buffer. If omitted, the
|
||||
--- filetype of the source buffer is used.
|
||||
--- - bufnr (number|nil): Buffer to draw the tree into. If omitted, a new
|
||||
--- - bufnr (integer|nil): Buffer to draw the tree into. If omitted, a new
|
||||
--- buffer is created.
|
||||
--- - winid (number|nil): Window id to display the tree buffer in. If omitted,
|
||||
--- - winid (integer|nil): Window id to display the tree buffer in. If omitted,
|
||||
--- a new window is created with {command}.
|
||||
--- - command (string|nil): Vimscript command to create the window. Default
|
||||
--- value is "topleft 60vnew". Only used when {winid} is nil.
|
||||
--- - title (string|fun(bufnr:number):string|nil): Title of the window. If a
|
||||
--- - title (string|fun(bufnr:integer):string|nil): Title of the window. If a
|
||||
--- function, it accepts the buffer number of the source buffer as its only
|
||||
--- argument and should return a string.
|
||||
function M.show_tree(opts)
|
||||
|
60
runtime/lua/vim/treesitter/_meta.lua
Normal file
60
runtime/lua/vim/treesitter/_meta.lua
Normal file
@ -0,0 +1,60 @@
|
||||
---@meta
|
||||
|
||||
---@class TSNode
|
||||
---@field id fun(self: TSNode): integer
|
||||
---@field range fun(self: TSNode): integer, integer, integer, integer
|
||||
---@field start fun(self: TSNode): integer, integer, integer
|
||||
---@field end_ fun(self: TSNode): integer, integer, integer
|
||||
---@field type fun(self: TSNode): string
|
||||
---@field symbol fun(self: TSNode): integer
|
||||
---@field named fun(self: TSNode): boolean
|
||||
---@field missing fun(self: TSNode): boolean
|
||||
---@field child_count fun(self: TSNode): integer
|
||||
---@field named_child_count fun(self: TSNode): integer
|
||||
---@field child fun(self: TSNode, integer): TSNode
|
||||
---@field name_child fun(self: TSNode, integer): TSNode
|
||||
---@field descendant_for_range fun(self: TSNode, integer, integer, integer, integer): TSNode
|
||||
---@field named_descendant_for_range fun(self: TSNode, integer, integer, integer, integer): TSNode
|
||||
---@field parent fun(self: TSNode): TSNode
|
||||
---@field next_sibling fun(self: TSNode): TSNode
|
||||
---@field prev_sibling fun(self: TSNode): TSNode
|
||||
---@field next_named_sibling fun(self: TSNode): TSNode
|
||||
---@field prev_named_sibling fun(self: TSNode): TSNode
|
||||
---@field named_children fun(self: TSNode): TSNode[]
|
||||
---@field has_error fun(self: TSNode): boolean
|
||||
---@field iter_children fun(self: TSNode): fun(): TSNode, string
|
||||
local TSNode = {}
|
||||
|
||||
---@param query userdata
|
||||
---@param captures true
|
||||
---@param start integer
|
||||
---@param end_ integer
|
||||
---@return fun(): integer, TSNode, any
|
||||
function TSNode:_rawquery(query, captures, start, end_) end
|
||||
|
||||
---@param query userdata
|
||||
---@param captures false
|
||||
---@param start integer
|
||||
---@param end_ integer
|
||||
---@return fun(): string, any
|
||||
function TSNode:_rawquery(query, captures, start, end_) end
|
||||
|
||||
---@class TSParser
|
||||
---@field parse fun(self: TSParser, tree, source: integer|string): TSTree, integer[]
|
||||
---@field included_ranges fun(self: TSParser): integer[]
|
||||
---@field set_included_ranges fun(self: TSParser, ranges: integer[][])
|
||||
|
||||
---@class TSTree
|
||||
---@field root fun(self: TSTree): TSNode
|
||||
---@field edit fun(self: TSTree, _: integer, _: integer, _: integer, _: integer, _: integer, _: integer, _: integer, _: integer, _:integer)
|
||||
---@field copy fun(self: TSTree): TSTree
|
||||
|
||||
---@return integer
|
||||
vim._ts_get_language_version = function() end
|
||||
|
||||
---@return integer
|
||||
vim._ts_get_minimum_language_version = function() end
|
||||
|
||||
---@param lang string
|
||||
---@return TSParser
|
||||
vim._create_ts_parser = function(lang) end
|
@ -1,13 +1,27 @@
|
||||
local a = vim.api
|
||||
local query = require('vim.treesitter.query')
|
||||
|
||||
-- support reload for quick experimentation
|
||||
---@alias TSHlIter fun(): integer, TSNode, TSMetadata
|
||||
|
||||
---@class TSHighlightState
|
||||
---@field next_row integer
|
||||
---@field iter TSHlIter|nil
|
||||
|
||||
---@class TSHighlighter
|
||||
---@field active table<integer,TSHighlighter>
|
||||
---@field bufnr integer
|
||||
---@field orig_spelloptions string
|
||||
---@field _highlight_states table<TSTree,TSHighlightState>
|
||||
---@field _queries table<string,TSHighlighterQuery>
|
||||
---@field tree LanguageTree
|
||||
local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {}
|
||||
TSHighlighter.__index = TSHighlighter
|
||||
|
||||
TSHighlighter.active = TSHighlighter.active or {}
|
||||
|
||||
---@class TSHighlighterQuery
|
||||
---@field _query Query|nil
|
||||
---@field hl_cache table<integer,integer>
|
||||
local TSHighlighterQuery = {}
|
||||
TSHighlighterQuery.__index = TSHighlighterQuery
|
||||
|
||||
@ -46,7 +60,7 @@ end
|
||||
|
||||
--- Creates a new highlighter using @param tree
|
||||
---
|
||||
---@param tree LanguageTree |LanguageTree| parser object to use for highlighting
|
||||
---@param tree LanguageTree parser object to use for highlighting
|
||||
---@param opts (table|nil) Configuration of the highlighter:
|
||||
--- - queries table overwrite queries used by the highlighter
|
||||
---@return TSHighlighter Created highlighter object
|
||||
@ -57,9 +71,10 @@ function TSHighlighter.new(tree, opts)
|
||||
error('TSHighlighter can not be used with a string parser source.')
|
||||
end
|
||||
|
||||
opts = opts or {}
|
||||
opts = opts or {} ---@type { queries: table<string,string> }
|
||||
self.tree = tree
|
||||
tree:register_cbs({
|
||||
---@diagnostic disable:invisible
|
||||
on_changedtree = function(...)
|
||||
self:on_changedtree(...)
|
||||
end,
|
||||
@ -67,17 +82,20 @@ function TSHighlighter.new(tree, opts)
|
||||
self:on_bytes(...)
|
||||
end,
|
||||
on_detach = function(...)
|
||||
---@diagnostic disable-next-line:redundant-parameter
|
||||
self:on_detach(...)
|
||||
end,
|
||||
})
|
||||
|
||||
self.bufnr = tree:source()
|
||||
self.bufnr = tree:source() --[[@as integer]]
|
||||
self.edit_count = 0
|
||||
self.redraw_count = 0
|
||||
self.line_count = {}
|
||||
-- A map of highlight states.
|
||||
-- This state is kept during rendering across each line update.
|
||||
self._highlight_states = {}
|
||||
|
||||
---@type table<string,TSHighlighterQuery>
|
||||
self._queries = {}
|
||||
|
||||
-- Queries for a specific language can be overridden by a custom
|
||||
@ -128,6 +146,8 @@ function TSHighlighter:destroy()
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param tstree TSTree
|
||||
---@return TSHighlightState
|
||||
function TSHighlighter:get_highlight_state(tstree)
|
||||
if not self._highlight_states[tstree] then
|
||||
self._highlight_states[tstree] = {
|
||||
@ -145,6 +165,8 @@ function TSHighlighter:reset_highlight_state()
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param start_row integer
|
||||
---@param new_end integer
|
||||
function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end)
|
||||
a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1)
|
||||
end
|
||||
@ -155,6 +177,7 @@ function TSHighlighter:on_detach()
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param changes integer[][]?
|
||||
function TSHighlighter:on_changedtree(changes)
|
||||
for _, ch in ipairs(changes or {}) do
|
||||
a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1)
|
||||
@ -165,7 +188,7 @@ end
|
||||
--
|
||||
---@private
|
||||
---@param lang string Language used by the highlighter.
|
||||
---@return Query
|
||||
---@return TSHighlighterQuery
|
||||
function TSHighlighter:get_query(lang)
|
||||
if not self._queries[lang] then
|
||||
self._queries[lang] = TSHighlighterQuery.new(lang)
|
||||
@ -175,7 +198,12 @@ function TSHighlighter:get_query(lang)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param self TSHighlighter
|
||||
---@param buf integer
|
||||
---@param line integer
|
||||
---@param is_spell_nav boolean
|
||||
local function on_line_impl(self, buf, line, is_spell_nav)
|
||||
---@diagnostic disable:invisible
|
||||
self.tree:for_each_tree(function(tstree, tree)
|
||||
if not tstree then
|
||||
return
|
||||
@ -213,7 +241,7 @@ local function on_line_impl(self, buf, line, is_spell_nav)
|
||||
local hl = highlighter_query.hl_cache[capture]
|
||||
|
||||
local capture_name = highlighter_query:query().captures[capture]
|
||||
local spell = nil
|
||||
local spell = nil ---@type boolean?
|
||||
if capture_name == 'spell' then
|
||||
spell = true
|
||||
elseif capture_name == 'nospell' then
|
||||
@ -242,6 +270,9 @@ local function on_line_impl(self, buf, line, is_spell_nav)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param _win integer
|
||||
---@param buf integer
|
||||
---@param line integer
|
||||
function TSHighlighter._on_line(_, _win, buf, line, _)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then
|
||||
@ -252,6 +283,9 @@ function TSHighlighter._on_line(_, _win, buf, line, _)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param buf integer
|
||||
---@param srow integer
|
||||
---@param erow integer
|
||||
function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then
|
||||
@ -266,6 +300,7 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param buf integer
|
||||
function TSHighlighter._on_buf(_, buf)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if self then
|
||||
@ -274,6 +309,9 @@ function TSHighlighter._on_buf(_, buf)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param _win integer
|
||||
---@param buf integer
|
||||
---@param _topline integer
|
||||
function TSHighlighter._on_win(_, _win, buf, _topline)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then
|
||||
|
@ -2,20 +2,39 @@ local a = vim.api
|
||||
local query = require('vim.treesitter.query')
|
||||
local language = require('vim.treesitter.language')
|
||||
|
||||
---@class LanguageTree
|
||||
---@field _callbacks function[] Callback handlers
|
||||
---@field _children LanguageTree[] Injected languages
|
||||
---@field _injection_query table Queries defining injected languages
|
||||
---@field _opts table Options
|
||||
---@field _parser userdata Parser for language
|
||||
---@field _regions table List of regions this tree should manage and parse
|
||||
---@field _lang string Language name
|
||||
---@field _regions table
|
||||
---@field _source (number|string) Buffer or string to parse
|
||||
---@field _trees userdata[] Reference to parsed |tstree| (one for each language)
|
||||
---@field _valid boolean If the parsed tree is valid
|
||||
---@alias Range {[1]: integer, [2]: integer, [3]: integer, [4]: integer}
|
||||
--
|
||||
---@alias TSCallbackName
|
||||
---| 'changedtree'
|
||||
---| 'bytes'
|
||||
---| 'detach'
|
||||
---| 'child_added'
|
||||
---| 'child_removed'
|
||||
|
||||
---@alias TSCallbackNameOn
|
||||
---| 'on_changedtree'
|
||||
---| 'on_bytes'
|
||||
---| 'on_detach'
|
||||
---| 'on_child_added'
|
||||
---| 'on_child_removed'
|
||||
|
||||
---@class LanguageTree
|
||||
---@field private _callbacks table<TSCallbackName,function[]> Callback handlers
|
||||
---@field private _children table<string,LanguageTree> Injected languages
|
||||
---@field private _injection_query Query Queries defining injected languages
|
||||
---@field private _opts table Options
|
||||
---@field private _parser TSParser Parser for language
|
||||
---@field private _regions Range[][] List of regions this tree should manage and parse
|
||||
---@field private _lang string Language name
|
||||
---@field private _source (integer|string) Buffer or string to parse
|
||||
---@field private _trees TSTree[] Reference to parsed tree (one for each language)
|
||||
---@field private _valid boolean If the parsed tree is valid
|
||||
local LanguageTree = {}
|
||||
|
||||
---@class LanguageTreeOpts
|
||||
---@field queries table<string,string> -- Deprecated
|
||||
---@field injections table<string,string>
|
||||
|
||||
LanguageTree.__index = LanguageTree
|
||||
|
||||
--- A |LanguageTree| holds the treesitter parser for a given language {lang} used
|
||||
@ -23,16 +42,17 @@ LanguageTree.__index = LanguageTree
|
||||
--- needs to store parsers for these child languages as well (which in turn may contain
|
||||
--- child languages themselves, hence the name).
|
||||
---
|
||||
---@param source (number|string) Buffer or a string of text to parse
|
||||
---@param source (integer|string) Buffer or a string of text to parse
|
||||
---@param lang string Root language this tree represents
|
||||
---@param opts (table|nil) Optional keyword arguments:
|
||||
--- - injections table Mapping language to injection query strings.
|
||||
--- This is useful for overriding the built-in
|
||||
--- runtime file searching for the injection language
|
||||
--- query per language.
|
||||
---@return LanguageTree |LanguageTree| parser object
|
||||
---@return LanguageTree parser object
|
||||
function LanguageTree.new(source, lang, opts)
|
||||
language.require_language(lang)
|
||||
---@type LanguageTreeOpts
|
||||
opts = opts or {}
|
||||
|
||||
if opts.queries then
|
||||
@ -65,6 +85,7 @@ function LanguageTree.new(source, lang, opts)
|
||||
end
|
||||
|
||||
--- Invalidates this parser and all its children
|
||||
---@param reload boolean|nil
|
||||
function LanguageTree:invalidate(reload)
|
||||
self._valid = false
|
||||
|
||||
@ -73,7 +94,7 @@ function LanguageTree:invalidate(reload)
|
||||
self._trees = {}
|
||||
end
|
||||
|
||||
for _, child in ipairs(self._children) do
|
||||
for _, child in pairs(self._children) do
|
||||
child:invalidate(reload)
|
||||
end
|
||||
end
|
||||
@ -111,8 +132,8 @@ end
|
||||
--- This will run the injection query for this language to
|
||||
--- determine if any child languages should be created.
|
||||
---
|
||||
---@return userdata[] Table of parsed |tstree|
|
||||
---@return table Change list
|
||||
---@return TSTree[]
|
||||
---@return table|nil Change list
|
||||
function LanguageTree:parse()
|
||||
if self._valid then
|
||||
return self._trees
|
||||
@ -146,7 +167,7 @@ function LanguageTree:parse()
|
||||
end
|
||||
|
||||
local injections_by_lang = self:_get_injections()
|
||||
local seen_langs = {}
|
||||
local seen_langs = {} ---@type table<string,boolean>
|
||||
|
||||
for lang, injection_ranges in pairs(injections_by_lang) do
|
||||
local has_lang = language.require_language(lang, nil, true)
|
||||
@ -188,8 +209,8 @@ end
|
||||
|
||||
--- Invokes the callback for each |LanguageTree| and its children recursively
|
||||
---
|
||||
---@param fn function(tree: LanguageTree, lang: string)
|
||||
---@param include_self boolean Whether to include the invoking tree in the results
|
||||
---@param fn fun(tree: LanguageTree, lang: string)
|
||||
---@param include_self boolean|nil Whether to include the invoking tree in the results
|
||||
function LanguageTree:for_each_child(fn, include_self)
|
||||
if include_self then
|
||||
fn(self, self._lang)
|
||||
@ -204,7 +225,7 @@ end
|
||||
---
|
||||
--- Note: This includes the invoking tree's child trees as well.
|
||||
---
|
||||
---@param fn function(tree: TSTree, languageTree: LanguageTree)
|
||||
---@param fn fun(tree: TSTree, ltree: LanguageTree)
|
||||
function LanguageTree:for_each_tree(fn)
|
||||
for _, tree in ipairs(self._trees) do
|
||||
fn(tree, self)
|
||||
@ -221,7 +242,7 @@ end
|
||||
---
|
||||
---@private
|
||||
---@param lang string Language to add.
|
||||
---@return LanguageTree Injected |LanguageTree|
|
||||
---@return LanguageTree injected
|
||||
function LanguageTree:add_child(lang)
|
||||
if self._children[lang] then
|
||||
self:remove_child(lang)
|
||||
@ -258,7 +279,7 @@ end
|
||||
--- `remove_child` must be called on the parent to remove it.
|
||||
function LanguageTree:destroy()
|
||||
-- Cleanup here
|
||||
for _, child in ipairs(self._children) do
|
||||
for _, child in pairs(self._children) do
|
||||
child:destroy()
|
||||
end
|
||||
end
|
||||
@ -280,20 +301,22 @@ end
|
||||
--- Note: This call invalidates the tree and requires it to be parsed again.
|
||||
---
|
||||
---@private
|
||||
---@param regions table List of regions this tree should manage and parse.
|
||||
---@param regions integer[][][] List of regions this tree should manage and parse.
|
||||
function LanguageTree:set_included_regions(regions)
|
||||
-- Transform the tables from 4 element long to 6 element long (with byte offset)
|
||||
for _, region in ipairs(regions) do
|
||||
for i, range in ipairs(region) do
|
||||
if type(range) == 'table' and #range == 4 then
|
||||
---@diagnostic disable-next-line:no-unknown
|
||||
local start_row, start_col, end_row, end_col = unpack(range)
|
||||
local start_byte = 0
|
||||
local end_byte = 0
|
||||
local source = self._source
|
||||
-- TODO(vigoux): proper byte computation here, and account for EOL ?
|
||||
if type(self._source) == 'number' then
|
||||
if type(source) == 'number' then
|
||||
-- Easy case, this is a buffer parser
|
||||
start_byte = a.nvim_buf_get_offset(self._source, start_row) + start_col
|
||||
end_byte = a.nvim_buf_get_offset(self._source, end_row) + end_col
|
||||
start_byte = a.nvim_buf_get_offset(source, start_row) + start_col
|
||||
end_byte = a.nvim_buf_get_offset(source, end_row) + end_col
|
||||
elseif type(self._source) == 'string' then
|
||||
-- string parser, single `\n` delimited string
|
||||
start_byte = vim.fn.byteidx(self._source, start_col)
|
||||
@ -320,9 +343,13 @@ function LanguageTree:included_regions()
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param node TSNode
|
||||
---@param id integer
|
||||
---@param metadata TSMetadata
|
||||
---@return Range
|
||||
local function get_range_from_metadata(node, id, metadata)
|
||||
if metadata[id] and metadata[id].range then
|
||||
return metadata[id].range
|
||||
return metadata[id].range --[[@as Range]]
|
||||
end
|
||||
return { node:range() }
|
||||
end
|
||||
@ -334,11 +361,13 @@ end
|
||||
--- TODO: Allow for an offset predicate to tailor the injection range
|
||||
--- instead of using the entire nodes range.
|
||||
---@private
|
||||
---@return table<string, integer[][]>
|
||||
function LanguageTree:_get_injections()
|
||||
if not self._injection_query then
|
||||
return {}
|
||||
end
|
||||
|
||||
---@type table<integer,table<string,table<integer,table>>>
|
||||
local injections = {}
|
||||
|
||||
for tree_index, tree in ipairs(self._trees) do
|
||||
@ -348,14 +377,14 @@ function LanguageTree:_get_injections()
|
||||
for pattern, match, metadata in
|
||||
self._injection_query:iter_matches(root_node, self._source, start_line, end_line + 1)
|
||||
do
|
||||
local lang = nil
|
||||
local ranges = {}
|
||||
local combined = metadata.combined
|
||||
local lang = nil ---@type string
|
||||
local ranges = {} ---@type Range[]
|
||||
local combined = metadata.combined ---@type boolean
|
||||
|
||||
-- Directives can configure how injections are captured as well as actual node captures.
|
||||
-- This allows more advanced processing for determining ranges and language resolution.
|
||||
if metadata.content then
|
||||
local content = metadata.content
|
||||
local content = metadata.content ---@type any
|
||||
|
||||
-- Allow for captured nodes to be used
|
||||
if type(content) == 'number' then
|
||||
@ -368,7 +397,7 @@ function LanguageTree:_get_injections()
|
||||
end
|
||||
|
||||
if metadata.language then
|
||||
lang = metadata.language
|
||||
lang = metadata.language ---@type string
|
||||
end
|
||||
|
||||
-- You can specify the content and language together
|
||||
@ -379,7 +408,7 @@ function LanguageTree:_get_injections()
|
||||
|
||||
-- Lang should override any other language tag
|
||||
if name == 'language' and not lang then
|
||||
lang = query.get_node_text(node, self._source)
|
||||
lang = query.get_node_text(node, self._source) --[[@as string]]
|
||||
elseif name == 'combined' then
|
||||
combined = true
|
||||
elseif name == 'content' and #ranges == 0 then
|
||||
@ -417,6 +446,7 @@ function LanguageTree:_get_injections()
|
||||
end
|
||||
end
|
||||
|
||||
---@type table<string,Range[][]>
|
||||
local result = {}
|
||||
|
||||
-- Generate a map by lang of node lists.
|
||||
@ -429,11 +459,13 @@ function LanguageTree:_get_injections()
|
||||
|
||||
for _, entry in pairs(patterns) do
|
||||
if entry.combined then
|
||||
---@diagnostic disable-next-line:no-unknown
|
||||
local regions = vim.tbl_map(function(e)
|
||||
return vim.tbl_flatten(e)
|
||||
end, entry.regions)
|
||||
table.insert(result[lang], regions)
|
||||
else
|
||||
---@diagnostic disable-next-line:no-unknown
|
||||
for _, ranges in ipairs(entry.regions) do
|
||||
table.insert(result[lang], ranges)
|
||||
end
|
||||
@ -446,6 +478,7 @@ function LanguageTree:_get_injections()
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param cb_name TSCallbackName
|
||||
function LanguageTree:_do_callback(cb_name, ...)
|
||||
for _, cb in ipairs(self._callbacks[cb_name]) do
|
||||
cb(...)
|
||||
@ -453,6 +486,17 @@ function LanguageTree:_do_callback(cb_name, ...)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param bufnr integer
|
||||
---@param changed_tick integer
|
||||
---@param start_row integer
|
||||
---@param start_col integer
|
||||
---@param start_byte integer
|
||||
---@param old_row integer
|
||||
---@param old_col integer
|
||||
---@param old_byte integer
|
||||
---@param new_row integer
|
||||
---@param new_col integer
|
||||
---@param new_byte integer
|
||||
function LanguageTree:_on_bytes(
|
||||
bufnr,
|
||||
changed_tick,
|
||||
@ -523,6 +567,7 @@ end
|
||||
--- - `on_child_added` : emitted when a child is added to the tree.
|
||||
--- - `on_child_removed` : emitted when a child is removed from the tree.
|
||||
function LanguageTree:register_cbs(cbs)
|
||||
---@cast cbs table<TSCallbackNameOn,function>
|
||||
if not cbs then
|
||||
return
|
||||
end
|
||||
@ -549,6 +594,9 @@ function LanguageTree:register_cbs(cbs)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param tree TSTree
|
||||
---@param range Range
|
||||
---@return boolean
|
||||
local function tree_contains(tree, range)
|
||||
local start_row, start_col, end_row, end_col = tree:root():range()
|
||||
local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2])
|
||||
@ -559,7 +607,7 @@ end
|
||||
|
||||
--- Determines whether {range} is contained in the |LanguageTree|.
|
||||
---
|
||||
---@param range table `{ start_line, start_col, end_line, end_col }`
|
||||
---@param range Range `{ start_line, start_col, end_line, end_col }`
|
||||
---@return boolean
|
||||
function LanguageTree:contains(range)
|
||||
for _, tree in pairs(self._trees) do
|
||||
@ -573,10 +621,10 @@ end
|
||||
|
||||
--- Gets the tree that contains {range}.
|
||||
---
|
||||
---@param range table `{ start_line, start_col, end_line, end_col }`
|
||||
---@param range Range `{ start_line, start_col, end_line, end_col }`
|
||||
---@param opts table|nil Optional keyword arguments:
|
||||
--- - ignore_injections boolean Ignore injected languages (default true)
|
||||
---@return userdata|nil Contained |tstree|
|
||||
---@return TSTree|nil
|
||||
function LanguageTree:tree_for_range(range, opts)
|
||||
opts = opts or {}
|
||||
local ignore = vim.F.if_nil(opts.ignore_injections, true)
|
||||
@ -602,10 +650,10 @@ end
|
||||
|
||||
--- Gets the smallest named node that contains {range}.
|
||||
---
|
||||
---@param range table `{ start_line, start_col, end_line, end_col }`
|
||||
---@param range Range `{ start_line, start_col, end_line, end_col }`
|
||||
---@param opts table|nil Optional keyword arguments:
|
||||
--- - ignore_injections boolean Ignore injected languages (default true)
|
||||
---@return userdata|nil Found |tsnode|
|
||||
---@return TSNode|nil Found node
|
||||
function LanguageTree:named_node_for_range(range, opts)
|
||||
local tree = self:tree_for_range(range, opts)
|
||||
if tree then
|
||||
@ -615,7 +663,7 @@ end
|
||||
|
||||
--- Gets the appropriate language that contains {range}.
|
||||
---
|
||||
---@param range table `{ start_line, start_col, end_line, end_col }`
|
||||
---@param range Range `{ start_line, start_col, end_line, end_col }`
|
||||
---@return LanguageTree Managing {range}
|
||||
function LanguageTree:language_for_range(range)
|
||||
for _, child in pairs(self._children) do
|
||||
|
@ -1,12 +1,13 @@
|
||||
local api = vim.api
|
||||
|
||||
local M = {}
|
||||
|
||||
---@class Playground
|
||||
---@class TSPlayground
|
||||
---@field ns number API namespace
|
||||
---@field opts table Options table with the following keys:
|
||||
--- - anon (boolean): If true, display anonymous nodes
|
||||
--- - lang (boolean): If true, display the language alongside each node
|
||||
---@field nodes Node[]
|
||||
---@field named Node[]
|
||||
local TSPlayground = {}
|
||||
---
|
||||
---@class Node
|
||||
---@field id number Node id
|
||||
@ -18,6 +19,7 @@ local M = {}
|
||||
---@field end_lnum number Final line number of this node in the source buffer
|
||||
---@field end_col number Final column number of this node in the source buffer
|
||||
---@field lang string Source language of this node
|
||||
---@field root TSNode
|
||||
|
||||
--- Traverse all child nodes starting at {node}.
|
||||
---
|
||||
@ -31,10 +33,10 @@ local M = {}
|
||||
--- node of each of these trees is contained within a node in the primary tree. The {injections}
|
||||
--- table maps nodes in the primary tree to root nodes of injected trees.
|
||||
---
|
||||
---@param node userdata Starting node to begin traversal |tsnode|
|
||||
---@param node TSNode Starting node to begin traversal |tsnode|
|
||||
---@param depth number Current recursion depth
|
||||
---@param lang string Language of the tree currently being traversed
|
||||
---@param injections table Mapping of node ids to root nodes of injected language trees (see
|
||||
---@param injections table<integer,Node> Mapping of node ids to root nodes of injected language trees (see
|
||||
--- explanation above)
|
||||
---@param tree Node[] Output table containing a list of tables each representing a node in the tree
|
||||
---@private
|
||||
@ -48,7 +50,7 @@ local function traverse(node, depth, lang, injections, tree)
|
||||
local type = child:type()
|
||||
local lnum, col, end_lnum, end_col = child:range()
|
||||
local named = child:named()
|
||||
local text
|
||||
local text ---@type string
|
||||
if named then
|
||||
if field then
|
||||
text = string.format('%s: (%s)', field, type)
|
||||
@ -79,14 +81,14 @@ end
|
||||
|
||||
--- Create a new Playground object.
|
||||
---
|
||||
---@param bufnr number Source buffer number
|
||||
---@param bufnr integer Source buffer number
|
||||
---@param lang string|nil Language of source buffer
|
||||
---
|
||||
---@return Playground|nil
|
||||
---@return TSPlayground|nil
|
||||
---@return string|nil Error message, if any
|
||||
---
|
||||
---@private
|
||||
function M.new(self, bufnr, lang)
|
||||
function TSPlayground:new(bufnr, lang)
|
||||
local ok, parser = pcall(vim.treesitter.get_parser, bufnr or 0, lang)
|
||||
if not ok then
|
||||
return nil, 'No parser available for the given buffer'
|
||||
@ -96,7 +98,7 @@ function M.new(self, bufnr, lang)
|
||||
-- the primary tree that contains that root. Add a mapping from the node in the primary tree to
|
||||
-- the root in the child tree to the {injections} table.
|
||||
local root = parser:parse()[1]:root()
|
||||
local injections = {}
|
||||
local injections = {} ---@type table<integer,table>
|
||||
parser:for_each_child(function(child, lang_)
|
||||
child:for_each_tree(function(tree)
|
||||
local r = tree:root()
|
||||
@ -112,7 +114,7 @@ function M.new(self, bufnr, lang)
|
||||
|
||||
local nodes = traverse(root, 0, parser:lang(), injections, {})
|
||||
|
||||
local named = {}
|
||||
local named = {} ---@type Node[]
|
||||
for _, v in ipairs(nodes) do
|
||||
if v.named then
|
||||
named[#named + 1] = v
|
||||
@ -138,9 +140,9 @@ end
|
||||
---
|
||||
---@param bufnr number Buffer number to write into.
|
||||
---@private
|
||||
function M.draw(self, bufnr)
|
||||
function TSPlayground:draw(bufnr)
|
||||
vim.bo[bufnr].modifiable = true
|
||||
local lines = {}
|
||||
local lines = {} ---@type string[]
|
||||
for _, item in self:iter() do
|
||||
lines[#lines + 1] = table.concat({
|
||||
string.rep(' ', item.depth),
|
||||
@ -168,19 +170,19 @@ end
|
||||
---@param i number Node number to get
|
||||
---@return Node
|
||||
---@private
|
||||
function M.get(self, i)
|
||||
function TSPlayground:get(i)
|
||||
local t = self.opts.anon and self.nodes or self.named
|
||||
return t[i]
|
||||
end
|
||||
|
||||
--- Iterate over all of the nodes in this Playground object.
|
||||
---
|
||||
---@return function Iterator over all nodes in this Playground
|
||||
---@return (fun(): integer, Node) Iterator over all nodes in this Playground
|
||||
---@return table
|
||||
---@return number
|
||||
---@private
|
||||
function M.iter(self)
|
||||
function TSPlayground:iter()
|
||||
return ipairs(self.opts.anon and self.nodes or self.named)
|
||||
end
|
||||
|
||||
return M
|
||||
return TSPlayground
|
||||
|
@ -1,21 +1,25 @@
|
||||
local a = vim.api
|
||||
local language = require('vim.treesitter.language')
|
||||
|
||||
-- query: pattern matching on trees
|
||||
-- predicate matching is implemented in lua
|
||||
--
|
||||
---@class Query
|
||||
---@field captures string[] List of captures used in query
|
||||
---@field info table Contains used queries, predicates, directives
|
||||
---@field info TSQueryInfo Contains used queries, predicates, directives
|
||||
---@field query userdata Parsed query
|
||||
local Query = {}
|
||||
Query.__index = Query
|
||||
|
||||
---@class TSQueryInfo
|
||||
---@field captures table
|
||||
---@field patterns table<string,any[][]>
|
||||
|
||||
local M = {}
|
||||
|
||||
---@private
|
||||
---@param files string[]
|
||||
---@return string[]
|
||||
local function dedupe_files(files)
|
||||
local result = {}
|
||||
---@type table<string,boolean>
|
||||
local seen = {}
|
||||
|
||||
for _, path in ipairs(files) do
|
||||
@ -65,10 +69,10 @@ function M.get_query_files(lang, query_name, is_included)
|
||||
return {}
|
||||
end
|
||||
|
||||
local base_query = nil
|
||||
local base_query = nil ---@type string?
|
||||
local extensions = {}
|
||||
|
||||
local base_langs = {}
|
||||
local base_langs = {} ---@type string[]
|
||||
|
||||
-- Now get the base languages by looking at the first line of every file
|
||||
-- The syntax is the following :
|
||||
@ -87,6 +91,7 @@ function M.get_query_files(lang, query_name, is_included)
|
||||
local extension = false
|
||||
|
||||
for modeline in
|
||||
---@return string
|
||||
function()
|
||||
return file:read('*l')
|
||||
end
|
||||
@ -97,6 +102,7 @@ function M.get_query_files(lang, query_name, is_included)
|
||||
|
||||
local langlist = modeline:match(MODELINE_FORMAT)
|
||||
if langlist then
|
||||
---@diagnostic disable-next-line:param-type-mismatch
|
||||
for _, incllang in ipairs(vim.split(langlist, ',', true)) do
|
||||
local is_optional = incllang:match('%(.*%)')
|
||||
|
||||
@ -137,6 +143,8 @@ function M.get_query_files(lang, query_name, is_included)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param filenames string[]
|
||||
---@return string
|
||||
local function read_query_files(filenames)
|
||||
local contents = {}
|
||||
|
||||
@ -147,7 +155,8 @@ local function read_query_files(filenames)
|
||||
return table.concat(contents, '')
|
||||
end
|
||||
|
||||
--- The explicitly set queries from |vim.treesitter.query.set_query()|
|
||||
-- The explicitly set queries from |vim.treesitter.query.set_query()|
|
||||
---@type table<string,table<string,Query>>
|
||||
local explicit_queries = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local lang_queries = {}
|
||||
@ -174,7 +183,7 @@ end
|
||||
---@param lang string Language to use for the query
|
||||
---@param query_name string Name of the query (e.g. "highlights")
|
||||
---
|
||||
---@return Query Parsed query
|
||||
---@return Query|nil Parsed query
|
||||
function M.get_query(lang, query_name)
|
||||
if explicit_queries[lang][query_name] then
|
||||
return explicit_queries[lang][query_name]
|
||||
@ -188,6 +197,7 @@ function M.get_query(lang, query_name)
|
||||
end
|
||||
end
|
||||
|
||||
---@type {[string]: {[string]: Query}}
|
||||
local query_cache = vim.defaulttable(function()
|
||||
return setmetatable({}, { __mode = 'v' })
|
||||
end)
|
||||
@ -226,11 +236,11 @@ end
|
||||
|
||||
--- Gets the text corresponding to a given node
|
||||
---
|
||||
---@param node userdata |tsnode|
|
||||
---@param node TSNode
|
||||
---@param source (number|string) Buffer or string from which the {node} is extracted
|
||||
---@param opts (table|nil) Optional parameters.
|
||||
--- - concat: (boolean) Concatenate result in a string (default true)
|
||||
---@return (string[]|string)
|
||||
---@return (string[]|string|nil)
|
||||
function M.get_node_text(node, source, opts)
|
||||
opts = opts or {}
|
||||
local concat = vim.F.if_nil(opts.concat, true)
|
||||
@ -239,12 +249,12 @@ function M.get_node_text(node, source, opts)
|
||||
local end_row, end_col, end_byte = node:end_()
|
||||
|
||||
if type(source) == 'number' then
|
||||
local lines
|
||||
local eof_row = a.nvim_buf_line_count(source)
|
||||
if start_row >= eof_row then
|
||||
return nil
|
||||
end
|
||||
|
||||
local lines ---@type string[]
|
||||
if end_col == 0 then
|
||||
lines = a.nvim_buf_get_lines(source, start_row, end_row, true)
|
||||
end_col = -1
|
||||
@ -267,8 +277,13 @@ function M.get_node_text(node, source, opts)
|
||||
end
|
||||
end
|
||||
|
||||
---@alias TSMatch table<integer,TSNode>
|
||||
|
||||
---@alias TSPredicate fun(match: TSMatch, _, _, predicate: any[]): boolean
|
||||
|
||||
-- Predicate handler receive the following arguments
|
||||
-- (match, pattern, bufnr, predicate)
|
||||
---@type table<string,TSPredicate>
|
||||
local predicate_handlers = {
|
||||
['eq?'] = function(match, _, source, predicate)
|
||||
local node = match[predicate[2]]
|
||||
@ -277,13 +292,13 @@ local predicate_handlers = {
|
||||
end
|
||||
local node_text = M.get_node_text(node, source)
|
||||
|
||||
local str
|
||||
local str ---@type string
|
||||
if type(predicate[3]) == 'string' then
|
||||
-- (#eq? @aa "foo")
|
||||
str = predicate[3]
|
||||
else
|
||||
-- (#eq? @aa @bb)
|
||||
str = M.get_node_text(match[predicate[3]], source)
|
||||
str = M.get_node_text(match[predicate[3]], source) --[[@as string]]
|
||||
end
|
||||
|
||||
if node_text ~= str or str == nil then
|
||||
@ -299,7 +314,7 @@ local predicate_handlers = {
|
||||
return true
|
||||
end
|
||||
local regex = predicate[3]
|
||||
return string.find(M.get_node_text(node, source), regex)
|
||||
return string.find(M.get_node_text(node, source) --[[@as string]], regex) ~= nil
|
||||
end,
|
||||
|
||||
['match?'] = (function()
|
||||
@ -321,10 +336,12 @@ local predicate_handlers = {
|
||||
})
|
||||
|
||||
return function(match, _, source, pred)
|
||||
---@cast match TSMatch
|
||||
local node = match[pred[2]]
|
||||
if not node then
|
||||
return true
|
||||
end
|
||||
---@diagnostic disable-next-line no-unknown
|
||||
local regex = compiled_vim_regexes[pred[3]]
|
||||
return regex:match_str(M.get_node_text(node, source))
|
||||
end
|
||||
@ -335,7 +352,7 @@ local predicate_handlers = {
|
||||
if not node then
|
||||
return true
|
||||
end
|
||||
local node_text = M.get_node_text(node, source)
|
||||
local node_text = M.get_node_text(node, source) --[[@as string]]
|
||||
|
||||
for i = 3, #predicate do
|
||||
if string.find(node_text, predicate[i], 1, true) then
|
||||
@ -359,6 +376,7 @@ local predicate_handlers = {
|
||||
if not string_set then
|
||||
string_set = {}
|
||||
for i = 3, #predicate do
|
||||
---@diagnostic disable-next-line:no-unknown
|
||||
string_set[predicate[i]] = true
|
||||
end
|
||||
predicate['string_set'] = string_set
|
||||
@ -371,21 +389,39 @@ local predicate_handlers = {
|
||||
-- As we provide lua-match? also expose vim-match?
|
||||
predicate_handlers['vim-match?'] = predicate_handlers['match?']
|
||||
|
||||
---@class TSMetadata
|
||||
---@field [integer] TSMetadata
|
||||
---@field [string] integer|string
|
||||
---@field range Range
|
||||
|
||||
---@alias TSDirective fun(match: TSMatch, _, _, predicate: any[], metadata: TSMetadata)
|
||||
|
||||
-- Predicate handler receive the following arguments
|
||||
-- (match, pattern, bufnr, predicate)
|
||||
|
||||
-- Directives store metadata or perform side effects against a match.
|
||||
-- Directives should always end with a `!`.
|
||||
-- Directive handler receive the following arguments
|
||||
-- (match, pattern, bufnr, predicate, metadata)
|
||||
---@type table<string,TSDirective>
|
||||
local directive_handlers = {
|
||||
['set!'] = function(_, _, _, pred, metadata)
|
||||
if #pred == 4 then
|
||||
-- (#set! @capture "key" "value")
|
||||
---@diagnostic disable-next-line:no-unknown
|
||||
local _, capture_id, key, value = unpack(pred)
|
||||
---@cast value integer|string
|
||||
---@cast capture_id integer
|
||||
---@cast key string
|
||||
if not metadata[capture_id] then
|
||||
metadata[capture_id] = {}
|
||||
end
|
||||
metadata[capture_id][key] = value
|
||||
else
|
||||
---@diagnostic disable-next-line:no-unknown
|
||||
local _, key, value = unpack(pred)
|
||||
---@cast value integer|string
|
||||
---@cast key string
|
||||
-- (#set! "key" "value")
|
||||
metadata[key] = value
|
||||
end
|
||||
@ -393,9 +429,11 @@ local directive_handlers = {
|
||||
-- Shifts the range of a node.
|
||||
-- Example: (#offset! @_node 0 1 0 -1)
|
||||
['offset!'] = function(match, _, _, pred, metadata)
|
||||
---@cast pred integer[]
|
||||
local capture_id = pred[2]
|
||||
local offset_node = match[capture_id]
|
||||
local range = { offset_node:range() }
|
||||
---@cast range integer[] bug in sumneko
|
||||
local start_row_offset = pred[3] or 0
|
||||
local start_col_offset = pred[4] or 0
|
||||
local end_row_offset = pred[5] or 0
|
||||
@ -419,8 +457,9 @@ local directive_handlers = {
|
||||
--- Adds a new predicate to be used in queries
|
||||
---
|
||||
---@param name string Name of the predicate, without leading #
|
||||
---@param handler function(match:table, pattern:string, bufnr:number, predicate:string[])
|
||||
---@param handler function(match:table<string,TSNode>, pattern:string, bufnr:number, predicate:string[])
|
||||
--- - see |vim.treesitter.query.add_directive()| for argument meanings
|
||||
---@param force boolean
|
||||
function M.add_predicate(name, handler, force)
|
||||
if predicate_handlers[name] and not force then
|
||||
error(string.format('Overriding %s', name))
|
||||
@ -437,12 +476,13 @@ end
|
||||
--- metadata table `metadata[capture_id].key = value`
|
||||
---
|
||||
---@param name string Name of the directive, without leading #
|
||||
---@param handler function(match:table, pattern:string, bufnr:number, predicate:string[], metadata:table)
|
||||
---@param handler function(match:table<string,TSNode>, pattern:string, bufnr:number, predicate:string[], metadata:table)
|
||||
--- - match: see |treesitter-query|
|
||||
--- - node-level data are accessible via `match[capture_id]`
|
||||
--- - pattern: see |treesitter-query|
|
||||
--- - predicate: list of strings containing the full directive being called, e.g.
|
||||
--- `(node (#set! conceal "-"))` would get the predicate `{ "#set!", "conceal", "-" }`
|
||||
---@param force boolean
|
||||
function M.add_directive(name, handler, force)
|
||||
if directive_handlers[name] and not force then
|
||||
error(string.format('Overriding %s', name))
|
||||
@ -474,6 +514,9 @@ local function is_directive(name)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param match TSMatch
|
||||
---@param pattern string
|
||||
---@param source integer|string
|
||||
function Query:match_preds(match, pattern, source)
|
||||
local preds = self.info.patterns[pattern]
|
||||
|
||||
@ -482,8 +525,9 @@ function Query:match_preds(match, pattern, source)
|
||||
-- continue on the other case. This way unknown predicates will not be considered,
|
||||
-- which allows some testing and easier user extensibility (#12173).
|
||||
-- Also, tree-sitter strips the leading # from predicates for us.
|
||||
local pred_name
|
||||
local is_not
|
||||
local pred_name ---@type string
|
||||
|
||||
local is_not ---@type boolean
|
||||
|
||||
-- Skip over directives... they will get processed after all the predicates.
|
||||
if not is_directive(pred[1]) then
|
||||
@ -513,6 +557,8 @@ function Query:match_preds(match, pattern, source)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param match TSMatch
|
||||
---@param metadata TSMetadata
|
||||
function Query:apply_directives(match, pattern, source, metadata)
|
||||
local preds = self.info.patterns[pattern]
|
||||
|
||||
@ -534,6 +580,10 @@ end
|
||||
-- When the node's range is used, the stop is incremented by 1
|
||||
-- to make the search inclusive.
|
||||
---@private
|
||||
---@param start integer
|
||||
---@param stop integer
|
||||
---@param node TSNode
|
||||
---@return integer, integer
|
||||
local function value_or_node_range(start, stop, node)
|
||||
if start == nil and stop == nil then
|
||||
local node_start, _, node_stop, _ = node:range()
|
||||
@ -565,14 +615,12 @@ end
|
||||
--- end
|
||||
--- </pre>
|
||||
---
|
||||
---@param node userdata |tsnode| under which the search will occur
|
||||
---@param source (number|string) Source buffer or string to extract text from
|
||||
---@param node TSNode under which the search will occur
|
||||
---@param source (integer|string) Source buffer or string to extract text from
|
||||
---@param start number Starting line for the search
|
||||
---@param stop number Stopping line for the search (end-exclusive)
|
||||
---
|
||||
---@return number capture Matching capture id
|
||||
---@return table capture_node Capture for {node}
|
||||
---@return table metadata for the {capture}
|
||||
---@return (fun(): integer, TSNode, TSMetadata): capture id, capture node, metadata
|
||||
function Query:iter_captures(node, source, start, stop)
|
||||
if type(source) == 'number' and source == 0 then
|
||||
source = vim.api.nvim_get_current_buf()
|
||||
@ -622,14 +670,12 @@ end
|
||||
--- end
|
||||
--- </pre>
|
||||
---
|
||||
---@param node userdata |tsnode| under which the search will occur
|
||||
---@param source (number|string) Source buffer or string to search
|
||||
---@param start number Starting line for the search
|
||||
---@param stop number Stopping line for the search (end-exclusive)
|
||||
---@param node TSNode under which the search will occur
|
||||
---@param source (integer|string) Source buffer or string to search
|
||||
---@param start integer Starting line for the search
|
||||
---@param stop integer Stopping line for the search (end-exclusive)
|
||||
---
|
||||
---@return number pattern id
|
||||
---@return table match
|
||||
---@return table metadata
|
||||
---@return (fun(): integer, table<integer,TSNode>, table): pattern id, match, metadata
|
||||
function Query:iter_matches(node, source, start, stop)
|
||||
if type(source) == 'number' and source == 0 then
|
||||
source = vim.api.nvim_get_current_buf()
|
||||
@ -638,6 +684,7 @@ function Query:iter_matches(node, source, start, stop)
|
||||
start, stop = value_or_node_range(start, stop, node)
|
||||
|
||||
local raw_iter = node:_rawquery(self.query, false, start, stop)
|
||||
---@cast raw_iter fun(): string, any
|
||||
local function iter()
|
||||
local pattern, match = raw_iter()
|
||||
local metadata = {}
|
||||
|
@ -286,7 +286,12 @@ local function checkComment4fn(Fn_magic, MagicLines)
|
||||
return fn_magic
|
||||
end
|
||||
|
||||
local types = { 'number', 'string', 'table', 'list', 'boolean', 'function' }
|
||||
local types = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'function' }
|
||||
|
||||
local tagged_types = { 'TSNode', 'LanguageTree' }
|
||||
|
||||
-- Document these as 'table'
|
||||
local alias_types = { 'Range' }
|
||||
|
||||
--! \brief run the filter
|
||||
function TLua2DoX_filter.readfile(this, AppStamp, Filename)
|
||||
@ -320,7 +325,12 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename)
|
||||
offset = 1
|
||||
end
|
||||
|
||||
if string.sub(line, 3, 3) == '@' or string.sub(line, 1, 4) == '---@' then -- it's a magic comment
|
||||
if vim.startswith(line, '---@cast')
|
||||
or vim.startswith(line, '---@diagnostic')
|
||||
or vim.startswith(line, '---@type') then
|
||||
-- Ignore LSP directives
|
||||
outStream:writeln('// gg:"' .. line .. '"')
|
||||
elseif string.sub(line, 3, 3) == '@' or string.sub(line, 1, 4) == '---@' then -- it's a magic comment
|
||||
state = 'in_magic_comment'
|
||||
local magic = string.sub(line, 4 + offset)
|
||||
|
||||
@ -366,6 +376,17 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename)
|
||||
magic_split[type_index] = magic_split[type_index]:gsub(k, v)
|
||||
end
|
||||
end
|
||||
|
||||
for _, type in ipairs(tagged_types) do
|
||||
magic_split[type_index] =
|
||||
magic_split[type_index]:gsub(type, '|%1|')
|
||||
end
|
||||
|
||||
for _, type in ipairs(alias_types) do
|
||||
magic_split[type_index] =
|
||||
magic_split[type_index]:gsub('^'..type..'$', 'table')
|
||||
end
|
||||
|
||||
-- surround some types by ()
|
||||
for _, type in ipairs(types) do
|
||||
magic_split[type_index] =
|
||||
@ -373,6 +394,8 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename)
|
||||
magic_split[type_index] =
|
||||
magic_split[type_index]:gsub('^(' .. type .. '):?$', '(%1)')
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
magic = table.concat(magic_split, ' ')
|
||||
|
Loading…
Reference in New Issue
Block a user