emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

emacs-29 cbef1422fe3: ruby-ts-mode: Fix/simplify Imenu index generation


From: Dmitry Gutov
Subject: emacs-29 cbef1422fe3: ruby-ts-mode: Fix/simplify Imenu index generation
Date: Sun, 26 Mar 2023 20:49:34 -0400 (EDT)

branch: emacs-29
commit cbef1422fe3ba5d3327835f3952a0f42f7881716
Author: Dmitry Gutov <dgutov@yandex.ru>
Commit: Dmitry Gutov <dgutov@yandex.ru>

    ruby-ts-mode: Fix/simplify Imenu index generation
    
    * lisp/progmodes/ruby-ts-mode.el (ruby-ts--full-name): Drop '#'
    from the end of resulting string when the node is not a method.
    Support 'singleton_method' nodes.
    (ruby-ts--imenu-helper): Simplify, to create a "flat" list of
    entries, rather than a nested one.  The previous implementation
    had problems (like producing a nested structure of full-qualified
    names, thus creating a lot of textual repetition), seems easier to
    just follow ruby-mode's example here, at least for Emacs 29's
    release.
    
    * test/lisp/progmodes/ruby-ts-mode-tests.el (ruby-ts-imenu-index):
    New test.
---
 lisp/progmodes/ruby-ts-mode.el            | 46 +++++++++++++++----------------
 test/lisp/progmodes/ruby-ts-mode-tests.el | 25 +++++++++++++++++
 2 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index 0915c29881d..91d65a2777b 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -883,32 +883,24 @@ a statement container is a node that matches
   "Return the fully qualified name of NODE."
   (let* ((name (ruby-ts--get-name node))
          (delimiter "#"))
+    (when (equal (treesit-node-type node) "singleton_method")
+      (setq delimiter "."
+            name (treesit-node-text (treesit-node-child-by-field-name node 
"name"))))
     (while (setq node (treesit-parent-until node #'ruby-ts--class-or-module-p))
-      (setq name (concat (ruby-ts--get-name node) delimiter name))
+      (if name
+          (setq name (concat (ruby-ts--get-name node) delimiter name))
+        (setq name (ruby-ts--get-name node)))
       (setq delimiter "::"))
     name))
 
-(defun ruby-ts--imenu-helper (node)
-  "Convert a treesit sparse tree NODE in an imenu list.
-Helper for `ruby-ts--imenu' which converts a treesit sparse
-NODE into a list of imenu ( name . pos ) nodes"
-  (let* ((ts-node (car node))
-         (subtrees (mapcan #'ruby-ts--imenu-helper (cdr node)))
-         (name (when ts-node
-                 (ruby-ts--full-name ts-node)))
-         (marker (when ts-node
-                   (set-marker (make-marker)
-                               (treesit-node-start ts-node)))))
-    (cond
-     ((or (null ts-node) (null name)) subtrees)
-     ;; Don't include the anonymous "class" and "module" nodes
-     ((string-match-p "(\"\\(class\\|module\\)\")"
-                      (treesit-node-string ts-node))
-      nil)
-     (subtrees
-      `((,name ,(cons name marker) ,@subtrees)))
-     (t
-      `((,name . ,marker))))))
+(defun ruby-ts--imenu-helper (tree)
+  "Convert a treesit sparse tree NODE in a flat imenu list."
+  (if (cdr tree)
+      ;; We only use the "leaf" values in the tree.  It does include a
+      ;; leaf node for every class or module body.
+      (cl-mapcan #'ruby-ts--imenu-helper (cdr tree))
+    (list (cons (ruby-ts--full-name (car tree))
+                (treesit-node-start (car tree))))))
 
 ;; For now, this is going to work like ruby-mode and return a list of
 ;; class, modules, def (methods), and alias.  It is likely that this
@@ -916,8 +908,14 @@ NODE into a list of imenu ( name . pos ) nodes"
 (defun ruby-ts--imenu ()
   "Return Imenu alist for the current buffer."
   (let* ((root (treesit-buffer-root-node))
-         (nodes (treesit-induce-sparse-tree root 
"^\\(method\\|alias\\|class\\|module\\)$")))
-    (ruby-ts--imenu-helper nodes)))
+         (tree (treesit-induce-sparse-tree root
+                                           (rx bol (or "singleton_method"
+                                                       "method"
+                                                       "alias"
+                                                       "class"
+                                                       "module")
+                                               eol))))
+    (ruby-ts--imenu-helper tree)))
 
 (defun ruby-ts--arrow-up-start (arg)
   "Move to the start ARG levels up or out."
diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el 
b/test/lisp/progmodes/ruby-ts-mode-tests.el
index e0d9f1b5c50..11125dc5cd3 100644
--- a/test/lisp/progmodes/ruby-ts-mode-tests.el
+++ b/test/lisp/progmodes/ruby-ts-mode-tests.el
@@ -281,6 +281,31 @@ The whitespace before and including \"|\" on each line is 
removed."
        (file-truename
         (expand-file-name (format "ruby-mode-resources/%s" ,file))))))
 
+(ert-deftest ruby-ts-imenu-index ()
+  (ruby-ts-with-temp-buffer
+      (ruby-ts-test-string
+       "module Foo
+       |  class Blub
+       |    def hi
+       |      'Hi!'
+       |    end
+       |
+       |    def bye
+       |      'Bye!'
+       |    end
+       |
+       |    private def self.hiding
+       |      'You can't see me'
+       |    end
+       |  end
+       |end")
+    (should (equal (mapcar #'car (ruby-ts--imenu))
+                   '("Foo"
+                     "Foo::Blub"
+                     "Foo::Blub#hi"
+                     "Foo::Blub#bye"
+                     "Foo::Blub.hiding")))))
+
 (defmacro ruby-ts-deftest-indent (file)
   `(ert-deftest ,(intern (format "ruby-ts-indent-test/%s" file)) ()
      ;; :tags '(:expensive-test)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]