Skip to content

Commit 0f02d2b

Browse files
committed
implement single_line_let_else_max_width
This allows users to configure the maximum length of a single line `let-else` statements. `let-else` statements that otherwise meet the requirements to be formatted on a single line will have their divergent `else block` formatted over multiple lines if they exceed this length.
1 parent 9386b32 commit 0f02d2b

File tree

19 files changed

+254
-7
lines changed

19 files changed

+254
-7
lines changed

Configurations.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2392,6 +2392,70 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi
23922392

23932393
See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
23942394

2395+
## `single_line_let_else_max_width`
2396+
2397+
Maximum line length for single line let-else statements.
2398+
See the [let-else statement section of the Rust Style Guide](https://github.com/rust-lang/rust/blob/master/src/doc/style-guide/src/statements.md#else-blocks-let-else-statements) for more details on when a let-else statement may be written on a single line.
2399+
A value of `0` (zero) means the divergent `else block` will always be formatted over multiple lines.
2400+
Note this occurs when `use_small_heuristics` is set to `Off`.
2401+
2402+
By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `single_line_let_else_max_width` will take precedence.
2403+
2404+
- **Default value**: `50`
2405+
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
2406+
- **Stable**: No (tracking issue: [N/A]())
2407+
2408+
#### `50` (default):
2409+
2410+
```rust
2411+
fn main() {
2412+
let Some(x) = opt else { return };
2413+
2414+
let Some(x) = some_very_very_very_very_long_name else {
2415+
return;
2416+
};
2417+
2418+
let Some(y) = opt else {
2419+
return;
2420+
};
2421+
}
2422+
```
2423+
2424+
#### `0`:
2425+
2426+
```rust
2427+
fn main() {
2428+
let Some(x) = opt else {
2429+
return;
2430+
};
2431+
2432+
let Some(x) = some_very_very_very_very_long_name else {
2433+
return;
2434+
};
2435+
2436+
let Some(y) = opt else {
2437+
return;
2438+
};
2439+
}
2440+
```
2441+
2442+
#### `100`:
2443+
2444+
```rust
2445+
fn main() {
2446+
let Some(x) = opt else { return };
2447+
2448+
let Some(x) = some_very_very_very_very_long_name else { return };
2449+
2450+
let Some(y) = opt else {
2451+
return;
2452+
};
2453+
}
2454+
```
2455+
2456+
See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
2457+
2458+
23952459
## `space_after_colon`
23962460

23972461
Leave a space after the colon.
@@ -2804,6 +2868,7 @@ The ratios are:
28042868
* [`array_width`](#array_width) - `60%`
28052869
* [`chain_width`](#chain_width) - `60%`
28062870
* [`single_line_if_else_max_width`](#single_line_if_else_max_width) - `50%`
2871+
* [`single_line_let_else_max_width`](#single_line_let_else_max_width) - `50%`
28072872

28082873
For example when `max_width` is set to `100`, the width settings are:
28092874
* `fn_call_width=60`

src/config/config_type.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ macro_rules! create_config {
121121
| "use_small_heuristics"
122122
| "fn_call_width"
123123
| "single_line_if_else_max_width"
124+
| "single_line_let_else_max_width"
124125
| "attr_fn_like_width"
125126
| "struct_lit_width"
126127
| "struct_variant_width"
@@ -269,6 +270,7 @@ macro_rules! create_config {
269270
| "use_small_heuristics"
270271
| "fn_call_width"
271272
| "single_line_if_else_max_width"
273+
| "single_line_let_else_max_width"
272274
| "attr_fn_like_width"
273275
| "struct_lit_width"
274276
| "struct_variant_width"
@@ -407,6 +409,14 @@ macro_rules! create_config {
407409
"single_line_if_else_max_width",
408410
);
409411
self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
412+
413+
let single_line_let_else_max_width = get_width_value(
414+
self.was_set().single_line_let_else_max_width(),
415+
self.single_line_let_else_max_width.2,
416+
heuristics.single_line_let_else_max_width,
417+
"single_line_let_else_max_width",
418+
);
419+
self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
410420
}
411421

412422
fn set_heuristics(&mut self) {

src/config/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ create_config! {
5858
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
5959
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single line if-else \
6060
expressions. A value of zero means always break if-else expressions.";
61+
single_line_let_else_max_width: usize, 50, false, "Maximum line length for single line \
62+
let-else statements. A value of zero means always format the divergent `else block` \
63+
over multiple lines.";
6164

6265
// Comments. macros, and strings
6366
wrap_comments: bool, false, false, "Break comments to fit on the line";
@@ -473,6 +476,9 @@ mod test {
473476
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
474477
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single \
475478
line if-else expressions. A value of zero means always break if-else expressions.";
479+
single_line_let_else_max_width: usize, 50, false, "Maximum line length for single \
480+
line let-else statements. A value of zero means always format the divergent \
481+
`else block` over multiple lines.";
476482

477483
// Options that are used by the tests
478484
stable_option: bool, false, true, "A stable option";
@@ -619,6 +625,7 @@ struct_variant_width = 35
619625
array_width = 60
620626
chain_width = 60
621627
single_line_if_else_max_width = 50
628+
single_line_let_else_max_width = 50
622629
wrap_comments = false
623630
format_code_in_doc_comments = false
624631
doc_comment_code_block_width = 100

src/config/options.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ pub struct WidthHeuristics {
236236
// Maximum line length for single line if-else expressions. A value
237237
// of zero means always break if-else expressions.
238238
pub(crate) single_line_if_else_max_width: usize,
239+
// Maximum line length for single line let-else statements. A value of zero means
240+
// always format the divergent `else block` over multiple lines."
241+
pub(crate) single_line_let_else_max_width: usize,
239242
}
240243

241244
impl fmt::Display for WidthHeuristics {
@@ -255,6 +258,7 @@ impl WidthHeuristics {
255258
array_width: usize::max_value(),
256259
chain_width: usize::max_value(),
257260
single_line_if_else_max_width: 0,
261+
single_line_let_else_max_width: 0,
258262
}
259263
}
260264

@@ -267,6 +271,7 @@ impl WidthHeuristics {
267271
array_width: max_width,
268272
chain_width: max_width,
269273
single_line_if_else_max_width: max_width,
274+
single_line_let_else_max_width: max_width,
270275
}
271276
}
272277

@@ -288,6 +293,7 @@ impl WidthHeuristics {
288293
array_width: (60.0 * max_width_ratio).round() as usize,
289294
chain_width: (60.0 * max_width_ratio).round() as usize,
290295
single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
296+
single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
291297
}
292298
}
293299
}

src/items.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,24 @@ impl Rewrite for ast::Local {
138138
);
139139
result.push_str(&else_kw);
140140

141-
let allow_single_line = allow_single_line_let_else_block(&result, block);
141+
let max_width =
142+
std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
143+
let available_space = max_width.saturating_sub(result.len());
144+
145+
let allow_single_line = !force_newline_else
146+
&& available_space > 0
147+
&& allow_single_line_let_else_block(&result, block);
142148

143149
let mut rw_else_block =
144150
rewrite_let_else_block(block, allow_single_line, context, shape)?;
145151

146-
if allow_single_line && !rw_else_block.contains('\n') {
147-
let available_space = shape.width.saturating_sub(result.len());
148-
if available_space <= rw_else_block.len() {
149-
// writing this on one line would exceed the available width
150-
rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
151-
}
152+
let single_line_else = !rw_else_block.contains('\n');
153+
let else_block_exceeds_width = available_space <= rw_else_block.len();
154+
155+
if allow_single_line && single_line_else && else_block_exceeds_width {
156+
// writing this on one line would exceed the available width
157+
// so rewrite the else block over multiple lines.
158+
rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
152159
}
153160

154161
result.push_str(&rw_else_block);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// rustfmt-single_line_let_else_max_width: 100
2+
3+
fn main() {
4+
let Some(a) = opt else {};
5+
6+
let Some(b) = opt else { return };
7+
8+
let Some(c) = opt else {
9+
return
10+
};
11+
12+
let Some(d) = some_very_very_very_very_long_name else { return };
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// rustfmt-single_line_let_else_max_width: 50
2+
3+
fn main() {
4+
let Some(a) = opt else {};
5+
6+
let Some(b) = opt else { return };
7+
8+
let Some(c) = opt else {
9+
return
10+
};
11+
12+
let Some(d) = some_very_very_very_very_long_name else { return };
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// rustfmt-single_line_let_else_max_width: 0
2+
3+
fn main() {
4+
let Some(a) = opt else {};
5+
6+
let Some(b) = opt else { return };
7+
8+
let Some(c) = opt else {
9+
return
10+
};
11+
12+
let Some(d) = some_very_very_very_very_long_name else { return };
13+
}

tests/source/configs/use_small_heuristics/default.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,13 @@ fn main() {
2323
sit
2424
};
2525
}
26+
27+
fn format_let_else() {
28+
let Some(a) = opt else {};
29+
30+
let Some(b) = opt else { return };
31+
32+
let Some(c) = opt else { return };
33+
34+
let Some(d) = some_very_very_very_very_long_name else { return };
35+
}

tests/source/configs/use_small_heuristics/max.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,13 @@ fn main() {
2323
sit
2424
};
2525
}
26+
27+
fn format_let_else() {
28+
let Some(a) = opt else {};
29+
30+
let Some(b) = opt else { return };
31+
32+
let Some(c) = opt else { return };
33+
34+
let Some(d) = some_very_very_very_very_long_name else { return };
35+
}

tests/source/configs/use_small_heuristics/off.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,13 @@ fn main() {
2323
sit
2424
};
2525
}
26+
27+
fn format_let_else() {
28+
let Some(a) = opt else {};
29+
30+
let Some(b) = opt else { return };
31+
32+
let Some(c) = opt else { return };
33+
34+
let Some(d) = some_very_very_very_very_long_name else { return };
35+
}

tests/source/let_else.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// rustfmt-single_line_let_else_max_width: 100
2+
13
fn main() {
24
// Although this won't compile it still parses so make sure we can format empty else blocks
35
let Some(x) = opt else {};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// rustfmt-single_line_let_else_max_width: 100
2+
3+
fn main() {
4+
let Some(a) = opt else {};
5+
6+
let Some(b) = opt else { return };
7+
8+
let Some(c) = opt else { return };
9+
10+
let Some(d) = some_very_very_very_very_long_name else { return };
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// rustfmt-single_line_let_else_max_width: 50
2+
3+
fn main() {
4+
let Some(a) = opt else {};
5+
6+
let Some(b) = opt else { return };
7+
8+
let Some(c) = opt else { return };
9+
10+
let Some(d) = some_very_very_very_very_long_name else {
11+
return;
12+
};
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// rustfmt-single_line_let_else_max_width: 0
2+
3+
fn main() {
4+
let Some(a) = opt else {};
5+
6+
let Some(b) = opt else {
7+
return;
8+
};
9+
10+
let Some(c) = opt else {
11+
return;
12+
};
13+
14+
let Some(d) = some_very_very_very_very_long_name else {
15+
return;
16+
};
17+
}

tests/target/configs/use_small_heuristics/default.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,15 @@ fn main() {
2424

2525
let lorem = if ipsum { dolor } else { sit };
2626
}
27+
28+
fn format_let_else() {
29+
let Some(a) = opt else {};
30+
31+
let Some(b) = opt else { return };
32+
33+
let Some(c) = opt else { return };
34+
35+
let Some(d) = some_very_very_very_very_long_name else {
36+
return;
37+
};
38+
}

tests/target/configs/use_small_heuristics/max.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,13 @@ fn main() {
1313

1414
let lorem = if ipsum { dolor } else { sit };
1515
}
16+
17+
fn format_let_else() {
18+
let Some(a) = opt else {};
19+
20+
let Some(b) = opt else { return };
21+
22+
let Some(c) = opt else { return };
23+
24+
let Some(d) = some_very_very_very_very_long_name else { return };
25+
}

tests/target/configs/use_small_heuristics/off.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,19 @@ fn main() {
2323
sit
2424
};
2525
}
26+
27+
fn format_let_else() {
28+
let Some(a) = opt else {};
29+
30+
let Some(b) = opt else {
31+
return;
32+
};
33+
34+
let Some(c) = opt else {
35+
return;
36+
};
37+
38+
let Some(d) = some_very_very_very_very_long_name else {
39+
return;
40+
};
41+
}

tests/target/let_else.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// rustfmt-single_line_let_else_max_width: 100
2+
13
fn main() {
24
// Although this won't compile it still parses so make sure we can format empty else blocks
35
let Some(x) = opt else {};

0 commit comments

Comments
 (0)