Skip to content

Commit

Permalink
implement single_line_let_else_max_width
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ytmimi committed Jun 20, 2023
1 parent 9386b32 commit 32fdb2d
Show file tree
Hide file tree
Showing 19 changed files with 258 additions and 7 deletions.
69 changes: 69 additions & 0 deletions Configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2392,6 +2392,70 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi

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

## `single_line_let_else_max_width`

Maximum line length for single line let-else statements.
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.
A value of `0` (zero) means the divergent `else block` will always be formatted over multiple lines.
Note this occurs when `use_small_heuristics` is set to `Off`.

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.

- **Default value**: `50`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: No (tracking issue: [N/A]())

#### `50` (default):

```rust
fn main() {
let Some(x) = opt else { return };

let Some(x) = some_very_very_very_very_long_name else {
return;
};

let Some(y) = opt else {
return;
};
}
```

#### `0`:

```rust
fn main() {
let Some(x) = opt else {
return;
};

let Some(x) = some_very_very_very_very_long_name else {
return;
};

let Some(y) = opt else {
return;
};
}
```

#### `100`:

```rust
fn main() {
let Some(x) = opt else { return };

let Some(x) = some_very_very_very_very_long_name else { return };

let Some(y) = opt else {
return;
};
}
```

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


## `space_after_colon`

Leave a space after the colon.
Expand Down Expand Up @@ -2804,6 +2868,7 @@ The ratios are:
* [`array_width`](#array_width) - `60%`
* [`chain_width`](#chain_width) - `60%`
* [`single_line_if_else_max_width`](#single_line_if_else_max_width) - `50%`
* [`single_line_let_else_max_width`](#single_line_let_else_max_width) - `50%`

For example when `max_width` is set to `100`, the width settings are:
* `fn_call_width=60`
Expand All @@ -2813,6 +2878,7 @@ For example when `max_width` is set to `100`, the width settings are:
* `array_width=60`
* `chain_width=60`
* `single_line_if_else_max_width=50`
* `single_line_let_else_max_width=50`

and when `max_width` is set to `200`:
* `fn_call_width=120`
Expand All @@ -2822,6 +2888,7 @@ and when `max_width` is set to `200`:
* `array_width=120`
* `chain_width=120`
* `single_line_if_else_max_width=100`
* `single_line_let_else_max_width=100`

```rust
enum Lorem {
Expand Down Expand Up @@ -2891,6 +2958,7 @@ So if `max_width` is set to `200`, then all the width settings are also set to `
* `array_width=200`
* `chain_width=200`
* `single_line_if_else_max_width=200`
* `single_line_let_else_max_width=200`

```rust
enum Lorem {
Expand Down Expand Up @@ -2918,6 +2986,7 @@ See also:
* [`array_width`](#array_width)
* [`chain_width`](#chain_width)
* [`single_line_if_else_max_width`](#single_line_if_else_max_width)
* [`single_line_let_else_max_width`](#single_line_let_else_max_width)

## `use_try_shorthand`

Expand Down
10 changes: 10 additions & 0 deletions src/config/config_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ macro_rules! create_config {
| "use_small_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
| "single_line_let_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
Expand Down Expand Up @@ -269,6 +270,7 @@ macro_rules! create_config {
| "use_small_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
| "single_line_let_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
Expand Down Expand Up @@ -407,6 +409,14 @@ macro_rules! create_config {
"single_line_if_else_max_width",
);
self.single_line_if_else_max_width.2 = single_line_if_else_max_width;

let single_line_let_else_max_width = get_width_value(
self.was_set().single_line_let_else_max_width(),
self.single_line_let_else_max_width.2,
heuristics.single_line_let_else_max_width,
"single_line_let_else_max_width",
);
self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
}

fn set_heuristics(&mut self) {
Expand Down
7 changes: 7 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ create_config! {
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single line if-else \
expressions. A value of zero means always break if-else expressions.";
single_line_let_else_max_width: usize, 50, false, "Maximum line length for single line \
let-else statements. A value of zero means always format the divergent `else block` \
over multiple lines.";

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

// Options that are used by the tests
stable_option: bool, false, true, "A stable option";
Expand Down Expand Up @@ -619,6 +625,7 @@ struct_variant_width = 35
array_width = 60
chain_width = 60
single_line_if_else_max_width = 50
single_line_let_else_max_width = 50
wrap_comments = false
format_code_in_doc_comments = false
doc_comment_code_block_width = 100
Expand Down
6 changes: 6 additions & 0 deletions src/config/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ pub struct WidthHeuristics {
// Maximum line length for single line if-else expressions. A value
// of zero means always break if-else expressions.
pub(crate) single_line_if_else_max_width: usize,
// Maximum line length for single line let-else statements. A value of zero means
// always format the divergent `else block` over multiple lines."
pub(crate) single_line_let_else_max_width: usize,
}

impl fmt::Display for WidthHeuristics {
Expand All @@ -255,6 +258,7 @@ impl WidthHeuristics {
array_width: usize::max_value(),
chain_width: usize::max_value(),
single_line_if_else_max_width: 0,
single_line_let_else_max_width: 0,
}
}

Expand All @@ -267,6 +271,7 @@ impl WidthHeuristics {
array_width: max_width,
chain_width: max_width,
single_line_if_else_max_width: max_width,
single_line_let_else_max_width: max_width,
}
}

Expand All @@ -288,6 +293,7 @@ impl WidthHeuristics {
array_width: (60.0 * max_width_ratio).round() as usize,
chain_width: (60.0 * max_width_ratio).round() as usize,
single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
}
}
}
Expand Down
21 changes: 14 additions & 7 deletions src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,24 @@ impl Rewrite for ast::Local {
);
result.push_str(&else_kw);

let allow_single_line = allow_single_line_let_else_block(&result, block);
let max_width =
std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
let available_space = max_width.saturating_sub(result.len());

let allow_single_line = !force_newline_else
&& available_space > 0
&& allow_single_line_let_else_block(&result, block);

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

if allow_single_line && !rw_else_block.contains('\n') {
let available_space = shape.width.saturating_sub(result.len());
if available_space <= rw_else_block.len() {
// writing this on one line would exceed the available width
rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
}
let single_line_else = !rw_else_block.contains('\n');
let else_block_exceeds_width = available_space <= rw_else_block.len();

if allow_single_line && single_line_else && else_block_exceeds_width {
// writing this on one line would exceed the available width
// so rewrite the else block over multiple lines.
rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
}

result.push_str(&rw_else_block);
Expand Down
13 changes: 13 additions & 0 deletions tests/source/configs/single_line_let_else_max_width/100.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// rustfmt-single_line_let_else_max_width: 100

fn main() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else {
return
};

let Some(d) = some_very_very_very_very_long_name else { return };
}
13 changes: 13 additions & 0 deletions tests/source/configs/single_line_let_else_max_width/50.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// rustfmt-single_line_let_else_max_width: 50

fn main() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else {
return
};

let Some(d) = some_very_very_very_very_long_name else { return };
}
13 changes: 13 additions & 0 deletions tests/source/configs/single_line_let_else_max_width/zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// rustfmt-single_line_let_else_max_width: 0

fn main() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else {
return
};

let Some(d) = some_very_very_very_very_long_name else { return };
}
10 changes: 10 additions & 0 deletions tests/source/configs/use_small_heuristics/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ fn main() {
sit
};
}

fn format_let_else() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else { return };
}
10 changes: 10 additions & 0 deletions tests/source/configs/use_small_heuristics/max.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ fn main() {
sit
};
}

fn format_let_else() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else { return };
}
10 changes: 10 additions & 0 deletions tests/source/configs/use_small_heuristics/off.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ fn main() {
sit
};
}

fn format_let_else() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else { return };
}
2 changes: 2 additions & 0 deletions tests/source/let_else.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// rustfmt-single_line_let_else_max_width: 100

fn main() {
// Although this won't compile it still parses so make sure we can format empty else blocks
let Some(x) = opt else {};
Expand Down
11 changes: 11 additions & 0 deletions tests/target/configs/single_line_let_else_max_width/100.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// rustfmt-single_line_let_else_max_width: 100

fn main() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else { return };
}
13 changes: 13 additions & 0 deletions tests/target/configs/single_line_let_else_max_width/50.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// rustfmt-single_line_let_else_max_width: 50

fn main() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else {
return;
};
}
17 changes: 17 additions & 0 deletions tests/target/configs/single_line_let_else_max_width/zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// rustfmt-single_line_let_else_max_width: 0

fn main() {
let Some(a) = opt else {};

let Some(b) = opt else {
return;
};

let Some(c) = opt else {
return;
};

let Some(d) = some_very_very_very_very_long_name else {
return;
};
}
12 changes: 12 additions & 0 deletions tests/target/configs/use_small_heuristics/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,15 @@ fn main() {

let lorem = if ipsum { dolor } else { sit };
}

fn format_let_else() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else {
return;
};
}
10 changes: 10 additions & 0 deletions tests/target/configs/use_small_heuristics/max.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,13 @@ fn main() {

let lorem = if ipsum { dolor } else { sit };
}

fn format_let_else() {
let Some(a) = opt else {};

let Some(b) = opt else { return };

let Some(c) = opt else { return };

let Some(d) = some_very_very_very_very_long_name else { return };
}
Loading

0 comments on commit 32fdb2d

Please sign in to comment.