[CC Randy, author of go-ts-mode, Theo, who asked to keep the patches coming :)] This is a patch which adds support to go-ts-mode to insert context-aware return statements for the current function. The return statements are pre-filled with the Go zero values of the output parameters. For example, all these return statements are inserted by M-x go-ts-mode-insert-return: ``` func f() (x, y, z int) { return 0, 0, 0 } func exotic() (bool, int, myStruct, *int, chan bool, error) { return false, 0, myStruct{}, nil, nil, err } func closure(numbers []int) { sort.Slice(numbers, func(i, j int) bool { return false }) } ``` The command go-ts-mode-insert-return is experimentally bound to a key C-c C-r ("r" as return statement). It's a user error to run C-c C-r outside of a function body. Customization: when the output params contain "error" the pre-filled text is "err". A customization variable is added to allow the user to pick a different value, for example they might pick `fmt.Errorf("...: %w", err)` which will result in error wrapping: ``` func f() (int, error) { return 0, fmt.Errorf("...: %w", err) } ``` Personally, I'll use yasnippet instead of C-c C-r. Something like this: ``` # -*- mode: snippet -*- # name: ret # key: ret # type: command # -- (let ((go-ts-mode-error-zero-value "${1:fmt.Errorf(\"${2:format}: %w\", err)}")) (yas-expand-snippet (go-ts-mode-return))) ``` I'm open to suggestions about how to best expose this functionality to the user. I think a snippet makes the most sense, but there's no standard way for major modes to expose snippets as far as I'm aware. It's possible to tweak C-c C-r to call (yas-expand-snippet) if available, otherwise call (insert). In general, I don't feel strong about the C-c C-r key binding, but I didn't have a better idea. Known bug: this example does not work, fails with error "Unknown Go type "[int]int"": ``` func notOk() (int, map[int]int) { } ``` The root cause is an issue with the tree-sitter-go parser. The bug has been reported here https://github.com/tree-sitter/tree-sitter-go/issues/107 Known limitation: unfamiliar types are assumed to be structs. This assumption does not work for aliased types. For example: ``` type MyInt = int func alias() MyInt { return MyInt{} } ``` Above the correct return statement is "return MyInt(0)". My assumption is that type aliases of primitive types are rare in Go codebases. In these rare cases, the user is expected to replace "MyInt{}" with "MyInt(0)", or not use C-c C-r at all. Inspired by: this emacs conf talk "08:21 Intelligent templates" https://emacsconf.org/2022/talks/treesitter/ Feedback is more than welcome! In particular: - how to best expose the functionality - key binding, snippet (how exactly?), something else? Evgeni