From a582bd6c059a9d5b04db364a0a8a2ecd3040ec23 Mon Sep 17 00:00:00 2001 From: bivashy Date: Thu, 18 Dec 2025 14:09:16 +0500 Subject: [PATCH 1/4] LazyUpdate, remove `ai` extras --- lazy-lock.json | 76 +++++++++++++++++++++------------------- lazyvim.json | 3 +- lua/plugins/neo-tree.lua | 1 + 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/lazy-lock.json b/lazy-lock.json index 3e36b22..cb6b27c 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -1,50 +1,54 @@ { - "CopilotChat.nvim": { "branch": "main", "commit": "4d9256418ca276b294f3e00445aa0d6faec4c1ea" }, - "LazyVim": { "branch": "main", "commit": "a65d5d530d372b39a468dfbb2ce633f344770c5c" }, - "SchemaStore.nvim": { "branch": "main", "commit": "960a5cf992c033170499ccc7003df59734ed40a8" }, + "LazyVim": { "branch": "main", "commit": "28db03f958d58dfff3c647ce28fdc1cb88ac158d" }, + "SchemaStore.nvim": { "branch": "main", "commit": "10e90771990622daec50d14ef3e278f429b9419f" }, "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" }, - "catppuccin": { "branch": "main", "commit": "af58927c55c9f3272c940ff02b3cee94a1249f26" }, + "catppuccin": { "branch": "main", "commit": "ce8d176faa4643e026e597ae3c31db59b63cef09" }, "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, - "cmp-nvim-lsp": { "branch": "main", "commit": "bd5a7d6db125d4654b50eeae9f5217f24bb22fd3" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" }, "cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" }, - "codeium.nvim": { "branch": "main", "commit": "821b570b526dbb05b57aa4ded578b709a704a38a" }, - "conform.nvim": { "branch": "master", "commit": "235dd79731c1dc51ec04abb4045cbc54727a172a" }, - "flash.nvim": { "branch": "main", "commit": "3be9bf7e85550045ec576379a0c45aac144d0438" }, + "conform.nvim": { "branch": "master", "commit": "9b8fa5e0b78168f68bee9bf886dc20f287c61e02" }, + "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" }, "friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" }, - "gitsigns.nvim": { "branch": "main", "commit": "20ad4419564d6e22b189f6738116b38871082332" }, - "grug-far.nvim": { "branch": "main", "commit": "3e72397465f774b01aa38e4fe8e6eecf23d766d9" }, - "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" }, - "lazydev.nvim": { "branch": "main", "commit": "e28ce52fc7ff79fcb76f0e79ee6fb6182fca90b9" }, - "lualine.nvim": { "branch": "master", "commit": "3946f0122255bc377d14a59b27b609fb3ab25768" }, + "gitsigns.nvim": { "branch": "main", "commit": "5813e4878748805f1518cee7abb50fd7205a3a48" }, + "grug-far.nvim": { "branch": "main", "commit": "b58b2d65863f4ebad88b10a1ddd519e5380466e0" }, + "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, + "lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" }, + "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "2304ff65ecc8cb2afc2484de3e2ed9a407edf0b9" }, - "mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" }, - "mini.ai": { "branch": "main", "commit": "11c57180bc9084089206e211ac7aa598bedc9673" }, - "mini.icons": { "branch": "main", "commit": "284798619aed9f4c1ac1b9417b9a5e3b4b85ef3a" }, - "mini.pairs": { "branch": "main", "commit": "b9aada8c0e59f2b938e98fbf4eae0799eba96ad9" }, - "neo-tree.nvim": { "branch": "main", "commit": "e1d464a45a2ff8328d3973e0f9737a81c3b42bf6" }, - "noice.nvim": { "branch": "main", "commit": "c86aea584d98be7ee1167ce4d4ef946fbd7f3ae0" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "3b3571b4dadbcb464804466e9872e7246c316af7" }, + "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" }, + "mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" }, + "mini.ai": { "branch": "main", "commit": "bfb26d9072670c3aaefab0f53024b2f3729c8083" }, + "mini.icons": { "branch": "main", "commit": "ff2e4f1d29f659cc2bad0f9256f2f6195c6b2428" }, + "mini.pairs": { "branch": "main", "commit": "d5a29b6254dad07757832db505ea5aeab9aad43a" }, + "neo-tree.nvim": { "branch": "main", "commit": "2ab61f0a4f97e909f80b430f43a1ddae142c548d" }, + "noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, - "nvim-cmp": { "branch": "main", "commit": "a7bcf1d88069fc67c9ace8a62ba480b8fe879025" }, - "nvim-jdtls": { "branch": "master", "commit": "380ac148f989e1291aac002dc959ecc68c5243d0" }, - "nvim-lint": { "branch": "master", "commit": "9da1fb942dd0668d5182f9c8dee801b9c190e2bb" }, - "nvim-lspconfig": { "branch": "master", "commit": "e5c61b02f33b5c6538be25b2696b33b4cc91e667" }, + "nvim-cmp": { "branch": "main", "commit": "d97d85e01339f01b842e6ec1502f639b080cb0fc" }, + "nvim-dap": { "branch": "master", "commit": "5860c7c501eb428d3137ee22c522828d20cca0b3" }, + "nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" }, + "nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" }, + "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, + "nvim-jdtls": { "branch": "master", "commit": "f73731b543f5971e0da9665eb1d7ceffe1fde71f" }, + "nvim-lint": { "branch": "master", "commit": "c47b71d146a0b638f46672e6704c322369385df6" }, + "nvim-lspconfig": { "branch": "master", "commit": "c4f67bf85b01a57e3c130352c0a0e453ab8cd5b9" }, + "nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" }, "nvim-snippets": { "branch": "main", "commit": "56b4052f71220144689caaa2e5b66222ba5661eb" }, - "nvim-treesitter": { "branch": "main", "commit": "30c466ad571b8b99fd06e3df8b2336e3ae63a53a" }, - "nvim-treesitter-context": { "branch": "master", "commit": "ec308c7827b5f8cb2dd0ad303a059c945dd21969" }, - "nvim-treesitter-textobjects": { "branch": "main", "commit": "1b2d85d3de6114c4bcea89ffb2cd1ce9e3a19931" }, + "nvim-treesitter": { "branch": "main", "commit": "4fc09bee78e91bf4ba471cdab4bf9dfa37fde51c" }, + "nvim-treesitter-context": { "branch": "master", "commit": "64dd4cf3f6fd0ab17622c5ce15c91fc539c3f24a" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "0d7c800fadcfe2d33089f5726cb8907fc846eece" }, "nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" }, - "persistence.nvim": { "branch": "main", "commit": "51eef57272742b773468949f6bd0503ec3f83874" }, + "persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" }, "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "render-markdown.nvim": { "branch": "main", "commit": "475d3ad8cae486b0df6fc6050cf5b5ea1de42db8" }, - "snacks.nvim": { "branch": "main", "commit": "471eb036c47abf9e71c33b9e01ebb1b2d464b791" }, + "render-markdown.nvim": { "branch": "main", "commit": "07d088bf8bdadd159eb807b90eaee86a4778383f" }, + "snacks.nvim": { "branch": "main", "commit": "fe7cfe9800a182274d0f868a74b7263b8c0c020b" }, "tailwindcss-colorizer-cmp.nvim": { "branch": "main", "commit": "3d3cd95e4a4135c250faf83dd5ed61b8e5502b86" }, - "todo-comments.nvim": { "branch": "main", "commit": "19d461ddd543e938eb22505fb03fa878800270b6" }, - "tokyonight.nvim": { "branch": "main", "commit": "8734a4e9a9b03549337faf5a86637abd5e16721e" }, - "trouble.nvim": { "branch": "main", "commit": "c098362fe603d3922095e7db595961e020bdf2d0" }, - "ts-comments.nvim": { "branch": "main", "commit": "217ab9cc137fceb6659b53790bd25e608219abe1" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "tokyonight.nvim": { "branch": "main", "commit": "5da1b76e64daf4c5d410f06bcb6b9cb640da7dfd" }, + "trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" }, + "ts-comments.nvim": { "branch": "main", "commit": "123a9fb12e7229342f807ec9e6de478b1102b041" }, "vim-dadbod": { "branch": "master", "commit": "e95afed23712f969f83b4857a24cf9d59114c2e6" }, "vim-dadbod-completion": { "branch": "master", "commit": "a8dac0b3cf6132c80dc9b18bef36d4cf7a9e1fe6" }, - "vim-dadbod-ui": { "branch": "master", "commit": "5a83ee1fdafcdedb03222bb46f7cfd70646025ee" }, - "which-key.nvim": { "branch": "main", "commit": "b4177e3eaf15fe5eb8357ebac2286d488be1ed00" } + "vim-dadbod-ui": { "branch": "master", "commit": "48c4f271da13d380592f4907e2d1d5558044e4e5" }, + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } } diff --git a/lazyvim.json b/lazyvim.json index 20691d3..13eb82d 100644 --- a/lazyvim.json +++ b/lazyvim.json @@ -1,8 +1,7 @@ { "extras": [ - "lazyvim.plugins.extras.ai.codeium", - "lazyvim.plugins.extras.ai.copilot-chat", "lazyvim.plugins.extras.coding.nvim-cmp", + "lazyvim.plugins.extras.dap.core", "lazyvim.plugins.extras.editor.neo-tree", "lazyvim.plugins.extras.lang.docker", "lazyvim.plugins.extras.lang.go", diff --git a/lua/plugins/neo-tree.lua b/lua/plugins/neo-tree.lua index b0a4cc7..11df3f7 100644 --- a/lua/plugins/neo-tree.lua +++ b/lua/plugins/neo-tree.lua @@ -9,6 +9,7 @@ return { filtered_items = { hide_by_pattern = { "*_test.go", + "test", }, }, group_empty_dirs = true, From 86796d6e12bcb62c733661b8294d0f40bf483e31 Mon Sep 17 00:00:00 2001 From: bivashy Date: Tue, 23 Dec 2025 16:56:46 +0500 Subject: [PATCH 2/4] Add "vibe-coded" go-helper utils --- lazy-lock.json | 21 +- lua/plugins/go-helper.lua | 15 ++ lua/scripts/go-extract-interface.lua | 137 +++++++++++ lua/scripts/go-gen-constructor.lua | 353 +++++++++++++++++++++++++++ 4 files changed, 516 insertions(+), 10 deletions(-) create mode 100644 lua/plugins/go-helper.lua create mode 100644 lua/scripts/go-extract-interface.lua create mode 100644 lua/scripts/go-gen-constructor.lua diff --git a/lazy-lock.json b/lazy-lock.json index cb6b27c..c15ca7e 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -1,42 +1,43 @@ { "LazyVim": { "branch": "main", "commit": "28db03f958d58dfff3c647ce28fdc1cb88ac158d" }, - "SchemaStore.nvim": { "branch": "main", "commit": "10e90771990622daec50d14ef3e278f429b9419f" }, + "SchemaStore.nvim": { "branch": "main", "commit": "8b92ea89835b8e5dbc779a675ebb0e5fcb9a1993" }, "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" }, "catppuccin": { "branch": "main", "commit": "ce8d176faa4643e026e597ae3c31db59b63cef09" }, "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, "cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" }, "cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" }, - "conform.nvim": { "branch": "master", "commit": "9b8fa5e0b78168f68bee9bf886dc20f287c61e02" }, + "conform.nvim": { "branch": "master", "commit": "5420c4b5ea0aeb99c09cfbd4fd0b70d257b44f25" }, "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" }, "friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" }, "gitsigns.nvim": { "branch": "main", "commit": "5813e4878748805f1518cee7abb50fd7205a3a48" }, - "grug-far.nvim": { "branch": "main", "commit": "b58b2d65863f4ebad88b10a1ddd519e5380466e0" }, + "go-tools.nvim": { "branch": "main", "commit": "f47209b9e58df1e13b42b1e2fd2817fce32ea0df" }, + "grug-far.nvim": { "branch": "main", "commit": "bc589a1ba340a00ae40bf1436401eac5b1454687" }, "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, "lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" }, "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "3b3571b4dadbcb464804466e9872e7246c316af7" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "9f9c67795d0795a6e8612f5a899ca64a074a1076" }, "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" }, "mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" }, "mini.ai": { "branch": "main", "commit": "bfb26d9072670c3aaefab0f53024b2f3729c8083" }, "mini.icons": { "branch": "main", "commit": "ff2e4f1d29f659cc2bad0f9256f2f6195c6b2428" }, "mini.pairs": { "branch": "main", "commit": "d5a29b6254dad07757832db505ea5aeab9aad43a" }, - "neo-tree.nvim": { "branch": "main", "commit": "2ab61f0a4f97e909f80b430f43a1ddae142c548d" }, + "neo-tree.nvim": { "branch": "main", "commit": "b0b73273b4f5a1f4b4aac8accd6e0c3b4b5a6967" }, "noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, "nvim-cmp": { "branch": "main", "commit": "d97d85e01339f01b842e6ec1502f639b080cb0fc" }, - "nvim-dap": { "branch": "master", "commit": "5860c7c501eb428d3137ee22c522828d20cca0b3" }, + "nvim-dap": { "branch": "master", "commit": "818cd8787a77a97703eb1d9090543a374f79a9ac" }, "nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" }, "nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" }, "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, "nvim-jdtls": { "branch": "master", "commit": "f73731b543f5971e0da9665eb1d7ceffe1fde71f" }, - "nvim-lint": { "branch": "master", "commit": "c47b71d146a0b638f46672e6704c322369385df6" }, - "nvim-lspconfig": { "branch": "master", "commit": "c4f67bf85b01a57e3c130352c0a0e453ab8cd5b9" }, + "nvim-lint": { "branch": "master", "commit": "1f19dacd945a7b1a57f29f32b2d7168384df3d36" }, + "nvim-lspconfig": { "branch": "master", "commit": "5eeb45c8c469b84777a5bd8796b698c8a1c780a7" }, "nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" }, "nvim-snippets": { "branch": "main", "commit": "56b4052f71220144689caaa2e5b66222ba5661eb" }, - "nvim-treesitter": { "branch": "main", "commit": "4fc09bee78e91bf4ba471cdab4bf9dfa37fde51c" }, + "nvim-treesitter": { "branch": "main", "commit": "6e42d823ce0a5a76180c473c119c7677738a09d1" }, "nvim-treesitter-context": { "branch": "master", "commit": "64dd4cf3f6fd0ab17622c5ce15c91fc539c3f24a" }, - "nvim-treesitter-textobjects": { "branch": "main", "commit": "0d7c800fadcfe2d33089f5726cb8907fc846eece" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "e91c585ac0ee760198dabc1fad2e6227effdcd5e" }, "nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" }, "persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" }, "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, diff --git a/lua/plugins/go-helper.lua b/lua/plugins/go-helper.lua new file mode 100644 index 0000000..349fa02 --- /dev/null +++ b/lua/plugins/go-helper.lua @@ -0,0 +1,15 @@ +return { + { + "go-helper", + dir = vim.fn.stdpath("config") .. "/lua/scripts", + ft = "go", + keys = { + { "cei", "GoExtractInterface", desc = "Extract Interface", ft = "go" }, + { "cec", "GoGenerateConstructor", desc = "Generate Constructor", ft = "go" }, + }, + config = function() + require("scripts.go-extract-interface").setup() + require("scripts.go-gen-constructor").setup() + end, + }, +} diff --git a/lua/scripts/go-extract-interface.lua b/lua/scripts/go-extract-interface.lua new file mode 100644 index 0000000..fa97fb7 --- /dev/null +++ b/lua/scripts/go-extract-interface.lua @@ -0,0 +1,137 @@ +local M = {} + +-- Parse method signature from a line +local function parse_method(line) + -- Match: func (receiver) MethodName(params) (returns) + local pattern = "^func%s+%([^)]+%)%s+([%w_]+)%s*(%b())%s*(.*)" + local name, params, returns = line:match(pattern) + + if name then + -- Clean up returns (remove leading spaces and parentheses if single return) + returns = returns:gsub("^%s+", "") + if returns:match("^%b()") then + returns = " " .. returns + elseif returns ~= "" then + returns = " " .. returns + end + + return name .. params .. returns + end + return nil +end + +-- Find all methods for a given struct type +local function find_struct_methods(struct_name, bufnr) + local methods = {} + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + + -- Pattern to match methods with the struct as receiver + -- Matches both pointer and value receivers + local patterns = { + "^func%s+%(%s*%w+%s+%*?" .. struct_name .. "%s*%)", -- Standard pattern + } + + for i, line in ipairs(lines) do + for _, pattern in ipairs(patterns) do + if line:match(pattern) then + local method_sig = parse_method(line) + if method_sig then + table.insert(methods, method_sig) + end + end + end + end + + return methods +end + +-- Get struct name under cursor +local function get_struct_name() + local line = vim.api.nvim_get_current_line() + + -- Try to match: type StructName struct + local struct_name = line:match("^type%s+([%w_]+)%s+struct") + + if not struct_name then + -- Try to match if cursor is on struct keyword + struct_name = line:match("type%s+([%w_]+)%s+struct") + end + + return struct_name +end + +-- Generate interface from methods +local function generate_interface(struct_name, methods) + if #methods == 0 then + return nil, "No methods found for struct " .. struct_name + end + + -- Create interface name (conventionally, I + StructName or StructName + er) + local interface_name = "I" .. struct_name + + local lines = { + "type " .. interface_name .. " interface {", + } + + for _, method in ipairs(methods) do + local method_without_bracket = method:gsub("{$", "") + local cleaned_method = method_without_bracket:gsub("%s+$", "") + table.insert(lines, "\t" .. cleaned_method) + end + + table.insert(lines, "}") + + return lines, nil +end + +-- Main function to extract interface +function M.extract_interface() + local bufnr = vim.api.nvim_get_current_buf() + + -- Check if we're in a Go file + local filetype = vim.bo[bufnr].filetype + if filetype ~= "go" then + vim.notify("This command only works in Go files", vim.log.levels.ERROR) + return + end + + -- Get struct name under cursor + local struct_name = get_struct_name() + if not struct_name then + vim.notify("Cursor is not on a struct definition", vim.log.levels.ERROR) + return + end + + -- Find all methods for this struct + local methods = find_struct_methods(struct_name, bufnr) + + -- Generate interface + local interface_lines, err = generate_interface(struct_name, methods) + if err then + vim.notify(err, vim.log.levels.WARN) + return + end + + -- Insert interface above the struct definition + local cursor_line = vim.api.nvim_win_get_cursor(0)[1] + vim.api.nvim_buf_set_lines(bufnr, cursor_line - 1, cursor_line - 1, false, interface_lines) + vim.api.nvim_buf_set_lines(bufnr, cursor_line, cursor_line, false, { "" }) -- Empty line + + vim.notify("Interface extracted: " .. #methods .. " methods found", vim.log.levels.INFO) +end + +-- Setup function for lazy.nvim +function M.setup() + -- Create command + vim.api.nvim_create_user_command("GoExtractInterface", M.extract_interface, { + desc = "Extract interface from Go struct under cursor", + }) + + -- Optional: Add keybinding + vim.keymap.set("n", "cei", M.extract_interface, { + desc = "Extract interface from struct", + silent = true, + }) +end + +return M diff --git a/lua/scripts/go-gen-constructor.lua b/lua/scripts/go-gen-constructor.lua new file mode 100644 index 0000000..65d6e4a --- /dev/null +++ b/lua/scripts/go-gen-constructor.lua @@ -0,0 +1,353 @@ +local M = {} + +-- Get the struct name from the current line +local function get_struct_name() + local line = vim.api.nvim_get_current_line() + + -- Try to match: type StructName struct + local struct_name = line:match("^type%s+([%w_]+)%s+struct") + + -- If not found, try to match if cursor is on struct definition + if not struct_name then + struct_name = line:match("type%s+([%w_]+)%s+struct") + end + + return struct_name +end + +-- Check if constructor already exists and find its location +local function find_existing_constructor(constructor_name, bufnr) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + + for i, line in ipairs(lines) do + -- Look for function definition with constructor name + if line:match("^func%s+" .. constructor_name .. "%s*%(") then + local start_line = i + local end_line = i + + -- Find the end of the function (matching braces) + local bracket_count = 0 + for j = i, #lines do + for char in lines[j]:gmatch(".") do + if char == "{" then + bracket_count = bracket_count + 1 + elseif char == "}" then + bracket_count = bracket_count - 1 + end + end + + if bracket_count == 0 and lines[j]:match("}") then + end_line = j + break + end + end + return { start_line = start_line, end_line = end_line, line = line } + end + end + + return nil +end + +-- Extract return type from existing constructor +local function extract_return_type_from_existing(constructor_line) + -- Match: func ConstructorName(params) ReturnType { + local return_type = constructor_line:match("%)%s*([%w%.]+)%s*{") + return return_type +end + +local function remove_existing_constructor(constructor_name, bufnr) + local location = find_existing_constructor(constructor_name, bufnr) + if location then + -- Remove the constructor + vim.api.nvim_buf_set_lines(bufnr, location.start_line - 1, location.end_line, false, {}) + return location + end + return nil +end + +-- Find interface that the struct should implement +local function find_interface_for_struct(struct_name, bufnr) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + + -- Look for interfaces defined in the file + for i, line in ipairs(lines) do + -- Match interface definition + local interface_name = line:match("^type%s+([%w_]+)%s+interface") + if interface_name then + -- Check if this interface has methods that match our struct + -- Simple check: if interface name contains struct name or vice versa + if + string.find(interface_name, struct_name) + or string.find(struct_name, interface_name) + or string.lower(struct_name) == string.lower(interface_name) + then + return interface_name + end + end + end + + -- If no matching interface found, check if struct has an interface with same name + "er" or "Service" + local possible_interfaces = { + string.gsub(struct_name, "Service$", "Service"), + struct_name .. "er", + "I" .. struct_name, + string.gsub(struct_name, "^%l", string.upper), + } + + for _, interface_name in ipairs(possible_interfaces) do + for i, line in ipairs(lines) do + if line:match("^type%s+" .. interface_name .. "%s+interface") then + return interface_name + end + end + end + + return nil +end + +-- Parse struct fields +local function parse_struct_fields(struct_name, bufnr) + local fields = {} + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + local in_struct = false + local bracket_count = 0 + local start_line = 0 + + for i, line in ipairs(lines) do + -- Find the struct definition + if line:match("^type%s+" .. struct_name .. "%s+struct") then + in_struct = true + start_line = i + -- Check if opening brace is on same line + if line:match("{") then + bracket_count = 1 + end + if line:match("}") then + break + end + elseif in_struct then + -- Count brackets to know when we're done + if not line:match("^%s*//") then -- Skip comment lines for bracket counting + for char in line:gmatch(".") do + if char == "{" then + bracket_count = bracket_count + 1 + elseif char == "}" then + bracket_count = bracket_count - 1 + end + end + end + + -- Parse field if we're inside the struct and it's not the closing brace + if bracket_count > 0 and i > start_line then + -- Remove comments and trim + local clean_line = line:gsub("//.*$", ""):gsub("^%s*(.-)%s*$", "%1") + print("Clean line: ", clean_line) + + -- Skip empty lines and closing braces + if clean_line ~= "" and not clean_line:match("^}") and not clean_line:match("^{") then + -- Extract field name and type + -- Handle multiple fields with same type: field1, field2 Type + local field_part = clean_line + + -- Check if line contains a type declaration + if field_part:match("[%w_]+%s+[%w%.%*%[%]]+$") then + -- Split by last space to get type and field names + local last_space = field_part:match("^.*()%s[%w%.%*%[%]]+$") + if last_space then + local type_part = field_part:sub(last_space + 1) + local fields_part = field_part:sub(1, last_space - 1) + + -- Split multiple field names by comma + for field_name in fields_part:gmatch("([%w_]+),?%s*") do + if field_name ~= "" then + table.insert(fields, { + name = field_name, + type = type_part, + line = clean_line, + }) + end + end + end + end + end + end + + -- Stop parsing when we exit the struct + if bracket_count == 0 then + break + end + end + end + + return fields +end + +-- Generate constructor function +local function generate_constructor(struct_name, interface_name, fields, existing_constructor) + local constructor_name = "New" .. struct_name + if string.match(struct_name, "^[a-z]") and interface_name then + constructor_name = "New" .. interface_name + else + constructor_name = "New" .. string.upper(string.sub(struct_name, 1, 1)) .. string.sub(struct_name, 2) + end + + local lines = {} + + -- Function signature + local return_type + if existing_constructor and existing_constructor.line then + return_type = extract_return_type_from_existing(existing_constructor.line) + end + + if not return_type then + return_type = interface_name or struct_name + end + + -- Build parameters + local params = {} + local field_params = {} + for _, field in ipairs(fields) do + local param_name = field.name + local param_type = field.type + + table.insert(params, param_name .. " " .. param_type) + field_params[param_name] = param_name + end + + -- Build function signature + local func_sig = "func " .. constructor_name .. "(" + if #params > 0 then + func_sig = func_sig .. table.concat(params, ", ") + end + func_sig = func_sig .. ") " .. return_type .. " {" + table.insert(lines, func_sig) + + -- Function body + table.insert(lines, "\treturn &" .. struct_name .. "{") + + -- Field assignments + local field_assignments = {} + for _, field in ipairs(fields) do + local value = field_params[field.name] or field.name + table.insert(field_assignments, "\t\t" .. field.name .. ": " .. value .. ",") + end + + for _, assignment in ipairs(field_assignments) do + table.insert(lines, assignment) + end + + table.insert(lines, "\t}") + table.insert(lines, "}") + + return lines, constructor_name +end + +-- Main function to generate constructor +function M.generate_constructor() + local bufnr = vim.api.nvim_get_current_buf() + + -- Check if we're in a Go file + local filetype = vim.bo[bufnr].filetype + if filetype ~= "go" then + vim.notify("This command only works in Go files", vim.log.levels.ERROR) + return + end + + -- Get struct name under cursor + local struct_name = get_struct_name() + if not struct_name then + vim.notify("Cursor is not on a struct definition", vim.log.levels.ERROR) + return + end + + -- Find interface if exists + local interface_name = find_interface_for_struct(struct_name, bufnr) + + -- Parse struct fields + local fields = parse_struct_fields(struct_name, bufnr) + + if #fields == 0 then + vim.notify("No fields found in struct " .. struct_name, vim.log.levels.WARN) + return + end + + -- Check for existing constructor and remove it (but save its info) + local constructor_name = "New" .. struct_name + if string.match(struct_name, "^[a-z]") and interface_name then + constructor_name = "New" .. interface_name + else + constructor_name = "New" .. string.upper(string.sub(struct_name, 1, 1)) .. string.sub(struct_name, 2) + end + + -- Remove existing constructor if it exists + local removed = remove_existing_constructor(constructor_name, bufnr) + + -- Generate constructor + local constructor_lines = generate_constructor(struct_name, interface_name, fields, removed) + + -- Find where to insert the constructor (after the struct) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + local insert_line = 0 + + for i, line in ipairs(lines) do + if line:match("^type%s+" .. struct_name .. "%s+struct") then + -- Find the end of the struct + local bracket_count = 0 + for j = i, #lines do + local current_line = lines[j] + -- Skip comment lines for bracket counting + if not current_line:match("^%s*//") then + for char in current_line:gmatch(".") do + if char == "{" then + bracket_count = bracket_count + 1 + elseif char == "}" then + bracket_count = bracket_count - 1 + end + end + end + + if bracket_count == 0 then + insert_line = j + break + end + end + break + end + end + + if insert_line > 0 then + -- Check if we need to add an empty line + if insert_line < #lines and lines[insert_line + 1] and lines[insert_line + 1]:match("^%s*$") then + -- Next line is already empty, insert after it + vim.api.nvim_buf_set_lines(bufnr, insert_line + 1, insert_line + 1, false, constructor_lines) + else + -- Add an empty line before constructor + table.insert(constructor_lines, 1, "") + vim.api.nvim_buf_set_lines(bufnr, insert_line, insert_line, false, constructor_lines) + end + + if removed then + vim.notify("Replaced existing constructor: " .. constructor_name, vim.log.levels.INFO) + else + vim.notify("Generated constructor: " .. constructor_name, vim.log.levels.INFO) + end + else + vim.notify("Could not find where to insert constructor", vim.log.levels.ERROR) + end +end + +-- Setup function +function M.setup() + -- Create command + vim.api.nvim_create_user_command("GoGenerateConstructor", M.generate_constructor, { + desc = "Generate constructor for Go struct under cursor", + }) + + -- Optional keybinding + vim.keymap.set("n", "cec", M.generate_constructor, { + desc = "Generate constructor for struct", + silent = true, + }) +end + +return M From 8b850041be230664eabe7132d1c2a40eb10acbd5 Mon Sep 17 00:00:00 2001 From: bivashy Date: Tue, 23 Dec 2025 17:12:31 +0500 Subject: [PATCH 3/4] Remove redundant print --- lua/scripts/go-gen-constructor.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/scripts/go-gen-constructor.lua b/lua/scripts/go-gen-constructor.lua index 65d6e4a..0222aaf 100644 --- a/lua/scripts/go-gen-constructor.lua +++ b/lua/scripts/go-gen-constructor.lua @@ -141,7 +141,6 @@ local function parse_struct_fields(struct_name, bufnr) if bracket_count > 0 and i > start_line then -- Remove comments and trim local clean_line = line:gsub("//.*$", ""):gsub("^%s*(.-)%s*$", "%1") - print("Clean line: ", clean_line) -- Skip empty lines and closing braces if clean_line ~= "" and not clean_line:match("^}") and not clean_line:match("^{") then From 10759108ae782f834c55cc2ca5c53883e3617bc6 Mon Sep 17 00:00:00 2001 From: bivashy Date: Wed, 31 Dec 2025 12:53:11 +0500 Subject: [PATCH 4/4] Remove optional keybinding, change explorer name --- lua/plugins/{exporer.lua => explorer.lua} | 0 lua/scripts/go-extract-interface.lua | 6 ------ lua/scripts/go-gen-constructor.lua | 6 ------ 3 files changed, 12 deletions(-) rename lua/plugins/{exporer.lua => explorer.lua} (100%) diff --git a/lua/plugins/exporer.lua b/lua/plugins/explorer.lua similarity index 100% rename from lua/plugins/exporer.lua rename to lua/plugins/explorer.lua diff --git a/lua/scripts/go-extract-interface.lua b/lua/scripts/go-extract-interface.lua index fa97fb7..1883308 100644 --- a/lua/scripts/go-extract-interface.lua +++ b/lua/scripts/go-extract-interface.lua @@ -126,12 +126,6 @@ function M.setup() vim.api.nvim_create_user_command("GoExtractInterface", M.extract_interface, { desc = "Extract interface from Go struct under cursor", }) - - -- Optional: Add keybinding - vim.keymap.set("n", "cei", M.extract_interface, { - desc = "Extract interface from struct", - silent = true, - }) end return M diff --git a/lua/scripts/go-gen-constructor.lua b/lua/scripts/go-gen-constructor.lua index 0222aaf..f5c6c00 100644 --- a/lua/scripts/go-gen-constructor.lua +++ b/lua/scripts/go-gen-constructor.lua @@ -341,12 +341,6 @@ function M.setup() vim.api.nvim_create_user_command("GoGenerateConstructor", M.generate_constructor, { desc = "Generate constructor for Go struct under cursor", }) - - -- Optional keybinding - vim.keymap.set("n", "cec", M.generate_constructor, { - desc = "Generate constructor for struct", - silent = true, - }) end return M