I want to get the signature of all the function definitions/declarations in a lua file and put them in a buffer.
Reading through the TreeSitter query syntax and neovim Treesitter help I came up with this query, also tested with :EditQuery
and :InspectTree
and it looks correct:
(
(function_declaration name: (identifier) @fn_name parameters: (_) @fn_params) @fn_decl
(#set! @fn_decl "name" @fn_name)
(#set! @fn_decl "parameters" @fn_params)
)
(
(
assignment_statement
(variable_list name: (identifier) @fn_name)
(expression_list value: (function_definition parameters: (_) @fn_params))
) @fn_assign
(#set! @fn_assign "name" @fn_name)
(#set! @fn_assign "parameters" @fn_params)
)
Saved in ~/.config/nvim/after/queries/lua/code_layout.scm
The idea is to find the nodes matching the structure I want and then store sub-nodes within them in the metadata of the match so that I can retrieve them later in the code and get the text of the entire function signature.
I'm testing this out on a lua file (the code at the end is the actual logic, just put it there for convenience so I can select and run it with :'<,'>lua
)
F = function()
end
local function some_local(param1, param2)
return param1
end
-- test code starts here
local query = vim.treesitter.query.get('lua', 'code_layout')
if query == nil then return end
local tree = vim.treesitter.get_parser():parse()[1]
local bufnr = vim.api.nvim_get_current_buf()
for _, matches, metadata in query:iter_matches(tree:root(), bufnr, 0, -1, { all = true }) do
for _, node_metadata in pairs(metadata) do
local fn_name_node = matches[node_metadata['name']]
local fn_params_node = matches[node_metadata['parameters']]
print('metadata: ' .. vim.inspect(node_metadata))
print('fn_name_node: ' .. vim.inspect(fn_name_node))
print('fn_params_node: ' .. vim.inspect(fn_params_node))
print('fn_name_node: ' .. vim.inspect(vim.treesitter.get_node_text(fn_name_node, bufnr)))
print('fn_params_node: ' .. vim.inspect(vim.treesitter.get_node_text(fn_params_node, bufnr)))
end
end
But when I run that test code I'm gettin the following error:
metadata: {
name = 1,
parameters = 2
}
fn_name_node: { <userdata 1> }
fn_params_node: { <userdata 1> }
Error detected while processing :{range}lua:
E5108: Error executing lua /usr/local/share/nvim/runtime/lua/vim/treesitter.lua:182: attempt to call method 'range' (a nil value)
stack traceback:
/usr/local/share/nvim/runtime/lua/vim/treesitter.lua:182: in function 'get_range'
/usr/local/share/nvim/runtime/lua/vim/treesitter.lua:217: in function 'get_node_text'
[string ":{range}lua"]:12: in main chunk
To me this seems to indicate that the matches
array returned by iter_matches()
is not an instance of TSNode
, as it should be according to the doc:
Return:
(fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata)
pattern id, match, metadata
Searching online I couldn't find anyone having such a problem with iter_matches
, am I missing something?
Ok, I realized what was the problem. What I missed was that matches[node_metadata['name']]
returns a list of TSNode
, not just one.
Doing matches[node_metadata['name']][1]
instead works as expected.
Amazing what taking a break can do sometimes.