unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
@ 2023-02-08 15:27 Evgeni Kolev
  2023-02-08 16:30 ` Eli Zaretskii
  2023-02-08 19:20 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 14+ messages in thread
From: Evgeni Kolev @ 2023-02-08 15:27 UTC (permalink / raw)
  To: 61368; +Cc: Randy Taylor, Theodor Thornhill

[-- Attachment #1: Type: text/plain, Size: 2804 bytes --]

[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

[-- Attachment #2: 0001-Extend-go-ts-mode-with-support-for-pre-filling-retur.patch --]
[-- Type: application/x-patch, Size: 6378 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-08 15:27 bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements Evgeni Kolev
@ 2023-02-08 16:30 ` Eli Zaretskii
  2023-02-09 11:47   ` Evgeni Kolev
  2023-02-08 19:20 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2023-02-08 16:30 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: dev, theo, 61368

> Cc: Randy Taylor <dev@rjt.dev>, Theodor Thornhill <theo@thornhill.no>
> From: Evgeni Kolev <evgenysw@gmail.com>
> Date: Wed, 8 Feb 2023 17:27:58 +0200
> 
> 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.

Instead of a command bound to a special key sequences, would it
perhaps make more sense to add some kind of "electric" behavior to
"normal" keys?  Like perhaps typing RET after inserting "return" would
add the "context-aware return statement"?  Then the user could turn on
the electric behavior with some minor mode, and get this behavior,
while avoiding the need to dedicate a key sequence.

WDYT?





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-08 15:27 bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements Evgeni Kolev
  2023-02-08 16:30 ` Eli Zaretskii
@ 2023-02-08 19:20 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 14+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-08 19:20 UTC (permalink / raw)
  To: evgenysw, 61368; +Cc: Randy Taylor

Evgeni Kolev <evgenysw@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





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-08 16:30 ` Eli Zaretskii
@ 2023-02-09 11:47   ` Evgeni Kolev
  2023-02-09 13:39     ` Eli Zaretskii
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-02-09 11:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: dev, theo, 61368

On Wed, Feb 8, 2023 at 9:20 PM Theodor Thornhill <theo@thornhill.no> wrote:
>
> Evgeni Kolev <evgenysw@gmail.com> writes:
>
> >
> > 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?

I've never used either of these packages. Is there a consensus which
one is preferred for major modes to use?

>
> 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?
>

Great suggestion! I did a quick research and this seems to already be
implemented in gopls here:
https://github.com/golang/tools/blob/master/gopls/internal/lsp/source/completion/statements.go#L179

To use it you have to enable "usePlaceholders", reference:
https://github.com/golang/tools/blob/master/gopls/doc/settings.md

Do you think it makes sense go-ts-mode to also have its own
implementation? I think it does - similar to how both gopls (eglot)
and tree sitter provide Imenu candidates. I personally use tree
sitter's Imenu (setq eglot-stay-out-of '(imenu)) because I find it
advantageous to avoid the RPC call to an external process.

Also having a tree sitter implementation is more flexible. For
example, I'm planning to have multiple yasnippet snippets for
different scenarios (wrap the error, don't wrap, return a new error,
etc.). The gopls implementation is ridgid - it only works if there's
an "err" variable in scope, and the trigger is one of these three "if
e", "if er" and "if err".

On Wed, Feb 8, 2023 at 6:30 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > 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.
>
> Instead of a command bound to a special key sequences, would it
> perhaps make more sense to add some kind of "electric" behavior to
> "normal" keys?  Like perhaps typing RET after inserting "return" would
> add the "context-aware return statement"?  Then the user could turn on
> the electric behavior with some minor mode, and get this behavior,
> while avoiding the need to dedicate a key sequence.
>
> WDYT?

Makes sense. I am familiar with electric-pair-mode. I see that it adds
a hook in post-self-insert-hook. Is your suggestion to do something
like this:
- add hook in post-self-insert-hook
- in the hook check if RET is typed after an "return"
- if yes, replace the "return" with the "context-aware return
statement", possibly using (yas-expand-snippet)

I'm wondering what customization options would make sense for users -
changing the electric trigger from "return" RET to "ret" RET for
example.

Is there another major mode which can be used as an example for such
electric behavior?





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-09 11:47   ` Evgeni Kolev
@ 2023-02-09 13:39     ` Eli Zaretskii
  2023-02-18 11:46       ` Evgeni Kolev
  0 siblings, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2023-02-09 13:39 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: dev, theo, 61368

> From: Evgeni Kolev <evgenysw@gmail.com>
> Date: Thu, 9 Feb 2023 13:47:01 +0200
> Cc: 61368@debbugs.gnu.org, dev@rjt.dev, theo@thornhill.no
> 
> > Instead of a command bound to a special key sequences, would it
> > perhaps make more sense to add some kind of "electric" behavior to
> > "normal" keys?  Like perhaps typing RET after inserting "return" would
> > add the "context-aware return statement"?  Then the user could turn on
> > the electric behavior with some minor mode, and get this behavior,
> > while avoiding the need to dedicate a key sequence.
> >
> > WDYT?
> 
> Makes sense. I am familiar with electric-pair-mode. I see that it adds
> a hook in post-self-insert-hook. Is your suggestion to do something
> like this:
> - add hook in post-self-insert-hook
> - in the hook check if RET is typed after an "return"
> - if yes, replace the "return" with the "context-aware return
> statement", possibly using (yas-expand-snippet)

Yes, something like that.  See electric.el for more examples.

> I'm wondering what customization options would make sense for users -
> changing the electric trigger from "return" RET to "ret" RET for
> example.
> 
> Is there another major mode which can be used as an example for such
> electric behavior?

Electric modes are usually minor modes that let major modes customize
them by setting variables.  Again, I think you will find examples in
electric.el.





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-09 13:39     ` Eli Zaretskii
@ 2023-02-18 11:46       ` Evgeni Kolev
  2023-02-18 12:14         ` João Távora
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-02-18 11:46 UTC (permalink / raw)
  To: Eli Zaretskii, João Távora; +Cc: dev, theo, 61368

[-- Attachment #1: Type: text/plain, Size: 1931 bytes --]

+ João, author of yasnippet.

Hi, João, I'd appreciate any suggestions you might have. I'm aiming to
extend go-ts-mode with a snippet-like feature. go-ts-mode would be
able to insert a "smart / context-aware" return statement. My question
is - is there a way for major modes to provide yasnippet snippets? My
understanding is the snippets are either created by each user
individually, or distributed as a collection of snippets (e.g.
yasnippet-snippets). Are there any major modes which provide snippets
(I wasn't able to find any in emacs' repo)?

On Thu, Feb 9, 2023 at 3:40 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > Makes sense. I am familiar with electric-pair-mode. I see that it adds
> > a hook in post-self-insert-hook. Is your suggestion to do something
> > like this:
> > - add hook in post-self-insert-hook
> > - in the hook check if RET is typed after an "return"
> > - if yes, replace the "return" with the "context-aware return
> > statement", possibly using (yas-expand-snippet)
>
> Yes, something like that.  See electric.el for more examples.
>
> Electric modes are usually minor modes that let major modes customize
> them by setting variables.  Again, I think you will find examples in
> electric.el.

The attached patch now adds a (go-ts-electric-return-mode) which, when
enabled, replaces "return RET" with a context-aware return statement.
I used sh-script.el's (sh-electric-here-document-mode) as an example.

I'm concerned this electric mode can turn out to be too
aggressive/surprising for the user - "return RET" is a common text to
be entered, I'm not sure the user would always want it to be replaced.
For example, when debugging I might insert return statements all over
the place.

Put differently, I would be more comfortable if there's a distinct
mechanism to trigger the context-aware return, for example with a
trigger key like when a snippet is inserted.

[-- Attachment #2: 0001-Extend-go-ts-mode-with-support-for-pre-filling-retur.patch --]
[-- Type: application/octet-stream, Size: 6340 bytes --]

From 3efaa713ac9fdcb4507e945c2db771f7bb3a1be6 Mon Sep 17 00:00:00 2001
From: Evgeni Kolev <evgenysw@gmail.com>
Date: Mon, 6 Feb 2023 09:49:52 +0200
Subject: [PATCH] Extend go-ts-mode with support for pre-filling return
 statements

Extend go-ts-mode to insert context-aware return statement for the
current function. The return statement is pre-filled with the zero
values of the function's output parameters.

For example, this return statement is added by Emacs:
```
func f() (bool, int, myStruct, *int, chan bool, error) {
    return false, 0, myStruct{}, nil, nil, err
}
```

* lisp/progmodes/go-ts-mode.el (go-ts-mode-error-zero-value): New
defcustom. (go-ts-mode-insert-return, go-ts-mode-return,
go-ts-mode--function-return-types, go-ts-mode--function-at-point,
go-ts-mode--types-from-param-declaration, go-ts-mode--zero-value) New
functions.
---
 lisp/progmodes/go-ts-mode.el | 103 +++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index 2a2783f45f6..0a163753f29 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -46,6 +46,15 @@ go-ts-mode-indent-offset
   :safe 'integerp
   :group 'go)
 
+(defcustom go-ts-mode-error-zero-value  "err"
+  "The zero value for type \"error\".
+The default is \"err\", assuming there's a varialbe named \"err\" in
+the current scope."
+  :version "30"
+  :type 'string
+  :options '("err", "fmt.Errorf(\"format: %w\", err)", "errors.Wrap(err, \"format\")")
+  :group 'go)
+
 (defvar go-ts-mode--syntax-table
   (let ((table (make-syntax-table)))
     (modify-syntax-entry ?+   "."      table)
@@ -328,6 +337,100 @@ go-ts-mode--comment-on-previous-line-p
      (<= (treesit-node-start node) point (treesit-node-end node))
      (string-equal "comment" (treesit-node-type node)))))
 
+(define-minor-mode go-ts-electric-return-mode
+  "Make `return RET' insert a return statement with zero values."
+  :lighter nil
+  (if go-ts-electric-return-mode
+      (add-hook 'post-self-insert-hook #'go-ts-mode--maybe-insert-return nil t)
+    (remove-hook 'post-self-insert-hook #'go-ts-mode--maybe-insert-return t)))
+
+(defun go-ts-mode--maybe-insert-return ()
+  "If RET is entered after `return', add zero values."
+  (when (and (equal (this-command-keys) (kbd "RET"))
+             (looking-back (rx word-boundary "return" "\n" (* space)) (pos-bol 0)))
+    (delete-region (point) (pos-eol 0)) ;; delete the line added by RET
+    (delete-char (- (length "return")))
+    (insert (go-ts-mode-return))))
+
+(defun go-ts-mode-return()
+  "Return a return statement with zero values for function at point.
+It's an error to call this function outside of a function body."
+  (interactive)
+  (let* ((func-node (go-ts-mode--function-at-point))
+         (body-node (treesit-node-child-by-field-name func-node "body")))
+
+    (unless (and body-node (< (treesit-node-start body-node) (point) (treesit-node-end body-node)))
+      (user-error "Point must be inside a Go function body"))
+
+    (let* ((types (go-ts-mode--function-return-types func-node))
+           (zero-values (mapcar 'go-ts-mode--zero-value types))
+           (return-statement (format "return %s" (string-join zero-values ", "))))
+      (string-trim-right return-statement))))
+
+(defun go-ts-mode--function-at-point ()
+  "Return the treesit function node at point.
+Function, methods and closures (anonymous functions) are recognized.
+If point is not in a recognized function, nil is returned."
+  (interactive)
+  (treesit-parent-until
+   (treesit-node-at (point))
+   (lambda (x)
+     (member (treesit-node-type x)
+             '("func_literal" "function_declaration" "method_declaration"))) t))
+
+(defun go-ts-mode--function-return-types (func-node)
+  "Return the types of the output variables of FUNC-NODE.
+The result is a list which could contain a single element (the Go
+function has one return argument), multiple elements (multiple return
+arguments), or no elements (no return arguments)."
+  (let ((result-node (treesit-node-child-by-field-name func-node "result")))
+    (pcase (treesit-node-type result-node)
+      ("parameter_list" ;; multiple return values
+       (let ((types-nested (treesit-induce-sparse-tree result-node "parameter_declaration" #'go-ts-mode--types-from-param-declaration)))
+         (apply #'append (mapcar 'car (cdr types-nested)))))
+      ((pred null) ;; no return value
+       nil)
+      (_ ;; single return value
+       (list (treesit-node-text result-node t))))))
+
+(defun go-ts-mode--types-from-param-declaration (node)
+ "Extract the Go type(s) from NODE.  It must have type parameter_declaration.
+
+A parameter_declaration node can contain single value `(int)', named
+single value `(sum int)', multiples values `(int, int)', or multiple
+named values `(x, y int)'.
+
+All the above cases are recognized.  Only the types are returned, for
+example, with parameter_declaration `(x, y int)', the result is
+\(\"int\", \"int\")."
+  (let ((type (treesit-node-child-by-field-name node "type"))
+        (count (length (treesit-query-capture node "(parameter_declaration name:(_) @name)" nil nil t))))
+    (make-list (if (zerop count) 1 count) (treesit-node-text type t))))
+
+(defun go-ts-mode--zero-value (go-type)
+  "Return the Go zero value for GO-TYPE.
+For type \"error\", the zero value is determined by variable
+`go-ts-mode-error-zero-value'.
+
+This function assumes arbitrary types are Go structs, for example for
+GO-TYPE \"person\", the retun value is \"person{}\"."
+  (pcase go-type
+    ((or "int"  "int8"  "int16"  "int32"  "int64") "0")
+    ((or "uint" "uint8" "uint16" "uint32" "uint64") "0")
+    ("bool" "false")
+    ("string" "\"\"")
+    ((or "uintptr" "byte" "rune") "0")
+    ((or "float32" "float64") "0.0")
+    ((or "complex64" "complex128") "complex(0, 0)")
+    ((pred (string-prefix-p "map")) "nil")
+    ((pred (string-prefix-p "*")) "nil")
+    ((pred (string-prefix-p "[]")) "nil")
+    ((pred (string-prefix-p "chan")) "nil")
+    ((pred (string-prefix-p "func")) "nil")
+    ("error" go-ts-mode-error-zero-value)
+    ((rx bol (1+ (or alphanumeric "_" ".")) eol) (concat go-type "{}"))
+    (_ (user-error "Unknown Go type \"%s\"" go-type))))
+
 ;; go.mod support.
 
 (defvar go-mod-ts-mode--syntax-table
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-18 11:46       ` Evgeni Kolev
@ 2023-02-18 12:14         ` João Távora
  2023-02-20  8:54           ` Evgeni Kolev
  0 siblings, 1 reply; 14+ messages in thread
From: João Távora @ 2023-02-18 12:14 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: Randy Taylor, Eli Zaretskii, Theodor Thornhill, 61368

[-- Attachment #1: Type: text/plain, Size: 1465 bytes --]

On Sat, Feb 18, 2023, 11:46 Evgeni Kolev <evgenysw@gmail.com> wrote:

> + João, author of yasnippet.
>
> Hi, João, I'd appreciate any suggestions you might have. I'm aiming to
> extend go-ts-mode with a snippet-like feature. go-ts-mode would be
> able to insert a "smart / context-aware" return statement. My question
> is - is there a way for major modes to provide yasnippet snippets? My
> understanding is the snippets are either created by each user
> individually, or distributed as a collection of snippets (e.g.
> yasnippet-snippets).


Snippets can be distributed as files, but that's not a very good way as I
see it today. One of the  reasons might be too leverage the TAB and menu
expansion of the yasnippet system. But probably you don't want this, and
snippets can also be defined programmatically, albeit not with a beautiful
language.

Are there any major modes which provide snippets
> (I wasn't able to find any in emacs' repo)?
>

That's because yasnippet is not part of the Emacs repo proper, i.e. the
"core". So adding snippets to major modes in the core would introduce into
the core a dependency on an non-core ELPA package.

Nevertheless, there are ways to conditionally provide functionality based
on whether the non-core package is detected.  A soft dependency. In my
opinion it makes sense for popular non-core packages: company,
markdown-mode, yasnippet, etc. Look at Eglot, for example.

João

João

[-- Attachment #2: Type: text/html, Size: 2199 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-18 12:14         ` João Távora
@ 2023-02-20  8:54           ` Evgeni Kolev
  2023-02-20 12:55             ` Eli Zaretskii
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-02-20  8:54 UTC (permalink / raw)
  To: João Távora, Eli Zaretskii
  Cc: Randy Taylor, Theodor Thornhill, 61368

Thank you João for the input! I think something like this would make
sense in go-ts-mode.el:
```
(with-eval-after-load 'yasnippet
  (yas-define-snippets 'go-ts-mode
                       '(("return" (yas-expand-snippet
                                    (go-ts-mode-return)))
                         ("iferr" (yas-expand-snippet
                                   (format "if err != nil {\n%s\n}"
                                           (go-ts-mode-return)))))))
```

A custom variable go-ts-mode-want-yasnippet could be added to
optionally prevent adding the snippets.

Eli, would you consider something like the code above acceptable as an
alternative to an electric "return" mode?

Having optional yasnippet integration was also brought up by Theo in
this message[1] and this one [2].

[1]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#11
[2]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#17





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-20  8:54           ` Evgeni Kolev
@ 2023-02-20 12:55             ` Eli Zaretskii
  2023-02-22 14:36               ` Evgeni Kolev
  0 siblings, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2023-02-20 12:55 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: dev, theo, joaotavora, 61368

> From: Evgeni Kolev <evgenysw@gmail.com>
> Date: Mon, 20 Feb 2023 10:54:06 +0200
> Cc: 61368@debbugs.gnu.org, Randy Taylor <dev@rjt.dev>, 
> 	Theodor Thornhill <theo@thornhill.no>
> 
> Thank you João for the input! I think something like this would make
> sense in go-ts-mode.el:
> ```
> (with-eval-after-load 'yasnippet
>   (yas-define-snippets 'go-ts-mode
>                        '(("return" (yas-expand-snippet
>                                     (go-ts-mode-return)))
>                          ("iferr" (yas-expand-snippet
>                                    (format "if err != nil {\n%s\n}"
>                                            (go-ts-mode-return)))))))
> ```
> 
> A custom variable go-ts-mode-want-yasnippet could be added to
> optionally prevent adding the snippets.
> 
> Eli, would you consider something like the code above acceptable as an
> alternative to an electric "return" mode?
> 
> Having optional yasnippet integration was also brought up by Theo in
> this message[1] and this one [2].
> 
> [1]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#11
> [2]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60805#17

IMO, if we are going to support yasnippet, we should do it in more
than just one mode.  So a short addition to just the go-ts-mode will
not do, and if we want to include stuff like that, it should be part
of a larger patch for Emacs 30.  Whether this is a good alternative
for some electricity is also a good topic for discussion: electric is
part of Emacs whereas yasnippet isn't, so there are advantages and
disadvantages to this proposal.

Thanks.





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-20 12:55             ` Eli Zaretskii
@ 2023-02-22 14:36               ` Evgeni Kolev
  2024-01-10 22:43                 ` Stefan Kangas
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-02-22 14:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: dev, theo, joaotavora, 61368

Thank you, makes sense. I'll think about the different options and
come up with a proposal.





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2023-02-22 14:36               ` Evgeni Kolev
@ 2024-01-10 22:43                 ` Stefan Kangas
  2024-01-15  8:21                   ` Evgeni Kolev
  0 siblings, 1 reply; 14+ messages in thread
From: Stefan Kangas @ 2024-01-10 22:43 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: dev, Eli Zaretskii, theo, joaotavora, 61368

Evgeni Kolev <evgenysw@gmail.com> writes:

> Thank you, makes sense. I'll think about the different options and
> come up with a proposal.

Did you make any progress here?





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2024-01-10 22:43                 ` Stefan Kangas
@ 2024-01-15  8:21                   ` Evgeni Kolev
  2024-01-15  8:39                     ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2024-01-15  8:21 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: dev, Eli Zaretskii, theo, joaotavora, 61368

On Thu, Jan 11, 2024 at 12:43 AM Stefan Kangas <stefankangas@gmail.com> wrote:
>
> Evgeni Kolev <evgenysw@gmail.com> writes:
>
> > Thank you, makes sense. I'll think about the different options and
> > come up with a proposal.
>
> Did you make any progress here?

I have since come across tempo.el and reviewed its use in org-tempo.el.

While tempo.el is a valid option, I still think yasnippet is a better approach.
However, yasnippet is still not used throughout emacs' core (other
than "light" uses
in eglot.el and python.el, and some faces in the themes).

Please let me know in case a generic mechanism for adding snippets to major
modes has been added - I might have missed it.





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2024-01-15  8:21                   ` Evgeni Kolev
@ 2024-01-15  8:39                     ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-15 11:40                       ` João Távora
  0 siblings, 1 reply; 14+ messages in thread
From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-15  8:39 UTC (permalink / raw)
  To: Evgeni Kolev, Stefan Kangas; +Cc: dev, Eli Zaretskii, joaotavora, 61368

Evgeni Kolev <evgenysw@gmail.com> writes:

> On Thu, Jan 11, 2024 at 12:43 AM Stefan Kangas <stefankangas@gmail.com> wrote:
>>
>> Evgeni Kolev <evgenysw@gmail.com> writes:
>>
>> > Thank you, makes sense. I'll think about the different options and
>> > come up with a proposal.
>>
>> Did you make any progress here?
>
> I have since come across tempo.el and reviewed its use in org-tempo.el.
>
> While tempo.el is a valid option, I still think yasnippet is a better approach.
> However, yasnippet is still not used throughout emacs' core (other
> than "light" uses
> in eglot.el and python.el, and some faces in the themes).
>
> Please let me know in case a generic mechanism for adding snippets to major
> modes has been added - I might have missed it.

Perhaps it's time to revisit the snippet.el that Joao has mentioned?

Theo





^ permalink raw reply	[flat|nested] 14+ messages in thread

* bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements
  2024-01-15  8:39                     ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-01-15 11:40                       ` João Távora
  0 siblings, 0 replies; 14+ messages in thread
From: João Távora @ 2024-01-15 11:40 UTC (permalink / raw)
  To: Theodor Thornhill; +Cc: Evgeni Kolev, Eli Zaretskii, 61368, Stefan Kangas, dev

On Mon, Jan 15, 2024 at 8:39 AM Theodor Thornhill <theo@thornhill.no> wrote:
>
> Evgeni Kolev <evgenysw@gmail.com> writes:
>
> > On Thu, Jan 11, 2024 at 12:43 AM Stefan Kangas <stefankangas@gmail.com> wrote:
> >>
> >> Evgeni Kolev <evgenysw@gmail.com> writes:
> >>
> >> > Thank you, makes sense. I'll think about the different options and
> >> > come up with a proposal.
> >>
> >> Did you make any progress here?
> >
> > I have since come across tempo.el and reviewed its use in org-tempo.el.
> >
> > While tempo.el is a valid option, I still think yasnippet is a better approach.
> > However, yasnippet is still not used throughout emacs' core (other
> > than "light" uses
> > in eglot.el and python.el, and some faces in the themes).
> >
> > Please let me know in case a generic mechanism for adding snippets to major
> > modes has been added - I might have missed it.
>
> Perhaps it's time to revisit the snippet.el that Joao has mentioned?

I've cleaned it up very minimally and put the most recent version here

https://github.com/joaotavora/snippet

It has unit tests which you can run with

/path/to/emacs -Q --batch -l snippet-tests.el -f ert-run-tests-batch-and-exit

Not many docs docs, some docstrings, many TODOs.  Have a look.





^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2024-01-15 11:40 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-08 15:27 bug#61368: [PATCH] Extend go-ts-mode with support for pre-filling return statements Evgeni Kolev
2023-02-08 16:30 ` Eli Zaretskii
2023-02-09 11:47   ` Evgeni Kolev
2023-02-09 13:39     ` Eli Zaretskii
2023-02-18 11:46       ` Evgeni Kolev
2023-02-18 12:14         ` João Távora
2023-02-20  8:54           ` Evgeni Kolev
2023-02-20 12:55             ` Eli Zaretskii
2023-02-22 14:36               ` Evgeni Kolev
2024-01-10 22:43                 ` Stefan Kangas
2024-01-15  8:21                   ` Evgeni Kolev
2024-01-15  8:39                     ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-15 11:40                       ` João Távora
2023-02-08 19:20 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).