如何从 Neovim 中的元数据中存储捕获的 TreeSitter 查询中获取 TSNode?

问题描述 投票:0回答:1

我想获取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
,我错过了什么吗?

neovim treesitter
1个回答
0
投票

好吧,我意识到问题所在了。我错过的是

matches[node_metadata['name']]
返回 TSNode
list
,而不仅仅是一个。

执行

matches[node_metadata['name']][1]
相反,可以按预期工作。

休息有时能带来惊人的效果。

© www.soinside.com 2019 - 2024. All rights reserved.