Skip to content

Commit 780adff

Browse files
committed
auto merge of #12486 : MicahChalmer/rust/emacs-fixes-round-3, r=brson
I've added details in the description of each comment as to what it does, which I won't redundantly repeat here in the PR. They all relate to indentation in the emacs rust-mode. What I will note here is that this closes #8787. It addresses the last remaining case (not in the original issue description but in a comment), of indenting `match` statements. With the changes here, I believe every problem described in the issue description or comments of #8787 is addressed.
2 parents fd02f90 + 04dc3e4 commit 780adff

File tree

2 files changed

+239
-47
lines changed

2 files changed

+239
-47
lines changed

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

+168-1
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,108 @@ fn foo()
425425
"
426426
))
427427

428+
(ert-deftest indent-match ()
429+
(test-indent
430+
"
431+
fn foo() {
432+
match blah {
433+
Pattern => stuff(),
434+
_ => whatever
435+
}
436+
}
437+
"
438+
))
439+
440+
(ert-deftest indent-match-multiline-pattern ()
441+
(test-indent
442+
"
443+
fn foo() {
444+
match blah {
445+
Pattern |
446+
Pattern2 => {
447+
hello()
448+
},
449+
_ => whatever
450+
}
451+
}
452+
"
453+
))
454+
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+
fn function_with_multiline_attribute() {}
515+
"
516+
))
517+
518+
519+
;; Make sure that in effort to cover match patterns we don't mistreat || or expressions
520+
(ert-deftest indent-nonmatch-or-expression ()
521+
(test-indent
522+
"
523+
fn foo() {
524+
let x = foo() ||
525+
bar();
526+
}
527+
"
528+
))
529+
428530
(setq rust-test-motion-string
429531
"
430532
fn fn1(arg: int) -> bool {
@@ -450,6 +552,26 @@ struct Foo {
450552
}
451553
"
452554
rust-test-region-string rust-test-motion-string
555+
rust-test-indent-motion-string
556+
"
557+
fn blank_line(arg:int) -> bool {
558+
559+
}
560+
561+
fn indenting_closing_brace() {
562+
if(true) {
563+
}
564+
}
565+
566+
fn indenting_middle_of_line() {
567+
if(true) {
568+
push_me_out();
569+
} else {
570+
pull_me_back_in();
571+
}
572+
}
573+
"
574+
453575
;; Symbol -> (line column)
454576
rust-test-positions-alist '((start-of-fn1 (2 0))
455577
(start-of-fn1-middle-of-line (2 15))
@@ -464,7 +586,17 @@ struct Foo {
464586
(middle-of-fn3 (16 4))
465587
(middle-of-struct (21 10))
466588
(before-start-of-struct (19 0))
467-
(after-end-of-struct (23 0))))
589+
(after-end-of-struct (23 0))
590+
(blank-line-indent-start (3 0))
591+
(blank-line-indent-target (3 4))
592+
(closing-brace-indent-start (8 1))
593+
(closing-brace-indent-target (8 5))
594+
(middle-push-indent-start (13 2))
595+
(middle-push-indent-target (13 9))
596+
(after-whitespace-indent-start (13 1))
597+
(after-whitespace-indent-target (13 8))
598+
(middle-pull-indent-start (15 19))
599+
(middle-pull-indent-target (15 12))))
468600

469601
(defun rust-get-buffer-pos (pos-symbol)
470602
"Get buffer position from POS-SYMBOL.
@@ -626,3 +758,38 @@ All positions are position symbols found in `rust-test-positions-alist'."
626758
'middle-of-struct
627759
'before-start-of-struct 'after-end-of-struct
628760
#'mark-defun))
761+
762+
(ert-deftest indent-line-blank-line-motion ()
763+
(rust-test-motion
764+
rust-test-indent-motion-string
765+
'blank-line-indent-start
766+
'blank-line-indent-target
767+
#'indent-for-tab-command))
768+
769+
(ert-deftest indent-line-closing-brace-motion ()
770+
(rust-test-motion
771+
rust-test-indent-motion-string
772+
'closing-brace-indent-start
773+
'closing-brace-indent-target
774+
#'indent-for-tab-command))
775+
776+
(ert-deftest indent-line-middle-push-motion ()
777+
(rust-test-motion
778+
rust-test-indent-motion-string
779+
'middle-push-indent-start
780+
'middle-push-indent-target
781+
#'indent-for-tab-command))
782+
783+
(ert-deftest indent-line-after-whitespace-motion ()
784+
(rust-test-motion
785+
rust-test-indent-motion-string
786+
'after-whitespace-indent-start
787+
'after-whitespace-indent-target
788+
#'indent-for-tab-command))
789+
790+
(ert-deftest indent-line-middle-pull-motion ()
791+
(rust-test-motion
792+
rust-test-indent-motion-string
793+
'middle-pull-indent-start
794+
'middle-pull-indent-target
795+
#'indent-for-tab-command))

src/etc/emacs/rust-mode.el

+71-46
Original file line numberDiff line numberDiff line change
@@ -59,70 +59,95 @@
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 or brace (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
109-
"[[,;{}(][[:space:]]*\\(?://.*\\)?")
110-
(* rust-indent-offset level)
111-
(back-to-indentation)
112-
(if (looking-at "#")
113-
(* rust-indent-offset level)
114-
(* rust-indent-offset (+ 1 level))))))))))
115-
116-
;; Otherwise we're in a column-zero definition
117-
(t 0))))))
118-
(cond
119-
;; If we're to the left of the indentation, reindent and jump to it.
120-
((<= (current-column) indent)
121-
(indent-line-to indent))
122-
123-
;; We're to the right; if it needs indent, do so but save excursion.
124-
((not (eq (current-indentation) indent))
125-
(save-excursion (indent-line-to indent))))))
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))))))))))
143+
(when (not (eq (current-indentation) indent))
144+
;; If we're at the beginning of the line (before or at the current
145+
;; indentation), jump with the indentation change. Otherwise, save the
146+
;; excursion so that adding the indentations will leave us at the
147+
;; equivalent position within the line to where we were before.
148+
(if (<= (current-column) (current-indentation))
149+
(indent-line-to indent)
150+
(save-excursion (indent-line-to indent))))))
126151

127152

128153
;; Font-locking definitions and helpers

0 commit comments

Comments
 (0)