[mirror] Make your go dev experience better github.com/olexsmir/gopher.nvim
neovim golang
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(strct-tags): add support for tag options (#126)

* feat(struct_tags): add options support

* refactor(struct-tags): give input field better name

* feat(struct-tag): add default option

* refactor: make it work on neovim version below 0.12

* chore(struct-tags): update the demo

* refactor: unite struct_tags util with main logic

+300 -14
+5
README.md
··· 72 72 " add json tag 73 73 :GoTagAdd json 74 74 75 + " add json tag with omitempty option 76 + :GoTagAdd json=omitempty 77 + 75 78 " remove yaml tag 76 79 :GoTagRm yaml 77 80 ``` ··· 233 236 transform = "snakecase", 234 237 -- default tags to add to struct fields 235 238 default_tag = "json", 239 + -- default tag option added struct fields, set to nil to disable 240 + option = nil, 236 241 }, 237 242 iferr = { 238 243 -- choose a custom error message
+7
doc/gopher.nvim.txt
··· 89 89 90 90 -- default tags to add to struct fields 91 91 default_tag = "json", 92 + 93 + -- default tag option added struct fields, set to nil to disable 94 + ---@type string|nil 95 + option = nil, 92 96 }, 93 97 iferr = { 94 98 -- choose a custom error message ··· 123 127 1. Place cursor on the struct 124 128 2. Run `:GoTagAdd json` to add json tags to struct fields 125 129 3. Run `:GoTagRm json` to remove json tags to struct fields 130 + 131 + If you want to add/remove tag with options, you can use `json=omitempty` (where json is tag, and omitempty is its option). 132 + Example: `:GoTagAdd xml json=omitempty` 126 133 127 134 To clear all tags from struct run: `:GoTagClear` 128 135
+19
lua/gopher/_utils/init.lua
··· 50 50 return string.rep(char, indent) 51 51 end 52 52 53 + ---@generic T 54 + ---@param tbl T[] 55 + ---@return T[] 56 + function utils.list_unique(tbl) 57 + if vim.fn.has "nvim-0.12" == 1 then 58 + return vim.list.unique(tbl) 59 + end 60 + 61 + for i = #tbl, 1, -1 do 62 + for j = 1, i - 1 do 63 + if tbl[i] == tbl[j] then 64 + table.remove(tbl, i) 65 + break 66 + end 67 + end 68 + end 69 + return tbl 70 + end 71 + 53 72 return utils
+5
lua/gopher/config.lua
··· 61 61 62 62 -- default tags to add to struct fields 63 63 default_tag = "json", 64 + 65 + -- default tag option added struct fields, set to nil to disable 66 + ---@type string|nil 67 + option = nil, 64 68 }, 65 69 iferr = { 66 70 -- choose a custom error message ··· 105 109 vim.validate("gotag", _config.gotag, "table") 106 110 vim.validate("gotag.transform", _config.gotag.transform, "string") 107 111 vim.validate("gotag.default_tag", _config.gotag.default_tag, "string") 112 + vim.validate("gotag.option", _config.gotag.option, { "string", "nil" }) 108 113 vim.validate("iferr", _config.iferr, "table") 109 114 vim.validate("iferr.message", _config.iferr.message, { "string", "nil" }) 110 115 end
+59 -11
lua/gopher/struct_tags.lua
··· 9 9 --- 2. Run `:GoTagAdd json` to add json tags to struct fields 10 10 --- 3. Run `:GoTagRm json` to remove json tags to struct fields 11 11 --- 12 + --- If you want to add/remove tag with options, you can use `json=omitempty` (where json is tag, and omitempty is its option). 13 + --- Example: `:GoTagAdd xml json=omitempty` 14 + --- 12 15 --- To clear all tags from struct run: `:GoTagClear` 13 16 --- 14 17 --- NOTE: if you dont specify the tag it will use `json` as default ··· 39 42 40 43 ---@dochide 41 44 ---@class gopher.StructTagInput 42 - ---@field tags string[] User provided tags 45 + ---@field input string[] User provided tags 43 46 ---@field range? gopher.StructTagRange (optional) 44 47 45 48 ---@dochide ··· 102 105 ) 103 106 end 104 107 108 + ---@dochide 109 + ---@param option string 110 + local function option_to_tag(option) 111 + return option:match "^(.-)=" 112 + end 113 + 114 + ---@dochide 105 115 ---@param args string[] 106 - ---@return string 116 + local function unwrap_if_needed(args) 117 + local out = {} 118 + for _, v in pairs(args) do 119 + for _, p in pairs(vim.split(v, ",")) do 120 + table.insert(out, p) 121 + end 122 + end 123 + return out 124 + end 125 + 126 + ---@dochide 127 + ---@class gopher.StructTagsArgs 128 + ---@field tags string 129 + ---@field options string 130 + 107 131 ---@dochide 108 - local function handler_user_tags(args) 109 - if #args == 0 then 110 - return c.gotag.default_tag 132 + ---@param args string[] 133 + ---@return gopher.StructTagsArgs 134 + function struct_tags.parse_args(args) 135 + args = unwrap_if_needed(args) 136 + 137 + local tags, options = {}, {} 138 + for _, v in pairs(args) do 139 + if string.find(v, "=") then 140 + table.insert(options, v) 141 + table.insert(tags, option_to_tag(v)) 142 + else 143 + table.insert(tags, v) 144 + end 111 145 end 112 - return table.concat(args, ",") 146 + 147 + return { 148 + tags = table.concat(u.list_unique(tags), ","), 149 + options = table.concat(u.list_unique(options), ","), 150 + } 113 151 end 114 152 115 153 -- Adds tags to a struct under the cursor 116 - -- See |gopher.nvim-struct-tags| 154 + -- See `:h gopher.nvim-struct-tags` 117 155 ---@param opts gopher.StructTagInput 118 156 ---@dochide 119 157 function struct_tags.add(opts) ··· 122 160 local fpath = vim.fn.expand "%" 123 161 local bufnr = vim.api.nvim_get_current_buf() 124 162 125 - local user_tags = handler_user_tags(opts.tags) 126 - handle_tags(fpath, bufnr, opts.range, { "-add-tags", user_tags }) 163 + local user_args = struct_tags.parse_args(opts.input) 164 + handle_tags(fpath, bufnr, opts.range, { 165 + "-add-tags", 166 + (user_args.tags ~= "") and user_args.tags or c.gotag.default_tag, 167 + (user_args.options ~= "" or c.gotag.option) and "-add-options" or nil, 168 + (user_args.options ~= "") and user_args.options or c.gotag.option, 169 + }) 127 170 end 128 171 129 172 -- Removes tags from a struct under the cursor ··· 136 179 local fpath = vim.fn.expand "%" 137 180 local bufnr = vim.api.nvim_get_current_buf() 138 181 139 - local user_tags = handler_user_tags(opts.tags) 140 - handle_tags(fpath, bufnr, opts.range, { "-remove-tags", user_tags }) 182 + local user_args = struct_tags.parse_args(opts.input) 183 + handle_tags(fpath, bufnr, opts.range, { 184 + "-remove-tags", 185 + (user_args.tags ~= "") and user_args.tags or c.gotag.default_tag, 186 + (user_args.options ~= "" or c.gotag.option ~= nil) and "-remove-options" or nil, 187 + (user_args.options ~= "") and user_args.options or c.gotag.option, 188 + }) 141 189 end 142 190 143 191 -- Removes all tags from a struct under the cursor
+2 -2
plugin/gopher.lua
··· 48 48 -- :GoTag 49 49 cmd("GoTagAdd", function(opts) 50 50 require("gopher").tags.add { 51 - tags = opts.fargs, 51 + input = opts.fargs, 52 52 range = (opts.count ~= -1) and { 53 53 start = opts.line1, 54 54 end_ = opts.line2, ··· 58 58 59 59 cmd("GoTagRm", function(opts) 60 60 require("gopher").tags.rm { 61 - tags = opts.fargs, 61 + input = opts.fargs, 62 62 range = (opts.count ~= -1) and { 63 63 start = opts.line1, 64 64 end_ = opts.line2,
+8
spec/fixtures/tags/overwrite_default_option_input.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int 5 + Another struct { 6 + Second string 7 + } 8 + }
+8
spec/fixtures/tags/overwrite_default_option_output.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int `xml:"id,otheroption"` 5 + Another struct { 6 + Second string `xml:"second,otheroption"` 7 + } `xml:"another,otheroption"` 8 + }
+11
spec/fixtures/tags/remove_with_option_input.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int `json:"id,omitempty" xml:"id,someoption"` 5 + Name string `json:"name,omitempty" xml:"name,someoption"` 6 + Num int64 `json:"num,omitempty" xml:"num,someoption"` 7 + Another struct { 8 + First int `json:"first,omitempty" xml:"first,someoption"` 9 + Second string `json:"second,omitempty" xml:"second,someoption"` 10 + } `json:"another,omitempty" xml:"another,someoption"` 11 + }
+11
spec/fixtures/tags/remove_with_option_output.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int `xml:"id,someoption"` 5 + Name string `xml:"name,someoption"` 6 + Num int64 `xml:"num,someoption"` 7 + Another struct { 8 + First int `xml:"first,someoption"` 9 + Second string `xml:"second,someoption"` 10 + } `xml:"another,someoption"` 11 + }
+8
spec/fixtures/tags/with_default_option_input.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int 5 + Another struct { 6 + Second string 7 + } 8 + }
+8
spec/fixtures/tags/with_default_option_output.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int `xml:"id,theoption"` 5 + Another struct { 6 + Second string `xml:"second,theoption"` 7 + } `xml:"another,theoption"` 8 + }
+11
spec/fixtures/tags/with_option_input.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int 5 + Name string 6 + Num int64 7 + Another struct { 8 + First int 9 + Second string 10 + } 11 + }
+11
spec/fixtures/tags/with_option_output.go
··· 1 + package main 2 + 3 + type Test struct { 4 + ID int `json:"id,omitempty"` 5 + Name string `json:"name,omitempty"` 6 + Num int64 `json:"num,omitempty"` 7 + Another struct { 8 + First int `json:"first,omitempty"` 9 + Second string `json:"second,omitempty"` 10 + } `json:"another,omitempty"` 11 + }
+48
spec/integration/struct_tags_test.lua
··· 96 96 t.cleanup(rs) 97 97 end 98 98 99 + struct_tags["should add tags with option"] = function() 100 + local rs = t.setup_test("tags/with_option", child, { 3, 6 }) 101 + child.cmd "GoTagAdd json=omitempty" 102 + child.cmd "write" 103 + 104 + t.eq(t.readfile(rs.tmp), rs.fixtures.output) 105 + t.cleanup(rs) 106 + end 107 + 108 + struct_tags["should add tags with default option"] = function() 109 + child.lua [[ 110 + require("gopher").setup { 111 + gotag = { option = "xml=theoption" }, 112 + } 113 + ]] 114 + 115 + local rs = t.setup_test("tags/with_default_option", child, { 3, 6 }) 116 + child.cmd "GoTagAdd xml" 117 + child.cmd "write" 118 + 119 + t.eq(t.readfile(rs.tmp), rs.fixtures.output) 120 + t.cleanup(rs) 121 + end 122 + 123 + struct_tags["should add tags and overwrite default option"] = function() 124 + child.lua [[ 125 + require("gopher").setup { 126 + gotag = { option = "xml=theoption" }, 127 + } 128 + ]] 129 + 130 + local rs = t.setup_test("tags/overwrite_default_option", child, { 3, 6 }) 131 + child.cmd "GoTagAdd xml=otheroption" 132 + child.cmd "write" 133 + 134 + t.eq(t.readfile(rs.tmp), rs.fixtures.output) 135 + t.cleanup(rs) 136 + end 137 + 138 + struct_tags["should remove tag with specified option"] = function() 139 + local rs = t.setup_test("tags/remove_with_option", child, { 3, 6 }) 140 + child.cmd "GoTagRm json=omitempty" 141 + child.cmd "write" 142 + 143 + t.eq(t.readfile(rs.tmp), rs.fixtures.output) 144 + t.cleanup(rs) 145 + end 146 + 99 147 return T
+68
spec/unit/struct_tag_test.lua
··· 1 + local t = require "spec.testutils" 2 + local _, T, st = t.setup "struct_tags" 3 + 4 + st["should parse tags"] = function() 5 + local out = require("gopher.struct_tags").parse_args { "json", "yaml", "etc" } 6 + 7 + t.eq(out.tags, "json,yaml,etc") 8 + t.eq(out.options, "") 9 + end 10 + 11 + st["should parse tags separated by commas"] = function() 12 + local out = require("gopher.struct_tags").parse_args { "json,yaml,etc" } 13 + 14 + t.eq(out.tags, "json,yaml,etc") 15 + t.eq(out.options, "") 16 + end 17 + 18 + st["should parse tags separated by command and spaces"] = function() 19 + local out = require("gopher.struct_tags").parse_args { 20 + "json,yaml", 21 + "json=omitempty", 22 + "xml=something", 23 + } 24 + 25 + t.eq(out.tags, "json,yaml,xml") 26 + t.eq(out.options, "json=omitempty,xml=something") 27 + end 28 + 29 + st["should parse tag with an option"] = function() 30 + local out = require("gopher.struct_tags").parse_args { 31 + "json=omitempty", 32 + "xml", 33 + "xml=theoption", 34 + } 35 + 36 + t.eq(out.tags, "json,xml") 37 + t.eq(out.options, "json=omitempty,xml=theoption") 38 + end 39 + 40 + st["should parse tags with an option"] = function() 41 + local out = require("gopher.struct_tags").parse_args { "json=omitempty", "yaml" } 42 + 43 + t.eq(out.tags, "json,yaml") 44 + t.eq(out.options, "json=omitempty") 45 + end 46 + 47 + st["should parse tags with an option separated with comma"] = function() 48 + local out = require("gopher.struct_tags").parse_args { "json=omitempty,yaml" } 49 + 50 + t.eq(out.tags, "json,yaml") 51 + t.eq(out.options, "json=omitempty") 52 + end 53 + 54 + st["should parse tags with options specified separately"] = function() 55 + local out = require("gopher.struct_tags").parse_args { "json", "yaml", "json=omitempty" } 56 + 57 + t.eq(out.tags, "json,yaml") 58 + t.eq(out.options, "json=omitempty") 59 + end 60 + 61 + st["should parse tags with options specified separately and separated by comma"] = function() 62 + local out = require("gopher.struct_tags").parse_args { "json,yaml,json=omitempty" } 63 + 64 + t.eq(out.tags, "json,yaml") 65 + t.eq(out.options, "json=omitempty") 66 + end 67 + 68 + return T
+10
spec/unit/utils_test.lua
··· 46 46 t.eq("\t\t", u.indent(line, indent)) 47 47 end 48 48 49 + utils["should .list_unique on list with duplicates"] = function() 50 + local u = require "gopher._utils" 51 + t.eq({ "json", "xml" }, u.list_unique { "json", "xml", "json" }) 52 + end 53 + 54 + utils["should .list_unique on list with no duplicates"] = function() 55 + local u = require "gopher._utils" 56 + t.eq({ "json", "xml" }, u.list_unique { "json", "xml" }) 57 + end 58 + 49 59 return T
vhs/tags.gif

This is a binary file and will not be displayed.

+1 -1
vhs/tags.tape
··· 26 26 Sleep 1s 27 27 28 28 Type@400ms "jVjj" 29 - Type ":GoTagAdd xml" Sleep 500ms Enter 29 + Type ":GoTagAdd json=omitempty" Sleep 500ms Enter 30 30 31 31 Sleep 5s