aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiley Bruins <ribru17@hotmail.com>2025-02-15 13:33:38 -0800
committerLewis Russell <me@lewisr.dev>2025-02-21 09:47:02 +0000
commit55b165ac15a7528a3c679d928b1edf9d701f850b (patch)
tree17c86f717b79a42e87cd9c58a031b0aff0a755f2
parent3e39250a79ef1a74bd64e283daf825208ca3875b (diff)
downloadrneovim-55b165ac15a7528a3c679d928b1edf9d701f850b.tar.gz
rneovim-55b165ac15a7528a3c679d928b1edf9d701f850b.tar.bz2
rneovim-55b165ac15a7528a3c679d928b1edf9d701f850b.zip
fix(treesitter): `TSNode:field()` returns all children with the given field
-rw-r--r--runtime/doc/treesitter.txt2
-rw-r--r--runtime/lua/vim/treesitter/_meta/tsnode.lua2
-rw-r--r--src/nvim/lua/treesitter.c15
-rw-r--r--test/functional/treesitter/node_spec.lua19
4 files changed, 31 insertions, 7 deletions
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index b04f13add5..344bd37ddd 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -713,7 +713,7 @@ TSNode:extra() *TSNode:extra()*
(`boolean`)
TSNode:field({name}) *TSNode:field()*
- Returns a table of the nodes corresponding to the {name} field.
+ Returns a list of all the node's children that have the given field name.
Parameters: ~
• {name} (`string`)
diff --git a/runtime/lua/vim/treesitter/_meta/tsnode.lua b/runtime/lua/vim/treesitter/_meta/tsnode.lua
index 552905c3f0..2f9d7f214a 100644
--- a/runtime/lua/vim/treesitter/_meta/tsnode.lua
+++ b/runtime/lua/vim/treesitter/_meta/tsnode.lua
@@ -43,7 +43,7 @@ function TSNode:prev_named_sibling() end
--- @return fun(): TSNode, string
function TSNode:iter_children() end
---- Returns a table of the nodes corresponding to the {name} field.
+--- Returns a list of all the node's children that have the given field name.
--- @param name string
--- @return TSNode[]
function TSNode:field(name) end
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 3e33fcd142..259f2d4739 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -998,16 +998,21 @@ static int node_symbol(lua_State *L)
static int node_field(lua_State *L)
{
TSNode node = node_check(L, 1);
+ uint32_t count = ts_node_child_count(node);
+ int curr_index = 0;
size_t name_len;
const char *field_name = luaL_checklstring(L, 2, &name_len);
- lua_newtable(L); // [table]
+ lua_newtable(L);
- TSNode field = ts_node_child_by_field_name(node, field_name, (uint32_t)name_len);
- if (!ts_node_is_null(field)) {
- push_node(L, field, 1); // [table, node]
- lua_rawseti(L, -2, 1);
+ for (uint32_t i = 0; i < count; i++) {
+ const char *child_field_name = ts_node_field_name_for_child(node, i);
+ if (strequal(field_name, child_field_name)) {
+ TSNode child = ts_node_child(node, i);
+ push_node(L, child, 1);
+ lua_rawseti(L, -2, ++curr_index);
+ }
}
return 1;
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index 235bf7861c..2a1fa497af 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -186,4 +186,23 @@ describe('treesitter node API', function()
eq(lua_eval('value:type()'), lua_eval('declarator:child_with_descendant(value):type()'))
eq(vim.NIL, lua_eval('value:child_with_descendant(value)'))
end)
+
+ it('gets all children with a given field name', function()
+ insert([[
+ function foo(a,b,c)
+ end
+ ]])
+
+ exec_lua(function()
+ local tree = vim.treesitter.get_parser(0, 'lua'):parse()[1]
+ _G.parameters_node = assert(tree:root():named_descendant_for_range(0, 18, 0, 18))
+ _G.children_by_field = _G.parameters_node:field('name')
+ end)
+
+ eq('parameters', lua_eval('parameters_node:type()'))
+ eq(3, lua_eval('#children_by_field'))
+ eq('a', lua_eval('vim.treesitter.get_node_text(children_by_field[1], 0)'))
+ eq('b', lua_eval('vim.treesitter.get_node_text(children_by_field[2], 0)'))
+ eq('c', lua_eval('vim.treesitter.get_node_text(children_by_field[3], 0)'))
+ end)
end)