我想获取lua文件中所有函数定义/声明的签名并将它们放入缓冲区中。
阅读TreeSitter查询语法和neovim Treesitter帮助我想出了这个查询,还用
:EditQuery
和:InspectTree
进行了测试,它看起来是正确的:
(
(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)
)
保存在~/.config/nvim/after/queries/lua/code_layout.scm
这个想法是找到与我想要的结构匹配的节点,然后将其中的子节点存储在匹配的元数据中,以便我可以稍后在代码中检索它们并获取整个函数签名的文本。
我正在一个lua文件上对此进行测试(最后的代码是实际的逻辑,只是为了方便起见将其放在那里,以便我可以使用
:'<,'>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
但是当我运行该测试代码时,出现以下错误:
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
对我来说,这似乎表明
matches
返回的 iter_matches()
数组不是 TSNode
的实例,因为它应该根据 doc:
Return:
(fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata)
pattern id, match, metadata
在网上搜索我找不到任何人有这样的问题
iter_matches
,我错过了什么吗?
好吧,我意识到问题所在了。我错过的是
matches[node_metadata['name']]
返回 TSNode
的 list,而不仅仅是一个。
执行
matches[node_metadata['name']][1]
相反,可以按预期工作。
休息有时能带来惊人的效果。