Skip to content

Commit eaf95af

Browse files
committed
Merge pull request #111 from mrBliss/where-indentation
Correctly indent where clauses
2 parents 0601540 + 92584c3 commit eaf95af

File tree

2 files changed

+247
-4
lines changed

2 files changed

+247
-4
lines changed

rust-mode-tests.el

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,177 @@ fn foo4(a:int,
443443
}
444444
"))
445445

446+
(ert-deftest indent-body-after-where ()
447+
(test-indent
448+
"
449+
fn foo1(a: A, b: B) -> A
450+
where A: Clone + Default, B: Eq {
451+
let body;
452+
Foo {
453+
bar: 3
454+
}
455+
}
456+
457+
fn foo2(a: A, b: B) -> A
458+
where A: Clone + Default, B: Eq
459+
{
460+
let body;
461+
Foo {
462+
bar: 3
463+
}
464+
}
465+
"))
466+
467+
(ert-deftest indent-align-where-clauses-style1a ()
468+
(test-indent
469+
"
470+
fn foo1a(a: A, b: B, c: C) -> D
471+
where A: Clone + Default,
472+
B: Eq,
473+
C: PartialEq,
474+
D: PartialEq {
475+
let body;
476+
Foo {
477+
bar: 3
478+
}
479+
}
480+
"))
481+
482+
(ert-deftest indent-align-where-clauses-style1b ()
483+
(test-indent
484+
"
485+
fn foo1b(a: A, b: B, c: C) -> D
486+
where A: Clone + Default,
487+
B: Eq,
488+
C: PartialEq,
489+
D: PartialEq
490+
{
491+
let body;
492+
Foo {
493+
bar: 3
494+
}
495+
}
496+
"))
497+
498+
(ert-deftest indent-align-where-clauses-style2a ()
499+
(test-indent
500+
"
501+
fn foo2a(a: A, b: B, c: C) -> D where A: Clone + Default,
502+
B: Eq,
503+
C: PartialEq,
504+
D: PartialEq {
505+
let body;
506+
Foo {
507+
bar: 3
508+
}
509+
}
510+
"))
511+
512+
(ert-deftest indent-align-where-clauses-style2b ()
513+
(test-indent
514+
"
515+
fn foo2b(a: A, b: B, c: C) -> D where A: Clone + Default,
516+
B: Eq,
517+
C: PartialEq,
518+
D: PartialEq
519+
{
520+
let body;
521+
Foo {
522+
bar: 3
523+
}
524+
}
525+
"))
526+
527+
(ert-deftest indent-align-where-clauses-style3a ()
528+
(test-indent
529+
"
530+
fn foo3a(a: A, b: B, c: C) -> D where
531+
A: Clone + Default,
532+
B: Eq,
533+
C: PartialEq,
534+
D: PartialEq {
535+
let body;
536+
Foo {
537+
bar: 3
538+
}
539+
}
540+
"))
541+
542+
(ert-deftest indent-align-where-clauses-style3b ()
543+
(test-indent
544+
"
545+
fn foo3b(a: A, b: B, c: C) -> D where
546+
A: Clone + Default,
547+
B: Eq,
548+
C: PartialEq,
549+
D: PartialEq
550+
{
551+
let body;
552+
Foo {
553+
bar: 3
554+
}
555+
}
556+
"))
557+
558+
(ert-deftest indent-align-where-clauses-style4a ()
559+
(let ((rust-indent-where-clause nil))
560+
(test-indent
561+
"
562+
fn foo4a(a: A, b: B, c: C) -> D
563+
where A: Clone + Default,
564+
B: Eq,
565+
C: PartialEq,
566+
D: PartialEq {
567+
let body;
568+
Foo {
569+
bar: 3
570+
}
571+
}
572+
")))
573+
574+
(ert-deftest indent-align-where-clauses-style4b ()
575+
(let ((rust-indent-where-clause nil))
576+
(test-indent
577+
"
578+
fn foo4b(a: A, b: B, c: C) -> D
579+
where A: Clone + Default,
580+
B: Eq,
581+
C: PartialEq,
582+
D: PartialEq
583+
{
584+
let body;
585+
Foo {
586+
bar: 3
587+
}
588+
}
589+
")))
590+
591+
(ert-deftest indent-align-where-clauses-impl-example ()
592+
(test-indent
593+
"
594+
impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
595+
where K: Eq + Hash + Borrow<Q>,
596+
Q: Eq + Hash,
597+
S: HashState,
598+
{
599+
let body;
600+
Foo {
601+
bar: 3
602+
}
603+
}
604+
"))
605+
606+
(ert-deftest indent-align-where-clauses-first-line ()
607+
(test-indent
608+
"fn foo1(a: A, b: B) -> A
609+
where A: Clone + Default, B: Eq {
610+
let body;
611+
Foo {
612+
bar: 3
613+
}
614+
}
615+
"))
616+
446617
(ert-deftest indent-square-bracket-alignment ()
447618
(test-indent
448619
"

rust-mode.el

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@
157157
:group 'rust-mode
158158
:safe #'booleanp)
159159

160+
(defcustom rust-indent-where-clause t
161+
"Indent the line starting with the where keyword following a
162+
function or trait. When nil, where will be aligned with fn or trait."
163+
:type 'boolean
164+
:group 'rust-mode
165+
:safe #'booleanp)
166+
160167
(defcustom rust-playpen-url-format "https://play.rust-lang.org/?code=%s"
161168
"Format string to use when submitting code to the playpen"
162169
:type 'string
@@ -213,7 +220,25 @@
213220
(back-to-indentation))
214221
(while (> (rust-paren-level) current-level)
215222
(backward-up-list)
216-
(back-to-indentation))))
223+
(back-to-indentation))
224+
;; When we're in the where clause, skip over it. First find out the start
225+
;; of the function and its paren level.
226+
(let ((function-start nil) (function-level nil))
227+
(save-excursion
228+
(rust-beginning-of-defun)
229+
(back-to-indentation)
230+
;; Avoid using multiple-value-bind
231+
(setq function-start (point)
232+
function-level (rust-paren-level)))
233+
;; On a where clause
234+
(when (or (looking-at "\\bwhere\\b")
235+
;; or in one of the following lines, e.g.
236+
;; where A: Eq
237+
;; B: Hash <- on this line
238+
(and (save-excursion
239+
(re-search-backward "\\bwhere\\b" function-start t))
240+
(= current-level function-level)))
241+
(goto-char function-start)))))
217242

218243
(defun rust-align-to-method-chain ()
219244
(save-excursion
@@ -348,6 +373,11 @@
348373
((and (nth 4 (syntax-ppss)) (looking-at "*"))
349374
(+ 1 baseline))
350375

376+
;; When the user chose not to indent the start of the where
377+
;; clause, put it on the baseline.
378+
((and (not rust-indent-where-clause) (looking-at "\\bwhere\\b"))
379+
baseline)
380+
351381
;; If we're in any other token-tree / sexp, then:
352382
(t
353383
(or
@@ -361,6 +391,47 @@
361391
;; Point is now at the beginning of the containing set of braces
362392
(rust-align-to-expr-after-brace)))
363393

394+
;; When where-clauses are spread over multiple lines, clauses
395+
;; should be aligned on the type parameters. In this case we
396+
;; take care of the second and following clauses (the ones
397+
;; that don't start with "where ")
398+
(save-excursion
399+
;; Find the start of the function, we'll use this to limit
400+
;; our search for "where ".
401+
(let ((function-start nil) (function-level nil))
402+
(save-excursion
403+
(rust-beginning-of-defun)
404+
(back-to-indentation)
405+
;; Avoid using multiple-value-bind
406+
(setq function-start (point)
407+
function-level (rust-paren-level)))
408+
;; When we're not on a line starting with "where ", but
409+
;; still on a where-clause line, go to "where "
410+
(when (and
411+
(not (looking-at "\\bwhere\\b"))
412+
;; We're looking at something like "F: ..."
413+
(and (looking-at (concat rust-re-ident ":"))
414+
;; There is a "where " somewhere after the
415+
;; start of the function.
416+
(re-search-backward "\\bwhere\\b"
417+
function-start t)
418+
;; Make sure we're not inside the function
419+
;; already (e.g. initializing a struct) by
420+
;; checking we are the same level.
421+
(= function-level level)))
422+
;; skip over "where"
423+
(forward-char 5)
424+
;; Unless "where" is at the end of the line
425+
(if (eolp)
426+
;; in this case the type parameters bounds are just
427+
;; indented once
428+
(+ baseline rust-indent-offset)
429+
;; otherwise, skip over whitespace,
430+
(skip-chars-forward "[:space:]")
431+
;; get the column of the type parameter and use that
432+
;; as indentation offset
433+
(current-column)))))
434+
364435
(progn
365436
(back-to-indentation)
366437
;; Point is now at the beginning of the current line
@@ -373,10 +444,11 @@
373444

374445
(save-excursion
375446
(rust-rewind-irrelevant)
376-
;; Point is now at the end of the previous ine
447+
;; Point is now at the end of the previous line
377448
(or
378-
;; If we are at the first line, no indentation is needed, so stay at baseline...
379-
(= 1 (line-number-at-pos (point)))
449+
;; If we are at the start of the buffer, no
450+
;; indentation is needed, so stay at baseline...
451+
(= (point) 1)
380452
;; ..or if the previous line ends with any of these:
381453
;; { ? : ( , ; [ }
382454
;; then we are at the beginning of an expression, so stay on the baseline...

0 commit comments

Comments
 (0)