From fd403a5c5a87adb8cf42f82c9c0cea4e029767d6 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Thu, 15 Dec 2022 03:21:14 +0200 Subject: [PATCH] Fix ruby-add-log-current-method after nested class definition * lisp/progmodes/ruby-mode.el (ruby--add-log-current-indent): New function. (ruby-add-log-current-method): Use it. Check for "class" and "module" indentation to filter out the definitions which don't include the given position. Also try to match "def" only once (for performance), because if the closest one doesn't include the given position, none will. * test/lisp/progmodes/ruby-mode-tests.el (ruby-add-log-current-method-after-inner-class-outside-methods) (ruby-add-log-current-method-after-inner-class-outside-methods-with-text): New tests. --- lisp/progmodes/ruby-mode.el | 38 +++++++++++++++++++++----- test/lisp/progmodes/ruby-mode-tests.el | 27 ++++++++++++++++++ 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 17467b55549..4ac289d529f 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -1611,7 +1611,8 @@ For example: See `add-log-current-defun-function'." (condition-case nil (save-excursion - (let* ((indent 0) mname mlist + (let* ((indent (ruby--add-log-current-indent)) + mname mlist (start (point)) (make-definition-re (lambda (re &optional method-name?) @@ -1626,18 +1627,30 @@ See `add-log-current-defun-function'." (definition-re (funcall make-definition-re ruby-defun-beg-re t)) (module-re (funcall make-definition-re "\\(class\\|module\\)"))) ;; Get the current method definition (or class/module). - (when (re-search-backward definition-re nil t) + (when (catch 'found + (while (and (re-search-backward definition-re nil t) + (if (if (string-equal "def" (match-string 1)) + ;; We're inside a method. + (if (ruby-block-contains-point start) + t + ;; Try to match a method only once. + (setq definition-re module-re) + nil) + ;; Class/module. For performance, + ;; comparing indentation. + (or (not (numberp indent)) + (> indent (current-indentation)))) + (throw 'found t) + t)))) (goto-char (match-beginning 1)) (if (not (string-equal "def" (match-string 1))) (setq mlist (list (match-string 2))) - ;; We're inside the method. For classes and modules, - ;; this check is skipped for performance. - (when (ruby-block-contains-point start) - (setq mname (match-string 2)))) + (setq mname (match-string 2))) (setq indent (current-column)) (beginning-of-line)) ;; Walk up the class/module nesting. - (while (and (> indent 0) + (while (and indent + (> indent 0) (re-search-backward module-re nil t)) (goto-char (match-beginning 1)) (when (< (current-column) indent) @@ -1691,6 +1704,17 @@ See `add-log-current-defun-function'." (ruby-forward-sexp)) (> (point) pt)))) +(defun ruby--add-log-current-indent () + (save-excursion + (back-to-indentation) + (cond + ((looking-at "[[:graph:]]") + (current-indentation)) + (ruby-use-smie + (smie-indent-calculate)) + (t + (ruby-calculate-indent))))) + (defun ruby-brace-to-do-end (orig end) (let (beg-marker end-marker) (goto-char end) diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el index 33fded5a59b..e90a9e40753 100644 --- a/test/lisp/progmodes/ruby-mode-tests.el +++ b/test/lisp/progmodes/ruby-mode-tests.el @@ -578,6 +578,33 @@ VALUES-PLIST is a list with alternating index and value elements." (search-backward "_") (should (string= (ruby-add-log-current-method) "M::C#foo")))) +(ert-deftest ruby-add-log-current-method-after-inner-class-outside-methods () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | class D + | end + | + |_ + | end + |end") + (search-backward "_") + (delete-char 1) + (should (string= (ruby-add-log-current-method) "M::C")))) + +(ert-deftest ruby-add-log-current-method-after-inner-class-outside-methods-with-text () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | class D + | end + | + | FOO = 5 + | end + |end") + (search-backward "FOO") + (should (string= (ruby-add-log-current-method) "M::C")))) + (defvar ruby-block-test-example (ruby-test-string "class C