diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index d1034d467ab..97c7cf6480c 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -469,7 +469,7 @@ non-nil." (let* (first-call ) (while (and parent (setq first-call (treesit-node-parent parent)) - (string-search "call" (treesit-node-type first-call))) + (equal "call" (treesit-node-type first-call))) (setq parent first-call)) (treesit-node-start (treesit-search-subtree parent "\\." nil t)))) @@ -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/lisp/subr.el b/lisp/subr.el index 99ddd813867..39866dd7acb 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -7114,7 +7114,7 @@ CONDITION is either: - the symbol t, to always match, - the symbol nil, which never matches, - a regular expression, to match a buffer name, -- a predicate function that takes a buffer object and ARG as +- a predicate function that takes BUFFER-OR-NAME and ARG as arguments, and returns non-nil if the buffer matches, - a cons-cell, where the car describes how to interpret the cdr. The car can be one of the following: @@ -7140,8 +7140,8 @@ CONDITION is either: (string-match-p condition (buffer-name buffer))) ((pred functionp) (if (eq 1 (cdr (func-arity condition))) - (funcall condition buffer) - (funcall condition buffer arg))) + (funcall condition buffer-or-name) + (funcall condition buffer-or-name arg))) (`(major-mode . ,mode) (eq (buffer-local-value 'major-mode buffer) diff --git a/lisp/window.el b/lisp/window.el index 08ce8498655..d53136d406b 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -7510,8 +7510,8 @@ Its value takes effect before processing the ACTION argument of If non-nil, this is an alist of elements (CONDITION . ACTION), where: - CONDITION is passed to `buffer-match-p', along with the buffer - that is to be displayed and the ACTION argument of + CONDITION is passed to `buffer-match-p', along with the name of + the buffer that is to be displayed and the ACTION argument of `display-buffer', to check if ACTION should be used. ACTION is a cons cell (FUNCTIONS . ALIST), where FUNCTIONS is an @@ -7568,12 +7568,16 @@ all fail. It should never be set by programs or users. See (defun display-buffer-assq-regexp (buffer-or-name alist action) "Retrieve ALIST entry corresponding to buffer specified by BUFFER-OR-NAME. This returns the cdr of the alist entry ALIST if the entry's -key (its car) and BUFFER-OR-NAME satisfy `buffer-match-p', using -the key as CONDITION argument of `buffer-match-p'. ACTION should -have the form of the action argument passed to `display-buffer'." +key (its car) and the name of the buffer designated by +BUFFER-OR-NAME satisfy `buffer-match-p', using the key as +CONDITION argument of `buffer-match-p'. ACTION should have the +form of the action argument passed to `display-buffer'." (catch 'match (dolist (entry alist) - (when (buffer-match-p (car entry) buffer-or-name action) + (when (buffer-match-p (car entry) (if (stringp buffer-or-name) + buffer-or-name + (buffer-name buffer-or-name)) + action) (throw 'match (cdr entry)))))) (defvar display-buffer--same-window-action 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)