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
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.