2

Is there a way to tweak the alignment rules in c-derived modes, in my case d-mode to indent D-style UFCS-Chains such as

    foreach (file; dirPath.expandTilde()
                          .buildNormalizedPath() 
                          .dirEntries(SpanMode.shallow)()

In this case I would like to align on the point, that is.

For details see https://github.com/Emacs-D-Mode-Maintainers/Emacs-D-Mode/issues/26

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
Nordlöw
  • 11,838
  • 10
  • 52
  • 99

1 Answers1

2

You have to modify the value of arglist-cont-nonempty key in your c-offsets-alist. Also, you will probably want to modify the statement-cont key to enable the same indentation in general statements (e.g. assignments) as well:

(add-to-list 'c-offsets-alist '(arglist-cont-nonempty . c-lineup-cascaded-calls))
(add-to-list 'c-offsets-alist '(statement-cont . c-lineup-cascaded-calls))

Obviously, you can use something like:

(add-hook 'd-mode-hook
                 '(lambda ()
                    (add-to-list 'c-offsets-alist '(arglist-cont-nonempty . c-lineup-cascaded-calls))
                    (add-to-list 'c-offsets-alist '(statement-cont . c-lineup-cascaded-calls))))

to enable this alignment in every d-mode buffer.

If you want to account for optional parenthesis, I believe you'll have to write your own "lining-up" function, since I can't think of a built-in solution. Here's a dirty rewrite of c-lineup-cascaded-calls:

(defun d-lineup-cascaded-calls (langelem)
  "This is a modified `c-lineup-cascaded-calls' function for the
D programming language which accounts for optional parenthesis
and compile-time parameters in function calls."

  (if (and (eq (c-langelem-sym langelem) 'arglist-cont-nonempty)
           (not (eq (c-langelem-2nd-pos c-syntactic-element)
                    (c-most-enclosing-brace (c-parse-state)))))
      ;; The innermost open paren is not our one, so don't do
      ;; anything.  This can occur for arglist-cont-nonempty with
      ;; nested arglist starts on the same line.
      nil

    (save-excursion
      (back-to-indentation)
      (let ((operator (and (looking-at "\\.")
                           (regexp-quote (match-string 0))))
            (stmt-start (c-langelem-pos langelem)) col)

        (when (and operator
                   (looking-at operator)
                   (or (and
                        (zerop (c-backward-token-2 1 t stmt-start))
                        (eq (char-after) ?\()
                        (zerop (c-backward-token-2 2 t stmt-start))
                        (looking-at operator))
                       (and
                        (zerop (c-backward-token-2 1 t stmt-start))
                        (looking-at operator))
                       (and
                        (zerop (c-backward-token-2 1 t stmt-start))
                        (looking-at operator))
                       )
                   )
          (setq col (current-column))

          (while (or (and
                      (zerop (c-backward-token-2 1 t stmt-start))
                      (eq (char-after) ?\()
                      (zerop (c-backward-token-2 2 t stmt-start))
                      (looking-at operator))
                     (and
                      (zerop (c-backward-token-2 1 t stmt-start))
                      (looking-at operator))
                     (and
                      (zerop (c-backward-token-2 1 t stmt-start))
                      (looking-at operator))
                     )
            (setq col (current-column)))

          (vector col))))))

It seems to work for the optional parenthesis and for double parenthesis call (i.e. call!(type)(arg) ) as well. But maybe there are some corner cases, so don't count on it too much, it's just an idea to work with.

Nordlöw
  • 11,838
  • 10
  • 52
  • 99
Sergei Nosov
  • 1,637
  • 11
  • 9