diff options
-rw-r--r-- | runtime/doc/deprecated.txt | 5 | ||||
-rw-r--r-- | runtime/doc/news.txt | 3 | ||||
-rw-r--r-- | runtime/doc/treesitter.txt | 31 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter.lua | 3 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/_meta/tsnode.lua | 18 | ||||
-rw-r--r-- | src/nvim/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/nvim/lua/treesitter.c | 14 | ||||
-rw-r--r-- | test/functional/treesitter/node_spec.lua | 24 | ||||
-rw-r--r-- | test/functional/treesitter/query_spec.lua | 14 |
9 files changed, 96 insertions, 18 deletions
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 72d2faca02..6895348d05 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -36,6 +36,11 @@ DIAGNOSTICS - The "cursor_position" parameter of |vim.diagnostic.JumpOpts| is renamed to "pos" +TREESITTER +• *TSNode:child_containing_descendant()* Use + |TSNode:child_with_descendant()| instead; it is identical except that it can + return the descendant itself. + ------------------------------------------------------------------------------ DEPRECATED IN 0.10 *deprecated-0.10* diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 9bc20c3827..1d364ba29a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -108,6 +108,9 @@ TREESITTER if no languages are explicitly registered. • |vim.treesitter.language.add()| returns `true` if a parser was loaded successfully and `nil,errmsg` otherwise instead of throwing an error. +• New |TSNode:child_with_descendant()|, which is nearly identical to + |TSNode:child_containing_descendant()| except that it can return the + descendant itself. TUI diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 35192cc43d..805876172d 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -622,9 +622,23 @@ TSNode:child({index}) *TSNode:child()* Return: ~ (`TSNode?`) - *TSNode:child_containing_descendant()* -TSNode:child_containing_descendant({descendant}) - Get the node's child that contains {descendant}. +TSNode:child_count() *TSNode:child_count()* + Get the node's number of children. + + Return: ~ + (`integer`) + + *TSNode:child_with_descendant()* +TSNode:child_with_descendant({descendant}) + Get the node's child that contains {descendant} (includes {descendant}). + + For example, with the following node hierarchy: > + a -> b -> c + + a:child_with_descendant(c) == b + a:child_with_descendant(b) == b + a:child_with_descendant(a) == nil +< Parameters: ~ • {descendant} (`TSNode`) @@ -632,12 +646,6 @@ TSNode:child_containing_descendant({descendant}) Return: ~ (`TSNode?`) -TSNode:child_count() *TSNode:child_count()* - Get the node's number of children. - - Return: ~ - (`integer`) - *TSNode:descendant_for_range()* TSNode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col}) Get the smallest node within this node that spans the given range of (row, @@ -778,9 +786,8 @@ TSNode:next_sibling() *TSNode:next_sibling()* (`TSNode?`) TSNode:parent() *TSNode:parent()* - Get the node's immediate parent. Prefer - |TSNode:child_containing_descendant()| for iterating over the node's - ancestors. + Get the node's immediate parent. Prefer |TSNode:child_with_descendant()| + for iterating over the node's ancestors. Return: ~ (`TSNode?`) diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index ed7d31e1f7..4727c0d61d 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -152,8 +152,7 @@ function M.is_ancestor(dest, source) return false end - -- child_containing_descendant returns nil if dest is a direct parent - return source:parent() == dest or dest:child_containing_descendant(source) ~= nil + return dest:child_with_descendant(source) ~= nil end --- Returns the node's range or an unpacked range table diff --git a/runtime/lua/vim/treesitter/_meta/tsnode.lua b/runtime/lua/vim/treesitter/_meta/tsnode.lua index acc9f8d24e..d982b6a505 100644 --- a/runtime/lua/vim/treesitter/_meta/tsnode.lua +++ b/runtime/lua/vim/treesitter/_meta/tsnode.lua @@ -15,7 +15,7 @@ error('Cannot require a meta file') local TSNode = {} -- luacheck: no unused --- Get the node's immediate parent. ---- Prefer |TSNode:child_containing_descendant()| +--- Prefer |TSNode:child_with_descendant()| --- for iterating over the node's ancestors. --- @return TSNode? function TSNode:parent() end @@ -71,8 +71,24 @@ function TSNode:named_child(index) end --- Get the node's child that contains {descendant}. --- @param descendant TSNode --- @return TSNode? +--- @deprecated function TSNode:child_containing_descendant(descendant) end +--- Get the node's child that contains {descendant} (includes {descendant}). +--- +--- For example, with the following node hierarchy: +--- +--- ``` +--- a -> b -> c +--- +--- a:child_with_descendant(c) == b +--- a:child_with_descendant(b) == b +--- a:child_with_descendant(a) == nil +--- ``` +--- @param descendant TSNode +--- @return TSNode? +function TSNode:child_with_descendant(descendant) end + --- Get the node's start position. Return three values: the row, column and --- total byte count (all zero-based). --- @return integer, integer, integer diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 8819da1ae5..0ba2eeb376 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -31,7 +31,7 @@ target_link_libraries(main_lib INTERFACE ${LUV_LIBRARY}) find_package(Iconv REQUIRED) find_package(Libuv 1.28.0 REQUIRED) find_package(Lpeg REQUIRED) -find_package(Treesitter 0.23.0 REQUIRED) +find_package(Treesitter 0.24.0 REQUIRED) find_package(Unibilium 2.0 REQUIRED) find_package(UTF8proc REQUIRED) diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index ab97704dfe..819ec41390 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -828,6 +828,7 @@ static struct luaL_Reg node_meta[] = { { "parent", node_parent }, { "__has_ancestor", __has_ancestor }, { "child_containing_descendant", node_child_containing_descendant }, + { "child_with_descendant", node_child_with_descendant }, { "iter_children", node_iter_children }, { "next_sibling", node_next_sibling }, { "prev_sibling", node_prev_sibling }, @@ -1146,7 +1147,7 @@ static int __has_ancestor(lua_State *L) int const pred_len = (int)lua_objlen(L, 2); TSNode node = ts_tree_root_node(descendant.tree); - while (!ts_node_is_null(node)) { + while (node.id != descendant.id) { char const *node_type = ts_node_type(node); size_t node_type_len = strlen(node_type); @@ -1163,7 +1164,7 @@ static int __has_ancestor(lua_State *L) lua_pop(L, 1); } - node = ts_node_child_containing_descendant(node, descendant); + node = ts_node_child_with_descendant(node, descendant); } lua_pushboolean(L, false); @@ -1179,6 +1180,15 @@ static int node_child_containing_descendant(lua_State *L) return 1; } +static int node_child_with_descendant(lua_State *L) +{ + TSNode node = node_check(L, 1); + TSNode descendant = node_check(L, 2); + TSNode child = ts_node_child_with_descendant(node, descendant); + push_node(L, child, 1); + return 1; +} + static int node_next_sibling(lua_State *L) { TSNode node = node_check(L, 1); diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index d07ed35368..c87a56b160 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -186,4 +186,28 @@ describe('treesitter node API', function() ) eq(vim.NIL, lua_eval('declarator:child_containing_descendant(value)')) end) + + it('child_with_descendant() works', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = assert(tree:root()) + _G.main = assert(_G.root:child(0)) + _G.body = assert(_G.main:child(2)) + _G.statement = assert(_G.body:child(1)) + _G.declarator = assert(_G.statement:child(1)) + _G.value = assert(_G.declarator:child(1)) + end) + + eq(lua_eval('main:type()'), lua_eval('root:child_with_descendant(value):type()')) + eq(lua_eval('body:type()'), lua_eval('main:child_with_descendant(value):type()')) + eq(lua_eval('statement:type()'), lua_eval('body:child_with_descendant(value):type()')) + eq(lua_eval('declarator:type()'), lua_eval('statement:child_with_descendant(value):type()')) + eq(lua_eval('value:type()'), lua_eval('declarator:child_with_descendant(value):type()')) + eq(vim.NIL, lua_eval('value:child_with_descendant(value)')) + end) end) diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index c97619c913..dfb5eb2685 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -405,6 +405,20 @@ void ui_refresh(void) { 'literal', 'number_literal', { 0, 8, 0, 11 }, '123' }, { 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' }, }, result) + + result = exec_lua( + get_query_result, + [[((number_literal) @literal (#has-ancestor? @literal "enumerator"))]] + ) + eq({ + { 'literal', 'number_literal', { 1, 13, 1, 16 }, '124' }, + }, result) + + result = exec_lua( + get_query_result, + [[((number_literal) @literal (#has-ancestor? @literal "number_literal"))]] + ) + eq({}, result) end) it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function() |