unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Dmitry Gutov <dgutov@yandex.ru>
To: Aaron Jensen <aaronjensen@gmail.com>
Cc: 60186@debbugs.gnu.org
Subject: bug#60186: 29.0.60; ruby-mode indentation of multi-line expressions
Date: Thu, 22 Dec 2022 00:48:38 +0200	[thread overview]
Message-ID: <2b4a91e1-bad1-382f-dd64-abf171efb404@yandex.ru> (raw)
In-Reply-To: <CAHyO48ybYrvkHbztSkUjLkh5vQWOVhBhi-7sdUqui5LZBrr5Rw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1888 bytes --]

On 20/12/2022 22:05, Aaron Jensen wrote:
>>     some_variable = some_number + some_other_number *
>>                                  some_third_number +
>>                    some_fourth_number -
>>                    some_fifth_number
> 
> Yeah, with this I'd probably be trying to give a name to some of the
> things (what is the name of the product there?) I don't think I've
> ever seen code like that in practice to be honest.

Sure, but if such complex structures are not used, it also doesn't 
matter that the ruby-mode indents them differently from the "community 
baseline".

But it could still help when prototyping code, fiddling with the 
implementation (to factor pieces out into named variables later), etc.

>> One might ask why it's lined up to 'map' only after it's moved to the
>> next line, but not in the first example.
> 
> It's never lined up to map, I don't think that's the right way to
> think about it. It's lined up to indent level 1. It isn't until after
> the `end' that the indent level returns to 0.
> 
> Line continuation (mid-expression): +1 indent level
> Block opening (mid-block): +1 indent level
> Paren opening (mid-arguments/params): +1 indent level
> And all the closing/endings: -1 indent level
> 
> Only one indent level can be added per line, so all that matters is
> where the line ends. In short, there are a set of expressions that
> require indentation if they span multiple lines:
>
> expression-start
>    expression-middle
> expression-end

I think I got it. Only one indent level can be added for the duration of 
a statement. Unless there are nested blocks or parens/brackets/braces.

> I haven't tried the patch yet, but I'll give it a shot.

See this new patch instead.

The code is messier than I'd like it to be, but it seems to handle all 
of the cases mentioned so far and more (including the 
dots-at-indentation style, thanks).

[-- Attachment #2: ruby-simplified-indent-v3.diff --]
[-- Type: text/x-patch, Size: 7190 bytes --]

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:

  reply	other threads:[~2022-12-21 22:48 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-19  2:54 bug#60186: 29.0.60; ruby-mode indentation of multi-line expressions Aaron Jensen
2022-12-20  2:12 ` Dmitry Gutov
2022-12-20  2:17   ` Dmitry Gutov
2022-12-20  4:48   ` Aaron Jensen
2022-12-20  5:56     ` Aaron Jensen
2022-12-20 15:53       ` Dmitry Gutov
2022-12-20 16:19     ` Dmitry Gutov
2022-12-20 17:31       ` Dmitry Gutov
2022-12-21  1:34         ` Aaron Jensen
2022-12-20 20:05       ` Aaron Jensen
2022-12-21 22:48         ` Dmitry Gutov [this message]
2022-12-22  2:31           ` Aaron Jensen
2022-12-22 21:21             ` Dmitry Gutov
2022-12-23  4:12               ` Aaron Jensen
2022-12-23 22:26                 ` Dmitry Gutov
2022-12-24  0:17                   ` Aaron Jensen
2022-12-24 22:47                     ` Dmitry Gutov
2022-12-25  0:12                       ` Aaron Jensen
2022-12-25 21:23                         ` Dmitry Gutov
2022-12-25 21:29                         ` bug#60321: 29.0.60; ruby-mode indentation of hash or array as first arg in multiline method call Dmitry Gutov
2022-12-25 23:46                           ` Aaron Jensen
2022-12-27  1:16                             ` Dmitry Gutov
2022-12-27  1:38                               ` Aaron Jensen
2022-12-25  0:14                       ` bug#60186: 29.0.60; ruby-mode indentation of multi-line expressions Aaron Jensen
2022-12-25 21:29                         ` Dmitry Gutov
2022-12-27  1:28                         ` Dmitry Gutov
2022-12-27  1:47                           ` Aaron Jensen
2022-12-27 15:56                             ` Dmitry Gutov
2022-12-27 16:34                               ` Aaron Jensen
2022-12-27 23:04                                 ` Dmitry Gutov
2022-12-28  0:38                                   ` Aaron Jensen
2022-12-28  1:02                                     ` Dmitry Gutov
2022-12-28  3:47                                       ` Aaron Jensen
2022-12-28 12:47                                         ` Dmitry Gutov
2022-12-28 21:24                                           ` Dmitry Gutov
2022-12-29 22:59                                             ` Aaron Jensen
2022-12-30 15:02                                               ` Dmitry Gutov
2022-12-30 18:00                                                 ` Aaron Jensen
2022-12-30 18:16                                                   ` Aaron Jensen
2022-12-30 22:07                                                     ` Dmitry Gutov
2022-12-31  1:11                                                       ` Aaron Jensen
2023-01-22  3:02                                                         ` Dmitry Gutov
2023-01-22  5:15                                                           ` Aaron Jensen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2b4a91e1-bad1-382f-dd64-abf171efb404@yandex.ru \
    --to=dgutov@yandex.ru \
    --cc=60186@debbugs.gnu.org \
    --cc=aaronjensen@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).