2022-10-25 09:16:50 +00:00
local nodes = require ( ' go.ts.nodes ' )
2021-04-19 06:09:39 +00:00
2022-10-25 09:16:50 +00:00
local tsutil = require ( ' nvim-treesitter.ts_utils ' )
local log = require ( ' go.utils ' ) . log
local warn = require ( ' go.utils ' ) . warn
local info = require ( ' go.utils ' ) . info
local debug = require ( ' go.utils ' ) . debug
-- debug = log
2021-07-16 15:58:44 +00:00
2022-04-18 14:13:51 +00:00
local M = {
2022-10-25 09:16:50 +00:00
query_struct = ' (type_spec name:(type_identifier) @definition.struct type: (struct_type)) ' ,
query_package = ' (package_clause (package_identifier)@package.name)@package.clause ' ,
query_struct_id = ' (type_spec name:(type_identifier) @definition.struct (struct_type)) ' ,
query_em_struct_id = ' (field_declaration name:(field_identifier) @definition.struct (struct_type)) ' ,
2022-07-06 17:12:24 +00:00
query_struct_block = [[((type_declaration (type_spec name:(type_identifier) @struct.name type: (struct_type)))@struct.declaration)]] ,
2023-03-03 09:43:47 +00:00
-- query_type_declaration = [[((type_declaration (type_spec name:(type_identifier)@type_decl.name type:(type_identifier)@type_decl.type))@type_decl.declaration)]], -- rename to gotype so not confuse with type
query_type_declaration = [[((type_declaration (type_spec name:(type_identifier)@type_decl.name)))]] ,
2021-04-19 06:09:39 +00:00
query_em_struct_block = [[(field_declaration name:(field_identifier)@struct.name type: (struct_type)) @struct.declaration]] ,
2021-03-12 02:54:08 +00:00
query_struct_block_from_id = [[(((type_spec name:(type_identifier) type: (struct_type)))@block.struct_from_id)]] ,
2021-07-16 15:58:44 +00:00
-- query_em_struct = "(field_declaration name:(field_identifier) @definition.struct type: (struct_type))",
2021-03-12 02:54:08 +00:00
query_interface_id = [[((type_declaration (type_spec name:(type_identifier) @interface.name type:(interface_type)))@interface.declaration)]] ,
query_interface_method = [[((method_spec name: (field_identifier)@method.name)@interface.method.declaration)]] ,
2022-10-25 09:16:50 +00:00
query_func = ' ((function_declaration name: (identifier)@function.name) @function.declaration) ' ,
query_method = ' (method_declaration receiver: (parameter_list (parameter_declaration name:(identifier)@method.receiver.name type:(type_identifier)@method.receiver.type)) name:(field_identifier)@method.name)@method.declaration ' ,
2021-03-12 02:54:08 +00:00
query_method_name = [ [ ( ( method_declaration
2021-03-10 12:15:06 +00:00
receiver : ( parameter_list ) @ method.receiver
name : ( field_identifier ) @ method.name
2021-03-12 02:54:08 +00:00
body : ( block ) ) @ method.declaration ) ] ] ,
query_method_void = [ [ ( ( method_declaration
2021-03-10 12:15:06 +00:00
receiver : ( parameter_list
( parameter_declaration
name : ( identifier ) @ method.receiver . name
type : ( pointer_type ) @ method.receiver . type )
)
name : ( field_identifier ) @ method.name
parameters : ( parameter_list ) @ method.parameter
body : ( block )
2021-03-12 02:54:08 +00:00
) @ method.declaration ) ] ] ,
2021-03-10 12:15:06 +00:00
query_method_multi_ret = [ [ ( method_declaration
receiver : ( parameter_list
( parameter_declaration
name : ( identifier ) @ method.receiver . name
type : ( pointer_type ) @ method.receiver . type )
)
name : ( field_identifier ) @ method.name
parameters : ( parameter_list ) @ method.parameter
result : ( parameter_list ) @ method.result
body : ( block )
) @ method.declaration ] ] ,
2021-03-12 02:54:08 +00:00
query_method_single_ret = [ [ ( ( method_declaration
2021-03-10 12:15:06 +00:00
receiver : ( parameter_list
( parameter_declaration
name : ( identifier ) @ method.receiver . name
type : ( pointer_type ) @ method.receiver . type )
)
name : ( field_identifier ) @ method.name
parameters : ( parameter_list ) @ method.parameter
result : ( type_identifier ) @ method.result
body : ( block )
2021-03-12 02:54:08 +00:00
) @ method.declaration ) ] ] ,
query_tr_method_void = [ [ ( ( method_declaration
2021-03-10 12:15:06 +00:00
receiver : ( parameter_list
( parameter_declaration
name : ( identifier ) @ method.receiver . name
type : ( type_identifier ) @ method.receiver . type )
)
name : ( field_identifier ) @ method.name
parameters : ( parameter_list ) @ method.parameter
body : ( block )
2021-03-12 02:54:08 +00:00
) @ method.declaration ) ] ] ,
query_tr_method_multi_ret = [ [ ( ( method_declaration
2021-03-10 12:15:06 +00:00
receiver : ( parameter_list
( parameter_declaration
name : ( identifier ) @ method.receiver . name
type : ( type_identifier ) @ method.receiver . type )
)
name : ( field_identifier ) @ method.name
parameters : ( parameter_list ) @ method.parameter
result : ( parameter_list ) @ method.result
body : ( block )
2021-03-12 02:54:08 +00:00
) @ method.declaration ) ] ] ,
query_tr_method_single_ret = [ [ ( ( method_declaration
2021-03-10 12:15:06 +00:00
receiver : ( parameter_list
( parameter_declaration
name : ( identifier ) @ method.receiver . name
type : ( type_identifier ) @ method.receiver . type )
)
name : ( field_identifier ) @ method.name
parameters : ( parameter_list ) @ method.parameter
result : ( type_identifier ) @ method.result
body : ( block )
2022-04-18 12:31:17 +00:00
) @ method.declaration ) ] ] ,
2022-04-18 14:13:51 +00:00
query_test_func = [ [ ( ( function_declaration name : ( identifier ) @ test_name
2022-04-18 12:31:17 +00:00
parameters : ( parameter_list
( parameter_declaration
name : ( identifier )
type : ( pointer_type
( qualified_type
package : ( package_identifier ) @ _param_package
name : ( type_identifier ) @ _param_name ) ) ) )
) @ testfunc
2023-12-02 08:33:56 +00:00
( # contains ? @ test_name " Test " ) ) ] ] ,
2023-10-02 23:51:31 +00:00
query_tbl_testcase_node = [ [ ( literal_value (
literal_element (
literal_value . (
keyed_element
( literal_element ( identifier ) )
( literal_element ( interpreted_string_literal ) @ test.name )
)
) @ test.block
) )
] ] ,
2023-12-02 08:33:56 +00:00
query_sub_testcase_node = [ [ ( call_expression
2023-10-02 23:51:31 +00:00
( selector_expression
( field_identifier ) @ method.name )
( argument_list
( interpreted_string_literal ) @ tc.name
( func_literal ) )
( # eq ? @ method.name " Run " )
) @ tc.run ] ] ,
2023-01-11 03:53:05 +00:00
query_string_literal = [[((interpreted_string_literal) @string.value)]] ,
2021-03-10 12:15:06 +00:00
}
2022-04-18 14:13:51 +00:00
2021-09-18 23:58:04 +00:00
local function get_name_defaults ( )
2022-10-25 09:16:50 +00:00
return { [ ' func ' ] = ' function ' , [ ' if ' ] = ' if ' , [ ' else ' ] = ' else ' , [ ' for ' ] = ' for ' }
2021-03-10 12:15:06 +00:00
end
2022-07-12 13:11:46 +00:00
M.get_struct_node_at_pos = function ( bufnr )
2022-10-25 09:16:50 +00:00
local query = M.query_struct_block .. ' ' .. M.query_em_struct_block
2021-09-18 23:58:04 +00:00
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
2022-07-12 13:11:46 +00:00
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufn )
2021-04-19 06:09:39 +00:00
if ns == nil then
2022-10-25 09:16:50 +00:00
debug ( ' struct not found ' )
2021-04-19 06:09:39 +00:00
else
2022-10-25 09:16:50 +00:00
log ( ' struct node ' , ns )
2021-04-19 06:09:39 +00:00
return ns [ # ns ]
end
2021-03-10 12:15:06 +00:00
end
2022-07-12 13:11:46 +00:00
M.get_type_node_at_pos = function ( bufnr )
2022-07-05 22:58:17 +00:00
local query = M.query_type_declaration
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
2022-07-12 13:11:46 +00:00
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufn )
2022-07-05 22:58:17 +00:00
if ns == nil then
2022-10-25 09:16:50 +00:00
debug ( ' type not found ' )
2022-07-05 22:58:17 +00:00
else
2022-10-25 09:16:50 +00:00
log ( ' type node ' , ns )
2022-07-05 22:58:17 +00:00
return ns [ # ns ]
end
end
2022-07-12 13:11:46 +00:00
M.get_interface_node_at_pos = function ( bufnr )
2021-04-19 06:09:39 +00:00
local query = M.query_interface_id
2021-03-10 12:15:06 +00:00
2021-09-18 23:58:04 +00:00
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
2022-07-12 13:11:46 +00:00
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufn )
2021-04-19 06:09:39 +00:00
if ns == nil then
2022-10-25 09:16:50 +00:00
debug ( ' interface not found ' )
2021-04-19 06:09:39 +00:00
else
return ns [ # ns ]
end
2021-03-10 12:15:06 +00:00
end
2022-07-12 13:11:46 +00:00
M.get_interface_method_node_at_pos = function ( bufnr )
2021-04-19 06:09:39 +00:00
local query = M.query_interface_method
2022-07-12 13:11:46 +00:00
bufnr = bufnr or vim.api . nvim_get_current_buf ( )
2021-03-10 12:15:06 +00:00
2022-07-12 13:11:46 +00:00
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufnr )
2021-04-19 06:09:39 +00:00
if ns == nil then
2022-10-25 09:16:50 +00:00
warn ( ' interface method not found ' )
2021-04-19 06:09:39 +00:00
else
return ns [ # ns ]
end
2021-03-10 12:15:06 +00:00
end
2022-07-12 13:11:46 +00:00
M.get_func_method_node_at_pos = function ( bufnr )
2022-10-25 09:16:50 +00:00
local query = M.query_func .. ' ' .. M.query_method_name
2021-03-10 12:15:06 +00:00
-- local query = require("go.ts.go").query_method_name
2021-09-18 23:58:04 +00:00
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
2021-03-10 12:15:06 +00:00
2022-07-12 13:11:46 +00:00
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufn )
2021-04-19 06:09:39 +00:00
if ns == nil then
return nil
end
if ns == nil then
2022-10-25 09:16:50 +00:00
warn ( ' function not found ' )
2021-04-19 06:09:39 +00:00
else
return ns [ # ns ]
end
2021-03-10 12:15:06 +00:00
end
2023-10-02 23:51:31 +00:00
M.get_tbl_testcase_node_name = function ( bufnr )
2023-01-11 03:53:05 +00:00
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
2023-10-02 23:51:31 +00:00
local ok , parser = pcall ( vim.treesitter . get_parser , bufn )
if not ok or not parser then
return
end
local tree = parser : parse ( )
tree = tree [ 1 ]
local tbl_case_query = vim.treesitter . query.parse ( ' go ' , M.query_tbl_testcase_node )
local curr_row , _ = unpack ( vim.api . nvim_win_get_cursor ( 0 ) )
for _ , match , _ in tbl_case_query : iter_matches ( tree : root ( ) , bufn , 0 , - 1 ) do
local tc_name = nil
for id , node in pairs ( match ) do
local name = tbl_case_query.captures [ id ]
-- IDK why test.name is captured before test.block
if name == ' test.name ' then
tc_name = tsutil.get_node_text ( node , bufn ) [ 1 ]
end
if name == ' test.block ' then
local start_row , _ , end_row , _ = node : range ( )
if ( curr_row >= start_row and curr_row <= end_row ) then
return tc_name
end
end
end
end
return nil
end
M.get_sub_testcase_name = function ( bufnr )
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
local sub_case_query = vim.treesitter . query.parse ( ' go ' , M.query_sub_testcase_node )
local ok , parser = pcall ( vim.treesitter . get_parser , bufn )
if not ok or not parser then
return
end
local tree = parser : parse ( )
tree = tree [ 1 ]
local is_inside_test = false
local curr_row , _ = unpack ( vim.api . nvim_win_get_cursor ( 0 ) )
for id , node in sub_case_query : iter_captures ( tree : root ( ) , bufn , 0 , - 1 ) do
local name = sub_case_query.captures [ id ]
-- tc_run is the first capture of a match, so we can use it to check if we are inside a test
if name == ' tc.run ' then
local start_row , _ , end_row , _ = node : range ( )
if ( curr_row >= start_row and curr_row <= end_row ) then
is_inside_test = true
else
is_inside_test = false
end
goto continue
end
if name == ' tc.name ' and is_inside_test then
local tc_name = tsutil.get_node_text ( node , bufn )
return tc_name [ 1 ]
end
:: continue ::
2023-01-11 03:53:05 +00:00
end
2023-10-02 23:51:31 +00:00
return nil
2023-01-11 03:53:05 +00:00
end
M.get_string_node = function ( bufnr )
local query = M.query_string_literal
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufn , ' value ' )
if ns == nil then
debug ( ' struct not found ' )
else
log ( ' struct node ' , ns [ # ns ] )
return ns [ # ns ]
end
end
2022-10-25 09:16:50 +00:00
M.get_import_node_at_pos = function ( bufnr )
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
local cur_node = tsutil.get_node_at_cursor ( )
if cur_node and ( cur_node : type ( ) == ' import_spec ' or cur_node : parent ( ) : type ( ) == ' import_spec ' ) then
return cur_node
end
end
M.get_module_at_pos = function ( bufnr )
local node = M.get_import_node_at_pos ( bufnr )
if node then
2023-04-04 11:55:20 +00:00
local module = require ( ' go.utils ' ) . get_node_text ( node , vim.api . nvim_get_current_buf ( ) )
2022-10-25 09:16:50 +00:00
-- log
module = string.gsub ( module , ' " ' , ' ' )
return module
end
end
2022-07-12 13:11:46 +00:00
M.get_package_node_at_pos = function ( bufnr )
local row , col = unpack ( vim.api . nvim_win_get_cursor ( 0 ) )
row , col = row , col + 1
2021-04-19 06:09:39 +00:00
if row > 10 then
return
end
local query = M.query_package
2021-03-10 12:15:06 +00:00
-- local query = require("go.ts.go").query_method_name
2021-09-18 23:58:04 +00:00
local bufn = bufnr or vim.api . nvim_get_current_buf ( )
2021-03-10 12:15:06 +00:00
2022-07-12 13:11:46 +00:00
local ns = nodes.nodes_at_cursor ( query , get_name_defaults ( ) , bufn )
2021-04-19 06:09:39 +00:00
if ns == nil then
return nil
end
if ns == nil then
2022-10-25 09:16:50 +00:00
warn ( ' package not found ' )
2021-04-19 06:09:39 +00:00
else
return ns [ # ns ]
end
2021-03-10 12:15:06 +00:00
end
2022-07-11 13:32:06 +00:00
function M . in_func ( )
2022-10-25 09:16:50 +00:00
local ok , ts_utils = pcall ( require , ' nvim-treesitter.ts_utils ' )
2022-07-11 13:32:06 +00:00
if not ok then
return false
end
local current_node = ts_utils.get_node_at_cursor ( )
if not current_node then
return false
end
local expr = current_node
while expr do
2022-10-25 09:16:50 +00:00
if expr : type ( ) == ' function_declaration ' or expr : type ( ) == ' method_declaration ' then
2022-07-11 13:32:06 +00:00
return true
end
expr = expr : parent ( )
end
return false
end
2021-03-10 12:15:06 +00:00
return M