load: function(file_name: string, language_name: string): Parser, string
Load a parser from a given file
Keep in mind that this includes the .so
or .dll
extension
On Unix this uses dlopen, on Windows this uses LoadLibrary so if a path without a path separator is given, these functions have their own path's that they will search for your file in.
So if in doubt use a file path like
local my_parser = ltreesitter.load("./my_parser.so", "my_language")
require: function(library_file_name: string, language_name?: string): Parser
Search ~/.tree-sitter/bin
and package.cpath
for a parser with the filename library_file_name.so
(or .dll
on Windows) and try to load the symbol tree_sitter_'language_name'
language_name
is optional and will be set to library_file_name
if not provided.
So if you want to load a Lua parser from a file named lua.so
then use ltreesitter.require("lua")
But if you want to load a Lua parser from a file named parser.so
then use ltreesitter.require("parser", "lua")
Like the regular require
, this will error if the parser is not found or the symbol couldn't be loaded. Use either pcall
or ltreesitter.load
to not error out on failure.
local my_parser = ltreesitter.require("my_language")
my_parser:parse_string(...)
-- etc.
Cursor.current_field_name: function(Cursor): string
Get the field name of the current node under the cursor
Cursor.current_node: function(Cursor): Node
Get the current node under the cursor
Cursor.goto_first_child: function(Cursor): boolean
Position the cursor at the first child of the current node
Cursor.goto_first_child_for_byte: function(Cursor, integer): integer
Move the given cursor to the first child of its current node that extends
beyond the given byte offset.
Returns the index of the found node, if a node wasn't found, returns nil
Cursor.goto_next_sibling: function(Cursor): boolean
Position the cursor at the sibling of the current node
Cursor.goto_parent: function(Cursor): boolean
Position the cursor at the parent of the current node
Cursor.reset: function(Cursor, Node)
Position the cursor at the given node
Node.child: function(Node, idx: integer): Node
Get the node's idx'th child (0-indexed)
Node.child_by_field_name: function(Node, string): Node
Get a node's child given a field name
Node.child_count: function(Node): integer
Get the number of children a node has
Node.children: function(Node): function(): Node
Iterate over a node's children
Node.create_cursor: function(Node): Cursor
Create a new cursor at the given node
Node.end_byte: function(Node): integer
Get the byte of the source string that the given node ends at
Node.end_point: function(Node): Point
Get the row and column of where the given node ends
Node.is_extra: function(Node): boolean
Get whether or not the current node is extra
Node.is_missing: function(Node): boolean
Get whether or not the current node is missing
Node.is_named: function(Node): boolean
Get whether or not the current node is named
Node.name: function(Node): string
Returns the name of a given node
print(node) -- => (comment)
print(node:name()) -- => comment
Node.named_child: function(Node, idx: integer): Node
Get the node's idx'th named child (0-indexed)
Node.named_child_count: function(Node): integer
Get the number of named children a node has
Node.named_children: function(Node): function(): Node
Iterate over a node's named children
Node.next_named_sibling: function(Node): Node
Get a node's next named sibling
Node.next_sibling: function(Node): Node
Get a node's next sibling
Node.prev_named_sibling: function(Node): Node
Get a node's previous named sibling
Node.prev_sibling: function(Node): Node
Get a node's previous sibling
Node.source: function(Node): string
Get the substring of the source that was parsed to create Node
Node.start_byte: function(Node): integer
Get the byte of the source string that the given node starts at
Node.start_point: function(Node): Point
Get the row and column of where the given node starts
Node.type: function(Node): string
Get the type of the given node
Parser.get_ranges: function(Parser): {Range}
Get the ranges of text that the parser will include when parsing
Parser.get_version: function(Parser): integer
get the api version of the parser's language
Parser.parse_string: function(Parser, string, ?Tree): Tree
Uses the given parser to parse the string
If Tree
is provided then it will be used to create a new updated tree
(but it is the responsibility of the programmer to make the correct Tree:edit
calls)
Could return nil
if the parser has a timeout
Parser.parse_with: function(Parser, reader: (function(integer, Point): string), old_tree?: Tree): Tree
reader
should be a function that takes a byte index
and a Point
and returns the text at that point. The
function should return either nil
or an empty string
to signal that there is no more text.
A Tree
can be provided to reuse parts of it for parsing,
provided the Tree:edit
has been called previously
Parser.query: function(Parser, string): Query
Create a query out of the given string for the language of the given parser
Parser.set_ranges: function(Parser, {Range}): boolean
Sets the ranges that Parser
will include when parsing, so you don't have to parse an entire document, but the ranges in the tree will still match the document.
The array of Range
s must satisfy the following relationship: for a positive integer i
within the length of ranges: {Range}
:
ranges[i].end_byte <= ranges[i + 1].start_byte
Parser.set_timeout: function(Parser, integer)
Sets how long the parser is allowed to take in microseconds
Query.capture: function(Query, Node, start?: integer | Point, end_?: integer | Point): function(): (Node, string)
Iterate over the captures of a given query in Node
, name
pairs.
start
and end
are optional.
They must be passed together with the same type, describing either two bytes or two points.
If passed, the query will be executed within the range denoted.
If not passed, the default behaviour is to execute the query through the entire range of the node.
local q = parser:query[[ (comment) @my_match ]]
for capture, name in q:capture(node) do
print(capture, name) -- => (comment), "my_match"
end
Query.exec: function(Query, Node, start?: integer | Point, end_?: integer | Point)
Runs a query. That's it. Nothing more, nothing less.
This is intended to be used with the Query.with
method and predicates that have side effects,
i.e. for when you would use Query.match or Query.capture, but do nothing in the for loop.
start
and end
are optional.
They must be passed together with the same type, describing either two bytes or two points.
If passed, the query will be executed within the range denoted.
If not passed, the default behaviour is to execute the query through the entire range of the node.
local parser = ltreesitter.require("teal")
-- grab a node to query against
local root_node = parser:parse_string[[
local x: string = "foo"
local y: string = "bar"
]]:root()
parser
:query[[(
(var_declaration
(var) @var-name
(string) @value)
(#set! @var-name @value)
)]]
:with{["set!"] = function(a, b) _G[a] = b:sub(2, -2) end}
:exec(root_node)
print(x) -- => foo
print(y) -- => bar
Query.match: function(Query, Node, start?: integer | Point, end_?: integer | Point): function(): Match
Iterate over the matches of a given query.
start
and end
are optional.
They must be passed together with the same type, describing either two bytes or two points.
If passed, the query will be executed within the range denoted.
If not passed, the default behaviour is to execute the query through the entire range of the node.
The match object is a record populated with all the information given by treesitter
type Match = record
id: integer
pattern_index: integer
capture_count: integer
captures: {string:Node|{Node}}
end
(node) @capture-name
patterns and (node)? @capture-name
patterns),nil
or that Node
.(node)* @capture-name
and (node)+ @capture-name
patterns)nil
or an array of Node
local q = parser:query[[ (comment) @my_match ]]
for match in q:match(node) do
print(match.captures.my_match)
end
Query.source: function(Query): string
Gets the source that the query was initialized with
Query.with: function(Query, {string:function(...: string | Node | {Node}): any...}): Query
Creates a new query equipped with predicates defined in the {string:function}
map given
Predicates that end in a '?'
character will be seen as conditions that must be met for the pattern to be matched.
Predicates that don't will be seen just as functions to be executed given the matches provided.
Additionally, you will not have access to the return values of these functions, if you'd like to keep the results of a computation, make your functions have side-effects to write somewhere you can access.
By default the following predicates are provided.
(#eq? ...)
will match if all arguments provided are equal
(#match? text pattern)
will match the provided text
matches the given pattern
. Matches are determined by Lua's standard string.match
function.
(#find? text substring)
will match if text
contains substring
. The substring is found with Lua's standard string.find
, but the search always starts from the beginning, and pattern matching is disabled. This is equivalent to string.find(text, substring, 0, true)
Example:
The following snippet will match lua functions that have a single LDoc/EmmyLua style comment above them
local parser = ltreesitter.require("lua")
-- grab a node to query against
local root_node = parser:parse_string[[
---@Doc this does stuff
local function stuff_doer()
do_stuff()
end
]]:root()
for match in parser
:query[[(
(comment) @the-comment
.
(function_definition
(function_name) @the-function-name)
(#is_doc_comment? @the-comment)
)]]
:with{
["is_doc_comment?"] = function(str)
return str:sub(1, 4) == "---@"
end
}
:match(root_node)
do
print("Function: " .. match.captures["the-function-name"] .. " has documentation")
print(" " .. match.captures["the-comment"])
end
Tree.copy: function(Tree): Tree
Creates a copy of the tree. Tree-sitter recommends to create copies if you are going to use multithreading since tree accesses are not thread-safe, but copying them is cheap and quick
Tree.edit: function(
Tree,
start_byte: integer,
old_end_byte: integer,
new_end_byte: integer,
start_point_row: integer,
start_point_col: integer,
old_end_point_row: integer,
old_end_point_col: integer,
new_end_point_row: integer,
new_end_point_col: integer
)
Create an edit to the given tree
Tree.edit_s: function(Tree, TreeEdit)
Create an edit to the given tree
Tree.get_changed_ranges: function(old: Tree, new: Tree): {Range}
Compare an old syntax tree to a new syntax tree.
This would usually be called right after a set of calls to Tree.edit(_s)
and Parser.parse_{string,with}
Tree.root: function(Tree): Node
Returns the root node of the given parse tree