Skip to content

Commit 1b27957

Browse files
KAAtheWiseGitytmimi
andcommitted
feat: add match_arm_indent option
Allows to disable the indentation of match arms. Related issue: #2937 Co-authored-by: Yacin Tmimi <[email protected]>
1 parent ee329d3 commit 1b27957

File tree

18 files changed

+527
-8
lines changed

18 files changed

+527
-8
lines changed

Configurations.md

+36
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,42 @@ fn foo() {
18621862
}
18631863
```
18641864

1865+
## `match_arm_indent`
1866+
1867+
Controls whether match arms are indented. If disabled, match arms will be formatted at the same indentation level as the outer `match` statement. Meaning that match blocks will only be indented once, not twice.
1868+
1869+
- **Default value**: `true`
1870+
- **Possible values**: `true`, `false`
1871+
- **Stable**: No (TODO tracking issue)
1872+
1873+
#### `true` (default):
1874+
1875+
```rust
1876+
fn main() {
1877+
match value {
1878+
Enum::A => {
1879+
let mut work = first();
1880+
work += second();
1881+
}
1882+
Enum::B => short_work(),
1883+
}
1884+
}
1885+
```
1886+
1887+
#### `false`:
1888+
1889+
```rust
1890+
fn main() {
1891+
match value {
1892+
Enum::A => {
1893+
let mut work = first();
1894+
work += second();
1895+
}
1896+
Enum::B => short_work(),
1897+
}
1898+
}
1899+
```
1900+
18651901
## `match_block_trailing_comma`
18661902

18671903
Put a trailing comma after a block based match arm (non-block arms are not affected)

src/config/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ create_config! {
131131
on the same line with the pattern of arms";
132132
match_arm_leading_pipes: MatchArmLeadingPipeConfig, true,
133133
"Determines whether leading pipes are emitted on match arms";
134+
match_arm_indent: MatchArmIndent, false,
135+
"Determines whether match arms are indented";
134136
force_multiline_blocks: ForceMultilineBlocks, false,
135137
"Force multiline closure bodies and match arms to be wrapped in a block";
136138
fn_args_layout: FnArgsLayout, true,
@@ -803,6 +805,7 @@ struct_field_align_threshold = 0
803805
enum_discrim_align_threshold = 0
804806
match_arm_blocks = true
805807
match_arm_leading_pipes = "Never"
808+
match_arm_indent = true
806809
force_multiline_blocks = false
807810
fn_params_layout = "Tall"
808811
brace_style = "SameLineWhere"
@@ -894,6 +897,7 @@ struct_field_align_threshold = 0
894897
enum_discrim_align_threshold = 0
895898
match_arm_blocks = true
896899
match_arm_leading_pipes = "Never"
900+
match_arm_indent = true
897901
force_multiline_blocks = false
898902
fn_params_layout = "Tall"
899903
brace_style = "SameLineWhere"

src/config/options.rs

+1
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ config_option_with_style_edition_default!(
665665
EnumDiscrimAlignThreshold, usize, _ => 0;
666666
MatchArmBlocks, bool, _ => true;
667667
MatchArmLeadingPipeConfig, MatchArmLeadingPipe, _ => MatchArmLeadingPipe::Never;
668+
MatchArmIndent, bool, _ => true;
668669
ForceMultilineBlocks, bool, _ => false;
669670
FnArgsLayout, Density, _ => Density::Tall;
670671
FnParamsLayout, Density, _ => Density::Tall;

src/matches.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,21 @@ pub(crate) fn rewrite_match(
100100
_ => " ",
101101
};
102102

103-
let nested_indent_str = shape
104-
.indent
105-
.block_indent(context.config)
106-
.to_string(context.config);
103+
let nested_indent = if context.config.match_arm_indent() {
104+
shape.indent.block_indent(context.config)
105+
} else {
106+
shape.indent
107+
};
108+
let nested_indent_str = nested_indent.to_string(context.config);
109+
107110
// Inner attributes.
108111
let inner_attrs = &inner_attributes(attrs);
109112
let inner_attrs_str = if inner_attrs.is_empty() {
110113
String::new()
111114
} else {
112-
let shape = if context.config.style_edition() <= StyleEdition::Edition2021 {
115+
let shape = if context.config.style_edition() <= StyleEdition::Edition2021
116+
|| !context.config.match_arm_indent()
117+
{
113118
shape
114119
} else {
115120
shape.block_indent(context.config.tab_spaces())
@@ -204,9 +209,12 @@ fn rewrite_match_arms(
204209
span: Span,
205210
open_brace_pos: BytePos,
206211
) -> RewriteResult {
207-
let arm_shape = shape
208-
.block_indent(context.config.tab_spaces())
209-
.with_max_width(context.config);
212+
let arm_shape = if context.config.match_arm_indent() {
213+
shape.block_indent(context.config.tab_spaces())
214+
} else {
215+
shape
216+
}
217+
.with_max_width(context.config);
210218

211219
let arm_len = arms.len();
212220
let is_last_iter = repeat(false)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// rustfmt-match_arm_indent: false
2+
3+
fn single_oneline() {
4+
match value { #[cfg(sslv2)] Sslv2 => handle(), }
5+
}
6+
7+
fn single_multiline() {
8+
match value {
9+
Sslv3 => handle(),
10+
#[cfg(sslv2)] Sslv2 => { handle1(); handle2();}
11+
#[cfg(TLSv1)] Tlsv1 if condition || something_else || and_a_third_thing || long_condition || basically => {}
12+
#[cfg(sslv23)] Sslv23 if condition || something_else || and_a_third_thing || long_condition || basically => {actuall_content(); "ret";}
13+
}
14+
}
15+
16+
fn multiple() {
17+
match value {
18+
Sslv3 => handle(),
19+
#[attr] #[cfg(sslv2)] Sslv2 => { handle1(); handle2();}
20+
#[attr] #[cfg(TLSv1)] Tlsv1 if condition || something_else || and_a_third_thing || long_condition || basically => {}
21+
22+
#[attr] #[cfg(sslv23)] Sslv23 if condition || something_else || and_a_third_thing || long_condition || basically => {actuall_content(); "ret";}
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// rustfmt-match_arm_indent: false
2+
3+
// Guards are indented if the pattern is longer than 6 characters
4+
fn test() {
5+
match value {
6+
LongOption
7+
if condition || something_else || and_a_third_thing || long_condition || basically =>
8+
{
9+
do_stuff();
10+
other_stuff();
11+
}
12+
13+
A23456 if loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong => {
14+
"1";
15+
"2";
16+
}
17+
}
18+
}
19+
20+
fn complicated() {
21+
match rewrite {
22+
// reflows
23+
Ok(ref body_str)
24+
if is_block
25+
|| (!body_str.contains('\n')
26+
&& unicode_str_width(body_str) <= body_shape.width) =>
27+
{
28+
return combine_orig_body(body_str);
29+
}
30+
_ => rewrite,
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// rustfmt-match_arm_indent: false
2+
// rustfmt-match_arm_leading_pipes: Always
3+
4+
fn pipes() {
5+
match value {
6+
SingleOption => {1;2;}
7+
8+
Multiple | Options | Together => {1;2;}
9+
10+
Multiple | Options | But | Long | And | This | Time | With | A | Guard if condition => {1; 2;}
11+
12+
Multiple | Options | But | Long | And | This | Time | With | A | Guard if condition || and || single_expr => 1,
13+
14+
a@Enum::Variant1 | a@Enum::Variant2 => {1;2;}
15+
16+
#[attr] JustInCase => r#final(),
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// rustfmt-match_arm_indent: false
2+
3+
fn r#match() {
4+
match value {
5+
Arm::Prev => f(),
6+
// inline match
7+
ModeratelyLongOption(n) => match n {
8+
A => f(),
9+
B => {
10+
1;
11+
2;
12+
3;
13+
}
14+
AnotherLongerOption => {
15+
1;
16+
2;
17+
}
18+
_ if there || is || a || guard => {
19+
nothing_changes();
20+
}
21+
},
22+
Arm::Next => {
23+
1;
24+
2;
25+
3;
26+
}
27+
}
28+
}
29+
30+
// things which break up the nested match arm
31+
fn r#break() {
32+
match value {
33+
Arm::Prev => f(),
34+
// inline match
35+
ModeratelyLongOption(n) => #[attr] match n {
36+
A => f(),
37+
B => c(),
38+
C => 1,
39+
},
40+
Arm::Next => n(),
41+
Two | Patterns => /* inline comment */ match val {
42+
C => 3,
43+
D => func(),
44+
}
45+
Arm::Last => l(),
46+
}
47+
}
48+
49+
fn parens() {
50+
let result = Some(Other(match value { Option1 => 1, Option2 => {stuff(); 2}}));
51+
}
52+
53+
fn silly() {
54+
match value {
55+
Inner(i1) => match i1 {
56+
Inner(i2) => match i2 {
57+
Inner(i3) => match i3 {
58+
Inner(i4) => match i4 {
59+
Inner => "it's a readability tradeoff, really"
60+
}
61+
}
62+
}
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// rustfmt-match_arm_indent: false
2+
3+
fn multiple() {
4+
match body.kind {
5+
// We do not allow `if` to stay on the same line, since we could easily mistake
6+
// `pat => if cond { ... }` and `pat if cond => { ... }`.
7+
ast::ExprKind::If(..) => false,
8+
// We do not allow collapsing a block around expression with condition
9+
// to avoid it being cluttered with match arm.
10+
ast::ExprKind::ForLoop { .. } | ast::ExprKind::While(..) => false,
11+
ast::ExprKind::Loop(..)
12+
| ast::ExprKind::Match(..)
13+
| ast::ExprKind::Block(..)
14+
| ast::ExprKind::Closure(..)
15+
| ast::ExprKind::Array(..)
16+
| ast::ExprKind::Call(..)
17+
| ast::ExprKind::MethodCall(..)
18+
| ast::ExprKind::MacCall(..)
19+
| ast::ExprKind::Struct(..)
20+
| ast::ExprKind::Tup(..) => true,
21+
ast::ExprKind::AddrOf(_, _, ref expr)
22+
| ast::ExprKind::Try(ref expr)
23+
| ast::ExprKind::Unary(_, ref expr)
24+
| ast::ExprKind::Index(ref expr, _, _)
25+
| ast::ExprKind::Cast(ref expr, _) => can_flatten_block_around_this(expr),
26+
_ => false,
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// rustfmt-match_arm_indent: false
2+
// Unindent the match arms
3+
4+
fn foo() {
5+
match x {
6+
a => {
7+
"line1";
8+
"line2"
9+
}
10+
ThisIsA::Guard if true => {
11+
"line1";
12+
"line2"
13+
}
14+
ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine) if true => {
15+
"line1";
16+
"line2"
17+
}
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// rustfmt-match_arm_indent: false
2+
3+
fn single_oneline() {
4+
match value {
5+
#[cfg(sslv2)]
6+
Sslv2 => handle(),
7+
}
8+
}
9+
10+
fn single_multiline() {
11+
match value {
12+
Sslv3 => handle(),
13+
#[cfg(sslv2)]
14+
Sslv2 => {
15+
handle1();
16+
handle2();
17+
}
18+
#[cfg(TLSv1)]
19+
Tlsv1 if condition || something_else || and_a_third_thing || long_condition || basically => {}
20+
#[cfg(sslv23)]
21+
Sslv23 if condition || something_else || and_a_third_thing || long_condition || basically => {
22+
actuall_content();
23+
"ret";
24+
}
25+
}
26+
}
27+
28+
fn multiple() {
29+
match value {
30+
Sslv3 => handle(),
31+
#[attr]
32+
#[cfg(sslv2)]
33+
Sslv2 => {
34+
handle1();
35+
handle2();
36+
}
37+
#[attr]
38+
#[cfg(TLSv1)]
39+
Tlsv1 if condition || something_else || and_a_third_thing || long_condition || basically => {}
40+
41+
#[attr]
42+
#[cfg(sslv23)]
43+
Sslv23 if condition || something_else || and_a_third_thing || long_condition || basically => {
44+
actuall_content();
45+
"ret";
46+
}
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// rustfmt-match_arm_indent: false
2+
3+
// Guards are indented if the pattern is longer than 6 characters
4+
fn test() {
5+
match value {
6+
LongOption
7+
if condition || something_else || and_a_third_thing || long_condition || basically =>
8+
{
9+
do_stuff();
10+
other_stuff();
11+
}
12+
13+
A23456 if loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong => {
14+
"1";
15+
"2";
16+
}
17+
}
18+
}
19+
20+
fn complicated() {
21+
match rewrite {
22+
// reflows
23+
Ok(ref body_str)
24+
if is_block
25+
|| (!body_str.contains('\n') && unicode_str_width(body_str) <= body_shape.width) =>
26+
{
27+
return combine_orig_body(body_str);
28+
}
29+
_ => rewrite,
30+
}
31+
}

0 commit comments

Comments
 (0)