[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/rust-mode b76e803 208/486: Correctly indent where clauses
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/rust-mode b76e803 208/486: Correctly indent where clauses |
Date: |
Sat, 7 Aug 2021 09:25:20 -0400 (EDT) |
branch: elpa/rust-mode
commit b76e803768bd572424b3f111aa55269f5d8226fc
Author: mrBliss <dewinant@gmail.com>
Commit: mrBliss <dewinant@gmail.com>
Correctly indent where clauses
Revisit #82. Now rustfmt has a default style for `where` clauses, it
makes sense to let rust-mode support it by default. How rust-mode
currently indents `where` clauses is totally broken anyway. The line
starting with `where` itself, the following lines that are part of the
`where` clause, and the body were all indented incorrectly. This commit
fixes this.
**Note that this commit does not prescribe a certain indentation style
for where clauses, but supports the most common ones, including
rustfmt's default.**
By choosing the location of (1) `where` and (2) the type parameter
bounds, the user can follow three major indentation styles. There is no
need for a configuration option to choose the style, as the locations of
1 and 2 dictate the style to follow. So all three styles can be used
together in the same file.
For each major style, the opening brace can be on the last line of the
type parameter bounds or on a new line (a or b in the examples). All 6
styles are supported without having to change any configuration option.
See the examples below and the new test cases.
There is one more style that is unfortunately incompatible with the
default `where` indentation style of rustfmt: when the user does not
want `where` to be indented, but aligned with the `fn` or `trait` on the
line before (see examples `foo4a` and `foo4b` below). To enable this
style, the user has to set the new option `rust-indent-where-clause` to
nil (it defaults to t).
Putting `where` and the type parameter bounds on the same line as the
function header is still supported of course (see examples `fooa` and
`foob` below). As there is no indentation, this commit does not
influence this.
Note that rust-mode's indentation has a different goal than rustfmt.
rustfmt reflows code, adds or removes line breaks, reindents, etc.
rust-mode's indentation only indents lines. The goal is not to imitate
rustfmt, but after running rustfmt on a file, reindenting it with
rust-mode should be idempotent. This way, users do not have to deal with
the eternal battle of differing indentation styles of rustfmt and
rust-mode.
The supported styles:
```rust
fn foo1a(a: A, b: B) -> C
where A: Clone + Default,
B: Eq,
C: PartialEq {
let body;
}
fn foo1b(a: A, b: B) -> C
where A: Clone + Default,
B: Eq,
C: PartialEq
{
let body;
}
```
```rust
fn foo2a(a: A, b: B) -> C where A: Clone + Default,
B: Eq,
C: PartialEq {
let body;
}
fn foo2b(a: A, b: B) -> C where A: Clone + Default,
B: Eq,
C: PartialEq
{
let body;
}
```
```rust
fn foo3a(a: A, b: B) -> C where
A: Clone + Default,
B: Eq,
C: PartialEq {
let body;
}
fn foo3b(a: A, b: B) -> C where
A: Clone + Default,
B: Eq,
C: PartialEq
{
let body;
}
```
If the user wants `foo4` instead of `foo1`, `rust-indent-where-clause`
must be set to nil. `foo2` and `foo3` are not influenced by this.
```rust
fn foo4a(a: A, b: B) -> C
where A: Clone + Default,
B: Eq,
C: PartialEq {
let body;
}
fn foo4a(a: A, b: B) -> C
where A: Clone + Default,
B: Eq,
C: PartialEq
{
let body;
}
```
Unchanged:
```rust
fn fooa(a: A, b: B) -> C where A: Clone + Default, ... {
let body;
}
fn foob(a: A, b: B) -> C where A: Clone + Default, ...
{
let body;
}
```
---
rust-mode-tests.el | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
rust-mode.el | 73 +++++++++++++++++++++++-
2 files changed, 232 insertions(+), 1 deletion(-)
diff --git a/rust-mode-tests.el b/rust-mode-tests.el
index e621f82..e224e67 100644
--- a/rust-mode-tests.el
+++ b/rust-mode-tests.el
@@ -443,6 +443,166 @@ fn foo4(a:int,
}
"))
+(ert-deftest indent-body-after-where ()
+ (test-indent
+ "
+fn foo1(a: A, b: B) -> A
+ where A: Clone + Default, B: Eq {
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+
+fn foo2(a: A, b: B) -> A
+ where A: Clone + Default, B: Eq
+{
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style1a ()
+ (test-indent
+ "
+fn foo1a(a: A, b: B, c: C) -> D
+ where A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq {
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style1b ()
+ (test-indent
+ "
+fn foo1b(a: A, b: B, c: C) -> D
+ where A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq
+{
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style2a ()
+ (test-indent
+ "
+fn foo2a(a: A, b: B, c: C) -> D where A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq {
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style2b ()
+ (test-indent
+ "
+fn foo2b(a: A, b: B, c: C) -> D where A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq
+{
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style3a ()
+ (test-indent
+ "
+fn foo3a(a: A, b: B, c: C) -> D where
+ A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq {
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style3b ()
+ (test-indent
+ "
+fn foo3b(a: A, b: B, c: C) -> D where
+ A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq
+{
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
+(ert-deftest indent-align-where-clauses-style4a ()
+ (let ((rust-indent-where-clause nil))
+ (test-indent
+ "
+fn foo4a(a: A, b: B, c: C) -> D
+where A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq {
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+")))
+
+(ert-deftest indent-align-where-clauses-style4b ()
+ (let ((rust-indent-where-clause nil))
+ (test-indent
+ "
+fn foo4b(a: A, b: B, c: C) -> D
+where A: Clone + Default,
+ B: Eq,
+ C: PartialEq,
+ D: PartialEq
+{
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+")))
+
+(ert-deftest indent-align-where-clauses-impl-example ()
+ (test-indent
+ "
+impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
+ where K: Eq + Hash + Borrow<Q>,
+ Q: Eq + Hash,
+ S: HashState,
+{
+ let body;
+ Foo {
+ bar: 3
+ }
+}
+"))
+
(ert-deftest indent-square-bracket-alignment ()
(test-indent
"
diff --git a/rust-mode.el b/rust-mode.el
index 5b50d29..d857f25 100644
--- a/rust-mode.el
+++ b/rust-mode.el
@@ -157,6 +157,13 @@
:group 'rust-mode
:safe #'booleanp)
+(defcustom rust-indent-where-clause t
+ "Indent the line starting with the where keyword following a
+function or trait. When nil, where will be aligned with fn or trait."
+ :type 'boolean
+ :group 'rust-mode
+ :safe #'booleanp)
+
(defcustom rust-playpen-url-format "https://play.rust-lang.org/?code=%s"
"Format string to use when submitting code to the playpen"
:type 'string
@@ -213,7 +220,25 @@
(back-to-indentation))
(while (> (rust-paren-level) current-level)
(backward-up-list)
- (back-to-indentation))))
+ (back-to-indentation))
+ ;; When we're in the where clause, skip over it. First find out the start
+ ;; of the function and its paren level.
+ (let ((function-start nil) (function-level nil))
+ (save-excursion
+ (rust-beginning-of-defun)
+ (back-to-indentation)
+ ;; Avoid using multiple-value-bind
+ (setq function-start (point)
+ function-level (rust-paren-level)))
+ ;; On a where clause
+ (when (or (looking-at "\\bwhere\\b")
+ ;; or in one of the following lines, e.g.
+ ;; where A: Eq
+ ;; B: Hash <- on this line
+ (and (save-excursion
+ (re-search-backward "\\bwhere\\b" function-start t))
+ (= current-level function-level)))
+ (goto-char function-start)))))
(defun rust-align-to-method-chain ()
(save-excursion
@@ -348,6 +373,11 @@
((and (nth 4 (syntax-ppss)) (looking-at "*"))
(+ 1 baseline))
+ ;; When the user chose not to indent the start of the where
+ ;; clause, put it on the baseline.
+ ((and (not rust-indent-where-clause) (looking-at "\\bwhere\\b"))
+ baseline)
+
;; If we're in any other token-tree / sexp, then:
(t
(or
@@ -361,6 +391,47 @@
;; Point is now at the beginning of the containing set of
braces
(rust-align-to-expr-after-brace)))
+ ;; When where-clauses are spread over multiple lines, clauses
+ ;; should be aligned on the type parameters. In this case we
+ ;; take care of the second and following clauses (the ones
+ ;; that don't start with "where ")
+ (save-excursion
+ ;; Find the start of the function, we'll use this to limit
+ ;; our search for "where ".
+ (let ((function-start nil) (function-level nil))
+ (save-excursion
+ (rust-beginning-of-defun)
+ (back-to-indentation)
+ ;; Avoid using multiple-value-bind
+ (setq function-start (point)
+ function-level (rust-paren-level)))
+ ;; When we're not on a line starting with "where ", but
+ ;; still on a where-clause line, go to "where "
+ (when (and
+ (not (looking-at "\\bwhere\\b"))
+ ;; We're looking at something like "F: ..."
+ (and (looking-at (concat rust-re-ident ":"))
+ ;; There is a "where " somewhere after the
+ ;; start of the function.
+ (re-search-backward "\\bwhere\\b"
+ function-start t)
+ ;; Make sure we're not inside the function
+ ;; already (e.g. initializing a struct) by
+ ;; checking we are the same level.
+ (= function-level level)))
+ ;; skip over "where"
+ (forward-char 5)
+ ;; Unless "where" is at the end of the line
+ (if (eolp)
+ ;; in this case the type parameters bounds are just
+ ;; indented once
+ (+ baseline rust-indent-offset)
+ ;; otherwise, skip over whitespace,
+ (skip-chars-forward "[:space:]")
+ ;; get the column of the type parameter and use that
+ ;; as indentation offset
+ (current-column)))))
+
(progn
(back-to-indentation)
;; Point is now at the beginning of the current line
- [nongnu] elpa/rust-mode f17e11a 162/486: Match panics during build as compilation warnings, (continued)
- [nongnu] elpa/rust-mode f17e11a 162/486: Match panics during build as compilation warnings, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode b4ff35c 168/486: remove rust-mode-character-literal-syntax-table, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 5ed4675 171/486: Merge pull request #73 from MicahChalmer/raw-string-multiline-edit-fix, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 9d773b4 170/486: Fix multi-line raw strings when editing, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 6bc1540 186/486: Support nested block comments, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 7baae9c 180/486: Merge pull request #78 from tromey/fix-issue-33, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode c0e3878 183/486: Merge pull request #81 from MicahChalmer/fix-issue-80, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 75da3b0 189/486: Merge pull request #89 from MicahChalmer/fix-slow-angle-bracket-matching, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode a2e9f56 199/486: Merge pull request #84 from birkenfeld/compilation-note, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 92584c3 209/486: Fix the special case for the first line, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode b76e803 208/486: Correctly indent where clauses,
ELPA Syncer <=
- [nongnu] elpa/rust-mode 304ae4b 219/486: Change font-lock face for module names., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode ae49380 221/486: Merge pull request #121 from fbergroth/integrate-rustfmt, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 315cc59 233/486: Re-indent on }, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode bc77e16 240/486: remove emacs 23 support, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 620d718 257/486: Fix #160, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode cffb950f2 258/486: [master] Remove redundant progn., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode b3b0f78 259/486: Merge pull request #161 from Fanael/master, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode ba5ff90 260/486: Merge pull request #159 from hotpxl/master, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode f73f321 264/486: Merge pull request #163 from Wilfred/preserve_point_rustfmt, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode cc59c83 270/486: Recognize imenu items starting with "unsafe", ELPA Syncer, 2021/08/07