Skip to content

Commit 55b3c19

Browse files
committed
Emacs: indent relative to enclosing block
This changes the indent to calculate positions relative to the enclosing block (or braced/parenthesized expression), rather than by an absolute nesting level within the whole file. This allows things like this to work: let x = match expr { Pattern => ... } With the old method, only one level of nesting would be added within the match braces, so "Pattern" would have ended up aligned with the match. The other change is that multiple parens/braces on the same line only increase the indent once. This is a very common case for passing closures/procs. The absolute nesting method would do this: spawn(proc() { // Indented out two indent levels... }) whereas the code in this commit does this: spawn(proc() { // Indented out only one level... })
1 parent 45008f9 commit 55b3c19

File tree

2 files changed

+127
-37
lines changed

2 files changed

+127
-37
lines changed

src/etc/emacs/rust-mode-tests.el

+64
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,70 @@ fn foo() {
452452
"
453453
))
454454

455+
(ert-deftest indent-indented-match ()
456+
(test-indent
457+
"
458+
fn foo() {
459+
let x =
460+
match blah {
461+
Pattern |
462+
Pattern2 => {
463+
hello()
464+
},
465+
_ => whatever
466+
};
467+
y();
468+
}
469+
"
470+
))
471+
472+
(ert-deftest indent-curly-braces-within-parens ()
473+
(test-indent
474+
"
475+
fn foo() {
476+
let x =
477+
foo(bar(|x| {
478+
only_one_indent_here();
479+
}));
480+
y();
481+
}
482+
"
483+
))
484+
485+
(ert-deftest indent-weirdly-indented-block ()
486+
(rust-test-manip-code
487+
"
488+
fn foo() {
489+
{
490+
this_block_is_over_to_the_left_for_some_reason();
491+
}
492+
493+
}
494+
"
495+
16
496+
#'indent-for-tab-command
497+
"
498+
fn foo() {
499+
{
500+
this_block_is_over_to_the_left_for_some_reason();
501+
}
502+
503+
}
504+
"
505+
))
506+
507+
(ert-deftest indent-multi-line-attrib ()
508+
(test-indent
509+
"
510+
#[attrib(
511+
this,
512+
that,
513+
theotherthing)]
514+
mod function_with_multiline_attribute() {}
515+
"
516+
))
517+
518+
455519
;; Make sure that in effort to cover match patterns we don't mistreat || or expressions
456520
(ert-deftest indent-nonmatch-or-expression ()
457521
(test-indent

src/etc/emacs/rust-mode.el

+63-37
Original file line numberDiff line numberDiff line change
@@ -59,61 +59,87 @@
5959
(backward-word 1))
6060
(current-column))))
6161

62+
(defun rust-rewind-to-beginning-of-current-level-expr ()
63+
(let ((current-level (rust-paren-level)))
64+
(back-to-indentation)
65+
(while (> (rust-paren-level) current-level)
66+
(backward-up-list)
67+
(back-to-indentation))))
68+
6269
(defun rust-mode-indent-line ()
6370
(interactive)
6471
(let ((indent
6572
(save-excursion
6673
(back-to-indentation)
67-
(let ((level (rust-paren-level)))
74+
;; Point is now at beginning of current line
75+
(let* ((level (rust-paren-level))
76+
(baseline
77+
;; Our "baseline" is one level out from the indentation of the expression
78+
;; containing the innermost enclosing opening bracket. That
79+
;; way if we are within a block that has a different
80+
;; indentation than this mode would give it, we still indent
81+
;; the inside of it correctly relative to the outside.
82+
(if (= 0 level)
83+
0
84+
(save-excursion
85+
(backward-up-list)
86+
(rust-rewind-to-beginning-of-current-level-expr)
87+
(+ (current-column) rust-indent-offset)))))
6888
(cond
6989
;; A function return type is indented to the corresponding function arguments
7090
((looking-at "->")
7191
(save-excursion
7292
(backward-list)
7393
(or (rust-align-to-expr-after-brace)
74-
(* rust-indent-offset (+ 1 level)))))
94+
(+ baseline rust-indent-offset))))
7595

7696
;; A closing brace is 1 level unindended
77-
((looking-at "}") (* rust-indent-offset (- level 1)))
97+
((looking-at "}") (- baseline rust-indent-offset))
7898

7999
;; Doc comments in /** style with leading * indent to line up the *s
80100
((and (nth 4 (syntax-ppss)) (looking-at "*"))
81-
(+ 1 (* rust-indent-offset level)))
101+
(+ 1 baseline))
82102

83103
;; If we're in any other token-tree / sexp, then:
84-
;; - [ or ( means line up with the opening token
85-
;; - { means indent to either nesting-level * rust-indent-offset,
86-
;; or one further indent from that if either current line
87-
;; begins with 'else', or previous line didn't end in
88-
;; semi, comma, brace or single pipe (other than whitespace and line
89-
;; comments) , and wasn't an attribute. But if we have
90-
;; something after the open brace and ending with a comma,
91-
;; treat it as fields and align them. PHEW.
92-
((> level 0)
93-
(let ((pt (point)))
94-
(rust-rewind-irrelevant)
95-
(backward-up-list)
96-
(or (and (looking-at "[[({]")
97-
(rust-align-to-expr-after-brace))
98-
(progn
99-
(goto-char pt)
100-
(back-to-indentation)
101-
(if (looking-at "\\<else\\>")
102-
(* rust-indent-offset (+ 1 level))
103-
(progn
104-
(goto-char pt)
105-
(beginning-of-line)
106-
(rust-rewind-irrelevant)
107-
(end-of-line)
108-
(if (looking-back "\\(?:[(,:;?[{}]\\|[^|]|\\)[[:space:]]*\\(?://.*\\)?")
109-
(* rust-indent-offset level)
110-
(back-to-indentation)
111-
(if (looking-at "#")
112-
(* rust-indent-offset level)
113-
(* rust-indent-offset (+ 1 level))))))))))
114-
115-
;; Otherwise we're in a column-zero definition
116-
(t 0))))))
104+
(t
105+
(or
106+
;; If we are inside a pair of braces, with something after the
107+
;; open brace on the same line and ending with a comma, treat
108+
;; it as fields and align them.
109+
(when (> level 0)
110+
(save-excursion
111+
(rust-rewind-irrelevant)
112+
(backward-up-list)
113+
;; Point is now at the beginning of the containing set of braces
114+
(rust-align-to-expr-after-brace)))
115+
116+
(progn
117+
(back-to-indentation)
118+
;; Point is now at the beginning of the current line
119+
(if (or
120+
;; If this line begins with "else" or "{", stay on the
121+
;; baseline as well (we are continuing an expression,
122+
;; but the "else" or "{" should align with the beginning
123+
;; of the expression it's in.)
124+
(looking-at "\\<else\\>\\|{")
125+
126+
(save-excursion
127+
(rust-rewind-irrelevant)
128+
;; Point is now at the end of the previous ine
129+
(or
130+
;; If we are at the first line, no indentation is needed, so stay at baseline...
131+
(= 1 (line-number-at-pos (point)))
132+
;; ..or if the previous line ends with any of these:
133+
;; { ? : ( , ; [ }
134+
;; then we are at the beginning of an expression, so stay on the baseline...
135+
(looking-back "[(,:;?[{}]\\|[^|]|")
136+
;; or if the previous line is the end of an attribute, stay at the baseline...
137+
(progn (rust-rewind-to-beginning-of-current-level-expr) (looking-at "#")))))
138+
baseline
139+
140+
;; Otherwise, we are continuing the same expression from the previous line,
141+
;; so add one additional indent level
142+
(+ baseline rust-indent-offset))))))))))
117143
(when (not (eq (current-indentation) indent))
118144
;; If we're at the beginning of the line (before or at the current
119145
;; indentation), jump with the indentation change. Otherwise, save the

0 commit comments

Comments
 (0)