Skip to content

Instantly share code, notes, and snippets.

@Jay-Madden
Last active July 24, 2024 04:04
Show Gist options
  • Save Jay-Madden/9a6479f6c31999927306ca6d5590637f to your computer and use it in GitHub Desktop.
Save Jay-Madden/9a6479f6c31999927306ca6d5590637f to your computer and use it in GitHub Desktop.
Quick and dirty neovim autocmd to add or remove the wrapping parenthesis around golang multi returns whenever they go from single return to multireturn
local function wrap_golang_multi_return()
-- If its not a go buffer dont bother doing any more work
if vim.bo.filetype ~= "go" then
return
end
local cursor_pos = vim.api.nvim_win_get_cursor(0)
local line_num, line_col = cursor_pos[1], cursor_pos[2]
local curr_buf = vim.api.nvim_get_current_buf()
local line = vim.api.nvim_buf_get_lines(curr_buf, line_num - 1, line_num, false)[1]
local P, R, S, C, Cs = vim.lpeg.P, vim.lpeg.R, vim.lpeg.S, vim.lpeg.C, vim.lpeg.Cs
local letter = R("az", "AZ") + S("_")
local digit = R("09")
local whitespace = S(" \t\n")
local repeat_whitespace = whitespace ^ 0
local alphanumeric = letter + digit
local identifier = alphanumeric ^ 1
local symbol = S("., &*-[]|")
local open_paren = P("(")
local close_paren = P(")")
local open_bracket = P("[")
local close_bracket = P("]")
local open_brace = P("{")
local close_brace = P("}")
local func_keyword = P("func")
local arguments = alphanumeric + symbol + whitespace
local function_argument_list = open_paren * arguments ^ 0 * close_paren
-- We are just gonna ignore that nested generics happen
local generic_argument_list = open_bracket * (arguments - close_bracket) ^ 0 * close_bracket
local reciever = open_paren
* alphanumeric ^ 1
* repeat_whitespace
* P("*") ^ -1
* identifier
* repeat_whitespace
* close_paren
--
-- The signature can be malformed, in fact it likely as this happens while we are typing
local return_signature = open_paren ^ 0 * (identifier + symbol) ^ 1 * close_paren ^ 0
local return_signature_capture = vim.lpeg.Cs((return_signature / function(match)
if match == nil then
return
end
local function gsub(s, patt, repl)
patt = vim.lpeg.P(patt)
patt = vim.lpeg.Cs((patt / repl + 1) ^ 0)
return vim.lpeg.match(patt, s)
end
-- Strip the parens off, we will add them back if we need to
local value = gsub(match, "(", "")
value = gsub(value, ")", "")
-- Disable the type error, lpeg match will work as a string
---@diagnostic disable-next-line: param-type-mismatch
local returns = vim.split(value, ",")
if #returns == 1 then
--line_col = line_col - 1
return value
else
--line_col = line_col + 1
return "(" .. value .. ")"
end
end))
local anonymous_function = C(func_keyword * function_argument_list * repeat_whitespace)
* return_signature_capture * C(repeat_whitespace * open_brace ^ 0 * repeat_whitespace)
local named_function = C(
func_keyword
* repeat_whitespace
* reciever ^ 0
* repeat_whitespace
* identifier
* generic_argument_list ^ 0
* repeat_whitespace
* function_argument_list
* repeat_whitespace
) * return_signature_capture * C(repeat_whitespace * open_brace ^ 0 * repeat_whitespace)
local full_function = anonymous_function + named_function
-- We want to ignore the start of the line incase it is a lambda
local full_line = Cs(((P(1) - func_keyword) ^ 0 * full_function))
local match = vim.lpeg.match(full_line, line)
if match == nil then
return
end
-- Disable the type error, lpeg match will work as a string
---@diagnostic disable-next-line: param-type-mismatch
vim.api.nvim_set_current_line(match)
-- When we add parenthesis we need to bump the cursor one block to the right to account for the paren on the left.
-- we bump the column number in the match handler and execute it here
vim.api.nvim_win_set_cursor(0, { line_num, line_col })
end
vim.api.nvim_create_autocmd(
{ "TextChanged", "TextChangedI" },
{ callback = wrap_golang_multi_return }
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment