From 9a5678463c96baf3b39cb3083ddf0da87d39aa23 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 4 Feb 2023 14:58:38 +0000 Subject: fix(treesitter): fix most diagnostics --- runtime/lua/vim/treesitter/query.lua | 109 +++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 31 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index dbf134573d..84ed2667b9 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -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 + local M = {} ---@private +---@param files string[] +---@return string[] local function dedupe_files(files) local result = {} + ---@type table 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> 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 + +---@alias TSPredicate fun(match: TSMatch, _, _, predicate: any[]): boolean + -- Predicate handler receive the following arguments -- (match, pattern, bufnr, predicate) +---@type table 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 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, 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, 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 --- --- ----@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 --- --- ----@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, 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 = {} -- cgit From bb8845340b1b9c2180fb19f049ff9deff5857d99 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 21 Jul 2022 12:08:37 +0100 Subject: feat(treesitter): allow capture text to be transformed Co-authored-by: Lewis Russell --- runtime/lua/vim/treesitter/query.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 84ed2667b9..5ec8c67462 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -452,6 +452,21 @@ local directive_handlers = { metadata[capture_id].range = range end end, + + -- Transform the content of the node + -- Example: (#gsub! @_node ".*%.(.*)" "%1") + ['gsub!'] = function(match, _, bufnr, pred, metadata) + assert(#pred == 4) + + local id = pred[2] + local node = match[id] + local text = M.get_node_text(node, bufnr, { metadata = metadata[id] }) or '' + + if not metadata[id] then + metadata[id] = {} + end + metadata[id].text = text:gsub(pred[3], pred[4]) + end, } --- Adds a new predicate to be used in queries -- cgit From e1d5ad1cb87d43c3d75619e239312d4ab2029b45 Mon Sep 17 00:00:00 2001 From: figsoda Date: Mon, 26 Dec 2022 16:10:59 -0500 Subject: feat(treesitter): add metadata option for get_node_text --- runtime/lua/vim/treesitter/query.lua | 70 +++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 28 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 5ec8c67462..9136b596be 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -55,6 +55,38 @@ local function add_included_lang(base_langs, lang, ilang) return false end +---@private +---@param buf (number) +---@param range (table) +---@param concat (boolean) +---@returns (string[]|string|nil) +local function buf_range_get_text(buf, range, concat) + local lines + local start_row, start_col, end_row, end_col = unpack(range) + local eof_row = a.nvim_buf_line_count(buf) + if start_row >= eof_row then + return nil + end + + if end_col == 0 then + lines = a.nvim_buf_get_lines(buf, start_row, end_row, true) + end_col = -1 + else + lines = a.nvim_buf_get_lines(buf, start_row, end_row + 1, true) + end + + if #lines > 0 then + if #lines == 1 then + lines[1] = string.sub(lines[1], start_col + 1, end_col) + else + lines[1] = string.sub(lines[1], start_col + 1) + lines[#lines] = string.sub(lines[#lines], 1, end_col) + end + end + + return concat and table.concat(lines, '\n') or lines +end + --- Gets the list of files used to make up a query --- ---@param lang string Language to get query for @@ -240,40 +272,22 @@ end ---@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) +--- - metadata (table) Metadata of a specific capture. This would be +--- set to `metadata[capture_id]` when using +--- |vim.treesitter.query.add_directive()|. ---@return (string[]|string|nil) function M.get_node_text(node, source, opts) opts = opts or {} local concat = vim.F.if_nil(opts.concat, true) + local metadata = opts.metadata or {} - local start_row, start_col, start_byte = node:start() - local end_row, end_col, end_byte = node:end_() - - if type(source) == 'number' then - 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 - else - lines = a.nvim_buf_get_lines(source, start_row, end_row + 1, true) - end - - if #lines > 0 then - if #lines == 1 then - lines[1] = string.sub(lines[1], start_col + 1, end_col) - else - lines[1] = string.sub(lines[1], start_col + 1) - lines[#lines] = string.sub(lines[#lines], 1, end_col) - end - end - - return concat and table.concat(lines, '\n') or lines + if metadata.text then + return metadata.text + elseif type(source) == 'number' then + return metadata.range and buf_range_get_text(source, metadata.range, concat) + or buf_range_get_text(source, { node:range() }, concat) elseif type(source) == 'string' then - return source:sub(start_byte + 1, end_byte) + return source:sub(select(3, node:start()) + 1, select(3, node:end_())) end end -- cgit From 4c66f5ff97a52fbc933fdbe1907c4b960d5a7403 Mon Sep 17 00:00:00 2001 From: figsoda Date: Mon, 26 Dec 2022 16:11:45 -0500 Subject: feat(treesitter): respect metadata[id].range for offset! --- runtime/lua/vim/treesitter/query.lua | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 9136b596be..a0522d7cda 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -445,9 +445,11 @@ local directive_handlers = { ['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 + if not metadata[capture_id] then + metadata[capture_id] = {} + end + + local range = metadata[capture_id].range or { match[capture_id]:range() } local start_row_offset = pred[3] or 0 local start_col_offset = pred[4] or 0 local end_row_offset = pred[5] or 0 @@ -460,9 +462,6 @@ local directive_handlers = { -- If this produces an invalid range, we just skip it. if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then - if not metadata[capture_id] then - metadata[capture_id] = {} - end metadata[capture_id].range = range end end, -- cgit From a289e82142fdc5ff657dd30198546eeb1e115fe9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 15 Feb 2023 12:26:07 +0000 Subject: fix(treesitter): make params optional --- runtime/lua/vim/treesitter/query.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index a0522d7cda..008e5a54d7 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -487,7 +487,7 @@ local directive_handlers = { ---@param name string Name of the predicate, without leading # ---@param handler function(match:table, pattern:string, bufnr:number, predicate:string[]) --- - see |vim.treesitter.query.add_directive()| for argument meanings ----@param force boolean +---@param force boolean|nil function M.add_predicate(name, handler, force) if predicate_handlers[name] and not force then error(string.format('Overriding %s', name)) @@ -510,7 +510,7 @@ end --- - 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 +---@param force boolean|nil function M.add_directive(name, handler, force) if directive_handlers[name] and not force then error(string.format('Overriding %s', name)) -- cgit From 8714a4009c0f0be0bb27a6b3eb486eeb3d9f3049 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 21 Feb 2023 17:09:18 +0000 Subject: feat(treesitter): add filetype -> lang API Problem: vim.treesitter does not know how to map a specific filetype to a parser. This creates problems since in a few places (including in vim.treesitter itself), the filetype is incorrectly used in place of lang. Solution: Add an API to enable this: - Add vim.treesitter.language.add() as a replacement for vim.treesitter.language.require_language(). - Optional arguments are now passed via an opts table. - Also takes a filetype (or list of filetypes) so we can keep track of what filetypes are associated with which langs. - Deprecated vim.treesitter.language.require_language(). - Add vim.treesitter.language.get_lang() which returns the associated lang for a given filetype. - Add vim.treesitter.language.register() to associate filetypes to a lang without loading the parser. --- runtime/lua/vim/treesitter/query.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 008e5a54d7..83910316a6 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -252,7 +252,7 @@ end) --- ---@return Query Parsed query function M.parse_query(lang, query) - language.require_language(lang) + language.add(lang) local cached = query_cache[lang][query] if cached then return cached -- cgit From 6dfbeb0d990d24657754463c6ab155c19e7f5f56 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 21 Feb 2023 17:39:29 +0100 Subject: docs: fix more treesitter parsing errors --- runtime/lua/vim/treesitter/query.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 83910316a6..58a29f2fe0 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -639,7 +639,7 @@ end --- -- 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 ... +--- -- ... use the info here ... --- end --- --- @@ -693,7 +693,7 @@ end --- --- local node_data = metadata[id] -- Node level metadata --- ---- ... use the info here ... +--- -- ... use the info here ... --- end --- end --- -- cgit From 75e53341f37eeeda7d9be7f934249f7e5e4397e9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 23 Feb 2023 15:19:52 +0000 Subject: perf(treesitter): smarter languagetree invalidation Problem: Treesitter injections are slow because all injected trees are invalidated on every change. Solution: Implement smarter invalidation to avoid reparsing injected regions. - In on_bytes, try and update self._regions as best we can. This PR just offsets any regions after the change. - Add valid flags for each region in self._regions. - Call on_bytes recursively for all children. - We still need to run the query every time for the top level tree. I don't know how to avoid this. However, if the new injection ranges don't change, then we re-use the old trees and avoid reparsing children. This should result in roughly a 2-3x reduction in tree parsing when the comment injections are enabled. --- runtime/lua/vim/treesitter/query.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 58a29f2fe0..13d98a0625 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -406,7 +406,7 @@ predicate_handlers['vim-match?'] = predicate_handlers['match?'] ---@class TSMetadata ---@field [integer] TSMetadata ---@field [string] integer|string ----@field range Range +---@field range Range4 ---@alias TSDirective fun(match: TSMatch, _, _, predicate: any[], metadata: TSMetadata) -- cgit From 8414cfe7f4d8888698343cb54a3f373a28b365db Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 2 Mar 2023 20:46:59 +0100 Subject: docs: fix vim.treesitter tags Problem: Help tags like vim.treesitter.language.add() are confusing because `vim.treesitter.language` is (thankfully) not a user-facing module. Solution: Ignore the "fstem" when generating "treesitter" tags. --- runtime/lua/vim/treesitter/query.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 13d98a0625..4e9871b59d 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -273,8 +273,7 @@ end ---@param opts (table|nil) Optional parameters. --- - concat: (boolean) Concatenate result in a string (default true) --- - metadata (table) Metadata of a specific capture. This would be ---- set to `metadata[capture_id]` when using ---- |vim.treesitter.query.add_directive()|. +--- set to `metadata[capture_id]` when using |vim.treesitter.add_directive()|. ---@return (string[]|string|nil) function M.get_node_text(node, source, opts) opts = opts or {} @@ -486,7 +485,7 @@ local directive_handlers = { --- ---@param name string Name of the predicate, without leading # ---@param handler function(match:table, pattern:string, bufnr:number, predicate:string[]) ---- - see |vim.treesitter.query.add_directive()| for argument meanings +--- - see |vim.treesitter.add_directive()| for argument meanings ---@param force boolean|nil function M.add_predicate(name, handler, force) if predicate_handlers[name] and not force then -- cgit From 128b82103ba477482bdfaf10ec71e0986876cca1 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 4 Mar 2023 22:04:05 +0900 Subject: docs(treesitter): number → integer (#22513) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/lua/vim/treesitter/query.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 4e9871b59d..22f706585e 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -56,7 +56,7 @@ local function add_included_lang(base_langs, lang, ilang) end ---@private ----@param buf (number) +---@param buf (integer) ---@param range (table) ---@param concat (boolean) ---@returns (string[]|string|nil) @@ -269,7 +269,7 @@ end --- Gets the text corresponding to a given node --- ---@param node TSNode ----@param source (number|string) Buffer or string from which the {node} is extracted +---@param source (integer|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) --- - metadata (table) Metadata of a specific capture. This would be @@ -484,7 +484,7 @@ 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, pattern:string, bufnr:integer, predicate:string[]) --- - see |vim.treesitter.add_directive()| for argument meanings ---@param force boolean|nil function M.add_predicate(name, handler, force) @@ -503,7 +503,7 @@ 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, pattern:string, bufnr:integer, predicate:string[], metadata:table) --- - match: see |treesitter-query| --- - node-level data are accessible via `match[capture_id]` --- - pattern: see |treesitter-query| @@ -644,8 +644,8 @@ end --- ---@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) +---@param start integer Starting line for the search +---@param stop integer Stopping line for the search (end-exclusive) --- ---@return (fun(): integer, TSNode, TSMetadata): capture id, capture node, metadata function Query:iter_captures(node, source, start, stop) -- cgit From ddd257f75301a50c177fc24a693d39a45b47a689 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 8 Mar 2023 11:03:11 +0000 Subject: feat(treesitter): use upstream format for injection queries --- runtime/lua/vim/treesitter/query.lua | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 22f706585e..59894cc7f5 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -407,7 +407,7 @@ predicate_handlers['vim-match?'] = predicate_handlers['match?'] ---@field [string] integer|string ---@field range Range4 ----@alias TSDirective fun(match: TSMatch, _, _, predicate: any[], metadata: TSMetadata) +---@alias TSDirective fun(match: TSMatch, _, _, predicate: (string|integer)[], metadata: TSMetadata) -- Predicate handler receive the following arguments -- (match, pattern, bufnr, predicate) @@ -419,24 +419,17 @@ predicate_handlers['vim-match?'] = predicate_handlers['match?'] ---@type table 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 #pred >= 3 and type(pred[2]) == 'number' then + -- (#set! @capture key value) + local capture_id, key, value = pred[2], pred[3], pred[4] 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 + -- (#set! key value) + local key, value = pred[2], pred[3] + metadata[key] = value or true end end, -- Shifts the range of a node. -- cgit From 276b647fdba07bf1762d8dd371c4b655b8a418df Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 8 Mar 2023 17:22:28 +0000 Subject: refactor(treesitter): delegate region calculation to treesitter (#22553) --- runtime/lua/vim/treesitter/query.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 59894cc7f5..e7cf42283d 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -277,6 +277,7 @@ end ---@return (string[]|string|nil) function M.get_node_text(node, source, opts) opts = opts or {} + -- TODO(lewis6991): concat only works when source is number. local concat = vim.F.if_nil(opts.concat, true) local metadata = opts.metadata or {} -- cgit From b9f19d3e286d95d9209afbc479fa2eb908067fb1 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 8 Mar 2023 17:59:45 +0000 Subject: Revert "refactor(treesitter): delegate region calculation to treesitter" (#22575) Revert "refactor(treesitter): delegate region calculation to treesitter (#22553)" This reverts commit 276b647fdba07bf1762d8dd371c4b655b8a418df. --- runtime/lua/vim/treesitter/query.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index e7cf42283d..59894cc7f5 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -277,7 +277,6 @@ end ---@return (string[]|string|nil) function M.get_node_text(node, source, opts) opts = opts or {} - -- TODO(lewis6991): concat only works when source is number. local concat = vim.F.if_nil(opts.concat, true) local metadata = opts.metadata or {} -- cgit From ae263aff9547b8b513c4fedaceb4cbf93c57b866 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 9 Mar 2023 16:09:39 +0000 Subject: refactor(treesitter): use byte ranges from treesitter (#22589) --- runtime/lua/vim/treesitter/query.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 59894cc7f5..e7cf42283d 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -277,6 +277,7 @@ end ---@return (string[]|string|nil) function M.get_node_text(node, source, opts) opts = opts or {} + -- TODO(lewis6991): concat only works when source is number. local concat = vim.F.if_nil(opts.concat, true) local metadata = opts.metadata or {} -- cgit From 9d70fe062ca01ac0673faa6ccbb88345916aeea7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 10 Mar 2023 16:10:05 +0000 Subject: feat(treesitter)!: consolidate query util functions - And address more type errors. - Removed the `concat` option from `get_node_text` since it was applied inconsistently and made typing awkward. --- runtime/lua/vim/treesitter/query.lua | 97 ++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 49 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index e7cf42283d..70af4f7bce 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -1,6 +1,8 @@ local a = vim.api local language = require('vim.treesitter.language') +local Range = require('vim.treesitter._range') + ---@class Query ---@field captures string[] List of captures used in query ---@field info TSQueryInfo Contains used queries, predicates, directives @@ -56,35 +58,13 @@ local function add_included_lang(base_langs, lang, ilang) end ---@private ----@param buf (integer) ----@param range (table) ----@param concat (boolean) ----@returns (string[]|string|nil) -local function buf_range_get_text(buf, range, concat) - local lines - local start_row, start_col, end_row, end_col = unpack(range) - local eof_row = a.nvim_buf_line_count(buf) - if start_row >= eof_row then - return nil - end - - if end_col == 0 then - lines = a.nvim_buf_get_lines(buf, start_row, end_row, true) - end_col = -1 - else - lines = a.nvim_buf_get_lines(buf, start_row, end_row + 1, true) - end - - if #lines > 0 then - if #lines == 1 then - lines[1] = string.sub(lines[1], start_col + 1, end_col) - else - lines[1] = string.sub(lines[1], start_col + 1) - lines[#lines] = string.sub(lines[#lines], 1, end_col) - end - end - - return concat and table.concat(lines, '\n') or lines +---@param buf integer +---@param range Range6 +---@returns string +local function buf_range_get_text(buf, range) + local start_row, start_col, end_row, end_col = Range.unpack4(range) + local lines = a.nvim_buf_get_text(buf, start_row, start_col, end_row, end_col, {}) + return table.concat(lines, '\n') end --- Gets the list of files used to make up a query @@ -256,14 +236,28 @@ function M.parse_query(lang, query) local cached = query_cache[lang][query] if cached then return cached - else - local self = setmetatable({}, Query) - self.query = vim._ts_parse_query(lang, query) - self.info = self.query:inspect() - self.captures = self.info.captures - query_cache[lang][query] = self - return self end + + local self = setmetatable({}, Query) + self.query = vim._ts_parse_query(lang, query) + self.info = self.query:inspect() + self.captures = self.info.captures + query_cache[lang][query] = self + return self +end + +---Get the range of a |TSNode|. Can also supply {source} and {metadata} +---to get the range with directives applied. +---@param node TSNode +---@param source integer|string|nil Buffer or string from which the {node} is extracted +---@param metadata TSMetadata|nil +---@return Range6 +function M.get_range(node, source, metadata) + if metadata and metadata.range then + assert(source) + return Range.add_bytes(source, metadata.range) + end + return { node:range(true) } end --- Gets the text corresponding to a given node @@ -271,24 +265,22 @@ end ---@param node TSNode ---@param source (integer|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) --- - metadata (table) Metadata of a specific capture. This would be --- set to `metadata[capture_id]` when using |vim.treesitter.add_directive()|. ----@return (string[]|string|nil) +---@return string function M.get_node_text(node, source, opts) opts = opts or {} - -- TODO(lewis6991): concat only works when source is number. - local concat = vim.F.if_nil(opts.concat, true) local metadata = opts.metadata or {} if metadata.text then return metadata.text elseif type(source) == 'number' then - return metadata.range and buf_range_get_text(source, metadata.range, concat) - or buf_range_get_text(source, { node:range() }, concat) - elseif type(source) == 'string' then - return source:sub(select(3, node:start()) + 1, select(3, node:end_())) + local range = M.get_range(node, source, metadata) + return buf_range_get_text(source, range) end + + ---@cast source string + return source:sub(select(3, node:start()) + 1, select(3, node:end_())) end ---@alias TSMatch table @@ -312,7 +304,7 @@ local predicate_handlers = { str = predicate[3] else -- (#eq? @aa @bb) - str = M.get_node_text(match[predicate[3]], source) --[[@as string]] + str = M.get_node_text(match[predicate[3]], source) end if node_text ~= str or str == nil then @@ -328,7 +320,7 @@ local predicate_handlers = { return true end local regex = predicate[3] - return string.find(M.get_node_text(node, source) --[[@as string]], regex) ~= nil + return string.find(M.get_node_text(node, source), regex) ~= nil end, ['match?'] = (function() @@ -366,7 +358,7 @@ local predicate_handlers = { if not node then return true end - local node_text = M.get_node_text(node, source) --[[@as string]] + local node_text = M.get_node_text(node, source) for i = 3, #predicate do if string.find(node_text, predicate[i], 1, true) then @@ -404,9 +396,9 @@ local predicate_handlers = { predicate_handlers['vim-match?'] = predicate_handlers['match?'] ---@class TSMetadata +---@field range Range4|Range6 ---@field [integer] TSMetadata ---@field [string] integer|string ----@field range Range4 ---@alias TSDirective fun(match: TSMatch, _, _, predicate: (string|integer)[], metadata: TSMetadata) @@ -465,13 +457,20 @@ local directive_handlers = { assert(#pred == 4) local id = pred[2] + assert(type(id) == 'number') + local node = match[id] local text = M.get_node_text(node, bufnr, { metadata = metadata[id] }) or '' if not metadata[id] then metadata[id] = {} end - metadata[id].text = text:gsub(pred[3], pred[4]) + + local pattern, replacement = pred[3], pred[3] + assert(type(pattern) == 'string') + assert(type(replacement) == 'string') + + metadata[id].text = text:gsub(pattern, replacement) end, } -- cgit From 58bbc2ea0b3dfed13471e8cc0447d7598be24276 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 10 Mar 2023 16:40:27 +0000 Subject: refactor(treesitter): add Range type aliase for Range4|Range6 --- runtime/lua/vim/treesitter/query.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 70af4f7bce..f4e038b2d8 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -59,10 +59,18 @@ end ---@private ---@param buf integer ----@param range Range6 +---@param range Range ---@returns string local function buf_range_get_text(buf, range) local start_row, start_col, end_row, end_col = Range.unpack4(range) + if end_col == 0 then + if start_row == end_row then + start_col = -1 + start_row = start_row - 1 + end + end_col = -1 + end_row = end_row - 1 + end local lines = a.nvim_buf_get_text(buf, start_row, start_col, end_row, end_col, {}) return table.concat(lines, '\n') end @@ -396,7 +404,7 @@ local predicate_handlers = { predicate_handlers['vim-match?'] = predicate_handlers['match?'] ---@class TSMetadata ----@field range Range4|Range6 +---@field range Range ---@field [integer] TSMetadata ---@field [string] integer|string -- cgit From cbbf8bd666c8419fdab80a0887948c8a36279c19 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 24 Mar 2023 14:43:14 +0000 Subject: feat(treesitter)!: deprecate top level indexes to modules (#22761) The following top level Treesitter functions have been moved: - vim.treesitter.inspect_language() -> vim.treesitter.language.inspect() - vim.treesitter.get_query_files() -> vim.treesitter.query.get_files() - vim.treesitter.set_query() -> vim.treesitter.query.set() - vim.treesitter.query.set_query() -> vim.treesitter.query.set() - vim.treesitter.get_query() -> vim.treesitter.query.get() - vim.treesitter.query.get_query() -> vim.treesitter.query.get() - vim.treesitter.parse_query() -> vim.treesitter.query.parse() - vim.treesitter.query.parse_query() -> vim.treesitter.query.parse() - vim.treesitter.add_predicate() -> vim.treesitter.query.add_predicate() - vim.treesitter.add_directive() -> vim.treesitter.query.add_directive() - vim.treesitter.list_predicates() -> vim.treesitter.query.list_predicates() - vim.treesitter.list_directives() -> vim.treesitter.query.list_directives() - vim.treesitter.query.get_range() -> vim.treesitter.get_range() - vim.treesitter.query.get_node_text() -> vim.treesitter.get_node_text() --- runtime/lua/vim/treesitter/query.lua | 123 ++++++++++++++++------------------- 1 file changed, 55 insertions(+), 68 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index f4e038b2d8..8ccd6da8a7 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -1,8 +1,6 @@ local a = vim.api local language = require('vim.treesitter.language') -local Range = require('vim.treesitter._range') - ---@class Query ---@field captures string[] List of captures used in query ---@field info TSQueryInfo Contains used queries, predicates, directives @@ -14,6 +12,7 @@ Query.__index = Query ---@field captures table ---@field patterns table +---@class TSQueryModule local M = {} ---@private @@ -57,22 +56,14 @@ local function add_included_lang(base_langs, lang, ilang) return false end ----@private ----@param buf integer ----@param range Range ----@returns string -local function buf_range_get_text(buf, range) - local start_row, start_col, end_row, end_col = Range.unpack4(range) - if end_col == 0 then - if start_row == end_row then - start_col = -1 - start_row = start_row - 1 - end - end_col = -1 - end_row = end_row - 1 - end - local lines = a.nvim_buf_get_text(buf, start_row, start_col, end_row, end_col, {}) - return table.concat(lines, '\n') +---@deprecated +function M.get_query_files(...) + vim.deprecate( + 'vim.treesitter.query.get_query_files()', + 'vim.treesitter.query.get_files()', + '0.10' + ) + return M.get_files(...) end --- Gets the list of files used to make up a query @@ -81,7 +72,7 @@ end ---@param query_name string Name of the query to load (e.g., "highlights") ---@param is_included (boolean|nil) Internal parameter, most of the time left as `nil` ---@return string[] query_files List of files to load for given query and language -function M.get_query_files(lang, query_name, is_included) +function M.get_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)) @@ -153,7 +144,7 @@ function M.get_query_files(lang, query_name, is_included) local query_files = {} for _, base_lang in ipairs(base_langs) do - local base_files = M.get_query_files(base_lang, query_name, true) + local base_files = M.get_files(base_lang, query_name, true) vim.list_extend(query_files, base_files) end vim.list_extend(query_files, { base_query }) @@ -175,7 +166,7 @@ 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()| ---@type table> local explicit_queries = setmetatable({}, { __index = function(t, k) @@ -186,6 +177,12 @@ local explicit_queries = setmetatable({}, { end, }) +---@deprecated +function M.set_query(...) + vim.deprecate('vim.treesitter.query.set_query()', 'vim.treesitter.query.set()', '0.10') + M.set(...) +end + --- Sets the runtime query named {query_name} for {lang} --- --- This allows users to override any runtime files and/or configuration @@ -194,8 +191,17 @@ local explicit_queries = setmetatable({}, { ---@param lang string Language to use for the query ---@param query_name string Name of the query (e.g., "highlights") ---@param text string Query text (unparsed). -function M.set_query(lang, query_name, text) - explicit_queries[lang][query_name] = M.parse_query(lang, text) +function M.set(lang, query_name, text) + explicit_queries[lang][query_name] = M.parse(lang, text) +end + +---@deprecated +---@param lang string Language to use for the query +---@param query_name string Name of the query (e.g. "highlights") +--- +---@return Query|nil Parsed query +function M.get_query(lang, query_name) + return M.get(lang, query_name) end --- Returns the runtime query {query_name} for {lang}. @@ -204,16 +210,16 @@ end ---@param query_name string Name of the query (e.g. "highlights") --- ---@return Query|nil Parsed query -function M.get_query(lang, query_name) +function M.get(lang, query_name) if explicit_queries[lang][query_name] then return explicit_queries[lang][query_name] end - local query_files = M.get_query_files(lang, query_name) + local query_files = M.get_files(lang, query_name) local query_string = read_query_files(query_files) if #query_string > 0 then - return M.parse_query(lang, query_string) + return M.parse(lang, query_string) end end @@ -222,6 +228,12 @@ local query_cache = vim.defaulttable(function() return setmetatable({}, { __mode = 'v' }) end) +---@deprecated +function M.parse_query(...) + vim.deprecate('vim.treesitter.query.parse_query()', 'vim.treesitter.query.parse()', '0.10') + return M.parse(...) +end + --- Parse {query} as a string. (If the query is in a file, the caller --- should read the contents into a string before calling). --- @@ -239,7 +251,7 @@ end) ---@param query string Query in s-expr syntax --- ---@return Query Parsed query -function M.parse_query(lang, query) +function M.parse(lang, query) language.add(lang) local cached = query_cache[lang][query] if cached then @@ -254,41 +266,16 @@ function M.parse_query(lang, query) return self end ----Get the range of a |TSNode|. Can also supply {source} and {metadata} ----to get the range with directives applied. ----@param node TSNode ----@param source integer|string|nil Buffer or string from which the {node} is extracted ----@param metadata TSMetadata|nil ----@return Range6 -function M.get_range(node, source, metadata) - if metadata and metadata.range then - assert(source) - return Range.add_bytes(source, metadata.range) - end - return { node:range(true) } +---@deprecated +function M.get_range(...) + vim.deprecate('vim.treesitter.query.get_range()', 'vim.treesitter.get_range()', '0.10') + return vim.treesitter.get_range(...) end ---- Gets the text corresponding to a given node ---- ----@param node TSNode ----@param source (integer|string) Buffer or string from which the {node} is extracted ----@param opts (table|nil) Optional parameters. ---- - metadata (table) Metadata of a specific capture. This would be ---- set to `metadata[capture_id]` when using |vim.treesitter.add_directive()|. ----@return string -function M.get_node_text(node, source, opts) - opts = opts or {} - local metadata = opts.metadata or {} - - if metadata.text then - return metadata.text - elseif type(source) == 'number' then - local range = M.get_range(node, source, metadata) - return buf_range_get_text(source, range) - end - - ---@cast source string - return source:sub(select(3, node:start()) + 1, select(3, node:end_())) +---@deprecated +function M.get_node_text(...) + vim.deprecate('vim.treesitter.query.get_node_text()', 'vim.treesitter.get_node_text()', '0.10') + return vim.treesitter.get_node_text(...) end ---@alias TSMatch table @@ -304,7 +291,7 @@ local predicate_handlers = { if not node then return true end - local node_text = M.get_node_text(node, source) + local node_text = vim.treesitter.get_node_text(node, source) local str ---@type string if type(predicate[3]) == 'string' then @@ -312,7 +299,7 @@ local predicate_handlers = { str = predicate[3] else -- (#eq? @aa @bb) - str = M.get_node_text(match[predicate[3]], source) + str = vim.treesitter.get_node_text(match[predicate[3]], source) end if node_text ~= str or str == nil then @@ -328,7 +315,7 @@ local predicate_handlers = { return true end local regex = predicate[3] - return string.find(M.get_node_text(node, source), regex) ~= nil + return string.find(vim.treesitter.get_node_text(node, source), regex) ~= nil end, ['match?'] = (function() @@ -357,7 +344,7 @@ local predicate_handlers = { end ---@diagnostic disable-next-line no-unknown local regex = compiled_vim_regexes[pred[3]] - return regex:match_str(M.get_node_text(node, source)) + return regex:match_str(vim.treesitter.get_node_text(node, source)) end end)(), @@ -366,7 +353,7 @@ local predicate_handlers = { if not node then return true end - local node_text = M.get_node_text(node, source) + local node_text = vim.treesitter.get_node_text(node, source) for i = 3, #predicate do if string.find(node_text, predicate[i], 1, true) then @@ -382,7 +369,7 @@ local predicate_handlers = { if not node then return true end - local node_text = M.get_node_text(node, source) + local node_text = vim.treesitter.get_node_text(node, source) -- Since 'predicate' will not be used by callers of this function, use it -- to store a string set built from the list of words to check against. @@ -468,7 +455,7 @@ local directive_handlers = { assert(type(id) == 'number') local node = match[id] - local text = M.get_node_text(node, bufnr, { metadata = metadata[id] }) or '' + local text = vim.treesitter.get_node_text(node, bufnr, { metadata = metadata[id] }) or '' if not metadata[id] then metadata[id] = {} @@ -486,7 +473,7 @@ local directive_handlers = { --- ---@param name string Name of the predicate, without leading # ---@param handler function(match:table, pattern:string, bufnr:integer, predicate:string[]) ---- - see |vim.treesitter.add_directive()| for argument meanings +--- - see |vim.treesitter.query.add_directive()| for argument meanings ---@param force boolean|nil function M.add_predicate(name, handler, force) if predicate_handlers[name] and not force then -- cgit From ac7397f4a06e451fedde86fb4eba0038d0d75e68 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 24 Mar 2023 16:31:30 +0000 Subject: fix(treesitter): add missing deprecate --- runtime/lua/vim/treesitter/query.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 8ccd6da8a7..25623c1498 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -196,12 +196,9 @@ function M.set(lang, query_name, text) end ---@deprecated ----@param lang string Language to use for the query ----@param query_name string Name of the query (e.g. "highlights") ---- ----@return Query|nil Parsed query -function M.get_query(lang, query_name) - return M.get(lang, query_name) +function M.get_query(...) + vim.deprecate('vim.treesitter.query.get_query()', 'vim.treesitter.query.get()', '0.10') + return M.get(...) end --- Returns the runtime query {query_name} for {lang}. -- cgit From 34ac75b32927328a0c691c5bda987c0fdb5ce9eb Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 5 Apr 2023 17:19:53 +0100 Subject: refactor: rename local API alias from a to api Problem: Codebase inconsistently binds vim.api onto a or api. Solution: Use api everywhere. a as an identifier is too short to have at the module level. --- runtime/lua/vim/treesitter/query.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 25623c1498..5b87e6ac31 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -1,4 +1,4 @@ -local a = vim.api +local api = vim.api local language = require('vim.treesitter.language') ---@class Query @@ -74,7 +74,7 @@ end ---@return string[] query_files List of files to load for given query and language function M.get_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)) + local lang_files = dedupe_files(api.nvim_get_runtime_file(query_path, true)) if #lang_files == 0 then return {} @@ -635,7 +635,7 @@ end ---@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() + source = api.nvim_get_current_buf() end start, stop = value_or_node_range(start, stop, node) @@ -690,7 +690,7 @@ end ---@return (fun(): integer, table, 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() + source = api.nvim_get_current_buf() end start, stop = value_or_node_range(start, stop, node) -- cgit From ccc0980f86c6ef9a86b0e5a3a691f37cea8eb776 Mon Sep 17 00:00:00 2001 From: Scott Ming Date: Tue, 11 Apr 2023 16:26:03 +0800 Subject: fix(treesitter): Use the correct replacement args for #gsub! directive (#23015) fix(treesitter): use the correct replacement args for #gsub! directive --- runtime/lua/vim/treesitter/query.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 5b87e6ac31..8a747ba14c 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -458,7 +458,7 @@ local directive_handlers = { metadata[id] = {} end - local pattern, replacement = pred[3], pred[3] + local pattern, replacement = pred[3], pred[4] assert(type(pattern) == 'string') assert(type(replacement) == 'string') -- cgit From c194acbfc479d8e5839fa629363f93f6550d035c Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Sat, 29 Apr 2023 18:22:26 +0200 Subject: feat(treesitter): add query_linter from nvim-treesitter/playground (#22784) Co-authored-by: clason Co-authored-by: lewis6991 --- runtime/lua/vim/treesitter/query.lua | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 8a747ba14c..492bfd1ffb 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -714,4 +714,33 @@ function Query:iter_matches(node, source, start, stop) return iter end +---@class QueryLinterOpts +---@field langs (string|string[]|nil) +---@field clear (boolean) + +--- Lint treesitter queries using installed parser, or clear lint errors. +--- +--- Use |treesitter-parsers| in runtimepath to check the query file in {buf} for errors: +--- +--- - verify that used nodes are valid identifiers in the grammar. +--- - verify that predicates and directives are valid. +--- - verify that top-level s-expressions are valid. +--- +--- The found diagnostics are reported using |diagnostic-api|. +--- By default, the parser used for verification is determined by the containing folder +--- of the query file, e.g., if the path is `**/lua/highlights.scm`, the parser for the +--- `lua` language will be used. +---@param buf (integer) Buffer handle +---@param opts (QueryLinterOpts|nil) Optional keyword arguments: +--- - langs (string|string[]|nil) Language(s) to use for checking the query. +--- If multiple languages are specified, queries are validated for all of them +--- - clear (boolean) if `true`, just clear current lint errors +function M.lint(buf, opts) + if opts and opts.clear then + require('vim.treesitter._query_linter').clear(buf) + else + require('vim.treesitter._query_linter').lint(buf, opts) + end +end + return M -- cgit From 668f16bac779ac52d7bd9452e6001a7a6d1e9965 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 30 Apr 2023 11:01:54 +0200 Subject: feat(treesitter): upstream query omnifunc from playground (#23394) and set by default in `ftplugin/query.lua` --- runtime/lua/vim/treesitter/query.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 492bfd1ffb..93841bb31e 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -728,7 +728,7 @@ end --- --- The found diagnostics are reported using |diagnostic-api|. --- By default, the parser used for verification is determined by the containing folder ---- of the query file, e.g., if the path is `**/lua/highlights.scm`, the parser for the +--- of the query file, e.g., if the path ends in `/lua/highlights.scm`, the parser for the --- `lua` language will be used. ---@param buf (integer) Buffer handle ---@param opts (QueryLinterOpts|nil) Optional keyword arguments: @@ -743,4 +743,14 @@ function M.lint(buf, opts) end end +--- Omnifunc for completing node names and predicates in treesitter queries. +--- +--- Use via +---
lua
+---   vim.bo.omnifunc = 'v:lua.vim.treesitter.query.omnifunc'
+--- 
+function M.omnifunc(findstart, base) + return require('vim.treesitter._query_linter').omnifunc(findstart, base) +end + return M -- cgit From af040c3a079f6e25db0ad6b908aa1327f67deb82 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 11 May 2023 11:13:32 +0100 Subject: feat(treesitter): add support for setting query depths --- runtime/lua/vim/treesitter/query.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 93841bb31e..e6a117557a 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -686,16 +686,20 @@ end ---@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) +---@param opts table|nil Options: +--- - max_start_depth (integer) if non-zero, sets the maximum start depth +--- for each match. This is used to prevent traversing too deep into a tree. +--- Requires treesitter >= 0.20.9. --- ---@return (fun(): integer, table, table): pattern id, match, metadata -function Query:iter_matches(node, source, start, stop) +function Query:iter_matches(node, source, start, stop, opts) if type(source) == 'number' and source == 0 then source = api.nvim_get_current_buf() end start, stop = value_or_node_range(start, stop, node) - local raw_iter = node:_rawquery(self.query, false, start, stop) + local raw_iter = node:_rawquery(self.query, false, start, stop, opts) ---@cast raw_iter fun(): string, any local function iter() local pattern, match = raw_iter() -- cgit From 08991b078267e5de0a19a136d00d4f71ad651a32 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 13 May 2023 21:33:22 +0200 Subject: docs: small fixes Co-authored-by: Christian Clason Co-authored-by: Gregory Anders Co-authored-by: HiPhish Co-authored-by: Julio B Co-authored-by: T727 <74924917+T-727@users.noreply.github.com> Co-authored-by: camoz Co-authored-by: champignoom <66909116+champignoom@users.noreply.github.com> --- runtime/lua/vim/treesitter/query.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/treesitter/query.lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesi