mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 12:27:24 +00:00
docs: Treesitter (#13260)
* doc & fixes: Generate treesitter docs * fixup to treesitter-core * docs(treesitter): fix docs for most functions Co-authored-by: Thomas Vigouroux <tomvig38@gmail.com>
This commit is contained in:
@@ -25,12 +25,12 @@ setmetatable(M, {
|
||||
})
|
||||
|
||||
--- Creates a new parser.
|
||||
--
|
||||
-- It is not recommended to use this, use vim.treesitter.get_parser() instead.
|
||||
--
|
||||
-- @param bufnr The buffer the parser will be tied to
|
||||
-- @param lang The language of the parser
|
||||
-- @param opts Options to pass to the language tree
|
||||
---
|
||||
--- It is not recommended to use this, use vim.treesitter.get_parser() instead.
|
||||
---
|
||||
--- @param bufnr The buffer the parser will be tied to
|
||||
--- @param lang The language of the parser
|
||||
--- @param opts Options to pass to the created language tree
|
||||
function M._create_parser(bufnr, lang, opts)
|
||||
language.require_language(lang)
|
||||
if bufnr == 0 then
|
||||
@@ -41,10 +41,12 @@ function M._create_parser(bufnr, lang, opts)
|
||||
|
||||
local self = LanguageTree.new(bufnr, lang, opts)
|
||||
|
||||
---@private
|
||||
local function bytes_cb(_, ...)
|
||||
self:_on_bytes(...)
|
||||
end
|
||||
|
||||
---@private
|
||||
local function detach_cb(_, ...)
|
||||
if parsers[bufnr] == self then
|
||||
parsers[bufnr] = nil
|
||||
@@ -52,6 +54,7 @@ function M._create_parser(bufnr, lang, opts)
|
||||
self:_on_detach(...)
|
||||
end
|
||||
|
||||
---@private
|
||||
local function reload_cb(_, ...)
|
||||
self:_on_reload(...)
|
||||
end
|
||||
@@ -64,15 +67,15 @@ function M._create_parser(bufnr, lang, opts)
|
||||
end
|
||||
|
||||
--- Gets the parser for this bufnr / ft combination.
|
||||
--
|
||||
-- If needed this will create the parser.
|
||||
-- Unconditionnally attach the provided callback
|
||||
--
|
||||
-- @param bufnr The buffer the parser should be tied to
|
||||
-- @param ft The filetype of this parser
|
||||
-- @param opts Options object to pass to the parser
|
||||
--
|
||||
-- @returns The parser
|
||||
---
|
||||
--- If needed this will create the parser.
|
||||
--- Unconditionnally attach the provided callback
|
||||
---
|
||||
--- @param bufnr The buffer the parser should be tied to
|
||||
--- @param lang The filetype of this parser
|
||||
--- @param opts Options object to pass to the created language tree
|
||||
---
|
||||
--- @returns The parser
|
||||
function M.get_parser(bufnr, lang, opts)
|
||||
opts = opts or {}
|
||||
|
||||
@@ -92,6 +95,11 @@ function M.get_parser(bufnr, lang, opts)
|
||||
return parsers[bufnr]
|
||||
end
|
||||
|
||||
--- Gets a string parser
|
||||
---
|
||||
--- @param str The string to parse
|
||||
--- @param lang The language of this string
|
||||
--- @param opts Options to pass to the created language tree
|
||||
function M.get_string_parser(str, lang, opts)
|
||||
vim.validate {
|
||||
str = { str, 'string' },
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
local M = {}
|
||||
local ts = vim.treesitter
|
||||
|
||||
--- Lists the parsers currently installed
|
||||
---
|
||||
---@return A list of parsers
|
||||
function M.list_parsers()
|
||||
return vim.api.nvim_get_runtime_file('parser/*', true)
|
||||
end
|
||||
|
||||
--- Performs a healthcheck for treesitter integration
|
||||
function M.check_health()
|
||||
local report_info = vim.fn['health#report_info']
|
||||
local report_ok = vim.fn['health#report_ok']
|
||||
|
||||
@@ -70,11 +70,13 @@ TSHighlighter.hl_map = {
|
||||
["include"] = "Include",
|
||||
}
|
||||
|
||||
---@private
|
||||
local function is_highlight_name(capture_name)
|
||||
local firstc = string.sub(capture_name, 1, 1)
|
||||
return firstc ~= string.lower(firstc)
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighterQuery.new(lang, query_string)
|
||||
local self = setmetatable({}, { __index = TSHighlighterQuery })
|
||||
|
||||
@@ -99,10 +101,12 @@ function TSHighlighterQuery.new(lang, query_string)
|
||||
return self
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighterQuery:query()
|
||||
return self._query
|
||||
end
|
||||
|
||||
---@private
|
||||
--- Get the hl from capture.
|
||||
--- Returns a tuple { highlight_name: string, is_builtin: bool }
|
||||
function TSHighlighterQuery:_get_hl_from_capture(capture)
|
||||
@@ -116,6 +120,11 @@ function TSHighlighterQuery:_get_hl_from_capture(capture)
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a new highlighter using @param tree
|
||||
---
|
||||
--- @param tree The language tree to use for highlighting
|
||||
--- @param opts Table used to configure the highlighter
|
||||
--- - queries: Table to overwrite queries used by the highlighter
|
||||
function TSHighlighter.new(tree, opts)
|
||||
local self = setmetatable({}, TSHighlighter)
|
||||
|
||||
@@ -165,12 +174,14 @@ function TSHighlighter.new(tree, opts)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Removes all internal references to the highlighter
|
||||
function TSHighlighter:destroy()
|
||||
if TSHighlighter.active[self.bufnr] then
|
||||
TSHighlighter.active[self.bufnr] = nil
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter:get_highlight_state(tstree)
|
||||
if not self._highlight_states[tstree] then
|
||||
self._highlight_states[tstree] = {
|
||||
@@ -182,24 +193,31 @@ function TSHighlighter:get_highlight_state(tstree)
|
||||
return self._highlight_states[tstree]
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter:reset_highlight_state()
|
||||
self._highlight_states = {}
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end)
|
||||
a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1)
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter:on_detach()
|
||||
self:destroy()
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter:on_changedtree(changes)
|
||||
for _, ch in ipairs(changes or {}) do
|
||||
a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3]+1)
|
||||
end
|
||||
end
|
||||
|
||||
--- Gets the query used for @param lang
|
||||
---
|
||||
--- @param lang A language used by the highlighter.
|
||||
function TSHighlighter:get_query(lang)
|
||||
if not self._queries[lang] then
|
||||
self._queries[lang] = TSHighlighterQuery.new(lang)
|
||||
@@ -208,6 +226,7 @@ function TSHighlighter:get_query(lang)
|
||||
return self._queries[lang]
|
||||
end
|
||||
|
||||
---@private
|
||||
local function on_line_impl(self, buf, line)
|
||||
self.tree:for_each_tree(function(tstree, tree)
|
||||
if not tstree then return end
|
||||
@@ -251,6 +270,7 @@ local function on_line_impl(self, buf, line)
|
||||
end, true)
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter._on_line(_, _win, buf, line, _)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then return end
|
||||
@@ -258,6 +278,7 @@ function TSHighlighter._on_line(_, _win, buf, line, _)
|
||||
on_line_impl(self, buf, line)
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter._on_buf(_, buf)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if self then
|
||||
@@ -265,6 +286,7 @@ function TSHighlighter._on_buf(_, buf)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
function TSHighlighter._on_win(_, _win, buf, _topline)
|
||||
local self = TSHighlighter.active[buf]
|
||||
if not self then
|
||||
|
||||
@@ -3,12 +3,12 @@ local a = vim.api
|
||||
local M = {}
|
||||
|
||||
--- Asserts that the provided language is installed, and optionally provide a path for the parser
|
||||
--
|
||||
-- Parsers are searched in the `parser` runtime directory.
|
||||
--
|
||||
-- @param lang The language the parser should parse
|
||||
-- @param path Optional path the parser is located at
|
||||
-- @param silent Don't throw an error if language not found
|
||||
---
|
||||
--- Parsers are searched in the `parser` runtime directory.
|
||||
---
|
||||
--- @param lang The language the parser should parse
|
||||
--- @param path Optional path the parser is located at
|
||||
--- @param silent Don't throw an error if language not found
|
||||
function M.require_language(lang, path, silent)
|
||||
if vim._ts_has_language(lang) then
|
||||
return true
|
||||
@@ -37,10 +37,10 @@ function M.require_language(lang, path, silent)
|
||||
end
|
||||
|
||||
--- Inspects the provided language.
|
||||
--
|
||||
-- Inspecting provides some useful informations on the language like node names, ...
|
||||
--
|
||||
-- @param lang The language.
|
||||
---
|
||||
--- Inspecting provides some useful informations on the language like node names, ...
|
||||
---
|
||||
--- @param lang The language.
|
||||
function M.inspect_language(lang)
|
||||
M.require_language(lang)
|
||||
return vim._ts_inspect_language(lang)
|
||||
|
||||
@@ -5,16 +5,16 @@ local language = require'vim.treesitter.language'
|
||||
local LanguageTree = {}
|
||||
LanguageTree.__index = LanguageTree
|
||||
|
||||
-- Represents a single treesitter parser for a language.
|
||||
-- The language can contain child languages with in its range,
|
||||
-- hence the tree.
|
||||
--
|
||||
-- @param source Can be a bufnr or a string of text to parse
|
||||
-- @param lang The language this tree represents
|
||||
-- @param opts Options table
|
||||
-- @param opts.injections A table of language to injection query strings.
|
||||
-- This is useful for overriding the built-in runtime file
|
||||
-- searching for the injection language query per language.
|
||||
--- Represents a single treesitter parser for a language.
|
||||
--- The language can contain child languages with in its range,
|
||||
--- hence the tree.
|
||||
---
|
||||
--- @param source Can be a bufnr or a string of text to parse
|
||||
--- @param lang The language this tree represents
|
||||
--- @param opts Options table
|
||||
--- @param opts.injections A table of language to injection query strings.
|
||||
--- This is useful for overriding the built-in runtime file
|
||||
--- searching for the injection language query per language.
|
||||
function LanguageTree.new(source, lang, opts)
|
||||
language.require_language(lang)
|
||||
opts = opts or {}
|
||||
@@ -50,7 +50,7 @@ function LanguageTree.new(source, lang, opts)
|
||||
return self
|
||||
end
|
||||
|
||||
-- Invalidates this parser and all its children
|
||||
--- Invalidates this parser and all its children
|
||||
function LanguageTree:invalidate(reload)
|
||||
self._valid = false
|
||||
|
||||
@@ -64,38 +64,38 @@ function LanguageTree:invalidate(reload)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns all trees this language tree contains.
|
||||
-- Does not include child languages.
|
||||
--- Returns all trees this language tree contains.
|
||||
--- Does not include child languages.
|
||||
function LanguageTree:trees()
|
||||
return self._trees
|
||||
end
|
||||
|
||||
-- Gets the language of this tree layer.
|
||||
--- Gets the language of this tree node.
|
||||
function LanguageTree:lang()
|
||||
return self._lang
|
||||
end
|
||||
|
||||
-- Determines whether this tree is valid.
|
||||
-- If the tree is invalid, `parse()` must be called
|
||||
-- to get the an updated tree.
|
||||
--- Determines whether this tree is valid.
|
||||
--- If the tree is invalid, `parse()` must be called
|
||||
--- to get the an updated tree.
|
||||
function LanguageTree:is_valid()
|
||||
return self._valid
|
||||
end
|
||||
|
||||
-- Returns a map of language to child tree.
|
||||
--- Returns a map of language to child tree.
|
||||
function LanguageTree:children()
|
||||
return self._children
|
||||
end
|
||||
|
||||
-- Returns the source content of the language tree (bufnr or string).
|
||||
--- Returns the source content of the language tree (bufnr or string).
|
||||
function LanguageTree:source()
|
||||
return self._source
|
||||
end
|
||||
|
||||
-- Parses all defined regions using a treesitter parser
|
||||
-- for the language this tree represents.
|
||||
-- This will run the injection query for this language to
|
||||
-- determine if any child languages should be created.
|
||||
--- Parses all defined regions using a treesitter parser
|
||||
--- for the language this tree represents.
|
||||
--- This will run the injection query for this language to
|
||||
--- determine if any child languages should be created.
|
||||
function LanguageTree:parse()
|
||||
if self._valid then
|
||||
return self._trees
|
||||
@@ -169,9 +169,10 @@ function LanguageTree:parse()
|
||||
return self._trees, changes
|
||||
end
|
||||
|
||||
-- Invokes the callback for each LanguageTree and it's children recursively
|
||||
-- @param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string)
|
||||
-- @param include_self Whether to include the invoking tree in the results.
|
||||
--- Invokes the callback for each LanguageTree and it's children recursively
|
||||
---
|
||||
--- @param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string)
|
||||
--- @param include_self 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)
|
||||
@@ -182,10 +183,12 @@ function LanguageTree:for_each_child(fn, include_self)
|
||||
end
|
||||
end
|
||||
|
||||
-- Invokes the callback for each treesitter trees recursively.
|
||||
-- Note, this includes the invoking language tree's trees as well.
|
||||
-- @param fn The callback to invoke. The callback is invoked with arguments
|
||||
-- (tree: TSTree, languageTree: LanguageTree)
|
||||
--- Invokes the callback for each treesitter trees recursively.
|
||||
---
|
||||
--- Note, this includes the invoking language tree's trees as well.
|
||||
---
|
||||
--- @param fn The callback to invoke. The callback is invoked with arguments
|
||||
--- (tree: TSTree, languageTree: LanguageTree)
|
||||
function LanguageTree:for_each_tree(fn)
|
||||
for _, tree in ipairs(self._trees) do
|
||||
fn(tree, self)
|
||||
@@ -196,9 +199,11 @@ function LanguageTree:for_each_tree(fn)
|
||||
end
|
||||
end
|
||||
|
||||
-- Adds a child language to this tree.
|
||||
-- If the language already exists as a child, it will first be removed.
|
||||
-- @param lang The language to add.
|
||||
--- Adds a child language to this tree.
|
||||
---
|
||||
--- If the language already exists as a child, it will first be removed.
|
||||
---
|
||||
--- @param lang The language to add.
|
||||
function LanguageTree:add_child(lang)
|
||||
if self._children[lang] then
|
||||
self:remove_child(lang)
|
||||
@@ -212,8 +217,9 @@ function LanguageTree:add_child(lang)
|
||||
return self._children[lang]
|
||||
end
|
||||
|
||||
-- Removes a child language from this tree.
|
||||
-- @param lang The language to remove.
|
||||
--- Removes a child language from this tree.
|
||||
---
|
||||
--- @param lang The language to remove.
|
||||
function LanguageTree:remove_child(lang)
|
||||
local child = self._children[lang]
|
||||
|
||||
@@ -225,10 +231,11 @@ function LanguageTree:remove_child(lang)
|
||||
end
|
||||
end
|
||||
|
||||
-- Destroys this language tree and all its children.
|
||||
-- Any cleanup logic should be performed here.
|
||||
-- Note, this DOES NOT remove this tree from a parent.
|
||||
-- `remove_child` must be called on the parent to remove it.
|
||||
--- Destroys this language tree and all its children.
|
||||
---
|
||||
--- Any cleanup logic should be performed here.
|
||||
--- Note, this DOES NOT remove this tree from a parent.
|
||||
--- `remove_child` must be called on the parent to remove it.
|
||||
function LanguageTree:destroy()
|
||||
-- Cleanup here
|
||||
for _, child in ipairs(self._children) do
|
||||
@@ -236,23 +243,23 @@ function LanguageTree:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Sets the included regions that should be parsed by this parser.
|
||||
-- A region is a set of nodes and/or ranges that will be parsed in the same context.
|
||||
--
|
||||
-- For example, `{ { node1 }, { node2} }` is two separate regions.
|
||||
-- This will be parsed by the parser in two different contexts... thus resulting
|
||||
-- in two separate trees.
|
||||
--
|
||||
-- `{ { node1, node2 } }` is a single region consisting of two nodes.
|
||||
-- This will be parsed by the parser in a single context... thus resulting
|
||||
-- in a single tree.
|
||||
--
|
||||
-- This allows for embedded languages to be parsed together across different
|
||||
-- nodes, which is useful for templating languages like ERB and EJS.
|
||||
--
|
||||
-- Note, this call invalidates the tree and requires it to be parsed again.
|
||||
--
|
||||
-- @param regions A list of regions this tree should manage and parse.
|
||||
--- Sets the included regions that should be parsed by this parser.
|
||||
--- A region is a set of nodes and/or ranges that will be parsed in the same context.
|
||||
---
|
||||
--- For example, `{ { node1 }, { node2} }` is two separate regions.
|
||||
--- This will be parsed by the parser in two different contexts... thus resulting
|
||||
--- in two separate trees.
|
||||
---
|
||||
--- `{ { node1, node2 } }` is a single region consisting of two nodes.
|
||||
--- This will be parsed by the parser in a single context... thus resulting
|
||||
--- in a single tree.
|
||||
---
|
||||
--- This allows for embedded languages to be parsed together across different
|
||||
--- nodes, which is useful for templating languages like ERB and EJS.
|
||||
---
|
||||
--- Note, this call invalidates the tree and requires it to be parsed again.
|
||||
---
|
||||
--- @param regions A list of regions this tree should manage and parse.
|
||||
function LanguageTree:set_included_regions(regions)
|
||||
-- TODO(vigoux): I don't think string parsers are useful for now
|
||||
if type(self._source) == "number" then
|
||||
@@ -281,16 +288,18 @@ function LanguageTree:set_included_regions(regions)
|
||||
self:invalidate()
|
||||
end
|
||||
|
||||
-- Gets the set of included regions
|
||||
--- Gets the set of included regions
|
||||
function LanguageTree:included_regions()
|
||||
return self._regions
|
||||
end
|
||||
|
||||
-- Gets language injection points by language.
|
||||
-- This is where most of the injection processing occurs.
|
||||
-- TODO: Allow for an offset predicate to tailor the injection range
|
||||
-- instead of using the entire nodes range.
|
||||
-- @private
|
||||
--- Gets language injection points by language.
|
||||
---
|
||||
--- This is where most of the injection processing occurs.
|
||||
---
|
||||
--- TODO: Allow for an offset predicate to tailor the injection range
|
||||
--- instead of using the entire nodes range.
|
||||
--- @private
|
||||
function LanguageTree:_get_injections()
|
||||
if not self._injection_query then return {} end
|
||||
|
||||
@@ -395,12 +404,14 @@ function LanguageTree:_get_injections()
|
||||
return result
|
||||
end
|
||||
|
||||
---@private
|
||||
function LanguageTree:_do_callback(cb_name, ...)
|
||||
for _, cb in ipairs(self._callbacks[cb_name]) do
|
||||
cb(...)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
function LanguageTree:_on_bytes(bufnr, changed_tick,
|
||||
start_row, start_col, start_byte,
|
||||
old_row, old_col, old_byte,
|
||||
@@ -425,24 +436,26 @@ function LanguageTree:_on_bytes(bufnr, changed_tick,
|
||||
new_row, new_col, new_byte)
|
||||
end
|
||||
|
||||
---@private
|
||||
function LanguageTree:_on_reload()
|
||||
self:invalidate(true)
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
function LanguageTree:_on_detach(...)
|
||||
self:invalidate(true)
|
||||
self:_do_callback('detach', ...)
|
||||
end
|
||||
|
||||
--- Registers callbacks for the parser
|
||||
-- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
|
||||
-- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
|
||||
-- `on_changedtree` : a callback that will be called every time the tree has syntactical changes.
|
||||
-- it will only be passed one argument, that is a table of the ranges (as node ranges) that
|
||||
-- changed.
|
||||
-- `on_child_added` : emitted when a child is added to the tree.
|
||||
-- `on_child_removed` : emitted when a child is removed from the tree.
|
||||
--- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
|
||||
--- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
|
||||
--- `on_changedtree` : a callback that will be called every time the tree has syntactical changes.
|
||||
--- it will only be passed one argument, that is a table of the ranges (as node ranges) that
|
||||
--- changed.
|
||||
--- `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)
|
||||
if not cbs then return end
|
||||
|
||||
@@ -467,6 +480,7 @@ function LanguageTree:register_cbs(cbs)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
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])
|
||||
@@ -479,6 +493,11 @@ local function tree_contains(tree, range)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Determines wether @param range is contained in this language tree
|
||||
---
|
||||
--- This goes down the tree to recursively check childs.
|
||||
---
|
||||
--- @param range A range, that is a `{ start_line, start_col, end_line, end_col }` table.
|
||||
function LanguageTree:contains(range)
|
||||
for _, tree in pairs(self._trees) do
|
||||
if tree_contains(tree, range) then
|
||||
@@ -489,6 +508,9 @@ function LanguageTree:contains(range)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Gets the appropriate language that contains @param range
|
||||
---
|
||||
--- @param range A text range, see |LanguageTree:contains|
|
||||
function LanguageTree:language_for_range(range)
|
||||
for _, child in pairs(self._children) do
|
||||
if child:contains(range) then
|
||||
|
||||
@@ -8,6 +8,7 @@ Query.__index = Query
|
||||
|
||||
local M = {}
|
||||
|
||||
---@private
|
||||
local function dedupe_files(files)
|
||||
local result = {}
|
||||
local seen = {}
|
||||
@@ -22,6 +23,7 @@ local function dedupe_files(files)
|
||||
return result
|
||||
end
|
||||
|
||||
---@private
|
||||
local function safe_read(filename, read_quantifier)
|
||||
local file, err = io.open(filename, 'r')
|
||||
if not file then
|
||||
@@ -32,6 +34,11 @@ local function safe_read(filename, read_quantifier)
|
||||
return content
|
||||
end
|
||||
|
||||
--- Gets the list of files used to make up a query
|
||||
---
|
||||
--- @param lang The language
|
||||
--- @param query_name The name of the query to load
|
||||
--- @param is_included Internal parameter, most of the time left as `nil`
|
||||
function M.get_query_files(lang, query_name, is_included)
|
||||
local query_path = string.format('queries/%s/%s.scm', lang, query_name)
|
||||
local lang_files = dedupe_files(a.nvim_get_runtime_file(query_path, true))
|
||||
@@ -79,6 +86,7 @@ function M.get_query_files(lang, query_name, is_included)
|
||||
return query_files
|
||||
end
|
||||
|
||||
---@private
|
||||
local function read_query_files(filenames)
|
||||
local contents = {}
|
||||
|
||||
@@ -103,19 +111,20 @@ local explicit_queries = setmetatable({}, {
|
||||
---
|
||||
--- This allows users to override any runtime files and/or configuration
|
||||
--- set by plugins.
|
||||
---@param lang string: The language to use for the query
|
||||
---@param query_name string: The name of the query (i.e. "highlights")
|
||||
---@param text string: The query text (unparsed).
|
||||
---
|
||||
--- @param lang string: The language to use for the query
|
||||
--- @param query_name string: The name of the query (i.e. "highlights")
|
||||
--- @param text string: The query text (unparsed).
|
||||
function M.set_query(lang, query_name, text)
|
||||
explicit_queries[lang][query_name] = M.parse_query(lang, text)
|
||||
end
|
||||
|
||||
--- Returns the runtime query {query_name} for {lang}.
|
||||
--
|
||||
-- @param lang The language to use for the query
|
||||
-- @param query_name The name of the query (i.e. "highlights")
|
||||
--
|
||||
-- @return The corresponding query, parsed.
|
||||
---
|
||||
--- @param lang The language to use for the query
|
||||
--- @param query_name The name of the query (i.e. "highlights")
|
||||
---
|
||||
--- @return The corresponding query, parsed.
|
||||
function M.get_query(lang, query_name)
|
||||
if explicit_queries[lang][query_name] then
|
||||
return explicit_queries[lang][query_name]
|
||||
@@ -129,12 +138,23 @@ function M.get_query(lang, query_name)
|
||||
end
|
||||
end
|
||||
|
||||
--- Parses a query.
|
||||
--
|
||||
-- @param language The language
|
||||
-- @param query A string containing the query (s-expr syntax)
|
||||
--
|
||||
-- @returns The query
|
||||
--- Parse {query} as a string. (If the query is in a file, the caller
|
||||
--- should read the contents into a string before calling).
|
||||
---
|
||||
--- Returns a `Query` (see |lua-treesitter-query|) object which can be used to
|
||||
--- search nodes in the syntax tree for the patterns defined in {query}
|
||||
--- using `iter_*` methods below.
|
||||
---
|
||||
--- Exposes `info` and `captures` with additional information about the {query}.
|
||||
--- - `captures` contains the list of unique capture names defined in
|
||||
--- {query}.
|
||||
--- -` info.captures` also points to `captures`.
|
||||
--- - `info.patterns` contains information about predicates.
|
||||
---
|
||||
--- @param lang The language
|
||||
--- @param query A string containing the query (s-expr syntax)
|
||||
---
|
||||
--- @returns The query
|
||||
function M.parse_query(lang, query)
|
||||
language.require_language(lang)
|
||||
local self = setmetatable({}, Query)
|
||||
@@ -147,8 +167,9 @@ end
|
||||
-- TODO(vigoux): support multiline nodes too
|
||||
|
||||
--- Gets the text corresponding to a given node
|
||||
-- @param node the node
|
||||
-- @param bufnr the buffer from which the node is extracted.
|
||||
---
|
||||
--- @param node the node
|
||||
--- @param bsource The buffer or string from which the node is extracted
|
||||
function M.get_node_text(node, source)
|
||||
local start_row, start_col, start_byte = node:start()
|
||||
local end_row, end_col, end_byte = node:end_()
|
||||
@@ -200,6 +221,7 @@ local predicate_handlers = {
|
||||
|
||||
["match?"] = (function()
|
||||
local magic_prefixes = {['\\v']=true, ['\\m']=true, ['\\M']=true, ['\\V']=true}
|
||||
---@private
|
||||
local function check_magic(str)
|
||||
if string.len(str) < 2 or magic_prefixes[string.sub(str,1,2)] then
|
||||
return str
|
||||
@@ -282,10 +304,10 @@ local directive_handlers = {
|
||||
}
|
||||
|
||||
--- Adds a new predicate to be used in queries
|
||||
--
|
||||
-- @param name the name of the predicate, without leading #
|
||||
-- @param handler the handler function to be used
|
||||
-- signature will be (match, pattern, bufnr, predicate)
|
||||
---
|
||||
--- @param name the name of the predicate, without leading #
|
||||
--- @param handler the handler function to be used
|
||||
--- signature will be (match, pattern, bufnr, predicate)
|
||||
function M.add_predicate(name, handler, force)
|
||||
if predicate_handlers[name] and not force then
|
||||
error(string.format("Overriding %s", name))
|
||||
@@ -295,10 +317,10 @@ function M.add_predicate(name, handler, force)
|
||||
end
|
||||
|
||||
--- Adds a new directive to be used in queries
|
||||
--
|
||||
-- @param name the name of the directive, without leading #
|
||||
-- @param handler the handler function to be used
|
||||
-- signature will be (match, pattern, bufnr, predicate)
|
||||
---
|
||||
--- @param name the name of the directive, without leading #
|
||||
--- @param handler the handler function to be used
|
||||
--- signature will be (match, pattern, bufnr, predicate)
|
||||
function M.add_directive(name, handler, force)
|
||||
if directive_handlers[name] and not force then
|
||||
error(string.format("Overriding %s", name))
|
||||
@@ -312,14 +334,17 @@ function M.list_predicates()
|
||||
return vim.tbl_keys(predicate_handlers)
|
||||
end
|
||||
|
||||
---@private
|
||||
local function xor(x, y)
|
||||
return (x or y) and not (x and y)
|
||||
end
|
||||
|
||||
---@private
|
||||
local function is_directive(name)
|
||||
return string.sub(name, -1) == "!"
|
||||
end
|
||||
|
||||
---@private
|
||||
function Query:match_preds(match, pattern, source)
|
||||
local preds = self.info.patterns[pattern]
|
||||
|
||||
@@ -358,7 +383,7 @@ function Query:match_preds(match, pattern, source)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Applies directives against a match and pattern.
|
||||
---@private
|
||||
function Query:apply_directives(match, pattern, source, metadata)
|
||||
local preds = self.info.patterns[pattern]
|
||||
|
||||
@@ -380,6 +405,7 @@ end
|
||||
--- Returns the start and stop value if set else the node's range.
|
||||
-- When the node's range is used, the stop is incremented by 1
|
||||
-- to make the search inclusive.
|
||||
---@private
|
||||
local function value_or_node_range(start, stop, node)
|
||||
if start == nil and stop == nil then
|
||||
local node_start, _, node_stop, _ = node:range()
|
||||
@@ -389,15 +415,36 @@ local function value_or_node_range(start, stop, node)
|
||||
return start, stop
|
||||
end
|
||||
|
||||
--- Iterates of the captures of self on a given range.
|
||||
--
|
||||
-- @param node The node under which the search will occur
|
||||
-- @param buffer The source buffer to search
|
||||
-- @param start The starting line of the search
|
||||
-- @param stop The stopping line of the search (end-exclusive)
|
||||
--
|
||||
-- @returns The matching capture id
|
||||
-- @returns The captured node
|
||||
--- Iterate over all captures from all matches inside {node}
|
||||
---
|
||||
--- {source} is needed if the query contains predicates, then the caller
|
||||
--- must ensure to use a freshly parsed tree consistent with the current
|
||||
--- text of the buffer (if relevent). {start_row} and {end_row} can be used to limit
|
||||
--- matches inside a row range (this is typically used with root node
|
||||
--- as the node, i e to get syntax highlight matches in the current
|
||||
--- viewport). When omitted the start and end row values are used from the given node.
|
||||
---
|
||||
--- The iterator returns three values, a numeric id identifying the capture,
|
||||
--- the captured node, and metadata from any directives processing the match.
|
||||
--- The following example shows how to get captures by name:
|
||||
---
|
||||
--- <pre>
|
||||
--- for id, node, metadata in query:iter_captures(tree:root(), bufnr, first, last) do
|
||||
--- local name = query.captures[id] -- name of the capture in the query
|
||||
--- -- typically useful info about the node:
|
||||
--- local type = node:type() -- type of the captured node
|
||||
--- local row1, col1, row2, col2 = node:range() -- range of the capture
|
||||
--- ... use the info here ...
|
||||
--- end
|
||||
--- </pre>
|
||||
---
|
||||
--- @param node The node under which the search will occur
|
||||
--- @param source The source buffer or string to exctract text from
|
||||
--- @param start The starting line of the search
|
||||
--- @param stop The stopping line of the search (end-exclusive)
|
||||
---
|
||||
--- @returns The matching capture id
|
||||
--- @returns The captured node
|
||||
function Query:iter_captures(node, source, start, stop)
|
||||
if type(source) == "number" and source == 0 then
|
||||
source = vim.api.nvim_get_current_buf()
|
||||
@@ -406,6 +453,7 @@ function Query:iter_captures(node, source, start, stop)
|
||||
start, stop = value_or_node_range(start, stop, node)
|
||||
|
||||
local raw_iter = node:_rawquery(self.query, true, start, stop)
|
||||
---@private
|
||||
local function iter()
|
||||
local capture, captured_node, match = raw_iter()
|
||||
local metadata = {}
|
||||
@@ -425,14 +473,35 @@ function Query:iter_captures(node, source, start, stop)
|
||||
end
|
||||
|
||||
--- Iterates the matches of self on a given range.
|
||||
--
|
||||
-- @param node The node under which the search will occur
|
||||
-- @param buffer The source buffer to search
|
||||
-- @param start The starting line of the search
|
||||
-- @param stop The stopping line of the search (end-exclusive)
|
||||
--
|
||||
-- @returns The matching pattern id
|
||||
-- @returns The matching match
|
||||
---
|
||||
--- Iterate over all matches within a node. The arguments are the same as
|
||||
--- for |query:iter_captures()| but the iterated values are different:
|
||||
--- an (1-based) index of the pattern in the query, a table mapping
|
||||
--- capture indices to nodes, and metadata from any directives processing the match.
|
||||
--- If the query has more than one pattern the capture table might be sparse,
|
||||
--- and e.g. `pairs()` method should be used over `ipairs`.
|
||||
--- Here an example iterating over all captures in every match:
|
||||
---
|
||||
--- <pre>
|
||||
--- for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, first, last) do
|
||||
--- for id, node in pairs(match) do
|
||||
--- local name = query.captures[id]
|
||||
--- -- `node` was captured by the `name` capture in the match
|
||||
---
|
||||
--- local node_data = metadata[id] -- Node level metadata
|
||||
---
|
||||
--- ... use the info here ...
|
||||
--- end
|
||||
--- end
|
||||
--- </pre>
|
||||
---
|
||||
--- @param node The node under which the search will occur
|
||||
--- @param source The source buffer or string to search
|
||||
--- @param start The starting line of the search
|
||||
--- @param stop The stopping line of the search (end-exclusive)
|
||||
---
|
||||
--- @returns The matching pattern id
|
||||
--- @returns The matching match
|
||||
function Query:iter_matches(node, source, start, stop)
|
||||
if type(source) == "number" and source == 0 then
|
||||
source = vim.api.nvim_get_current_buf()
|
||||
|
||||
Reference in New Issue
Block a user