From 969db908f8304aa18fc127a1fb73f1c8de8a5fd0 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sat, 22 Mar 2025 13:21:15 +0200 Subject: [PATCH] fix(struct_tags): edge case with structs declared as var (#99) * fix(struct_tags): edge case with structs declared as var * test: test it and fix it * fixup! test: test it and fix it * fixup! fix(struct_tags): edge case with structs declared as var * fixup! test: test it and fix it --- lua/gopher/_utils/ts.lua | 28 +++++++++++++++++++++++---- lua/gopher/struct_tags.lua | 10 ++++++++-- spec/fixtures/tags/svar_input.go | 11 +++++++++++ spec/fixtures/tags/svar_output.go | 11 +++++++++++ spec/fixtures/tags/var_input.go | 8 ++++++++ spec/fixtures/tags/var_output.go | 8 ++++++++ spec/integration/struct_tags_test.lua | 26 +++++++++++++++++++++++++ 7 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 spec/fixtures/tags/svar_input.go create mode 100644 spec/fixtures/tags/svar_output.go create mode 100644 spec/fixtures/tags/var_input.go create mode 100644 spec/fixtures/tags/var_output.go diff --git a/lua/gopher/_utils/ts.lua b/lua/gopher/_utils/ts.lua index 9c74f47..b5e6d32 100644 --- a/lua/gopher/_utils/ts.lua +++ b/lua/gopher/_utils/ts.lua @@ -1,8 +1,15 @@ local ts = {} local queries = { struct = [[ - (type_spec name: (type_identifier) @_name - type: (struct_type)) + [(type_spec name: (type_identifier) @_name + type: (struct_type)) + (var_declaration (var_spec + name: (identifier) @_name @_var + type: (struct_type))) + (short_var_declaration + left: (expression_list (identifier) @_name @_var) + right: (expression_list (composite_literal + type: (struct_type))))] ]], func = [[ [(function_declaration name: (identifier) @_name) @@ -40,7 +47,7 @@ end ---@param query vim.treesitter.Query ---@param node TSNode ---@param bufnr integer ----@return {name:string} +---@return {name:string, is_varstruct:boolean} local function get_captures(query, node, bufnr) local res = {} for _, match, _ in query:iter_matches(node, bufnr) do @@ -49,6 +56,10 @@ local function get_captures(query, node, bufnr) if capture_name == "_name" then res["name"] = vim.treesitter.get_node_text(captured_node, bufnr) end + + if capture_name == "_var" then + res["is_varstruct"] = true + end end end @@ -59,6 +70,7 @@ end ---@field name string ---@field start_line integer ---@field end_line integer +---@field is_varstruct boolean ---@param bufnr integer ---@param parent_type string[] @@ -93,7 +105,15 @@ function ts.get_struct_under_cursor(bufnr) --- should be both type_spec and type_declaration --- because in cases like `type ( T struct{}, U strict{} )` --- i will be choosing always last struct in the list - return do_stuff(bufnr, { "type_spec", "type_declaration" }, queries.struct) + --- + --- var_declaration is for cases like `var x struct{}` + --- short_var_declaration is for cases like `x := struct{}{}` + return do_stuff(bufnr, { + "type_spec", + "type_declaration", + "var_declaration", + "short_var_declaration", + }, queries.struct) end ---@param bufnr integer diff --git a/lua/gopher/struct_tags.lua b/lua/gopher/struct_tags.lua index 4545640..86689e4 100644 --- a/lua/gopher/struct_tags.lua +++ b/lua/gopher/struct_tags.lua @@ -44,11 +44,18 @@ local function handle_tags(fpath, bufnr, user_args) c.commands.gomodifytags, "-transform", c.gotag.transform, "-format", "json", - "-struct", st.name, "-file", fpath, "-w", } + if st.is_varstruct then + table.insert(cmd, "-line") + table.insert(cmd, string.format("%d,%d", st.start_line, st.end_line)) + else + table.insert(cmd, "-struct") + table.insert(cmd, st.name) + end + for _, v in ipairs(user_args) do table.insert(cmd, v) end @@ -60,7 +67,6 @@ local function handle_tags(fpath, bufnr, user_args) end local res = vim.json.decode(rs.stdout) - if res["errors"] then log.error("tags: got an error " .. vim.inspect(res)) error("failed to set tags " .. vim.inspect(res["errors"])) diff --git a/spec/fixtures/tags/svar_input.go b/spec/fixtures/tags/svar_input.go new file mode 100644 index 0000000..7831d01 --- /dev/null +++ b/spec/fixtures/tags/svar_input.go @@ -0,0 +1,11 @@ +package main + +func main() { + s := struct { + API string + Key string + }{ + API: "api.com", + Key: "key", + } +} diff --git a/spec/fixtures/tags/svar_output.go b/spec/fixtures/tags/svar_output.go new file mode 100644 index 0000000..f320eb2 --- /dev/null +++ b/spec/fixtures/tags/svar_output.go @@ -0,0 +1,11 @@ +package main + +func main() { + s := struct { + API string `xml:"api"` + Key string `xml:"key"` + }{ + API: "api.com", + Key: "key", + } +} diff --git a/spec/fixtures/tags/var_input.go b/spec/fixtures/tags/var_input.go new file mode 100644 index 0000000..97b4bc3 --- /dev/null +++ b/spec/fixtures/tags/var_input.go @@ -0,0 +1,8 @@ +package main + +func main() { + var a struct { + TestField1 string + TestField2 string + } +} diff --git a/spec/fixtures/tags/var_output.go b/spec/fixtures/tags/var_output.go new file mode 100644 index 0000000..e158a3a --- /dev/null +++ b/spec/fixtures/tags/var_output.go @@ -0,0 +1,8 @@ +package main + +func main() { + var a struct { + TestField1 string `yaml:"test_field_1"` + TestField2 string `yaml:"test_field_2"` + } +} diff --git a/spec/integration/struct_tags_test.lua b/spec/integration/struct_tags_test.lua index 4ac245b..9552339 100644 --- a/spec/integration/struct_tags_test.lua +++ b/spec/integration/struct_tags_test.lua @@ -82,4 +82,30 @@ T["struct_tags"]["should add more than one tag"] = function() t.eq(t.readfile(tmp), fixtures.output) end +T["struct_tags"]["should add tags on var"] = function() + local tmp = t.tmpfile() + local fixtures = t.get_fixtures "tags/var" + t.writefile(tmp, fixtures.input) + + child.cmd("silent edit " .. tmp) + child.fn.setpos(".", { child.fn.bufnr(tmp), 5, 3 }) + child.cmd "GoTagAdd yaml" + child.cmd "write" + + t.eq(t.readfile(tmp), fixtures.output) +end + +T["struct_tags"]["should add tags on short declr var"] = function() + local tmp = t.tmpfile() + local fixtures = t.get_fixtures "tags/svar" + t.writefile(tmp, fixtures.input) + + child.cmd("silent edit " .. tmp) + child.fn.setpos(".", { child.fn.bufnr(tmp), 4, 3 }) + child.cmd "GoTagAdd xml" + child.cmd "write" + + t.eq(t.readfile(tmp), fixtures.output) +end + return T