Skip to content

Commit

Permalink
Update width heuristic configuration (#4063)
Browse files Browse the repository at this point in the history
  • Loading branch information
calebcartwright authored Apr 18, 2020
1 parent 9ace1de commit f1a44c5
Show file tree
Hide file tree
Showing 20 changed files with 645 additions and 68 deletions.
142 changes: 137 additions & 5 deletions Configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@ To enable unstable options, set `unstable_features = true` in `rustfmt.toml` or

Below you find a detailed visual guide on all the supported configuration options of rustfmt:

## `array_width`

Maximum width of an array literal before falling back to vertical formatting.

- **Default value**: `60`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `array_width` will take precedence.

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

## `attr_fn_like_width`

Maximum width of the args of a function-like attributes before falling back to vertical formatting.

- **Default value**: `70`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `attr_fn_like_width` will take precedence.

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

## `binop_separator`

Expand Down Expand Up @@ -272,6 +295,17 @@ where
}
```

## `chain_width`

Maximum width of a chain to fit on one line.

- **Default value**: `60`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `chain_width` will take precedence.

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

## `color`

Expand Down Expand Up @@ -717,6 +751,17 @@ trait Lorem {
}
```

## `fn_call_width`

Maximum width of the args of a function call before falling back to vertical formatting.

- **Default value**: `60`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `fn_call_width` will take precedence.

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

## `fn_single_line`

Expand Down Expand Up @@ -1881,6 +1926,18 @@ specific version of rustfmt is used in your CI, use this option.
- **Possible values**: any published version (e.g. `"0.3.8"`)
- **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386))

## `single_line_if_else_max_width`

Maximum line length for single line if-else expressions. A value of `0` (zero) results in if-else expressions always being broken into multiple lines. Note this occurs when `width_heuristics` is set to `Off`.

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

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `single_line_if_else_max_width` will take precedence.

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

## `space_after_colon`

Leave a space after the colon.
Expand Down Expand Up @@ -2080,6 +2137,29 @@ fn main() {

See also: [`indent_style`](#indent_style).

## `struct_lit_width`

Maximum width in the body of a struct literal before falling back to vertical formatting. A value of `0` (zero) results in struct literals always being broken into multiple lines. Note this occurs when `width_heuristics` is set to `Off`.

- **Default value**: `18`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `struct_lit_width` will take precedence.

See also [`max_width`](#max_width), [`width_heuristics`](#width_heuristics), and [`struct_lit_single_line`](#struct_lit_single_line)

## `struct_variant_width`

Maximum width in the body of a struct variant before falling back to vertical formatting. A value of `0` (zero) results in struct literals always being broken into multiple lines. Note this occurs when `width_heuristics` is set to `Off`.

- **Default value**: `35`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes

By default this option is set as a percentage of [`max_width`](#max_width) provided by [`width_heuristics`](#width_heuristics), but a value set directly for `struct_variant_width` will take precedence.

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

## `tab_spaces`

Expand Down Expand Up @@ -2270,15 +2350,45 @@ fn main() {
}
```

## `use_small_heuristics`
## `width_heuristics`

This option can be used to simplify the management and bulk updates of the granular width configuration settings ([`fn_call_width`](#fn_call_width), [`attr_fn_like_width`](#attr_fn_like_width), [`struct_lit_width`](#struct_lit_width), [`struct_variant_width`](#struct_variant_width), [`array_width`](#array_width), [`chain_width`](#chain_width), [`single_line_if_else_max_width`](#single_line_if_else_max_width)), that respectively control when formatted constructs are multi-lined/vertical based on width.

Whether to use different formatting for items and expressions if they satisfy a heuristic notion of 'small'.
Note that explicitly provided values for the width configuration settings take precedence and override the calculated values determined by `width_heuristics`.

- **Default value**: `"Default"`
- **Possible values**: `"Default"`, `"Off"`, `"Max"`
- **Default value**: `"Scaled"`
- **Possible values**: `"Scaled"`, `"Off"`, `"Max"`
- **Stable**: Yes

#### `Default` (default):
#### `Scaled` (default):
When `width_heuristics` is set to `Scaled`, the values for the granular width settings are calculated as a ratio of the value for `max_width`.

The ratios are:
* [`fn_call_width`](#fn_call_width) - `60%`
* [`attr_fn_like_width`](#attr_fn_like_width) - `70%`
* [`struct_lit_width`](#struct_lit_width) - `18%`
* [`struct_variant_width`](#struct_variant_width) - `35%`
* [`array_width`](#array_width) - `60%`
* [`chain_width`](#chain_width) - `60%`
* [`single_line_if_else_max_width`](#single_line_if_else_max_width) - `50%`

For example when `max_width` is set to `100`, the width settings are:
* `fn_call_width=60`
* `attr_fn_like_width=70`
* `struct_lit_width=18`
* `struct_variant_width=35`
* `array_width=60`
* `chain_width=60`
* `single_line_if_else_max_width=50`

and when `max_width` is set to `200`:
* `fn_call_width=120`
* `attr_fn_like_width=140`
* `struct_lit_width=36`
* `struct_variant_width=70`
* `array_width=120`
* `chain_width=120`
* `single_line_if_else_max_width=100`

```rust
enum Lorem {
Expand Down Expand Up @@ -2309,6 +2419,7 @@ fn main() {
```

#### `Off`:
When `width_heuristics` is set to `Off`, the granular width settings are functionally disabled and ignored. See the documentation for the respective width config options for specifics.

```rust
enum Lorem {
Expand Down Expand Up @@ -2337,6 +2448,16 @@ fn main() {
```

#### `Max`:
When `width_heuristics` is set to `Max`, then each granular width setting is set to the same value as `max_width`.

So if `max_width` is set to `200`, then all the width settings are also set to `200`.
* `fn_call_width=200`
* `attr_fn_like_width=200`
* `struct_lit_width=200`
* `struct_variant_width=200`
* `array_width=200`
* `chain_width=200`
* `single_line_if_else_max_width=200`

```rust
enum Lorem {
Expand All @@ -2354,6 +2475,17 @@ fn main() {
}
```


See also:
* [`max_width`](#max_width)
* [`fn_call_width`](#fn_call_width)
* [`attr_fn_like_width`](#attr_fn_like_width)
* [`struct_lit_width`](#struct_lit_width)
* [`struct_variant_width`](#struct_variant_width)
* [`array_width`](#array_width)
* [`chain_width`](#chain_width)
* [`single_line_if_else_max_width`](#single_line_if_else_max_width)

## `use_try_shorthand`

Replace uses of the try! macro by the ? shorthand
Expand Down
119 changes: 106 additions & 13 deletions rustfmt-core/rustfmt-config/src/config_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,15 @@ macro_rules! create_config {
(self.0).$i.1 = true;
(self.0).$i.2 = value;
match stringify!($i) {
"max_width" | "use_small_heuristics" => self.0.set_heuristics(),
"max_width"
| "width_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
| "array_width"
| "chain_width" => self.0.set_heuristics(),
"license_template_path" => self.0.set_license_template(),
&_ => (),
}
Expand Down Expand Up @@ -228,16 +236,24 @@ macro_rules! create_config {
}

match key {
"max_width" | "use_small_heuristics" => self.set_heuristics(),
"max_width"
| "width_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
| "array_width"
| "chain_width" => self.set_heuristics(),
"license_template_path" => self.set_license_template(),
&_ => (),
}
}

#[allow(unreachable_pub)]
pub fn is_hidden_option(name: &str) -> bool {
const HIDE_OPTIONS: [&str; 6] = [
"verbose", "verbose_diff", "file_lines", "width_heuristics",
const HIDE_OPTIONS: [&str; 5] = [
"verbose", "verbose_diff", "file_lines",
"recursive", "print_misformatted_file_names",
];
HIDE_OPTIONS.contains(&name)
Expand Down Expand Up @@ -280,16 +296,93 @@ macro_rules! create_config {
)+
}

fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
let max_width = self.max_width.2;
let get_width_value = |
was_set: bool,
override_value: usize,
heuristic_value: usize,
config_key: &str,
| -> usize {
if !was_set {
return heuristic_value;
}
if override_value > max_width {
eprintln!(
"`{0}` cannot have a value that exceeds `max_width`. \
`{0}` will be set to the same value as `max_width`",
config_key,
);
return max_width;
}
override_value
};

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

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

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

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

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

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

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

fn set_heuristics(&mut self) {
if self.use_small_heuristics.2 == Heuristics::Default {
let max_width = self.max_width.2;
self.set().width_heuristics(WidthHeuristics::scaled(max_width));
} else if self.use_small_heuristics.2 == Heuristics::Max {
let max_width = self.max_width.2;
self.set().width_heuristics(WidthHeuristics::set(max_width));
} else {
self.set().width_heuristics(WidthHeuristics::null());
}
let max_width = self.max_width.2;
match self.width_heuristics.2 {
Heuristics::Scaled =>
self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
};
}

fn set_license_template(&mut self) {
Expand Down
Loading

0 comments on commit f1a44c5

Please sign in to comment.