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