[mirror] Make your go dev experience better github.com/olexsmir/gopher.nvim
neovim golang
at main 4.5 kB view raw
1local ts = {} 2local queries = { 3 struct = [[ 4 [(type_spec name: (type_identifier) @_name 5 type: (struct_type)) 6 (var_declaration (var_spec 7 name: (identifier) @_name @_var 8 type: (struct_type))) 9 (short_var_declaration 10 left: (expression_list (identifier) @_name @_var) 11 right: (expression_list (composite_literal 12 type: (struct_type))))] 13 ]], 14 struct_field = [[ 15 (field_declaration name: (field_identifier) @_name) 16 ]], 17 func = [[ 18 [(function_declaration name: (identifier) @_name) 19 (method_declaration name: (field_identifier) @_name) 20 (method_elem name: (field_identifier) @_name)] 21 ]], 22 package = [[ 23 (package_identifier) @_name 24 ]], 25 interface = [[ 26 (type_spec 27 name: (type_identifier) @_name 28 type: (interface_type)) 29 ]], 30 var = [[ 31 [(var_declaration (var_spec name: (identifier) @_name)) 32 (short_var_declaration 33 left: (expression_list (identifier) @_name @_var))] 34 ]], 35} 36 37---@param parent_type string[] 38---@param node TSNode 39---@return TSNode? 40local function get_parent_node(parent_type, node) 41 ---@type TSNode? 42 local current = node 43 while current do 44 if vim.tbl_contains(parent_type, current:type()) then 45 break 46 end 47 48 current = current:parent() 49 if current == nil then 50 return nil 51 end 52 end 53 return current 54end 55 56---@param query vim.treesitter.Query 57---@param node TSNode 58---@param bufnr integer 59---@return {name:string, is_varstruct:boolean} 60local function get_captures(query, node, bufnr) 61 local res = {} 62 for id, _node in query:iter_captures(node, bufnr) do 63 if query.captures[id] == "_name" then 64 res["name"] = vim.treesitter.get_node_text(_node, bufnr) 65 end 66 67 if query.captures[id] == "_var" then 68 res["is_varstruct"] = true 69 end 70 end 71 72 return res 73end 74 75---@class gopher.TsResult 76---@field name string Name of the struct, function, etc 77---@field start integer Line number where the declaration starts 78---@field end_ integer Line number where the declaration ends 79---@field indent integer Number of spaces/tabs in the current cursor line 80---@field is_varstruct boolean Is struct declared as `var S struct{}` or `s := struct{}{}` 81 82---@param bufnr integer 83---@param parent_type string[] 84---@param query string 85---@return gopher.TsResult 86local function do_stuff(bufnr, parent_type, query) 87 if not vim.treesitter.get_parser(bufnr, "go") then 88 error "No treesitter parser found for go" 89 end 90 91 local node = vim.treesitter.get_node { bufnr = bufnr } 92 if not node then 93 error "No nodes found under the cursor" 94 end 95 96 local parent_node = get_parent_node(parent_type, node) 97 if not parent_node then 98 error "No parent node found under the cursor" 99 end 100 101 local q = vim.treesitter.query.parse("go", query) 102 local res = get_captures(q, parent_node, bufnr) 103 assert(res.name ~= nil, "No capture name found") 104 105 local start_row, start_col, end_row, _ = parent_node:range() 106 res["indent"] = start_col 107 res["start"] = start_row + 1 108 res["end_"] = end_row + 1 109 110 return res 111end 112 113---@param bufnr integer 114function ts.get_struct_under_cursor(bufnr) 115 --- should be both type_spec and type_declaration 116 --- because in cases like `type ( T struct{}, U struct{} )` 117 --- 118 --- var_declaration is for cases like `var x struct{}` 119 --- short_var_declaration is for cases like `x := struct{}{}` 120 --- 121 --- it always chooses last struct type in the list 122 return do_stuff(bufnr, { 123 "type_spec", 124 "type_declaration", 125 "var_declaration", 126 "short_var_declaration", 127 }, queries.struct) 128end 129 130---@param bufnr integer 131function ts.get_struct_field_under_cursor(bufnr) 132 return do_stuff(bufnr, { "field_declaration" }, queries.struct_field) 133end 134 135---@param bufnr integer 136function ts.get_func_under_cursor(bufnr) 137 --- since this handles both and funcs and methods we should check for both parent nodes 138 return do_stuff(bufnr, { 139 "method_elem", 140 "function_declaration", 141 "method_declaration", 142 }, queries.func) 143end 144 145---@param bufnr integer 146function ts.get_package_under_cursor(bufnr) 147 return do_stuff(bufnr, { "package_clause" }, queries.package) 148end 149 150---@param bufnr integer 151function ts.get_interface_under_cursor(bufnr) 152 return do_stuff(bufnr, { "type_declaration" }, queries.interface) 153end 154 155---@param bufnr integer 156function ts.get_variable_under_cursor(bufnr) 157 return do_stuff(bufnr, { "var_declaration", "short_var_declaration" }, queries.var) 158end 159 160return ts