diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 1f3e9b6ae7b..184ff6a61e0 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -285,6 +285,11 @@ ruby-method-params-indent :safe (lambda (val) (or (memq val '(t nil)) (numberp val))) :version "29.1") +(defcustom ruby-indent-simplified t + "Foo bar." + :type 'boolean + :safe 'booleanp) + (defcustom ruby-deep-arglist t "Deep indent lists in parenthesis when non-nil. Also ignores spaces after parenthesis when `space'. @@ -416,6 +421,7 @@ ruby-smie-grammar '((right "=") (right "+=" "-=" "*=" "/=" "%=" "**=" "&=" "|=" "^=" "<<=" ">>=" "&&=" "||=") + (right "?") (nonassoc ".." "...") (left "&&" "||") (nonassoc "<=>") @@ -608,10 +614,22 @@ ruby-smie--backward-token "def=") (t tok))))))) -(defun ruby-smie--indent-to-stmt () +(defun ruby-smie--indent-to-stmt (&optional offset) (save-excursion (smie-backward-sexp ";") - (cons 'column (smie-indent-virtual)))) + (cons 'column (+ (smie-indent-virtual) (or offset 0))))) + +(defun ruby-smie--indent-with-continuation (token) + (let* (indent + (stmt-beg (save-excursion + (smie-backward-sexp ";") + (setq indent (smie-indent-virtual)) + (point))) + (nls (1- (count-lines stmt-beg (point))))) + (when (and (not (equal token "do")) (smie-indent--hanging-p)) + (cl-incf nls)) + (when (> nls 0) (cl-incf indent ruby-indent-level)) + (cons 'column indent))) (defun ruby-smie--indent-to-stmt-p (keyword) (or (eq t ruby-align-to-stmt-keywords) @@ -642,7 +660,9 @@ ruby-smie-rules (forward-comment -1) (not (eq (preceding-char) ?:)))) ;; Curly block opener. - (ruby-smie--indent-to-stmt)) + (if ruby-indent-simplified + (ruby-smie--indent-with-continuation token) + (ruby-smie--indent-to-stmt))) ((smie-rule-hanging-p) ;; Treat purely syntactic block-constructs as being part of their parent, ;; when the opening token is hanging and the parent is not an @@ -683,7 +703,6 @@ ruby-smie-rules (skip-chars-forward " \t") (cons 'column (current-column))) (smie-rule-parent (or ruby-method-params-indent 0)))) - ('(:before . "do") (ruby-smie--indent-to-stmt)) ('(:before . ".") (if (smie-rule-sibling-p) (when ruby-align-chained-calls @@ -696,8 +715,10 @@ ruby-smie-rules (not (smie-rule-bolp))))) (cons 'column (current-column))) (smie-backward-sexp ".") - (cons 'column (+ (current-column) - ruby-indent-level)))) + (if ruby-indent-simplified + (ruby-smie--indent-to-stmt ruby-indent-level) + (cons 'column (+ (current-column) + ruby-indent-level))))) (`(:before . ,(or "else" "then" "elsif" "rescue" "ensure")) (smie-rule-parent)) (`(:before . ,(or "when" "in")) @@ -710,14 +731,16 @@ ruby-smie-rules "<<=" ">>=" "&&=" "||=" "and" "or")) (and (smie-rule-parent-p ";" nil) (smie-indent--hanging-p) - ruby-indent-level)) + (if ruby-indent-simplified + (ruby-smie--indent-to-stmt ruby-indent-level) + ruby-indent-level))) (`(:before . "=") (save-excursion (and (smie-rule-parent-p " @ ") (goto-char (nth 1 (smie-indent--parent))) (smie-rule-prev-p "def=") (cons 'column (+ (current-column) ruby-indent-level -3))))) - (`(:after . ,(or "?" ":")) ruby-indent-level) + (`(:after . ,(or "?" ":")) (unless ruby-indent-simplified ruby-indent-level)) (`(:before . ,(guard (memq (intern-soft token) ruby-alignable-keywords))) (when (not (ruby--at-indentation-p)) (if (ruby-smie--indent-to-stmt-p token) @@ -725,7 +748,18 @@ ruby-smie-rules (cons 'column (current-column))))) ('(:before . "iuwu-mod") (smie-rule-parent ruby-indent-level)) - )) + (`(:before . ,_) + (when (and ruby-indent-simplified + (not (or (member token '(",")) + (smie-rule-prev-p ";")))) + (let* ((stmt-beg (save-excursion + (smie-backward-sexp ";") + (point))) + (nls (1- (count-lines stmt-beg (point))))) + (when (and (not (equal token "do")) (smie-indent--hanging-p)) + (cl-incf nls)) + (ruby-smie--indent-to-stmt (if (> nls 0) ruby-indent-level 0))))) + ('(:before . "do") (ruby-smie--indent-to-stmt)))) (defun ruby--at-indentation-p (&optional point) (save-excursion diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby.rb b/test/lisp/progmodes/ruby-mode-resources/ruby.rb index 6a69d9db78a..3bf35790099 100644 --- a/test/lisp/progmodes/ruby-mode-resources/ruby.rb +++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb @@ -185,14 +185,14 @@ def test2 (arg) # Example from https://ruby-doc.com/docs/ProgrammingRuby/ d = 4 + 5 + # no '\' needed - 6 + 7 + 6 + 7 # Example from https://www.ruby-doc.org/docs/ProgrammingRuby/ e = 8 + 9 \ - + 10 # '\' needed + + 10 # '\' needed foo = obj.bar { |m| tee(m) } + - obj.qux { |m| hum(m) } + obj.qux { |m| hum(m) } begin foo @@ -215,7 +215,7 @@ def begin end a = foo(j, k) - - bar_tee + bar_tee while a < b do # "do" is optional foo @@ -224,8 +224,8 @@ def begin desc "foo foo" \ "bar bar" -foo. - bar +foo + .bar # https://github.com/rails/rails/blob/17f5d8e062909f1fcae25351834d8e89967b645e/activesupport/lib/active_support/time_with_zone.rb#L206 foo # comment intended to confuse the tokenizer @@ -288,7 +288,7 @@ def begin } if foo && - bar + bar end foo + @@ -312,10 +312,10 @@ def begin tee + qux 1 .. 2 && - 3 + 3 3 < 4 + - 5 + 5 10 << 4 ^ 20 @@ -418,8 +418,9 @@ def qux ddd qux = foo.fee ? - bar : - tee + bar + 3 * + 4 : + tee zoo.keep.bar!( {x: y, @@ -439,9 +440,9 @@ def qux foo2 = subject. - update( - 2 - ) + update( + 2 + ) # FIXME: This is not consistent with the example below it, but this # offset only happens if the colon is at eol, which wouldn't be often. @@ -451,7 +452,7 @@ def qux tee) foo(:bar => - tee) + tee) regions = foo( OpenStruct.new(id: 0, name: "foo") => [ @@ -500,9 +501,17 @@ def qux # Tokenizing "**" and "|" separately. def resolve(**args) - members = proc do |**args| - p(**args) - end + members = foo + .asdasd + .proc do |**args| + p(**args) + end + + members = foo + .asdasd + .proc { |**args| + p(**args) + } member.call(**args) end @@ -510,7 +519,7 @@ def resolve(**args) # Endless methods. class Bar def foo(abc) = bar + - baz + baz def self.bar = 123 + @@ -541,4 +550,5 @@ def baz.full_name = "#{bar} 3" # Local Variables: # ruby-method-params-indent: t +# ruby-indent-simplified: t # End: