From a2818819bb5afc3283e935727d5a1b0e9d1cf6b3 Mon Sep 17 00:00:00 2001 From: “jvgrootveld” <“justin.vangrootveld@gmail.com”> Date: Fri, 15 Jan 2021 21:44:40 +0100 Subject: treesitter: default start and end row when omitted Add support for default start and end row when omitted in the query:iter_captures and query:iter_matches functions. When the start and end row values are omitted, the values of the given node is used. The end row value is incremented by 1 to include the node end row in the match. Updated tests and docs accordingly. --- runtime/doc/treesitter.txt | 3 ++- runtime/lua/vim/treesitter/query.lua | 12 ++++++++++ test/functional/treesitter/parser_spec.lua | 35 +++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 911e7b8b47..1696d3b9ba 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -195,7 +195,8 @@ query:iter_captures({node}, {bufnr}, {start_row}, {end_row}) text of the buffer. {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) + 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. diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 5a27d740a2..9d1f265e54 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -353,6 +353,12 @@ function Query:iter_captures(node, source, start, stop) if type(source) == "number" and source == 0 then source = vim.api.nvim_get_current_buf() end + + if start == nil and stop == nil then + start, _, stop, _ = node:range() + stop = stop + 1 -- Make stop inclusive + end + local raw_iter = node:_rawquery(self.query, true, start, stop) local function iter() local capture, captured_node, match = raw_iter() @@ -385,6 +391,12 @@ function Query:iter_matches(node, source, start, stop) if type(source) == "number" and source == 0 then source = vim.api.nvim_get_current_buf() end + + if start == nil and stop == nil then + start, _, stop, _ = node:range() + stop = stop + 1 -- Make stop inclusive + end + local raw_iter = node:_rawquery(self.query, false, start, stop) local function iter() local pattern, match = raw_iter() diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 520574c08a..f99362fbdf 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -245,7 +245,7 @@ void ui_refresh(void) parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) do + for pattern, match in cquery:iter_matches(tree:root(), 0) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid,node in pairs(match) do @@ -289,7 +289,7 @@ void ui_refresh(void) local query = query.parse_query("c", ...) local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do table.insert(nodes, {node:range()}) end @@ -365,7 +365,7 @@ void ui_refresh(void) query = vim.treesitter.parse_query("c", "(declaration) @decl") local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do table.insert(nodes, node) end @@ -412,7 +412,7 @@ void ui_refresh(void) local nodes = {} local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))') - for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do + for _, node in query:iter_captures(parser:parse()[1]:root(), str) do table.insert(nodes, { node:range() }) end @@ -421,6 +421,29 @@ void ui_refresh(void) eq({ {0, 10, 0, 13} }, ret) end) + it("should use node range when omitted", function() + local txt = [[ + int foo = 42; + int bar = 13; + ]] + + local ret = exec_lua([[ + local str = ... + local parser = vim.treesitter.get_string_parser(str, "c") + + local nodes = {} + local query = vim.treesitter.parse_query("c", '((identifier) @foo)') + local first_child = parser:parse()[1]:root():child(1) + + for _, node in query:iter_captures(first_child, str) do + table.insert(nodes, { node:range() }) + end + + return nodes]], txt) + + eq({ {1, 10, 1, 13} }, ret) + end) + describe("when creating a language tree", function() local function get_ranges() return exec_lua([[ @@ -539,7 +562,7 @@ int x = INT_MAX; query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))') parser = vim.treesitter.get_parser(0, "c") - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do result = metadata.key end @@ -562,7 +585,7 @@ int x = INT_MAX; query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') parser = vim.treesitter.get_parser(0, "c") - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do result = metadata[pattern].key end -- cgit From 9bed991cfb2d40911eaf149b705da4d3b77a9c28 Mon Sep 17 00:00:00 2001 From: “jvgrootveld” <“justin.vangrootveld@gmail.com”> Date: Mon, 18 Jan 2021 08:17:12 +0100 Subject: treesitter: Fix linter warning and add helper function to remove duplicated logic This function returns the start and stop value if set else the node's range is used When the node's range is used, the stop is incremented by 1 to make the search inclusive --- runtime/lua/vim/treesitter/query.lua | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 9d1f265e54..e49f54681d 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -340,6 +340,19 @@ function Query:apply_directives(match, pattern, source, metadata) end 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. +local function value_or_node_range(start, stop, node) + if start == nil and stop == nil then + local node_start, _, node_stop, _ = node:range() + return node_start, node_stop + 1 -- Make stop inclusive + end + + return start, stop +end + --- Iterates of the captures of self on a given range. -- -- @param node The node under witch the search will occur @@ -354,10 +367,7 @@ function Query:iter_captures(node, source, start, stop) source = vim.api.nvim_get_current_buf() end - if start == nil and stop == nil then - start, _, stop, _ = node:range() - stop = stop + 1 -- Make stop inclusive - end + start, stop = value_or_node_range(start, stop, node) local raw_iter = node:_rawquery(self.query, true, start, stop) local function iter() @@ -392,10 +402,7 @@ function Query:iter_matches(node, source, start, stop) source = vim.api.nvim_get_current_buf() end - if start == nil and stop == nil then - start, _, stop, _ = node:range() - stop = stop + 1 -- Make stop inclusive - end + start, stop = value_or_node_range(start, stop, node) local raw_iter = node:_rawquery(self.query, false, start, stop) local function iter() -- cgit