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.
This commit is contained in:
parent
a0d5fba74a
commit
cbef1422fe
2 changed files with 47 additions and 24 deletions
|
@ -883,32 +883,24 @@ a statement container is a node that matches
|
||||||
"Return the fully qualified name of NODE."
|
"Return the fully qualified name of NODE."
|
||||||
(let* ((name (ruby-ts--get-name node))
|
(let* ((name (ruby-ts--get-name node))
|
||||||
(delimiter "#"))
|
(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))
|
(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 "::"))
|
(setq delimiter "::"))
|
||||||
name))
|
name))
|
||||||
|
|
||||||
(defun ruby-ts--imenu-helper (node)
|
(defun ruby-ts--imenu-helper (tree)
|
||||||
"Convert a treesit sparse tree NODE in an imenu list.
|
"Convert a treesit sparse tree NODE in a flat imenu list."
|
||||||
Helper for `ruby-ts--imenu' which converts a treesit sparse
|
(if (cdr tree)
|
||||||
NODE into a list of imenu ( name . pos ) nodes"
|
;; We only use the "leaf" values in the tree. It does include a
|
||||||
(let* ((ts-node (car node))
|
;; leaf node for every class or module body.
|
||||||
(subtrees (mapcan #'ruby-ts--imenu-helper (cdr node)))
|
(cl-mapcan #'ruby-ts--imenu-helper (cdr tree))
|
||||||
(name (when ts-node
|
(list (cons (ruby-ts--full-name (car tree))
|
||||||
(ruby-ts--full-name ts-node)))
|
(treesit-node-start (car tree))))))
|
||||||
(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))))))
|
|
||||||
|
|
||||||
;; For now, this is going to work like ruby-mode and return a list of
|
;; 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
|
;; 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 ()
|
(defun ruby-ts--imenu ()
|
||||||
"Return Imenu alist for the current buffer."
|
"Return Imenu alist for the current buffer."
|
||||||
(let* ((root (treesit-buffer-root-node))
|
(let* ((root (treesit-buffer-root-node))
|
||||||
(nodes (treesit-induce-sparse-tree root "^\\(method\\|alias\\|class\\|module\\)$")))
|
(tree (treesit-induce-sparse-tree root
|
||||||
(ruby-ts--imenu-helper nodes)))
|
(rx bol (or "singleton_method"
|
||||||
|
"method"
|
||||||
|
"alias"
|
||||||
|
"class"
|
||||||
|
"module")
|
||||||
|
eol))))
|
||||||
|
(ruby-ts--imenu-helper tree)))
|
||||||
|
|
||||||
(defun ruby-ts--arrow-up-start (arg)
|
(defun ruby-ts--arrow-up-start (arg)
|
||||||
"Move to the start ARG levels up or out."
|
"Move to the start ARG levels up or out."
|
||||||
|
|
|
@ -281,6 +281,31 @@ The whitespace before and including \"|\" on each line is removed."
|
||||||
(file-truename
|
(file-truename
|
||||||
(expand-file-name (format "ruby-mode-resources/%s" ,file))))))
|
(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)
|
(defmacro ruby-ts-deftest-indent (file)
|
||||||
`(ert-deftest ,(intern (format "ruby-ts-indent-test/%s" file)) ()
|
`(ert-deftest ,(intern (format "ruby-ts-indent-test/%s" file)) ()
|
||||||
;; :tags '(:expensive-test)
|
;; :tags '(:expensive-test)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue