diff options
-rw-r--r-- | runtime/doc/treesitter.txt | 2 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/_meta/tsnode.lua | 2 | ||||
-rw-r--r-- | src/nvim/lua/treesitter.c | 15 | ||||
-rw-r--r-- | test/functional/treesitter/node_spec.lua | 19 |
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) |