diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 4ac289d529..295a2a67e9 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -134,6 +134,12 @@ ruby-symbol-chars (defconst ruby-symbol-re (concat "[" ruby-symbol-chars "]") "Regexp to match symbols.") +(defconst ruby-endless-method-head-re + (format " *\\(self\\.\\)?%s+[?!]? *\\(([^()]*)\\)? *=" ruby-symbol-re) + "Regexp to match the beginning of an endless method definition. + +It should match the part after \"def\" and until \"=\".") + (defvar ruby-use-smie t) (make-obsolete-variable 'ruby-use-smie nil "28.1") @@ -351,7 +357,8 @@ ruby-smie-grammar (exp (exp1) (exp "," exp) (exp "=" exp) (id " @ " exp)) (exp1 (exp2) (exp2 "?" exp1 ":" exp1)) - (exp2 (exp3) (exp3 "." exp3)) + (exp2 (exp3) (exp3 "." exp3) + (exp3 "def=" exp3)) (exp3 ("def" insts "end") ("begin" insts-rescue-insts "end") ("do" insts "end") @@ -528,6 +535,9 @@ ruby-smie--forward-token (ruby-smie--forward-token)) ;Fully redundant. (t ";"))) ((equal tok "&.") ".") + ((and (equal tok "def") + (looking-at ruby-endless-method-head-re)) + "def=") (t tok))))))))) (defun ruby-smie--backward-token () @@ -575,6 +585,9 @@ ruby-smie--backward-token (ruby-smie--backward-token)) ;Fully redundant. (t ";"))) ((equal tok "&.") ".") + ((and (equal tok "def") + (looking-at (concat "def" ruby-endless-method-head-re))) + "def=") (t tok))))))) (defun ruby-smie--indent-to-stmt () @@ -629,6 +642,13 @@ ruby-smie-rules (not (ruby-smie--bosp))) (forward-char -1)) (smie-indent-virtual)) + ((and (smie-rule-parent-p " @ ") + (save-excursion + (goto-char (nth 1 (smie-indent--parent))) + (and + (smie-rule-prev-p "def=") + (smie-indent-backward-token) + (smie-indent-virtual))))) (t (smie-rule-parent)))))) (`(:after . ,(or "(" "[" "{")) ;; FIXME: Shouldn't this be the default behavior of @@ -672,6 +692,11 @@ ruby-smie-rules (and (smie-rule-parent-p ";" nil) (smie-indent--hanging-p) ruby-indent-level)) + (`(:before . "=") + (when (smie-rule-parent-p " @ ") + (goto-char (nth 1 (smie-indent--parent))) + (smie-indent-backward-token) + (cons 'column (+ (smie-indent-virtual) ruby-indent-level)))) (`(:after . ,(or "?" ":")) ruby-indent-level) (`(:before . ,(guard (memq (intern-soft token) ruby-alignable-keywords))) (when (not (ruby--at-indentation-p)) @@ -1631,7 +1656,7 @@ ruby-add-log-current-method (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) + (if (ruby-block-contains-point (1- start)) t ;; Try to match a method only once. (setq definition-re module-re) diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby.rb b/test/lisp/progmodes/ruby-mode-resources/ruby.rb index f39489071e..9d9b46fa31 100644 --- a/test/lisp/progmodes/ruby-mode-resources/ruby.rb +++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb @@ -500,3 +500,41 @@ def resolve(**args) member.call(**args) end + +# Endless methods. +class Bar + def foo(abc) = + bar + + bar + .baz + + def self.bar = + 123 + + 4 + + def request_params = { + headers: request_headers, + body: request_body + } + + foo a = 5, + b + + def foo( + baz, + bar + ) = + what + + def foo( + baz, + bar + ) + hello + end +end + +class Foo + def foo(...) = z + def bar = y +end diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el index e90a9e4075..9be01dc78f 100644 --- a/test/lisp/progmodes/ruby-mode-tests.el +++ b/test/lisp/progmodes/ruby-mode-tests.el @@ -605,6 +605,18 @@ ruby-add-log-current-method-after-inner-class-outside-methods-with-text (search-backward "FOO") (should (string= (ruby-add-log-current-method) "M::C")))) +(ert-deftest ruby-add-log-current-method-after-endless-method () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | def foo = + | 4_ + | end + |end") + (search-backward "_") + (delete-char 1) + (should (string= (ruby-add-log-current-method) "M::C#foo")))) + (defvar ruby-block-test-example (ruby-test-string "class C