diff --git a/Configurations.md b/Configurations.md index ac638ff91e6..7598057d70b 100644 --- a/Configurations.md +++ b/Configurations.md @@ -573,7 +573,6 @@ impl Lorem { See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_style). - ## `enum_discrim_align_threshold` The maximum length of enum variant having discriminant, that gets vertically aligned with others. @@ -620,6 +619,74 @@ enum Bar { } ``` +## `enum_variant_layout` + +Control the layout of enum variants. + +- **Default value**: `"Tall"` +- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` +- **Stable**: No + +#### `"Tall"` (default): + +```rust +enum MyType { + A { + field1: bool, + field2: bool, + }, + #[something] + B { + field1: bool, + field2: bool, + }, +} + +enum T { + A { fieldA: T }, + B { fieldB: U }, +} +``` + +#### `"Compressed"` + +```rust +enum MyType { + A { field1: bool, field2: bool }, + #[something] + B { field1: bool, field2: bool }, +} + +enum T { + A { fieldA: T }, + B { fieldB: U }, +} +``` + +#### `"Vertical"` + +```rust +enum MyType { + A { + field1: bool, + field2: bool, + }, + #[something] + B { + field1: bool, + field2: bool, + }, +} + +enum T { + A { + fieldA: T, + }, + B { + fieldB: U, + }, +} +``` ## `error_on_line_overflow` diff --git a/src/config/mod.rs b/src/config/mod.rs index 14f27f3f8b6..57aa4c35a4c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -148,6 +148,8 @@ create_config! { "Write an item and its attribute on the same line \ if their combined width is below a threshold"; format_generated_files: bool, true, false, "Format generated files"; + enum_variant_layout: Density, Density::Tall, false, + "Control the layout of enum variants"; // Options that can change the source code beyond whitespace/blocks (somewhat linty things) merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one"; @@ -667,6 +669,7 @@ edition = "2015" version = "One" inline_attribute_width = 0 format_generated_files = true +enum_variant_layout = "Tall" merge_derives = true use_try_shorthand = false use_field_init_shorthand = false diff --git a/src/items.rs b/src/items.rs index 3c5293b6bf5..8900a8edbaf 100644 --- a/src/items.rs +++ b/src/items.rs @@ -14,13 +14,15 @@ use crate::comment::{ recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment, FindUncommented, }; -use crate::config::lists::*; +use crate::config::{lists::*, Density}; use crate::config::{BraceStyle, Config, IndentStyle, Version}; use crate::expr::{ is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with, rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics, }; -use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}; +use crate::lists::{ + definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator, +}; use crate::macros::{rewrite_macro, MacroPosition}; use crate::overflow; use crate::rewrite::{Rewrite, RewriteContext}; @@ -515,11 +517,32 @@ impl<'a> FmtVisitor<'a> { }; let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width()); + let is_multiline_variant = |item: &ListItem| { + item.inner_as_ref() + .lines() + .skip_while(|l| { + if self.config.enum_variant_layout() == Density::Compressed { + l.trim_start().starts_with("#") || l.trim_start().starts_with("///") + } else { + false + } + }) + .count() + > 1 + }; + // 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')); - if has_multiline_variant && has_single_line_variant { - items = itemize_list_with(0); + let has_multiline_variant = items.iter().any(|item| is_multiline_variant(item)); + let has_single_line_variant = items + .iter() + .any(|item| item.inner_as_ref().lines().count() == 1); + + match self.config.enum_variant_layout() { + Density::Vertical => items = itemize_list_with(0), + Density::Tall if has_multiline_variant && has_single_line_variant => { + items = itemize_list_with(0) + } + _ => {} } let shape = self.shape().sub_width(2)?; diff --git a/tests/source/configs/enum_variant_layout/compressed.rs b/tests/source/configs/enum_variant_layout/compressed.rs new file mode 100644 index 00000000000..3b95d5adebb --- /dev/null +++ b/tests/source/configs/enum_variant_layout/compressed.rs @@ -0,0 +1,20 @@ +// rustfmt-enum_variant_layout: Compressed + +pub enum MultiAndSingleLine { + A { field1: () }, + #[attr] + B { field1 : (), field2: (), }, +} + +enum SingleLine { + A { field: () }, + B { test: () }, +} + +enum MyType { + A { field1: bool, field2: bool }, + B { field1: bool, field2: bool }, + /// OMG a comment + C { field1: bool, field2: bool }, + D { field1: bool, field2: bool }, +} \ No newline at end of file diff --git a/tests/source/configs/enum_variant_layout/tall.rs b/tests/source/configs/enum_variant_layout/tall.rs new file mode 100644 index 00000000000..f0d47d7d881 --- /dev/null +++ b/tests/source/configs/enum_variant_layout/tall.rs @@ -0,0 +1,12 @@ +// rustfmt-enum_variant_layout: Tall + +pub enum MultiAndSingleLine { + A { field1: () }, + #[attr] + B { field1 : (), field2: (), }, +} + +enum SingleLine { + A { field: () }, + B { test: () }, +} \ No newline at end of file diff --git a/tests/source/configs/enum_variant_layout/vertical.rs b/tests/source/configs/enum_variant_layout/vertical.rs new file mode 100644 index 00000000000..7aad8a6b01e --- /dev/null +++ b/tests/source/configs/enum_variant_layout/vertical.rs @@ -0,0 +1,12 @@ +// rustfmt-enum_variant_layout: Vertical + +pub enum MultiAndSingleLine { + A { field1: () }, + #[attr] + B { field1: (), field2: (), }, +} + +enum SingleLine { + A { field: () }, + B { test: () }, +} \ No newline at end of file diff --git a/tests/target/configs/enum_variant_layout/compressed.rs b/tests/target/configs/enum_variant_layout/compressed.rs new file mode 100644 index 00000000000..b44c3e26dab --- /dev/null +++ b/tests/target/configs/enum_variant_layout/compressed.rs @@ -0,0 +1,20 @@ +// rustfmt-enum_variant_layout: Compressed + +pub enum MultiAndSingleLine { + A { field1: () }, + #[attr] + B { field1: (), field2: () }, +} + +enum SingleLine { + A { field: () }, + B { test: () }, +} + +enum MyType { + A { field1: bool, field2: bool }, + B { field1: bool, field2: bool }, + /// OMG a comment + C { field1: bool, field2: bool }, + D { field1: bool, field2: bool }, +} diff --git a/tests/target/configs/enum_variant_layout/tall.rs b/tests/target/configs/enum_variant_layout/tall.rs new file mode 100644 index 00000000000..987df785714 --- /dev/null +++ b/tests/target/configs/enum_variant_layout/tall.rs @@ -0,0 +1,17 @@ +// rustfmt-enum_variant_layout: Tall + +pub enum MultiAndSingleLine { + A { + field1: (), + }, + #[attr] + B { + field1: (), + field2: (), + }, +} + +enum SingleLine { + A { field: () }, + B { test: () }, +} diff --git a/tests/target/configs/enum_variant_layout/vertical.rs b/tests/target/configs/enum_variant_layout/vertical.rs new file mode 100644 index 00000000000..e613c906cee --- /dev/null +++ b/tests/target/configs/enum_variant_layout/vertical.rs @@ -0,0 +1,21 @@ +// rustfmt-enum_variant_layout: Vertical + +pub enum MultiAndSingleLine { + A { + field1: (), + }, + #[attr] + B { + field1: (), + field2: (), + }, +} + +enum SingleLine { + A { + field: (), + }, + B { + test: (), + }, +}