unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
@ 2022-12-29 16:05 Evgeni Kolev
  2023-01-01  9:07 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Evgeni Kolev @ 2022-12-29 16:05 UTC (permalink / raw)
  To: 60407

This patch updates go-ts-mode to use Imenu facility added in
https://git.savannah.gnu.org/cgit/emacs.git/commit/?h=emacs-29&id=b39dc7ab27a696a8607ab859aeff3c71509231f5

The Imenu items are extended to support "Method", in addition to
"Function" and "Type".

The current Imenu approach uses "type_spec" to identify "Type" which
acts as a catch-all for many Go constructs, for example struct and
interface definitions. This catch-all approach is not optimal because
structs and interfaces are put in the same "Type" bucket. In a
follow-up patch I'll try to change the approach and have separate
"Interface" and "Struct" types.

The patch is below.

commit 71ff7b21fe92167313bd1761b68b6e6fd879b09f
Author: Evgeni Kolev <evgenysw@gmail.com>
Date:   Thu Dec 29 17:49:40 2022 +0200

    Update go-ts-mode to use Imenu facility

    go-ts-mode is updated to use the Imenu facility added in commit
    b39dc7ab27a696a8607ab859aeff3c71509231f5.

    The Imenu items are extended to support "Method", in addition to
    "Function" and "Type".

    * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
    Remove functions.
    (go-ts-mode--defun-name): New function.

diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index 124d9b044a2..c6c1c61d9f4 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
    '((ERROR) @font-lock-warning-face))
   "Tree-sitter font-lock settings for `go-ts-mode'.")

-(defun go-ts-mode--imenu ()
-  "Return Imenu alist for the current buffer."
-  (let* ((node (treesit-buffer-root-node))
-         (func-tree (treesit-induce-sparse-tree
-                     node "function_declaration" nil 1000))
-         (type-tree (treesit-induce-sparse-tree
-                     node "type_spec" nil 1000))
-         (func-index (go-ts-mode--imenu-1 func-tree))
-         (type-index (go-ts-mode--imenu-1 type-tree)))
-    (append
-     (when func-index `(("Function" . ,func-index)))
-     (when type-index `(("Type" . ,type-index))))))
-
-(defun go-ts-mode--imenu-1 (node)
-  "Helper for `go-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
-  (let* ((ts-node (car node))
-         (children (cdr node))
-         (subtrees (mapcan #'go-ts-mode--imenu-1
-                           children))
-         (name (when ts-node
-                 (treesit-node-text
-                  (pcase (treesit-node-type ts-node)
-                    ("function_declaration"
-                     (treesit-node-child-by-field-name ts-node "name"))
-                    ("type_spec"
-                     (treesit-node-child-by-field-name ts-node "name"))))))
-         (marker (when ts-node
-                   (set-marker (make-marker)
-                               (treesit-node-start ts-node)))))
-    (cond
-     ((or (null ts-node) (null name)) subtrees)
-     (subtrees
-      `((,name ,(cons name marker) ,@subtrees)))
-     (t
-      `((,name . ,marker))))))
-
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))

@@ -228,9 +190,18 @@ go-ts-mode
     (setq-local comment-end "")
     (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))

+    ;; Navigation.
+    (setq-local treesit-defun-type-regexp
+                (regexp-opt '("method_declaration"
+                              "function_declaration"
+                              "type_spec")))
+    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
+
     ;; Imenu.
-    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
-    (setq-local which-func-functions nil)
+    (setq-local treesit-simple-imenu-settings
+                `(("Function" "\\`function_declaration\\'" nil nil)
+                  ("Type" "\\`type_spec\\'" nil nil)
+                  ("Method" "\\`method_declaration\\'" nil nil)))

     ;; Indent.
     (setq-local indent-tabs-mode t
@@ -247,6 +218,18 @@ go-ts-mode

     (treesit-major-mode-setup)))

+(defun go-ts-mode--defun-name (node)
+  "Return the defun name of NODE.
+Return nil if there is no name or if NODE is not a defun node."
+  (pcase (treesit-node-type node)
+    ((or "function_declaration"
+         "method_declaration"
+         "type_spec")
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       node "name")
+      t))))
+
 ;; go.mod support.

 (defvar go-mod-ts-mode--syntax-table





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2022-12-29 16:05 bug#60407: [PATCH] Update go-ts-mode to use Imenu facility Evgeni Kolev
@ 2023-01-01  9:07 ` Eli Zaretskii
  2023-01-01 13:05   ` Evgeni Kolev
  2023-01-01 13:08   ` Randy Taylor
  2023-01-08  0:20 ` Yuan Fu
  2023-01-09  0:35 ` Yuan Fu
  2 siblings, 2 replies; 14+ messages in thread
From: Eli Zaretskii @ 2023-01-01  9:07 UTC (permalink / raw)
  To: Evgeni Kolev, Randy Taylor; +Cc: 60407, Yuan Fu

> From: Evgeni Kolev <evgenysw@gmail.com>
> Date: Thu, 29 Dec 2022 18:05:49 +0200
> 
> This patch updates go-ts-mode to use Imenu facility added in
> https://git.savannah.gnu.org/cgit/emacs.git/commit/?h=emacs-29&id=b39dc7ab27a696a8607ab859aeff3c71509231f5
> 
> The Imenu items are extended to support "Method", in addition to
> "Function" and "Type".
> 
> The current Imenu approach uses "type_spec" to identify "Type" which
> acts as a catch-all for many Go constructs, for example struct and
> interface definitions. This catch-all approach is not optimal because
> structs and interfaces are put in the same "Type" bucket. In a
> follow-up patch I'll try to change the approach and have separate
> "Interface" and "Struct" types.
> 
> The patch is below.

Randy, Yuan, are you looking into this?

> commit 71ff7b21fe92167313bd1761b68b6e6fd879b09f
> Author: Evgeni Kolev <evgenysw@gmail.com>
> Date:   Thu Dec 29 17:49:40 2022 +0200
> 
>     Update go-ts-mode to use Imenu facility
> 
>     go-ts-mode is updated to use the Imenu facility added in commit
>     b39dc7ab27a696a8607ab859aeff3c71509231f5.
> 
>     The Imenu items are extended to support "Method", in addition to
>     "Function" and "Type".
> 
>     * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
>     Remove functions.
>     (go-ts-mode--defun-name): New function.
> 
> diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
> index 124d9b044a2..c6c1c61d9f4 100644
> --- a/lisp/progmodes/go-ts-mode.el
> +++ b/lisp/progmodes/go-ts-mode.el
> @@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
>     '((ERROR) @font-lock-warning-face))
>    "Tree-sitter font-lock settings for `go-ts-mode'.")
> 
> -(defun go-ts-mode--imenu ()
> -  "Return Imenu alist for the current buffer."
> -  (let* ((node (treesit-buffer-root-node))
> -         (func-tree (treesit-induce-sparse-tree
> -                     node "function_declaration" nil 1000))
> -         (type-tree (treesit-induce-sparse-tree
> -                     node "type_spec" nil 1000))
> -         (func-index (go-ts-mode--imenu-1 func-tree))
> -         (type-index (go-ts-mode--imenu-1 type-tree)))
> -    (append
> -     (when func-index `(("Function" . ,func-index)))
> -     (when type-index `(("Type" . ,type-index))))))
> -
> -(defun go-ts-mode--imenu-1 (node)
> -  "Helper for `go-ts-mode--imenu'.
> -Find string representation for NODE and set marker, then recurse
> -the subtrees."
> -  (let* ((ts-node (car node))
> -         (children (cdr node))
> -         (subtrees (mapcan #'go-ts-mode--imenu-1
> -                           children))
> -         (name (when ts-node
> -                 (treesit-node-text
> -                  (pcase (treesit-node-type ts-node)
> -                    ("function_declaration"
> -                     (treesit-node-child-by-field-name ts-node "name"))
> -                    ("type_spec"
> -                     (treesit-node-child-by-field-name ts-node "name"))))))
> -         (marker (when ts-node
> -                   (set-marker (make-marker)
> -                               (treesit-node-start ts-node)))))
> -    (cond
> -     ((or (null ts-node) (null name)) subtrees)
> -     (subtrees
> -      `((,name ,(cons name marker) ,@subtrees)))
> -     (t
> -      `((,name . ,marker))))))
> -
>  ;;;###autoload
>  (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
> 
> @@ -228,9 +190,18 @@ go-ts-mode
>      (setq-local comment-end "")
>      (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
> 
> +    ;; Navigation.
> +    (setq-local treesit-defun-type-regexp
> +                (regexp-opt '("method_declaration"
> +                              "function_declaration"
> +                              "type_spec")))
> +    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
> +
>      ;; Imenu.
> -    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
> -    (setq-local which-func-functions nil)
> +    (setq-local treesit-simple-imenu-settings
> +                `(("Function" "\\`function_declaration\\'" nil nil)
> +                  ("Type" "\\`type_spec\\'" nil nil)
> +                  ("Method" "\\`method_declaration\\'" nil nil)))
> 
>      ;; Indent.
>      (setq-local indent-tabs-mode t
> @@ -247,6 +218,18 @@ go-ts-mode
> 
>      (treesit-major-mode-setup)))
> 
> +(defun go-ts-mode--defun-name (node)
> +  "Return the defun name of NODE.
> +Return nil if there is no name or if NODE is not a defun node."
> +  (pcase (treesit-node-type node)
> +    ((or "function_declaration"
> +         "method_declaration"
> +         "type_spec")
> +     (treesit-node-text
> +      (treesit-node-child-by-field-name
> +       node "name")
> +      t))))
> +
>  ;; go.mod support.
> 
>  (defvar go-mod-ts-mode--syntax-table
> 
> 
> 
> 





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-01  9:07 ` Eli Zaretskii
@ 2023-01-01 13:05   ` Evgeni Kolev
  2023-01-01 17:08     ` Evgeni Kolev
  2023-01-01 13:08   ` Randy Taylor
  1 sibling, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-01-01 13:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Randy Taylor, 60407, Yuan Fu

To illustrate the change, here's a comparison before VS after (VS eglot).

I'm using a sample .go file (at the bottom of this mail).

Before:
     4 candidates:
         Function: measure
         Type: geometry
         Type: rect
         Type: circle

After:
     8 candidates:
         Function: measure
         Type: geometry
         Type: rect
         Type: circle
         Method: area
         Method: perim
         Method: area
         Method: perim

For comparison, here's eglot's Imenu (using Go's gopls language server):
     13 candidates:
         Interface: geometry
         Struct: rect
         Struct: circle
         Field.rect: width
         Field.rect: height
         Field.circle: radius
         Method.geometry: area
         Method.geometry: perim
         Method: (rect).area
         Method: (rect).perim
         Method: (circle).area
         Method: (circle).perim
         Function: measure

Sample .go file:

> type geometry interface {
>     area() float64
>     perim() float64
> }
>
> type rect struct {
>     width, height float64
> }
>
> type circle struct {
>     radius float64
> }
>
> func (r rect) area() float64 {
>     return r.width * r.height
> }
>
> func (r rect) perim() float64 {
>     return 2*r.width + 2*r.height
> }
>
> func (c circle) area() float64 {
>     return math.Pi * c.radius * c.radius
> }
>
> func (c circle) perim() float64 {
>     return 2 * math.Pi * c.radius
> }
>
> func measure(g geometry) {
>     fmt.Println(g)
>     fmt.Println(g.area())
>     fmt.Println(g.perim())
> }

On Sun, Jan 1, 2023 at 11:07 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Evgeni Kolev <evgenysw@gmail.com>
> > Date: Thu, 29 Dec 2022 18:05:49 +0200
> >
> > This patch updates go-ts-mode to use Imenu facility added in
> > https://git.savannah.gnu.org/cgit/emacs.git/commit/?h=emacs-29&id=b39dc7ab27a696a8607ab859aeff3c71509231f5
> >
> > The Imenu items are extended to support "Method", in addition to
> > "Function" and "Type".
> >
> > The current Imenu approach uses "type_spec" to identify "Type" which
> > acts as a catch-all for many Go constructs, for example struct and
> > interface definitions. This catch-all approach is not optimal because
> > structs and interfaces are put in the same "Type" bucket. In a
> > follow-up patch I'll try to change the approach and have separate
> > "Interface" and "Struct" types.
> >
> > The patch is below.
>
> Randy, Yuan, are you looking into this?
>
> > commit 71ff7b21fe92167313bd1761b68b6e6fd879b09f
> > Author: Evgeni Kolev <evgenysw@gmail.com>
> > Date:   Thu Dec 29 17:49:40 2022 +0200
> >
> >     Update go-ts-mode to use Imenu facility
> >
> >     go-ts-mode is updated to use the Imenu facility added in commit
> >     b39dc7ab27a696a8607ab859aeff3c71509231f5.
> >
> >     The Imenu items are extended to support "Method", in addition to
> >     "Function" and "Type".
> >
> >     * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
> >     Remove functions.
> >     (go-ts-mode--defun-name): New function.
> >
> > diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
> > index 124d9b044a2..c6c1c61d9f4 100644
> > --- a/lisp/progmodes/go-ts-mode.el
> > +++ b/lisp/progmodes/go-ts-mode.el
> > @@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
> >     '((ERROR) @font-lock-warning-face))
> >    "Tree-sitter font-lock settings for `go-ts-mode'.")
> >
> > -(defun go-ts-mode--imenu ()
> > -  "Return Imenu alist for the current buffer."
> > -  (let* ((node (treesit-buffer-root-node))
> > -         (func-tree (treesit-induce-sparse-tree
> > -                     node "function_declaration" nil 1000))
> > -         (type-tree (treesit-induce-sparse-tree
> > -                     node "type_spec" nil 1000))
> > -         (func-index (go-ts-mode--imenu-1 func-tree))
> > -         (type-index (go-ts-mode--imenu-1 type-tree)))
> > -    (append
> > -     (when func-index `(("Function" . ,func-index)))
> > -     (when type-index `(("Type" . ,type-index))))))
> > -
> > -(defun go-ts-mode--imenu-1 (node)
> > -  "Helper for `go-ts-mode--imenu'.
> > -Find string representation for NODE and set marker, then recurse
> > -the subtrees."
> > -  (let* ((ts-node (car node))
> > -         (children (cdr node))
> > -         (subtrees (mapcan #'go-ts-mode--imenu-1
> > -                           children))
> > -         (name (when ts-node
> > -                 (treesit-node-text
> > -                  (pcase (treesit-node-type ts-node)
> > -                    ("function_declaration"
> > -                     (treesit-node-child-by-field-name ts-node "name"))
> > -                    ("type_spec"
> > -                     (treesit-node-child-by-field-name ts-node "name"))))))
> > -         (marker (when ts-node
> > -                   (set-marker (make-marker)
> > -                               (treesit-node-start ts-node)))))
> > -    (cond
> > -     ((or (null ts-node) (null name)) subtrees)
> > -     (subtrees
> > -      `((,name ,(cons name marker) ,@subtrees)))
> > -     (t
> > -      `((,name . ,marker))))))
> > -
> >  ;;;###autoload
> >  (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
> >
> > @@ -228,9 +190,18 @@ go-ts-mode
> >      (setq-local comment-end "")
> >      (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
> >
> > +    ;; Navigation.
> > +    (setq-local treesit-defun-type-regexp
> > +                (regexp-opt '("method_declaration"
> > +                              "function_declaration"
> > +                              "type_spec")))
> > +    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
> > +
> >      ;; Imenu.
> > -    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
> > -    (setq-local which-func-functions nil)
> > +    (setq-local treesit-simple-imenu-settings
> > +                `(("Function" "\\`function_declaration\\'" nil nil)
> > +                  ("Type" "\\`type_spec\\'" nil nil)
> > +                  ("Method" "\\`method_declaration\\'" nil nil)))
> >
> >      ;; Indent.
> >      (setq-local indent-tabs-mode t
> > @@ -247,6 +218,18 @@ go-ts-mode
> >
> >      (treesit-major-mode-setup)))
> >
> > +(defun go-ts-mode--defun-name (node)
> > +  "Return the defun name of NODE.
> > +Return nil if there is no name or if NODE is not a defun node."
> > +  (pcase (treesit-node-type node)
> > +    ((or "function_declaration"
> > +         "method_declaration"
> > +         "type_spec")
> > +     (treesit-node-text
> > +      (treesit-node-child-by-field-name
> > +       node "name")
> > +      t))))
> > +
> >  ;; go.mod support.
> >
> >  (defvar go-mod-ts-mode--syntax-table
> >
> >
> >
> >





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-01  9:07 ` Eli Zaretskii
  2023-01-01 13:05   ` Evgeni Kolev
@ 2023-01-01 13:08   ` Randy Taylor
  1 sibling, 0 replies; 14+ messages in thread
From: Randy Taylor @ 2023-01-01 13:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Evgeni Kolev, 60407, Yuan Fu

On Sunday, January 1st, 2023 at 04:07, Eli Zaretskii <eliz@gnu.org> wrote:
> 
> > From: Evgeni Kolev evgenysw@gmail.com
> 
> > Date: Thu, 29 Dec 2022 18:05:49 +0200
> > 
> > This patch updates go-ts-mode to use Imenu facility added in
> > https://git.savannah.gnu.org/cgit/emacs.git/commit/?h=emacs-29&id=b39dc7ab27a696a8607ab859aeff3c71509231f5
> > 
> > The Imenu items are extended to support "Method", in addition to
> > "Function" and "Type".
> > 
> > The current Imenu approach uses "type_spec" to identify "Type" which
> > acts as a catch-all for many Go constructs, for example struct and
> > interface definitions. This catch-all approach is not optimal because
> > structs and interfaces are put in the same "Type" bucket. In a
> > follow-up patch I'll try to change the approach and have separate
> > "Interface" and "Struct" types.
> > 
> > The patch is below.
> 
> 
> Randy, Yuan, are you looking into this?

Sorry, been preoccupied recently. It's on my radar and I'll take a look and test it out later today.





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-01 13:05   ` Evgeni Kolev
@ 2023-01-01 17:08     ` Evgeni Kolev
  2023-01-01 22:31       ` Randy Taylor
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-01-01 17:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Randy Taylor, 60407, Yuan Fu

As I mentioned in the start of the mail thread - go-ts-mode's Imenu
puts Go interfaces and structs in the same "Type" bucket. This can be
improved in go-ts-mode.

I'm providing a second patch below which splits the interfaces and
structs into their own Imenu categories.

Please let me know if I should provide the second patch later, in a
separate thread, after the first patch is finished. I'm assuming it's
simpler to review the patches together. If it's not - I'll provide
them in a way to make the review easier, just let me know.

The second patch is below.

commit a5c4a0b25e0385516ad1f8c3444830111d467843
Author: Evgeni Kolev <evgenysw@gmail.com>
Date:   Sun Jan 1 18:57:26 2023 +0200

    Improve go-ts-mode Imenu

    go-ts-mode Imenu is improved to distinguish between Go interfaces and
    structs. Previously both were put in "Type" category. Now each has its
    own category: "Interface" and "Struct" respectively.

    * lisp/progmodes/go-ts-mode.el (go-ts-mode--interface-node-p)
    (go-ts-mode--struct-node-p): New functions.

diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index c6c1c61d9f4..cb8d740727a 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -194,13 +194,14 @@ go-ts-mode
     (setq-local treesit-defun-type-regexp
                 (regexp-opt '("method_declaration"
                               "function_declaration"
-                              "type_spec")))
+                              "type_declaration")))
     (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)

     ;; Imenu.
     (setq-local treesit-simple-imenu-settings
                 `(("Function" "\\`function_declaration\\'" nil nil)
-                  ("Type" "\\`type_spec\\'" nil nil)
+                  ("Interface" "\\`type_declaration\\'"
go-ts-mode--interface-node-p nil)
+                  ("Struct" "\\`type_declaration\\'"
go-ts-mode--struct-node-p nil)
                   ("Method" "\\`method_declaration\\'" nil nil)))

     ;; Indent.
@@ -223,13 +224,30 @@ go-ts-mode--defun-name
 Return nil if there is no name or if NODE is not a defun node."
   (pcase (treesit-node-type node)
     ((or "function_declaration"
-         "method_declaration"
-         "type_spec")
+         "method_declaration")
      (treesit-node-text
       (treesit-node-child-by-field-name
        node "name")
+      t))
+    ((or "type_declaration")
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       (treesit-node-child node 0 t) "name")
       t))))

+(defun go-ts-mode--interface-node-p (node)
+  "Return t if NODE is a Go interface."
+  (string-equal "interface_type"
+                (treesit-node-type
+                 (treesit-node-child-by-field-name
+                  (treesit-node-child node 0 t) "type"))))
+
+(defun go-ts-mode--struct-node-p (node)
+  "Return t if NODE is a Go struct"
+  (string-equal "struct_type" (treesit-node-type
+                               (treesit-node-child-by-field-name
+                                (treesit-node-child node 0 t) "type"))))
+
 ;; go.mod support.

 (defvar go-mod-ts-mode--syntax-table

On Sun, Jan 1, 2023 at 3:05 PM Evgeni Kolev <evgenysw@gmail.com> wrote:
>
> To illustrate the change, here's a comparison before VS after (VS eglot).
>
> I'm using a sample .go file (at the bottom of this mail).
>
> Before:
>      4 candidates:
>          Function: measure
>          Type: geometry
>          Type: rect
>          Type: circle
>
> After:
>      8 candidates:
>          Function: measure
>          Type: geometry
>          Type: rect
>          Type: circle
>          Method: area
>          Method: perim
>          Method: area
>          Method: perim
>
> For comparison, here's eglot's Imenu (using Go's gopls language server):
>      13 candidates:
>          Interface: geometry
>          Struct: rect
>          Struct: circle
>          Field.rect: width
>          Field.rect: height
>          Field.circle: radius
>          Method.geometry: area
>          Method.geometry: perim
>          Method: (rect).area
>          Method: (rect).perim
>          Method: (circle).area
>          Method: (circle).perim
>          Function: measure
>
> Sample .go file:
>
> > type geometry interface {
> >     area() float64
> >     perim() float64
> > }
> >
> > type rect struct {
> >     width, height float64
> > }
> >
> > type circle struct {
> >     radius float64
> > }
> >
> > func (r rect) area() float64 {
> >     return r.width * r.height
> > }
> >
> > func (r rect) perim() float64 {
> >     return 2*r.width + 2*r.height
> > }
> >
> > func (c circle) area() float64 {
> >     return math.Pi * c.radius * c.radius
> > }
> >
> > func (c circle) perim() float64 {
> >     return 2 * math.Pi * c.radius
> > }
> >
> > func measure(g geometry) {
> >     fmt.Println(g)
> >     fmt.Println(g.area())
> >     fmt.Println(g.perim())
> > }
>
> On Sun, Jan 1, 2023 at 11:07 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > > From: Evgeni Kolev <evgenysw@gmail.com>
> > > Date: Thu, 29 Dec 2022 18:05:49 +0200
> > >
> > > This patch updates go-ts-mode to use Imenu facility added in
> > > https://git.savannah.gnu.org/cgit/emacs.git/commit/?h=emacs-29&id=b39dc7ab27a696a8607ab859aeff3c71509231f5
> > >
> > > The Imenu items are extended to support "Method", in addition to
> > > "Function" and "Type".
> > >
> > > The current Imenu approach uses "type_spec" to identify "Type" which
> > > acts as a catch-all for many Go constructs, for example struct and
> > > interface definitions. This catch-all approach is not optimal because
> > > structs and interfaces are put in the same "Type" bucket. In a
> > > follow-up patch I'll try to change the approach and have separate
> > > "Interface" and "Struct" types.
> > >
> > > The patch is below.
> >
> > Randy, Yuan, are you looking into this?
> >
> > > commit 71ff7b21fe92167313bd1761b68b6e6fd879b09f
> > > Author: Evgeni Kolev <evgenysw@gmail.com>
> > > Date:   Thu Dec 29 17:49:40 2022 +0200
> > >
> > >     Update go-ts-mode to use Imenu facility
> > >
> > >     go-ts-mode is updated to use the Imenu facility added in commit
> > >     b39dc7ab27a696a8607ab859aeff3c71509231f5.
> > >
> > >     The Imenu items are extended to support "Method", in addition to
> > >     "Function" and "Type".
> > >
> > >     * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
> > >     Remove functions.
> > >     (go-ts-mode--defun-name): New function.
> > >
> > > diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
> > > index 124d9b044a2..c6c1c61d9f4 100644
> > > --- a/lisp/progmodes/go-ts-mode.el
> > > +++ b/lisp/progmodes/go-ts-mode.el
> > > @@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
> > >     '((ERROR) @font-lock-warning-face))
> > >    "Tree-sitter font-lock settings for `go-ts-mode'.")
> > >
> > > -(defun go-ts-mode--imenu ()
> > > -  "Return Imenu alist for the current buffer."
> > > -  (let* ((node (treesit-buffer-root-node))
> > > -         (func-tree (treesit-induce-sparse-tree
> > > -                     node "function_declaration" nil 1000))
> > > -         (type-tree (treesit-induce-sparse-tree
> > > -                     node "type_spec" nil 1000))
> > > -         (func-index (go-ts-mode--imenu-1 func-tree))
> > > -         (type-index (go-ts-mode--imenu-1 type-tree)))
> > > -    (append
> > > -     (when func-index `(("Function" . ,func-index)))
> > > -     (when type-index `(("Type" . ,type-index))))))
> > > -
> > > -(defun go-ts-mode--imenu-1 (node)
> > > -  "Helper for `go-ts-mode--imenu'.
> > > -Find string representation for NODE and set marker, then recurse
> > > -the subtrees."
> > > -  (let* ((ts-node (car node))
> > > -         (children (cdr node))
> > > -         (subtrees (mapcan #'go-ts-mode--imenu-1
> > > -                           children))
> > > -         (name (when ts-node
> > > -                 (treesit-node-text
> > > -                  (pcase (treesit-node-type ts-node)
> > > -                    ("function_declaration"
> > > -                     (treesit-node-child-by-field-name ts-node "name"))
> > > -                    ("type_spec"
> > > -                     (treesit-node-child-by-field-name ts-node "name"))))))
> > > -         (marker (when ts-node
> > > -                   (set-marker (make-marker)
> > > -                               (treesit-node-start ts-node)))))
> > > -    (cond
> > > -     ((or (null ts-node) (null name)) subtrees)
> > > -     (subtrees
> > > -      `((,name ,(cons name marker) ,@subtrees)))
> > > -     (t
> > > -      `((,name . ,marker))))))
> > > -
> > >  ;;;###autoload
> > >  (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
> > >
> > > @@ -228,9 +190,18 @@ go-ts-mode
> > >      (setq-local comment-end "")
> > >      (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
> > >
> > > +    ;; Navigation.
> > > +    (setq-local treesit-defun-type-regexp
> > > +                (regexp-opt '("method_declaration"
> > > +                              "function_declaration"
> > > +                              "type_spec")))
> > > +    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
> > > +
> > >      ;; Imenu.
> > > -    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
> > > -    (setq-local which-func-functions nil)
> > > +    (setq-local treesit-simple-imenu-settings
> > > +                `(("Function" "\\`function_declaration\\'" nil nil)
> > > +                  ("Type" "\\`type_spec\\'" nil nil)
> > > +                  ("Method" "\\`method_declaration\\'" nil nil)))
> > >
> > >      ;; Indent.
> > >      (setq-local indent-tabs-mode t
> > > @@ -247,6 +218,18 @@ go-ts-mode
> > >
> > >      (treesit-major-mode-setup)))
> > >
> > > +(defun go-ts-mode--defun-name (node)
> > > +  "Return the defun name of NODE.
> > > +Return nil if there is no name or if NODE is not a defun node."
> > > +  (pcase (treesit-node-type node)
> > > +    ((or "function_declaration"
> > > +         "method_declaration"
> > > +         "type_spec")
> > > +     (treesit-node-text
> > > +      (treesit-node-child-by-field-name
> > > +       node "name")
> > > +      t))))
> > > +
> > >  ;; go.mod support.
> > >
> > >  (defvar go-mod-ts-mode--syntax-table
> > >
> > >
> > >
> > >





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-01 17:08     ` Evgeni Kolev
@ 2023-01-01 22:31       ` Randy Taylor
  2023-01-03  9:01         ` Evgeni Kolev
  0 siblings, 1 reply; 14+ messages in thread
From: Randy Taylor @ 2023-01-01 22:31 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: Eli Zaretskii, Yuan Fu, 60407

On Sunday, January 1st, 2023 at 12:08, Evgeni Kolev <evgenysw@gmail.com> wrote:
> 
> As I mentioned in the start of the mail thread - go-ts-mode's Imenu
> puts Go interfaces and structs in the same "Type" bucket. This can be
> improved in go-ts-mode.
> 
> I'm providing a second patch below which splits the interfaces and
> structs into their own Imenu categories.
> 
> Please let me know if I should provide the second patch later, in a
> separate thread, after the first patch is finished. I'm assuming it's
> simpler to review the patches together. If it's not - I'll provide
> them in a way to make the review easier, just let me know.
>

Hi Evgeni!

Thanks for working on this, and apologies for the delay.

The patches look good to me and work well, except for one issue (and a few minor nits) mentioned below. All in one patch is probably best.

- Type definitions are no longer captured. For example:
type Quack int
Does not show up anymore.
- go-ts-mode--struct-node-p's docstring is missing a period at the end.
- In go-ts-mode--interface-node-p and go-ts-mode--struct-node-p's docstrings, I'm not sure it's worthwhile to mention "Go". Just interface and struct should be fine.
- Should the commit message mention changes to go-ts-mode (as in the actual define-derived-mode mode part)?





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-01 22:31       ` Randy Taylor
@ 2023-01-03  9:01         ` Evgeni Kolev
  2023-01-03 14:30           ` Randy Taylor
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-01-03  9:01 UTC (permalink / raw)
  To: Randy Taylor; +Cc: Eli Zaretskii, Yuan Fu, 60407

Hi Randy, thank you for your feedback!

I'm providing an updated patch below. I tested with "type Quack int"
and other cases such as:
    type MyInt = int
    type Option func(s string)
    type List[T any] struct {
        head, tail *element[T]
    }
    type Number interface {
        int64 | float64
    }

After experimenting, I decided to add additional Imenu categories:
"Alias" and "Type".
So the final list of newly added categories is "Method", "Struct",
"Interface", "Alias" and "Type".

Structs and interfaces are technically a private case for "Type", but
are put in their own Imenu category.
Hence the "Type" category now holds all types except structs,
interfaces and aliases (aliases have their own tree sitter type
defined in Go's grammar.js).

For reference, eglot's Imenu uses category "Class" instead of "Type".
But I decided to not replicate this behavior - "Class" is not a widely
used Go concept.
However, I decided to replicate another eglot behaviour - prefixing
the method names with the type of the receiver (for example,
"(rect).area" for "func (r rect) area() float64...").

I've also addressed the other comments. I'm a bit unsure how the git
commit should be formatted - the part of the message which describes
changed functions/files.

Please let me know if the patch can be improved. The patch is below.

commit a96e70052a79881ac666ab699ffd63ed916eaf83
Author: Evgeni Kolev <evgenysw@gmail.com>
Date:   Thu Dec 29 17:49:40 2022 +0200

    Improve go-ts-mode Imenu

    The Imenu items are extended to support "Method", "Struct",
    "Interface", "Alias" and "Type".

    go-ts-mode is updated to use the Imenu facility added in commit
    b39dc7ab27a696a8607ab859aeff3c71509231f5.

    * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
    Remove functions.
    (go-ts-mode--defun-name) (go-ts-mode--interface-node-p)
    (go-ts-mode--struct-node-p) (go-ts-mode--other-type-node-p)
    (go-ts-mode--alias-node-p): New functions.
    (go-ts-mode): Improve Imenu settings.

diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index 1d6a8a30db5..d91b555e03e 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
    '((ERROR) @font-lock-warning-face))
   "Tree-sitter font-lock settings for `go-ts-mode'.")

-(defun go-ts-mode--imenu ()
-  "Return Imenu alist for the current buffer."
-  (let* ((node (treesit-buffer-root-node))
-         (func-tree (treesit-induce-sparse-tree
-                     node "function_declaration" nil 1000))
-         (type-tree (treesit-induce-sparse-tree
-                     node "type_spec" nil 1000))
-         (func-index (go-ts-mode--imenu-1 func-tree))
-         (type-index (go-ts-mode--imenu-1 type-tree)))
-    (append
-     (when func-index `(("Function" . ,func-index)))
-     (when type-index `(("Type" . ,type-index))))))
-
-(defun go-ts-mode--imenu-1 (node)
-  "Helper for `go-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
-  (let* ((ts-node (car node))
-         (children (cdr node))
-         (subtrees (mapcan #'go-ts-mode--imenu-1
-                           children))
-         (name (when ts-node
-                 (treesit-node-text
-                  (pcase (treesit-node-type ts-node)
-                    ("function_declaration"
-                     (treesit-node-child-by-field-name ts-node "name"))
-                    ("type_spec"
-                     (treesit-node-child-by-field-name ts-node "name"))))))
-         (marker (when ts-node
-                   (set-marker (make-marker)
-                               (treesit-node-start ts-node)))))
-    (cond
-     ((or (null ts-node) (null name)) subtrees)
-     (subtrees
-      `((,name ,(cons name marker) ,@subtrees)))
-     (t
-      `((,name . ,marker))))))
-
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))

@@ -228,9 +190,21 @@ go-ts-mode
     (setq-local comment-end "")
     (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))

+    ;; Navigation.
+    (setq-local treesit-defun-type-regexp
+                (regexp-opt '("method_declaration"
+                              "function_declaration"
+                              "type_declaration")))
+    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
+
     ;; Imenu.
-    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
-    (setq-local which-func-functions nil)
+    (setq-local treesit-simple-imenu-settings
+                `(("Function" "\\`function_declaration\\'" nil nil)
+                  ("Method" "\\`method_declaration\\'" nil nil)
+                  ("Struct" "\\`type_declaration\\'"
go-ts-mode--struct-node-p nil)
+                  ("Interface" "\\`type_declaration\\'"
go-ts-mode--interface-node-p nil)
+                  ("Type" "\\`type_declaration\\'"
go-ts-mode--other-type-node-p nil)
+                  ("Alias" "\\`type_declaration\\'"
go-ts-mode--alias-node-p nil)))

     ;; Indent.
     (setq-local indent-tabs-mode t
@@ -247,6 +221,53 @@ go-ts-mode

     (treesit-major-mode-setup)))

+(defun go-ts-mode--defun-name (node)
+  "Return the defun name of NODE.
+Return nil if there is no name or if NODE is not a defun node."
+  (pcase (treesit-node-type node)
+    ("function_declaration"
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       node "name")
+      t))
+    ("method_declaration"
+     (let* ((receiver-node (treesit-node-child-by-field-name node "receiver"))
+            (type-node (treesit-search-subtree receiver-node
"type_identifier"))
+            (name-node (treesit-node-child-by-field-name node "name")))
+       (concat
+        "(" (treesit-node-text type-node) ")."
+        (treesit-node-text name-node))))
+    ("type_declaration"
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       (treesit-node-child node 0 t) "name")
+      t))))
+
+(defun go-ts-mode--interface-node-p (node)
+  "Return t if NODE is an interface."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "interface_type" nil nil 2)))
+
+(defun go-ts-mode--struct-node-p (node)
+  "Return t if NODE is a struct."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "struct_type" nil nil 2)))
+
+(defun go-ts-mode--alias-node-p (node)
+  "Return t if NODE is a type alias."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "type_alias" nil nil 1)))
+
+(defun go-ts-mode--other-type-node-p (node)
+  "Return t if NODE is a type, other than interface or struct."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (not (go-ts-mode--interface-node-p node))
+   (not (go-ts-mode--struct-node-p node))))
+
 ;; go.mod support.

 (defvar go-mod-ts-mode--syntax-table

On Mon, Jan 2, 2023 at 12:31 AM Randy Taylor <dev@rjt.dev> wrote:
>
> On Sunday, January 1st, 2023 at 12:08, Evgeni Kolev <evgenysw@gmail.com> wrote:
> >
> > As I mentioned in the start of the mail thread - go-ts-mode's Imenu
> > puts Go interfaces and structs in the same "Type" bucket. This can be
> > improved in go-ts-mode.
> >
> > I'm providing a second patch below which splits the interfaces and
> > structs into their own Imenu categories.
> >
> > Please let me know if I should provide the second patch later, in a
> > separate thread, after the first patch is finished. I'm assuming it's
> > simpler to review the patches together. If it's not - I'll provide
> > them in a way to make the review easier, just let me know.
> >
>
> Hi Evgeni!
>
> Thanks for working on this, and apologies for the delay.
>
> The patches look good to me and work well, except for one issue (and a few minor nits) mentioned below. All in one patch is probably best.
>
> - Type definitions are no longer captured. For example:
> type Quack int
> Does not show up anymore.
> - go-ts-mode--struct-node-p's docstring is missing a period at the end.
> - In go-ts-mode--interface-node-p and go-ts-mode--struct-node-p's docstrings, I'm not sure it's worthwhile to mention "Go". Just interface and struct should be fine.
> - Should the commit message mention changes to go-ts-mode (as in the actual define-derived-mode mode part)?





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-03  9:01         ` Evgeni Kolev
@ 2023-01-03 14:30           ` Randy Taylor
  2023-01-05  7:24             ` Evgeni Kolev
  0 siblings, 1 reply; 14+ messages in thread
From: Randy Taylor @ 2023-01-03 14:30 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: Eli Zaretskii, Yuan Fu, 60407

On Tuesday, January 3rd, 2023 at 04:01, Evgeni Kolev <evgenysw@gmail.com> wrote:
>
> Hi Randy, thank you for your feedback!
> 
> I'm providing an updated patch below. I tested with "type Quack int"
> and other cases such as:
> type MyInt = int
> type Option func(s string)
> type List[T any] struct {
> head, tail *element[T]
> }
> type Number interface {
> int64 | float64
> }
> 
> After experimenting, I decided to add additional Imenu categories:
> "Alias" and "Type".
> So the final list of newly added categories is "Method", "Struct",
> "Interface", "Alias" and "Type".

Sounds good to me.

It looks like the alias type MyInt = int shows up in both categories: Alias and Type.
It should probably belong just in the Alias category.

> 
> Structs and interfaces are technically a private case for "Type", but
> are put in their own Imenu category.
> Hence the "Type" category now holds all types except structs,
> interfaces and aliases (aliases have their own tree sitter type
> defined in Go's grammar.js).
> 
> For reference, eglot's Imenu uses category "Class" instead of "Type".
> But I decided to not replicate this behavior - "Class" is not a widely
> used Go concept.
> However, I decided to replicate another eglot behaviour - prefixing
> the method names with the type of the receiver (for example,
> "(rect).area" for "func (r rect) area() float64...").

Great! I was going to suggest that but forgot.

> 
> I've also addressed the other comments. I'm a bit unsure how the git
> commit should be formatted - the part of the message which describes
> changed functions/files.
> 
> Please let me know if the patch can be improved. The patch is below.

Comments below.

> 
> commit a96e70052a79881ac666ab699ffd63ed916eaf83
> Author: Evgeni Kolev evgenysw@gmail.com
> 
> Date: Thu Dec 29 17:49:40 2022 +0200
> 
> Improve go-ts-mode Imenu

Maybe this should also say "and add navigation support" (or something similar)?

> 
> The Imenu items are extended to support "Method", "Struct",
> "Interface", "Alias" and "Type".
> 
> go-ts-mode is updated to use the Imenu facility added in commit
> b39dc7ab27a696a8607ab859aeff3c71509231f5.
> 
> * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
> Remove functions.
> (go-ts-mode--defun-name) (go-ts-mode--interface-node-p)

I'm no commit format expert, but I think this can be (go-ts-mode--defun-name, go-ts-mode--interface-node-p)
Whenever it fits on a single line, you can combine them like that. Same for the line below.

> (go-ts-mode--struct-node-p) (go-ts-mode--other-type-node-p)
> (go-ts-mode--alias-node-p): New functions.
> (go-ts-mode): Improve Imenu settings.

I think the (go-ts-mode) part should mention that navigation support was added.

> 
> diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
> index 1d6a8a30db5..d91b555e03e 100644
> --- a/lisp/progmodes/go-ts-mode.el
> +++ b/lisp/progmodes/go-ts-mode.el
> @@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
> '((ERROR) @font-lock-warning-face))
> "Tree-sitter font-lock settings for `go-ts-mode'.") -(defun go-ts-mode--imenu () - "Return Imenu alist for the current buffer." - (let* ((node (treesit-buffer-root-node)) - (func-tree (treesit-induce-sparse-tree - node "function_declaration" nil 1000)) - (type-tree (treesit-induce-sparse-tree - node "type_spec" nil 1000)) - (func-index (go-ts-mode--imenu-1 func-tree)) - (type-index (go-ts-mode--imenu-1 type-tree))) - (append - (when func-index` (("Function" . ,func-index)))
> - (when type-index `(("Type" . ,type-index)))))) - -(defun go-ts-mode--imenu-1 (node) - "Helper for` go-ts-mode--imenu'.
> -Find string representation for NODE and set marker, then recurse
> -the subtrees."
> - (let* ((ts-node (car node))
> - (children (cdr node))
> - (subtrees (mapcan #'go-ts-mode--imenu-1
> - children))
> - (name (when ts-node
> - (treesit-node-text
> - (pcase (treesit-node-type ts-node)
> - ("function_declaration"
> - (treesit-node-child-by-field-name ts-node "name"))
> - ("type_spec"
> - (treesit-node-child-by-field-name ts-node "name"))))))
> - (marker (when ts-node
> - (set-marker (make-marker)
> - (treesit-node-start ts-node)))))
> - (cond
> - ((or (null ts-node) (null name)) subtrees)
> - (subtrees
> - `((,name ,(cons name marker) ,@subtrees))) - (t -` ((,name . ,marker))))))
> -
> ;;;###autoload
> (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
> 
> @@ -228,9 +190,21 @@ go-ts-mode
> (setq-local comment-end "")
> (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
> 
> + ;; Navigation.
> + (setq-local treesit-defun-type-regexp
> + (regexp-opt '("method_declaration"
> + "function_declaration"
> + "type_declaration")))
> + (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
> +
> ;; Imenu.
> - (setq-local imenu-create-index-function #'go-ts-mode--imenu)
> - (setq-local which-func-functions nil)
> + (setq-local treesit-simple-imenu-settings
> + `(("Function" "\\\\`function_declaration\\'" nil nil)
> + ("Method" "\\`method_declaration\\\\'" nil nil) + ("Struct" "\\\\`type_declaration\\'"
> go-ts-mode--struct-node-p nil)
> + ("Interface" "\\`type_declaration\\\\'" go-ts-mode--interface-node-p nil) + ("Type" "\\\\`type_declaration\\'"
> go-ts-mode--other-type-node-p nil)
> + ("Alias" "\\`type_declaration\\'"
> go-ts-mode--alias-node-p nil)))
> 
> ;; Indent.
> (setq-local indent-tabs-mode t
> @@ -247,6 +221,53 @@ go-ts-mode
> 
> (treesit-major-mode-setup)))
> 
> +(defun go-ts-mode--defun-name (node)
> + "Return the defun name of NODE.
> +Return nil if there is no name or if NODE is not a defun node."
> + (pcase (treesit-node-type node)
> + ("function_declaration"
> + (treesit-node-text
> + (treesit-node-child-by-field-name
> + node "name")
> + t))
> + ("method_declaration"
> + (let* ((receiver-node (treesit-node-child-by-field-name node "receiver"))
> + (type-node (treesit-search-subtree receiver-node
> "type_identifier"))
> + (name-node (treesit-node-child-by-field-name node "name")))
> + (concat
> + "(" (treesit-node-text type-node) ")."
> + (treesit-node-text name-node))))
> + ("type_declaration"
> + (treesit-node-text
> + (treesit-node-child-by-field-name
> + (treesit-node-child node 0 t) "name")
> + t))))
> +
> +(defun go-ts-mode--interface-node-p (node)
> + "Return t if NODE is an interface."
> + (and
> + (string-equal "type_declaration" (treesit-node-type node))
> + (treesit-search-subtree node "interface_type" nil nil 2)))

I think you need to add (declare-function treesit-search-subtree "treesit.c") after the last one at the top of the file.

> +
> +(defun go-ts-mode--struct-node-p (node)
> + "Return t if NODE is a struct."
> + (and
> + (string-equal "type_declaration" (treesit-node-type node))
> + (treesit-search-subtree node "struct_type" nil nil 2)))
> +
> +(defun go-ts-mode--alias-node-p (node)
> + "Return t if NODE is a type alias."
> + (and
> + (string-equal "type_declaration" (treesit-node-type node))
> + (treesit-search-subtree node "type_alias" nil nil 1)))
> +
> +(defun go-ts-mode--other-type-node-p (node)
> + "Return t if NODE is a type, other than interface or struct."
> + (and
> + (string-equal "type_declaration" (treesit-node-type node))
> + (not (go-ts-mode--interface-node-p node))
> + (not (go-ts-mode--struct-node-p node))))

Here I guess we just need a (not alias) (and the docstring updated) to fix the issue mentioned above.

> +
> ;; go.mod support.
> 
> (defvar go-mod-ts-mode--syntax-table
>





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-03 14:30           ` Randy Taylor
@ 2023-01-05  7:24             ` Evgeni Kolev
  2023-01-05 14:21               ` Randy Taylor
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-01-05  7:24 UTC (permalink / raw)
  To: Randy Taylor; +Cc: Eli Zaretskii, Yuan Fu, 60407

Hi Randy,

I'm providing the updated patch - I've addressed your comments and
also added Electric Pair mode settings (variable
electric-indent-chars).

Thanks for your feedback. Again, please let me know if the patch can
be improved.

The patch is below.

commit c38df01b088c3fdc0b86340a230b7397b5c81317
Author: Evgeni Kolev <evgenysw@gmail.com>
Date:   Thu Dec 29 17:49:40 2022 +0200

    Improve go-ts-mode Imenu, navigation and electric pair configuration

    The Imenu items are extended to support "Method", "Struct",
    "Interface", "Alias" and "Type".

    go-ts-mode is updated to use the Imenu facility added in commit
    b39dc7ab27a696a8607ab859aeff3c71509231f5.

    Variable electric-indent-chars is set in order to improve integration
    with Electric Pair mode.

    * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
    Remove functions.
    (go-ts-mode--defun-name, go-ts-mode--interface-node-p)
    (go-ts-mode--struct-node-p, go-ts-mode--other-type-node-p)
    (go-ts-mode--alias-node-p): New functions.
    (go-ts-mode): Improve Imenu settings, navigation, add Electric Pair
    mode settings.

diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index 1d6a8a30db5..64e761d2f72 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -36,6 +36,7 @@
 (declare-function treesit-node-child-by-field-name "treesit.c")
 (declare-function treesit-node-start "treesit.c")
 (declare-function treesit-node-type "treesit.c")
+(declare-function treesit-search-subtree "treesit.c")

 (defcustom go-ts-mode-indent-offset 4
   "Number of spaces for each indentation step in `go-ts-mode'."
@@ -173,44 +174,6 @@ go-ts-mode--font-lock-settings
    '((ERROR) @font-lock-warning-face))
   "Tree-sitter font-lock settings for `go-ts-mode'.")

-(defun go-ts-mode--imenu ()
-  "Return Imenu alist for the current buffer."
-  (let* ((node (treesit-buffer-root-node))
-         (func-tree (treesit-induce-sparse-tree
-                     node "function_declaration" nil 1000))
-         (type-tree (treesit-induce-sparse-tree
-                     node "type_spec" nil 1000))
-         (func-index (go-ts-mode--imenu-1 func-tree))
-         (type-index (go-ts-mode--imenu-1 type-tree)))
-    (append
-     (when func-index `(("Function" . ,func-index)))
-     (when type-index `(("Type" . ,type-index))))))
-
-(defun go-ts-mode--imenu-1 (node)
-  "Helper for `go-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
-  (let* ((ts-node (car node))
-         (children (cdr node))
-         (subtrees (mapcan #'go-ts-mode--imenu-1
-                           children))
-         (name (when ts-node
-                 (treesit-node-text
-                  (pcase (treesit-node-type ts-node)
-                    ("function_declaration"
-                     (treesit-node-child-by-field-name ts-node "name"))
-                    ("type_spec"
-                     (treesit-node-child-by-field-name ts-node "name"))))))
-         (marker (when ts-node
-                   (set-marker (make-marker)
-                               (treesit-node-start ts-node)))))
-    (cond
-     ((or (null ts-node) (null name)) subtrees)
-     (subtrees
-      `((,name ,(cons name marker) ,@subtrees)))
-     (t
-      `((,name . ,marker))))))
-
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))

@@ -228,14 +191,30 @@ go-ts-mode
     (setq-local comment-end "")
     (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))

+    ;; Navigation.
+    (setq-local treesit-defun-type-regexp
+                (regexp-opt '("method_declaration"
+                              "function_declaration"
+                              "type_declaration")))
+    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
+
     ;; Imenu.
-    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
-    (setq-local which-func-functions nil)
+    (setq-local treesit-simple-imenu-settings
+                `(("Function" "\\`function_declaration\\'" nil nil)
+                  ("Method" "\\`method_declaration\\'" nil nil)
+                  ("Struct" "\\`type_declaration\\'"
go-ts-mode--struct-node-p nil)
+                  ("Interface" "\\`type_declaration\\'"
go-ts-mode--interface-node-p nil)
+                  ("Type" "\\`type_declaration\\'"
go-ts-mode--other-type-node-p nil)
+                  ("Alias" "\\`type_declaration\\'"
go-ts-mode--alias-node-p nil)))

     ;; Indent.
     (setq-local indent-tabs-mode t
                 treesit-simple-indent-rules go-ts-mode--indent-rules)

+    ;; Electric
+    (setq-local electric-indent-chars
+                (append "{}()" electric-indent-chars))
+
     ;; Font-lock.
     (setq-local treesit-font-lock-settings go-ts-mode--font-lock-settings)
     (setq-local treesit-font-lock-feature-list
@@ -247,6 +226,54 @@ go-ts-mode

     (treesit-major-mode-setup)))

+(defun go-ts-mode--defun-name (node)
+  "Return the defun name of NODE.
+Return nil if there is no name or if NODE is not a defun node."
+  (pcase (treesit-node-type node)
+    ("function_declaration"
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       node "name")
+      t))
+    ("method_declaration"
+     (let* ((receiver-node (treesit-node-child-by-field-name node "receiver"))
+            (type-node (treesit-search-subtree receiver-node
"type_identifier"))
+            (name-node (treesit-node-child-by-field-name node "name")))
+       (concat
+        "(" (treesit-node-text type-node) ")."
+        (treesit-node-text name-node))))
+    ("type_declaration"
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       (treesit-node-child node 0 t) "name")
+      t))))
+
+(defun go-ts-mode--interface-node-p (node)
+  "Return t if NODE is an interface."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "interface_type" nil nil 2)))
+
+(defun go-ts-mode--struct-node-p (node)
+  "Return t if NODE is a struct."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "struct_type" nil nil 2)))
+
+(defun go-ts-mode--alias-node-p (node)
+  "Return t if NODE is a type alias."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "type_alias" nil nil 1)))
+
+(defun go-ts-mode--other-type-node-p (node)
+  "Return t if NODE is a type, other than interface, struct or alias."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (not (go-ts-mode--interface-node-p node))
+   (not (go-ts-mode--struct-node-p node))
+   (not (go-ts-mode--alias-node-p node))))
+
 ;; go.mod support.

 (defvar go-mod-ts-mode--syntax-table

On Tue, Jan 3, 2023 at 4:31 PM Randy Taylor <dev@rjt.dev> wrote:
>
> On Tuesday, January 3rd, 2023 at 04:01, Evgeni Kolev <evgenysw@gmail.com> wrote:
> >
> > Hi Randy, thank you for your feedback!
> >
> > I'm providing an updated patch below. I tested with "type Quack int"
> > and other cases such as:
> > type MyInt = int
> > type Option func(s string)
> > type List[T any] struct {
> > head, tail *element[T]
> > }
> > type Number interface {
> > int64 | float64
> > }
> >
> > After experimenting, I decided to add additional Imenu categories:
> > "Alias" and "Type".
> > So the final list of newly added categories is "Method", "Struct",
> > "Interface", "Alias" and "Type".
>
> Sounds good to me.
>
> It looks like the alias type MyInt = int shows up in both categories: Alias and Type.
> It should probably belong just in the Alias category.
>
> >
> > Structs and interfaces are technically a private case for "Type", but
> > are put in their own Imenu category.
> > Hence the "Type" category now holds all types except structs,
> > interfaces and aliases (aliases have their own tree sitter type
> > defined in Go's grammar.js).
> >
> > For reference, eglot's Imenu uses category "Class" instead of "Type".
> > But I decided to not replicate this behavior - "Class" is not a widely
> > used Go concept.
> > However, I decided to replicate another eglot behaviour - prefixing
> > the method names with the type of the receiver (for example,
> > "(rect).area" for "func (r rect) area() float64...").
>
> Great! I was going to suggest that but forgot.
>
> >
> > I've also addressed the other comments. I'm a bit unsure how the git
> > commit should be formatted - the part of the message which describes
> > changed functions/files.
> >
> > Please let me know if the patch can be improved. The patch is below.
>
> Comments below.
>
> >
> > commit a96e70052a79881ac666ab699ffd63ed916eaf83
> > Author: Evgeni Kolev evgenysw@gmail.com
> >
> > Date: Thu Dec 29 17:49:40 2022 +0200
> >
> > Improve go-ts-mode Imenu
>
> Maybe this should also say "and add navigation support" (or something similar)?
>
> >
> > The Imenu items are extended to support "Method", "Struct",
> > "Interface", "Alias" and "Type".
> >
> > go-ts-mode is updated to use the Imenu facility added in commit
> > b39dc7ab27a696a8607ab859aeff3c71509231f5.
> >
> > * lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
> > Remove functions.
> > (go-ts-mode--defun-name) (go-ts-mode--interface-node-p)
>
> I'm no commit format expert, but I think this can be (go-ts-mode--defun-name, go-ts-mode--interface-node-p)
> Whenever it fits on a single line, you can combine them like that. Same for the line below.
>
> > (go-ts-mode--struct-node-p) (go-ts-mode--other-type-node-p)
> > (go-ts-mode--alias-node-p): New functions.
> > (go-ts-mode): Improve Imenu settings.
>
> I think the (go-ts-mode) part should mention that navigation support was added.
>
> >
> > diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
> > index 1d6a8a30db5..d91b555e03e 100644
> > --- a/lisp/progmodes/go-ts-mode.el
> > +++ b/lisp/progmodes/go-ts-mode.el
> > @@ -173,44 +173,6 @@ go-ts-mode--font-lock-settings
> > '((ERROR) @font-lock-warning-face))
> > "Tree-sitter font-lock settings for `go-ts-mode'.") -(defun go-ts-mode--imenu () - "Return Imenu alist for the current buffer." - (let* ((node (treesit-buffer-root-node)) - (func-tree (treesit-induce-sparse-tree - node "function_declaration" nil 1000)) - (type-tree (treesit-induce-sparse-tree - node "type_spec" nil 1000)) - (func-index (go-ts-mode--imenu-1 func-tree)) - (type-index (go-ts-mode--imenu-1 type-tree))) - (append - (when func-index` (("Function" . ,func-index)))
> > - (when type-index `(("Type" . ,type-index)))))) - -(defun go-ts-mode--imenu-1 (node) - "Helper for` go-ts-mode--imenu'.
> > -Find string representation for NODE and set marker, then recurse
> > -the subtrees."
> > - (let* ((ts-node (car node))
> > - (children (cdr node))
> > - (subtrees (mapcan #'go-ts-mode--imenu-1
> > - children))
> > - (name (when ts-node
> > - (treesit-node-text
> > - (pcase (treesit-node-type ts-node)
> > - ("function_declaration"
> > - (treesit-node-child-by-field-name ts-node "name"))
> > - ("type_spec"
> > - (treesit-node-child-by-field-name ts-node "name"))))))
> > - (marker (when ts-node
> > - (set-marker (make-marker)
> > - (treesit-node-start ts-node)))))
> > - (cond
> > - ((or (null ts-node) (null name)) subtrees)
> > - (subtrees
> > - `((,name ,(cons name marker) ,@subtrees))) - (t -` ((,name . ,marker))))))
> > -
> > ;;;###autoload
> > (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
> >
> > @@ -228,9 +190,21 @@ go-ts-mode
> > (setq-local comment-end "")
> > (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
> >
> > + ;; Navigation.
> > + (setq-local treesit-defun-type-regexp
> > + (regexp-opt '("method_declaration"
> > + "function_declaration"
> > + "type_declaration")))
> > + (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
> > +
> > ;; Imenu.
> > - (setq-local imenu-create-index-function #'go-ts-mode--imenu)
> > - (setq-local which-func-functions nil)
> > + (setq-local treesit-simple-imenu-settings
> > + `(("Function" "\\\\`function_declaration\\'" nil nil)
> > + ("Method" "\\`method_declaration\\\\'" nil nil) + ("Struct" "\\\\`type_declaration\\'"
> > go-ts-mode--struct-node-p nil)
> > + ("Interface" "\\`type_declaration\\\\'" go-ts-mode--interface-node-p nil) + ("Type" "\\\\`type_declaration\\'"
> > go-ts-mode--other-type-node-p nil)
> > + ("Alias" "\\`type_declaration\\'"
> > go-ts-mode--alias-node-p nil)))
> >
> > ;; Indent.
> > (setq-local indent-tabs-mode t
> > @@ -247,6 +221,53 @@ go-ts-mode
> >
> > (treesit-major-mode-setup)))
> >
> > +(defun go-ts-mode--defun-name (node)
> > + "Return the defun name of NODE.
> > +Return nil if there is no name or if NODE is not a defun node."
> > + (pcase (treesit-node-type node)
> > + ("function_declaration"
> > + (treesit-node-text
> > + (treesit-node-child-by-field-name
> > + node "name")
> > + t))
> > + ("method_declaration"
> > + (let* ((receiver-node (treesit-node-child-by-field-name node "receiver"))
> > + (type-node (treesit-search-subtree receiver-node
> > "type_identifier"))
> > + (name-node (treesit-node-child-by-field-name node "name")))
> > + (concat
> > + "(" (treesit-node-text type-node) ")."
> > + (treesit-node-text name-node))))
> > + ("type_declaration"
> > + (treesit-node-text
> > + (treesit-node-child-by-field-name
> > + (treesit-node-child node 0 t) "name")
> > + t))))
> > +
> > +(defun go-ts-mode--interface-node-p (node)
> > + "Return t if NODE is an interface."
> > + (and
> > + (string-equal "type_declaration" (treesit-node-type node))
> > + (treesit-search-subtree node "interface_type" nil nil 2)))
>
> I think you need to add (declare-function treesit-search-subtree "treesit.c") after the last one at the top of the file.
>
> > +
> > +(defun go-ts-mode--struct-node-p (node)
> > + "Return t if NODE is a struct."
> > + (and
> > + (string-equal "type_declaration" (treesit-node-type node))
> > + (treesit-search-subtree node "struct_type" nil nil 2)))
> > +
> > +(defun go-ts-mode--alias-node-p (node)
> > + "Return t if NODE is a type alias."
> > + (and
> > + (string-equal "type_declaration" (treesit-node-type node))
> > + (treesit-search-subtree node "type_alias" nil nil 1)))
> > +
> > +(defun go-ts-mode--other-type-node-p (node)
> > + "Return t if NODE is a type, other than interface or struct."
> > + (and
> > + (string-equal "type_declaration" (treesit-node-type node))
> > + (not (go-ts-mode--interface-node-p node))
> > + (not (go-ts-mode--struct-node-p node))))
>
> Here I guess we just need a (not alias) (and the docstring updated) to fix the issue mentioned above.
>
> > +
> > ;; go.mod support.
> >
> > (defvar go-mod-ts-mode--syntax-table
> >





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-05  7:24             ` Evgeni Kolev
@ 2023-01-05 14:21               ` Randy Taylor
  0 siblings, 0 replies; 14+ messages in thread
From: Randy Taylor @ 2023-01-05 14:21 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: Eli Zaretskii, 60407, Yuan Fu

On Thursday, January 5th, 2023 at 02:24, Evgeni Kolev <evgenysw@gmail.com> wrote: 
> 
> Hi Randy,
> 
> I'm providing the updated patch - I've addressed your comments and
> also added Electric Pair mode settings (variable
> electric-indent-chars).
> 
> Thanks for your feedback. Again, please let me know if the patch can
> be improved.

I can't speak to the electric stuff, but everything else looks good to me!
Thanks for working on this.

Yuan, feel free to apply if it looks good to you.





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2022-12-29 16:05 bug#60407: [PATCH] Update go-ts-mode to use Imenu facility Evgeni Kolev
  2023-01-01  9:07 ` Eli Zaretskii
@ 2023-01-08  0:20 ` Yuan Fu
  2023-01-08  8:10   ` Evgeni Kolev
  2023-01-09  0:35 ` Yuan Fu
  2 siblings, 1 reply; 14+ messages in thread
From: Yuan Fu @ 2023-01-08  0:20 UTC (permalink / raw)
  To: Randy Taylor; +Cc: evgenysw, Eli Zaretskii, 60407


Randy Taylor <dev@rjt.dev> writes:

> On Thursday, January 5th, 2023 at 02:24, Evgeni Kolev <evgenysw@gmail.com> wrote: 
>> 
>> Hi Randy,
>> 
>> I'm providing the updated patch - I've addressed your comments and
>> also added Electric Pair mode settings (variable
>> electric-indent-chars).
>> 
>> Thanks for your feedback. Again, please let me know if the patch can
>> be improved.
>
> I can't speak to the electric stuff, but everything else looks good to me!
> Thanks for working on this.
>
> Yuan, feel free to apply if it looks good to you.

Ok! However, Evgeni, could you resend your patch as a attachment please?
My ad-hoc setup couldn’t apply the inline patch directly :-)

Yuan





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-08  0:20 ` Yuan Fu
@ 2023-01-08  8:10   ` Evgeni Kolev
  2023-01-08 10:59     ` Eli Zaretskii
  0 siblings, 1 reply; 14+ messages in thread
From: Evgeni Kolev @ 2023-01-08  8:10 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Randy Taylor, Eli Zaretskii, 60407

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

Hi Yuan, sure, the .patch is attached.

A side question - does it make sense to extend go-ts-mode with
interactive functions?

For example a function (go-ts-mode-docstring) which adds a docstring
for the current type:
with Go code:
    func sum(a, b int) int {...}
the function would add a comment above the func:
    // sum
    func sum(a, b int) int {...}

This is something I've implemented for myself, I'm wondering if it
makes sense to contribute it to go-ts-mode.

Or should I first discuss this in the devel mail list? Or maybe send
another patch and have the discussion there?


On Sun, Jan 8, 2023 at 2:20 AM Yuan Fu <casouri@gmail.com> wrote:
>
>
> Randy Taylor <dev@rjt.dev> writes:
>
> > On Thursday, January 5th, 2023 at 02:24, Evgeni Kolev <evgenysw@gmail.com> wrote:
> >>
> >> Hi Randy,
> >>
> >> I'm providing the updated patch - I've addressed your comments and
> >> also added Electric Pair mode settings (variable
> >> electric-indent-chars).
> >>
> >> Thanks for your feedback. Again, please let me know if the patch can
> >> be improved.
> >
> > I can't speak to the electric stuff, but everything else looks good to me!
> > Thanks for working on this.
> >
> > Yuan, feel free to apply if it looks good to you.
>
> Ok! However, Evgeni, could you resend your patch as a attachment please?
> My ad-hoc setup couldn’t apply the inline patch directly :-)
>
> Yuan

[-- Attachment #2: 0001-Improve-go-ts-mode-Imenu-navigation-and-electric-pai.patch --]
[-- Type: application/octet-stream, Size: 6671 bytes --]

From dd618f10ec750e363ac2f7c89433dd2f8a647c31 Mon Sep 17 00:00:00 2001
From: Evgeni Kolev <evgenysw@gmail.com>
Date: Thu, 29 Dec 2022 17:49:40 +0200
Subject: [PATCH] Improve go-ts-mode Imenu, navigation and electric pair
 configuration

The Imenu items are extended to support "Method", "Struct",
"Interface", "Alias" and "Type".

go-ts-mode is updated to use the Imenu facility added in commit
b39dc7ab27a696a8607ab859aeff3c71509231f5.

Variable electric-indent-chars is set in order to improve integration
with Electric Pair mode.

* lisp/progmodes/go-ts-mode.el (go-ts-mode--imenu-1) (go-ts-mode--imenu):
Remove functions.
(go-ts-mode--defun-name, go-ts-mode--interface-node-p)
(go-ts-mode--struct-node-p, go-ts-mode--other-type-node-p)
(go-ts-mode--alias-node-p): New functions.
(go-ts-mode): Improve Imenu settings, navigation, add Electric Pair
mode settings.
---
 lisp/progmodes/go-ts-mode.el | 107 ++++++++++++++++++++++-------------
 1 file changed, 67 insertions(+), 40 deletions(-)

diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index 1d6a8a30db5..64e761d2f72 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -36,6 +36,7 @@
 (declare-function treesit-node-child-by-field-name "treesit.c")
 (declare-function treesit-node-start "treesit.c")
 (declare-function treesit-node-type "treesit.c")
+(declare-function treesit-search-subtree "treesit.c")
 
 (defcustom go-ts-mode-indent-offset 4
   "Number of spaces for each indentation step in `go-ts-mode'."
@@ -173,44 +174,6 @@ go-ts-mode--font-lock-settings
    '((ERROR) @font-lock-warning-face))
   "Tree-sitter font-lock settings for `go-ts-mode'.")
 
-(defun go-ts-mode--imenu ()
-  "Return Imenu alist for the current buffer."
-  (let* ((node (treesit-buffer-root-node))
-         (func-tree (treesit-induce-sparse-tree
-                     node "function_declaration" nil 1000))
-         (type-tree (treesit-induce-sparse-tree
-                     node "type_spec" nil 1000))
-         (func-index (go-ts-mode--imenu-1 func-tree))
-         (type-index (go-ts-mode--imenu-1 type-tree)))
-    (append
-     (when func-index `(("Function" . ,func-index)))
-     (when type-index `(("Type" . ,type-index))))))
-
-(defun go-ts-mode--imenu-1 (node)
-  "Helper for `go-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
-  (let* ((ts-node (car node))
-         (children (cdr node))
-         (subtrees (mapcan #'go-ts-mode--imenu-1
-                           children))
-         (name (when ts-node
-                 (treesit-node-text
-                  (pcase (treesit-node-type ts-node)
-                    ("function_declaration"
-                     (treesit-node-child-by-field-name ts-node "name"))
-                    ("type_spec"
-                     (treesit-node-child-by-field-name ts-node "name"))))))
-         (marker (when ts-node
-                   (set-marker (make-marker)
-                               (treesit-node-start ts-node)))))
-    (cond
-     ((or (null ts-node) (null name)) subtrees)
-     (subtrees
-      `((,name ,(cons name marker) ,@subtrees)))
-     (t
-      `((,name . ,marker))))))
-
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
 
@@ -228,14 +191,30 @@ go-ts-mode
     (setq-local comment-end "")
     (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
 
+    ;; Navigation.
+    (setq-local treesit-defun-type-regexp
+                (regexp-opt '("method_declaration"
+                              "function_declaration"
+                              "type_declaration")))
+    (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
+
     ;; Imenu.
-    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
-    (setq-local which-func-functions nil)
+    (setq-local treesit-simple-imenu-settings
+                `(("Function" "\\`function_declaration\\'" nil nil)
+                  ("Method" "\\`method_declaration\\'" nil nil)
+                  ("Struct" "\\`type_declaration\\'" go-ts-mode--struct-node-p nil)
+                  ("Interface" "\\`type_declaration\\'" go-ts-mode--interface-node-p nil)
+                  ("Type" "\\`type_declaration\\'" go-ts-mode--other-type-node-p nil)
+                  ("Alias" "\\`type_declaration\\'" go-ts-mode--alias-node-p nil)))
 
     ;; Indent.
     (setq-local indent-tabs-mode t
                 treesit-simple-indent-rules go-ts-mode--indent-rules)
 
+    ;; Electric
+    (setq-local electric-indent-chars
+                (append "{}()" electric-indent-chars))
+
     ;; Font-lock.
     (setq-local treesit-font-lock-settings go-ts-mode--font-lock-settings)
     (setq-local treesit-font-lock-feature-list
@@ -247,6 +226,54 @@ go-ts-mode
 
     (treesit-major-mode-setup)))
 
+(defun go-ts-mode--defun-name (node)
+  "Return the defun name of NODE.
+Return nil if there is no name or if NODE is not a defun node."
+  (pcase (treesit-node-type node)
+    ("function_declaration"
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       node "name")
+      t))
+    ("method_declaration"
+     (let* ((receiver-node (treesit-node-child-by-field-name node "receiver"))
+            (type-node (treesit-search-subtree receiver-node "type_identifier"))
+            (name-node (treesit-node-child-by-field-name node "name")))
+       (concat
+        "(" (treesit-node-text type-node) ")."
+        (treesit-node-text name-node))))
+    ("type_declaration"
+     (treesit-node-text
+      (treesit-node-child-by-field-name
+       (treesit-node-child node 0 t) "name")
+      t))))
+
+(defun go-ts-mode--interface-node-p (node)
+  "Return t if NODE is an interface."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "interface_type" nil nil 2)))
+
+(defun go-ts-mode--struct-node-p (node)
+  "Return t if NODE is a struct."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "struct_type" nil nil 2)))
+
+(defun go-ts-mode--alias-node-p (node)
+  "Return t if NODE is a type alias."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (treesit-search-subtree node "type_alias" nil nil 1)))
+
+(defun go-ts-mode--other-type-node-p (node)
+  "Return t if NODE is a type, other than interface, struct or alias."
+  (and
+   (string-equal "type_declaration" (treesit-node-type node))
+   (not (go-ts-mode--interface-node-p node))
+   (not (go-ts-mode--struct-node-p node))
+   (not (go-ts-mode--alias-node-p node))))
+
 ;; go.mod support.
 
 (defvar go-mod-ts-mode--syntax-table
-- 
2.30.2


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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2023-01-08  8:10   ` Evgeni Kolev
@ 2023-01-08 10:59     ` Eli Zaretskii
  0 siblings, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2023-01-08 10:59 UTC (permalink / raw)
  To: Evgeni Kolev; +Cc: dev, casouri, 60407

> From: Evgeni Kolev <evgenysw@gmail.com>
> Date: Sun, 8 Jan 2023 10:10:33 +0200
> Cc: Randy Taylor <dev@rjt.dev>, Eli Zaretskii <eliz@gnu.org>, 60407@debbugs.gnu.org
> 
> A side question - does it make sense to extend go-ts-mode with
> interactive functions?
> 
> For example a function (go-ts-mode-docstring) which adds a docstring
> for the current type:
> with Go code:
>     func sum(a, b int) int {...}
> the function would add a comment above the func:
>     // sum
>     func sum(a, b int) int {...}
> 
> This is something I've implemented for myself, I'm wondering if it
> makes sense to contribute it to go-ts-mode.

It makes sense, but it will have to wait until Emacs 30.  The release
branch is frozen, and no new features are accepted.

> Or should I first discuss this in the devel mail list? Or maybe send
> another patch and have the discussion there?

Either one would be good.

Thanks.





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

* bug#60407: [PATCH] Update go-ts-mode to use Imenu facility
  2022-12-29 16:05 bug#60407: [PATCH] Update go-ts-mode to use Imenu facility Evgeni Kolev
  2023-01-01  9:07 ` Eli Zaretskii
  2023-01-08  0:20 ` Yuan Fu
@ 2023-01-09  0:35 ` Yuan Fu
  2 siblings, 0 replies; 14+ messages in thread
From: Yuan Fu @ 2023-01-09  0:35 UTC (permalink / raw)
  To: evgenysw; +Cc: 60407-done


Evgeni Kolev <evgenysw@gmail.com> writes:

> Hi Yuan, sure, the .patch is attached.

Thanks. I applied the patch.

Yuan





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

end of thread, other threads:[~2023-01-09  0:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-29 16:05 bug#60407: [PATCH] Update go-ts-mode to use Imenu facility Evgeni Kolev
2023-01-01  9:07 ` Eli Zaretskii
2023-01-01 13:05   ` Evgeni Kolev
2023-01-01 17:08     ` Evgeni Kolev
2023-01-01 22:31       ` Randy Taylor
2023-01-03  9:01         ` Evgeni Kolev
2023-01-03 14:30           ` Randy Taylor
2023-01-05  7:24             ` Evgeni Kolev
2023-01-05 14:21               ` Randy Taylor
2023-01-01 13:08   ` Randy Taylor
2023-01-08  0:20 ` Yuan Fu
2023-01-08  8:10   ` Evgeni Kolev
2023-01-08 10:59     ` Eli Zaretskii
2023-01-09  0:35 ` Yuan Fu

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).