diff --git a/Configurations.md b/Configurations.md index c92be5df010..37cb7474130 100644 --- a/Configurations.md +++ b/Configurations.md @@ -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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `array_width` will take precedence. + +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `attr_fn_like_width` will take precedence. + +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) ## `binop_separator` @@ -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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `chain_width` will take precedence. + +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) ## `color` @@ -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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `fn_call_width` will take precedence. + +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) ## `fn_single_line` @@ -2079,6 +2124,18 @@ Don't reformat out of line modules - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: #3389) +## `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 `use_small_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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `single_line_if_else_max_width` will take precedence. + +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) + ## `space_after_colon` Leave a space after the colon. @@ -2256,6 +2313,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 `use_small_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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `struct_lit_width` will take precedence. + +See also [`max_width`](#max_width), [`use_small_heuristics`](#use_small_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 `use_small_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 [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `struct_variant_width` will take precedence. + +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) ## `tab_spaces` @@ -2448,13 +2528,43 @@ fn main() { ## `use_small_heuristics` -Whether to use different formatting for items and expressions if they satisfy a heuristic notion of 'small'. +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. + +Note that explicitly provided values for the width configuration settings take precedence and override the calculated values determined by `use_small_heuristics`. - **Default value**: `"Default"` - **Possible values**: `"Default"`, `"Off"`, `"Max"` - **Stable**: Yes #### `Default` (default): +When `use_small_heuristics` is set to `Default`, 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 { @@ -2485,6 +2595,7 @@ fn main() { ``` #### `Off`: +When `use_small_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 { @@ -2513,6 +2624,16 @@ fn main() { ``` #### `Max`: +When `use_small_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 { @@ -2530,6 +2651,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 diff --git a/src/attr.rs b/src/attr.rs index 015e9f9b252..0b5a0aba330 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -300,7 +300,7 @@ impl Rewrite for ast::MetaItem { // 1 = "]" shape.sub_width(1)?, self.span, - context.config.width_heuristics().attr_fn_like_width, + context.config.attr_fn_like_width(), Some(if has_trailing_comma { SeparatorTactic::Always } else { diff --git a/src/chains.rs b/src/chains.rs index ac14ec9e110..8053f0e8fec 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -577,7 +577,7 @@ impl<'a> ChainFormatterShared<'a> { let one_line_budget = if self.child_count == 1 { shape.width } else { - min(shape.width, context.config.width_heuristics().chain_width) + min(shape.width, context.config.chain_width()) } .saturating_sub(almost_total); diff --git a/src/config/config_type.rs b/src/config/config_type.rs index bd4a847e0f1..2f567b25521 100644 --- a/src/config/config_type.rs +++ b/src/config/config_type.rs @@ -95,7 +95,15 @@ macro_rules! create_config { pub fn $i(&mut self, value: $ty) { (self.0).$i.2 = value; match stringify!($i) { - "max_width" | "use_small_heuristics" => self.0.set_heuristics(), + "max_width" + | "use_small_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(), "merge_imports" => self.0.set_merge_imports(), &_ => (), @@ -230,7 +238,15 @@ macro_rules! create_config { } match key { - "max_width" | "use_small_heuristics" => self.set_heuristics(), + "max_width" + | "use_small_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(), "merge_imports" => self.set_merge_imports(), &_ => (), @@ -281,16 +297,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.use_small_heuristics.2 { + Heuristics::Default => + 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) { diff --git a/src/config/mod.rs b/src/config/mod.rs index dfce7977bfe..8c04363b1fd 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -35,9 +35,26 @@ create_config! { hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment"; tab_spaces: usize, 4, true, "Number of spaces per tab"; newline_style: NewlineStyle, NewlineStyle::Auto, true, "Unix or Windows line endings"; + indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items"; + + // Width Heuristics use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different \ formatting for items and expressions if they satisfy a heuristic notion of 'small'"; - indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items"; + width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false, + "'small' heuristic values"; + fn_call_width: usize, 60, true, "Maximum width of the args of a function call before \ + falling back to vertical formatting."; + attr_fn_like_width: usize, 70, true, "Maximum width of the args of a function-like \ + attributes before falling back to vertical formatting."; + struct_lit_width: usize, 18, true, "Maximum width in the body of a struct lit before \ + falling back to vertical formatting."; + struct_variant_width: usize, 35, true, "Maximum width in the body of a struct variant before \ + falling back to vertical formatting."; + array_width: usize, 60, true, "Maximum width of an array literal before falling \ + back to vertical formatting."; + 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."; // Comments. macros, and strings wrap_comments: bool, false, false, "Break comments to fit on the line"; @@ -154,8 +171,6 @@ create_config! { file_lines: FileLines, FileLines::all(), false, "Lines to format; this is not supported in rustfmt.toml, and can only be specified \ via the --file-lines option"; - width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false, - "'small' heuristic values"; emit_mode: EmitMode, EmitMode::Files, false, "What emit Mode to use when none is supplied"; make_backup: bool, false, false, "Backup changed files"; @@ -394,9 +409,6 @@ mod test { create_config! { // Options that are used by the generated functions max_width: usize, 100, true, "Maximum width of each line"; - use_small_heuristics: Heuristics, Heuristics::Default, true, - "Whether to use different formatting for items and \ - expressions if they satisfy a heuristic notion of 'small'."; license_template_path: String, String::default(), false, "Beginning of file must match license template"; required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false, @@ -408,13 +420,33 @@ mod test { file_lines: FileLines, FileLines::all(), false, "Lines to format; this is not supported in rustfmt.toml, and can only be specified \ via the --file-lines option"; - width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false, - "'small' heuristic values"; + // merge_imports deprecation imports_granularity: ImportGranularity, ImportGranularity::Preserve, false, "Merge imports"; merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)"; + // Width Heuristics + use_small_heuristics: Heuristics, Heuristics::Default, true, + "Whether to use different formatting for items and \ + expressions if they satisfy a heuristic notion of 'small'."; + width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false, + "'small' heuristic values"; + + fn_call_width: usize, 60, true, "Maximum width of the args of a function call before \ + falling back to vertical formatting."; + attr_fn_like_width: usize, 70, true, "Maximum width of the args of a function-like \ + attributes before falling back to vertical formatting."; + struct_lit_width: usize, 18, true, "Maximum width in the body of a struct lit before \ + falling back to vertical formatting."; + struct_variant_width: usize, 35, true, "Maximum width in the body of a struct \ + variant before falling back to vertical formatting."; + array_width: usize, 60, true, "Maximum width of an array literal before falling \ + back to vertical formatting."; + 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."; + // Options that are used by the tests stable_option: bool, false, true, "A stable option"; unstable_option: bool, false, false, "An unstable option"; @@ -519,8 +551,15 @@ mod test { hard_tabs = false tab_spaces = 4 newline_style = "Auto" -use_small_heuristics = "Default" indent_style = "Block" +use_small_heuristics = "Default" +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 wrap_comments = false format_code_in_doc_comments = false comment_width = 80 @@ -683,4 +722,242 @@ make_backup = false assert_eq!(config.imports_granularity(), ImportGranularity::Module); } } + + #[cfg(test)] + mod use_small_heuristics { + use super::*; + + #[test] + fn test_default_sets_correct_widths() { + let toml = r#" + use_small_heuristics = "Default" + max_width = 200 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), 120); + assert_eq!(config.attr_fn_like_width(), 140); + assert_eq!(config.chain_width(), 120); + assert_eq!(config.fn_call_width(), 120); + assert_eq!(config.single_line_if_else_max_width(), 100); + assert_eq!(config.struct_lit_width(), 36); + assert_eq!(config.struct_variant_width(), 70); + } + + #[test] + fn test_max_sets_correct_widths() { + let toml = r#" + use_small_heuristics = "Max" + max_width = 120 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), 120); + assert_eq!(config.attr_fn_like_width(), 120); + assert_eq!(config.chain_width(), 120); + assert_eq!(config.fn_call_width(), 120); + assert_eq!(config.single_line_if_else_max_width(), 120); + assert_eq!(config.struct_lit_width(), 120); + assert_eq!(config.struct_variant_width(), 120); + } + + #[test] + fn test_off_sets_correct_widths() { + let toml = r#" + use_small_heuristics = "Off" + max_width = 100 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), usize::max_value()); + assert_eq!(config.attr_fn_like_width(), usize::max_value()); + assert_eq!(config.chain_width(), usize::max_value()); + assert_eq!(config.fn_call_width(), usize::max_value()); + assert_eq!(config.single_line_if_else_max_width(), 0); + assert_eq!(config.struct_lit_width(), 0); + assert_eq!(config.struct_variant_width(), 0); + } + + #[test] + fn test_override_works_with_default() { + let toml = r#" + use_small_heuristics = "Default" + array_width = 20 + attr_fn_like_width = 40 + chain_width = 20 + fn_call_width = 90 + single_line_if_else_max_width = 40 + struct_lit_width = 30 + struct_variant_width = 34 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), 20); + assert_eq!(config.attr_fn_like_width(), 40); + assert_eq!(config.chain_width(), 20); + assert_eq!(config.fn_call_width(), 90); + assert_eq!(config.single_line_if_else_max_width(), 40); + assert_eq!(config.struct_lit_width(), 30); + assert_eq!(config.struct_variant_width(), 34); + } + + #[test] + fn test_override_with_max() { + let toml = r#" + use_small_heuristics = "Max" + array_width = 20 + attr_fn_like_width = 40 + chain_width = 20 + fn_call_width = 90 + single_line_if_else_max_width = 40 + struct_lit_width = 30 + struct_variant_width = 34 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), 20); + assert_eq!(config.attr_fn_like_width(), 40); + assert_eq!(config.chain_width(), 20); + assert_eq!(config.fn_call_width(), 90); + assert_eq!(config.single_line_if_else_max_width(), 40); + assert_eq!(config.struct_lit_width(), 30); + assert_eq!(config.struct_variant_width(), 34); + } + + #[test] + fn test_override_with_off() { + let toml = r#" + use_small_heuristics = "Off" + array_width = 20 + attr_fn_like_width = 40 + chain_width = 20 + fn_call_width = 90 + single_line_if_else_max_width = 40 + struct_lit_width = 30 + struct_variant_width = 34 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), 20); + assert_eq!(config.attr_fn_like_width(), 40); + assert_eq!(config.chain_width(), 20); + assert_eq!(config.fn_call_width(), 90); + assert_eq!(config.single_line_if_else_max_width(), 40); + assert_eq!(config.struct_lit_width(), 30); + assert_eq!(config.struct_variant_width(), 34); + } + + #[test] + fn test_fn_call_width_config_exceeds_max_width() { + let toml = r#" + max_width = 90 + fn_call_width = 95 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.fn_call_width(), 90); + } + + #[test] + fn test_attr_fn_like_width_config_exceeds_max_width() { + let toml = r#" + max_width = 80 + attr_fn_like_width = 90 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.attr_fn_like_width(), 80); + } + + #[test] + fn test_struct_lit_config_exceeds_max_width() { + let toml = r#" + max_width = 78 + struct_lit_width = 90 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.struct_lit_width(), 78); + } + + #[test] + fn test_struct_variant_width_config_exceeds_max_width() { + let toml = r#" + max_width = 80 + struct_variant_width = 90 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.struct_variant_width(), 80); + } + + #[test] + fn test_array_width_config_exceeds_max_width() { + let toml = r#" + max_width = 60 + array_width = 80 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.array_width(), 60); + } + + #[test] + fn test_chain_width_config_exceeds_max_width() { + let toml = r#" + max_width = 80 + chain_width = 90 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.chain_width(), 80); + } + + #[test] + fn test_single_line_if_else_max_width_config_exceeds_max_width() { + let toml = r#" + max_width = 70 + single_line_if_else_max_width = 90 + "#; + let config = Config::from_toml(toml, Path::new("")).unwrap(); + assert_eq!(config.single_line_if_else_max_width(), 70); + } + + #[test] + fn test_override_fn_call_width_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("fn_call_width", "101"); + assert_eq!(config.fn_call_width(), 100); + } + + #[test] + fn test_override_attr_fn_like_width_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("attr_fn_like_width", "101"); + assert_eq!(config.attr_fn_like_width(), 100); + } + + #[test] + fn test_override_struct_lit_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("struct_lit_width", "101"); + assert_eq!(config.struct_lit_width(), 100); + } + + #[test] + fn test_override_struct_variant_width_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("struct_variant_width", "101"); + assert_eq!(config.struct_variant_width(), 100); + } + + #[test] + fn test_override_array_width_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("array_width", "101"); + assert_eq!(config.array_width(), 100); + } + + #[test] + fn test_override_chain_width_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("chain_width", "101"); + assert_eq!(config.chain_width(), 100); + } + + #[test] + fn test_override_single_line_if_else_max_width_exceeds_max_width() { + let mut config = Config::default(); + config.override_value("single_line_if_else_max_width", "101"); + assert_eq!(config.single_line_if_else_max_width(), 100); + } + } } diff --git a/src/config/options.rs b/src/config/options.rs index c0491630c00..3b91021813c 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -79,13 +79,15 @@ pub enum TypeDensity { } #[config_type] -/// To what extent does rustfmt pursue its heuristics? +/// Heuristic settings that can be used to simply +/// the configuration of the granular width configurations +/// like `struct_lit_width`, `array_width`, etc. pub enum Heuristics { /// Turn off any heuristics Off, /// Turn on max heuristics Max, - /// Use Rustfmt's defaults + /// Use scaled values based on the value of `max_width` Default, } diff --git a/src/expr.rs b/src/expr.rs index d3fd22653b4..ced382c4915 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -899,22 +899,11 @@ impl<'a> ControlFlow<'a> { || last_line_offsetted(shape.used_width(), &pat_expr_string)); // Try to format if-else on single line. - if self.allow_single_line - && context - .config - .width_heuristics() - .single_line_if_else_max_width - > 0 - { + if self.allow_single_line && context.config.single_line_if_else_max_width() > 0 { let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width); if let Some(cond_str) = trial { - if cond_str.len() - <= context - .config - .width_heuristics() - .single_line_if_else_max_width - { + if cond_str.len() <= context.config.single_line_if_else_max_width() { return Some((cond_str, 0)); } } @@ -1246,7 +1235,7 @@ pub(crate) fn rewrite_call( args.iter(), shape, span, - context.config.width_heuristics().fn_call_width, + context.config.fn_call_width(), choose_separator_tactic(context, span), ) } @@ -1785,7 +1774,7 @@ pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>( items, shape, span, - context.config.width_heuristics().fn_call_width, + context.config.fn_call_width(), force_tactic, ) } else { diff --git a/src/items.rs b/src/items.rs index 61b49911e76..ecbd0bd12ec 100644 --- a/src/items.rs +++ b/src/items.rs @@ -505,8 +505,8 @@ impl<'a> FmtVisitor<'a> { ) .collect() }; - let mut items: Vec<_> = - itemize_list_with(self.config.width_heuristics().struct_variant_width); + let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width()); + // If one of the variants use multiple lines, use multi-lined formatting for all variants. let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n')); let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n')); @@ -1479,7 +1479,7 @@ fn format_tuple_struct( fields.iter(), shape, span, - context.config.width_heuristics().fn_call_width, + context.config.fn_call_width(), None, )?; } diff --git a/src/lists.rs b/src/lists.rs index bc55ef6686a..ccf8f784c04 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -863,7 +863,7 @@ pub(crate) fn struct_lit_shape( }; let shape_width = shape.width.checked_sub(prefix_width + suffix_width); if let Some(w) = shape_width { - let shape_width = cmp::min(w, context.config.width_heuristics().struct_lit_width); + let shape_width = cmp::min(w, context.config.struct_lit_width()); Some((Some(Shape::legacy(shape_width, shape.indent)), v_shape)) } else { Some((None, v_shape)) diff --git a/src/macros.rs b/src/macros.rs index 190f4b599b0..52534b216a6 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -382,7 +382,7 @@ fn rewrite_macro_inner( arg_vec.iter(), shape, mac.span(), - context.config.width_heuristics().fn_call_width, + context.config.fn_call_width(), if trailing_comma { Some(SeparatorTactic::Always) } else { diff --git a/src/overflow.rs b/src/overflow.rs index f1b870101e5..d670b0a41e8 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -318,7 +318,7 @@ pub(crate) fn rewrite_with_square_brackets<'a, T: 'a + IntoOverflowableItem<'a>> span, lhs, rhs, - context.config.width_heuristics().array_width, + context.config.array_width(), force_separator_tactic, Some(("[", "]")), ) diff --git a/tests/source/configs/chain_width/always.rs b/tests/source/configs/chain_width/always.rs new file mode 100644 index 00000000000..2d16d66aec1 --- /dev/null +++ b/tests/source/configs/chain_width/always.rs @@ -0,0 +1,23 @@ +// rustfmt-chain_width: 1 +// setting an unachievable chain_width to always get chains +// on separate lines + +struct Fluent {} + +impl Fluent { + fn blorp(&self) -> &Self { + self + } +} + +fn main() { + let test = Fluent {}; + + // should be left alone + test.blorp(); + + // should be wrapped + test.blorp().blorp(); + test.blorp().blorp().blorp(); + test.blorp().blorp().blorp().blorp(); +} diff --git a/tests/source/configs/chain_width/small.rs b/tests/source/configs/chain_width/small.rs new file mode 100644 index 00000000000..26f9354537a --- /dev/null +++ b/tests/source/configs/chain_width/small.rs @@ -0,0 +1,23 @@ +// rustfmt-chain_width: 40 + +struct Fluent {} + +impl Fluent { + fn blorp(&self) -> &Self { + self + } +} + +fn main() { + let test = Fluent {}; + + // should not be wrapped + test.blorp(); + test.blorp().blorp(); + test.blorp().blorp().blorp(); + test.blorp().blorp().blorp().blorp(); + + // should be wrapped + test.blorp().blorp().blorp().blorp().blorp(); + test.blorp().blorp().blorp().blorp().blorp().blorp(); +} diff --git a/tests/source/configs/chain_width/tiny.rs b/tests/source/configs/chain_width/tiny.rs new file mode 100644 index 00000000000..fffc81dd5d6 --- /dev/null +++ b/tests/source/configs/chain_width/tiny.rs @@ -0,0 +1,21 @@ +// rustfmt-chain_width: 20 + +struct Fluent {} + +impl Fluent { + fn blorp(&self) -> &Self { + self + } +} + +fn main() { + let test = Fluent {}; + + // should not be wrapped + test.blorp(); + test.blorp().blorp(); + + // should be wrapped + test.blorp().blorp().blorp(); + test.blorp().blorp().blorp().blorp(); +} diff --git a/tests/source/configs/use_small_heuristics/default.rs b/tests/source/configs/use_small_heuristics/default.rs new file mode 100644 index 00000000000..68bc40271a1 --- /dev/null +++ b/tests/source/configs/use_small_heuristics/default.rs @@ -0,0 +1,25 @@ +// rustfmt-use_small_heuristics: Default + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { + amet: Consectetur, + adipiscing: Elit, + }, +} + +fn main() { + lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); + + let lorem = Lorem { + ipsum: dolor, + sit: amet, + }; + + let lorem = if ipsum { + dolor + } else { + sit + }; +} diff --git a/tests/source/configs/use_small_heuristics/off.rs b/tests/source/configs/use_small_heuristics/off.rs new file mode 100644 index 00000000000..f76392d2404 --- /dev/null +++ b/tests/source/configs/use_small_heuristics/off.rs @@ -0,0 +1,25 @@ +// rustfmt-use_small_heuristics: Off + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { + amet: Consectetur, + adipiscing: Elit, + }, +} + +fn main() { + lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); + + let lorem = Lorem { + ipsum: dolor, + sit: amet, + }; + + let lorem = if ipsum { + dolor + } else { + sit + }; +} diff --git a/tests/target/configs/chain_width/always.rs b/tests/target/configs/chain_width/always.rs new file mode 100644 index 00000000000..b16d25251f6 --- /dev/null +++ b/tests/target/configs/chain_width/always.rs @@ -0,0 +1,29 @@ +// rustfmt-chain_width: 1 +// setting an unachievable chain_width to always get chains +// on separate lines + +struct Fluent {} + +impl Fluent { + fn blorp(&self) -> &Self { + self + } +} + +fn main() { + let test = Fluent {}; + + // should be left alone + test.blorp(); + + // should be wrapped + test.blorp() + .blorp(); + test.blorp() + .blorp() + .blorp(); + test.blorp() + .blorp() + .blorp() + .blorp(); +} diff --git a/tests/target/configs/chain_width/small.rs b/tests/target/configs/chain_width/small.rs new file mode 100644 index 00000000000..2f2f72777f8 --- /dev/null +++ b/tests/target/configs/chain_width/small.rs @@ -0,0 +1,32 @@ +// rustfmt-chain_width: 40 + +struct Fluent {} + +impl Fluent { + fn blorp(&self) -> &Self { + self + } +} + +fn main() { + let test = Fluent {}; + + // should not be wrapped + test.blorp(); + test.blorp().blorp(); + test.blorp().blorp().blorp(); + test.blorp().blorp().blorp().blorp(); + + // should be wrapped + test.blorp() + .blorp() + .blorp() + .blorp() + .blorp(); + test.blorp() + .blorp() + .blorp() + .blorp() + .blorp() + .blorp(); +} diff --git a/tests/target/configs/chain_width/tiny.rs b/tests/target/configs/chain_width/tiny.rs new file mode 100644 index 00000000000..960d245f8a1 --- /dev/null +++ b/tests/target/configs/chain_width/tiny.rs @@ -0,0 +1,26 @@ +// rustfmt-chain_width: 20 + +struct Fluent {} + +impl Fluent { + fn blorp(&self) -> &Self { + self + } +} + +fn main() { + let test = Fluent {}; + + // should not be wrapped + test.blorp(); + test.blorp().blorp(); + + // should be wrapped + test.blorp() + .blorp() + .blorp(); + test.blorp() + .blorp() + .blorp() + .blorp(); +} diff --git a/tests/target/configs/use_small_heuristics/default.rs b/tests/target/configs/use_small_heuristics/default.rs new file mode 100644 index 00000000000..d67bd9aafaf --- /dev/null +++ b/tests/target/configs/use_small_heuristics/default.rs @@ -0,0 +1,26 @@ +// rustfmt-use_small_heuristics: Default + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { amet: Consectetur, adipiscing: Elit }, +} + +fn main() { + lorem( + "lorem", + "ipsum", + "dolor", + "sit", + "amet", + "consectetur", + "adipiscing", + ); + + let lorem = Lorem { + ipsum: dolor, + sit: amet, + }; + + let lorem = if ipsum { dolor } else { sit }; +} diff --git a/tests/target/configs/use_small_heuristics/off.rs b/tests/target/configs/use_small_heuristics/off.rs new file mode 100644 index 00000000000..f76392d2404 --- /dev/null +++ b/tests/target/configs/use_small_heuristics/off.rs @@ -0,0 +1,25 @@ +// rustfmt-use_small_heuristics: Off + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { + amet: Consectetur, + adipiscing: Elit, + }, +} + +fn main() { + lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); + + let lorem = Lorem { + ipsum: dolor, + sit: amet, + }; + + let lorem = if ipsum { + dolor + } else { + sit + }; +} diff --git a/tests/target/issue_4049.rs b/tests/target/issue_4049.rs new file mode 100644 index 00000000000..fe025a0f649 --- /dev/null +++ b/tests/target/issue_4049.rs @@ -0,0 +1,26 @@ +// rustfmt-max_width: 110 +// rustfmt-use_small_heuristics: Max +// rustfmt-hard_tabs: true +// rustfmt-use_field_init_shorthand: true +// rustfmt-overflow_delimited_expr: true + +// https://github.com/rust-lang/rustfmt/issues/4049 +fn foo() { + { + { + if let Some(MpcEv::PlayDrum(pitch, vel)) = + // self.mpc.handle_input(e, /*btn_ctrl_down,*/ tx_launch_to_daw, state_view) + self.mpc.handle_input(e, &mut MyBorrowedState { tx_launch_to_daw, state_view }) + { + println!("bar"); + } + + if let Some(e) = + // self.note_input.handle_input(e, /*btn_ctrl_down,*/ tx_launch_to_daw, state_view) + self.note_input.handle_input(e, &mut MyBorrowedState { tx_launch_to_daw, state_view }) + { + println!("baz"); + } + } + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy