GNU bug report logs -
#61368
[PATCH] Extend go-ts-mode with support for pre-filling return statements
Previous Next
Full log
Message #11 received at submit <at> debbugs.gnu.org (full text, mbox):
Evgeni Kolev <evgenysw <at> gmail.com> writes:
> [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
> })
> }
> ```
Cool!
>
> 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.
>
How about using tempo or skeleton as fallbacks when yasnippet isn't
installed?
> 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?
>
Personally I think this should be a contrib to gopls as a code action so
that others can benefit from it. Is upstreaming it to gopls too hard?
Theo
This bug report was last modified 1 year and 155 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.