diff --git a/Configurations.md b/Configurations.md index 8861d7b2a13..824868bca09 100644 --- a/Configurations.md +++ b/Configurations.md @@ -885,6 +885,53 @@ 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. +Variants without discriminants would be ignored for the purpose of alignment. + +Note that this is not how much whitespace is inserted, but instead the longest variant name that +doesn't get ignored when aligning. + +- **Default value** : 0 +- **Possible values**: any positive integer +- **Stable**: No + +#### `0` (default): + +```rust +enum Bar { + A = 0, + Bb = 1, + RandomLongVariantGoesHere = 10, + Ccc = 71, +} + +enum Bar { + VeryLongVariantNameHereA = 0, + VeryLongVariantNameHereBb = 1, + VeryLongVariantNameHereCcc = 2, +} +``` + +#### `20`: + +```rust +enum Foo { + A = 0, + Bb = 1, + RandomLongVariantGoesHere = 10, + Ccc = 2, +} + +enum Bar { + VeryLongVariantNameHereA = 0, + VeryLongVariantNameHereBb = 1, + VeryLongVariantNameHereCcc = 2, +} +``` + + ## `fn_single_line` Put single-expression functions on a single line diff --git a/src/config/mod.rs b/src/config/mod.rs index 52401a18d92..a553bf2ee3c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -89,6 +89,8 @@ create_config! { combine_control_expr: bool, true, false, "Combine control expressions with function calls"; struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \ threshold"; + enum_discrim_align_threshold: usize, 0, false, + "Align enum variants discrims, if their diffs fit within threshold"; match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \ the same line with the pattern of arms"; force_multiline_blocks: bool, false, false, diff --git a/src/items.rs b/src/items.rs index a7ba48776d6..17a9e529692 100644 --- a/src/items.rs +++ b/src/items.rs @@ -500,6 +500,23 @@ impl<'a> FmtVisitor<'a> { let original_offset = self.block_indent; self.block_indent = self.block_indent.block_indent(self.config); + // If enum variants have discriminants, try to vertically align those, + // provided the discrims are not shifted too much to the right + let align_threshold: usize = self.config.enum_discrim_align_threshold(); + let discr_ident_lens: Vec = enum_def + .variants + .iter() + .filter(|var| var.node.disr_expr.is_some()) + .map(|var| rewrite_ident(&self.get_context(), var.node.ident).len()) + .collect(); + // cut the list at the point of longest discrim shorter than the threshold + // All of the discrims under the threshold will get padded, and all above - left as is. + let pad_discrim_ident_to = *discr_ident_lens + .iter() + .filter(|&l| *l <= align_threshold) + .max() + .unwrap_or(&0); + let itemize_list_with = |one_line_width: usize| { itemize_list( self.snippet_provider, @@ -514,7 +531,7 @@ impl<'a> FmtVisitor<'a> { } }, |f| f.span.hi(), - |f| self.format_variant(f, one_line_width), + |f| self.format_variant(f, one_line_width, pad_discrim_ident_to), body_lo, body_hi, false, @@ -543,7 +560,12 @@ impl<'a> FmtVisitor<'a> { } // Variant of an enum. - fn format_variant(&self, field: &ast::Variant, one_line_width: usize) -> Option { + fn format_variant( + &self, + field: &ast::Variant, + one_line_width: usize, + pad_discrim_ident_to: usize, + ) -> Option { if contains_skip(&field.node.attrs) { let lo = field.node.attrs[0].span.lo(); let span = mk_sp(lo, field.span.hi()); @@ -570,7 +592,11 @@ impl<'a> FmtVisitor<'a> { )?, ast::VariantData::Unit(..) => { if let Some(ref expr) = field.node.disr_expr { - let lhs = format!("{} =", rewrite_ident(&context, field.node.ident)); + let lhs = format!( + "{:1$} =", + rewrite_ident(&context, field.node.ident), + pad_discrim_ident_to + ); rewrite_assign_rhs(&context, lhs, &*expr.value, shape)? } else { rewrite_ident(&context, field.node.ident).to_owned() diff --git a/tests/source/configs/enum_discrim_align_threshold/40.rs b/tests/source/configs/enum_discrim_align_threshold/40.rs new file mode 100644 index 00000000000..796e47c384b --- /dev/null +++ b/tests/source/configs/enum_discrim_align_threshold/40.rs @@ -0,0 +1,34 @@ +// rustfmt-enum_discrim_align_threshold: 40 + +enum Standard { + A = 1, + Bcdef = 2, +} + +enum NoDiscrims { + ThisIsAFairlyLongEnumVariantWithoutDiscrimLongerThan40, + A = 1, + ThisIsAnotherFairlyLongEnumVariantWithoutDiscrimLongerThan40, + Bcdef = 2, +} + +enum TooLong { + ThisOneHasDiscrimAaaaaaaaaaaaaaaaaaaaaaChar40 = 10, + A = 1, + Bcdef = 2, +} + +enum Borderline { + ThisOneHasDiscrimAaaaaaaaaaaaaaaaaaaaaa = 10, + A = 1, + Bcdef = 2, +} + +// Live specimen from #1686 +enum LongWithSmallDiff { + SceneColorimetryEstimates = 0x73636F65, + SceneAppearanceEstimates = 0x73617065, + FocalPlaneColorimetryEstimates = 0x66706365, + ReflectionHardcopyOriginalColorimetry = 0x72686F63, + ReflectionPrintOutputColorimetry = 0x72706F63, +} \ No newline at end of file diff --git a/tests/target/configs/enum_discrim_align_threshold/40.rs b/tests/target/configs/enum_discrim_align_threshold/40.rs new file mode 100644 index 00000000000..3ed66039c9d --- /dev/null +++ b/tests/target/configs/enum_discrim_align_threshold/40.rs @@ -0,0 +1,34 @@ +// rustfmt-enum_discrim_align_threshold: 40 + +enum Standard { + A = 1, + Bcdef = 2, +} + +enum NoDiscrims { + ThisIsAFairlyLongEnumVariantWithoutDiscrimLongerThan40, + A = 1, + ThisIsAnotherFairlyLongEnumVariantWithoutDiscrimLongerThan40, + Bcdef = 2, +} + +enum TooLong { + ThisOneHasDiscrimAaaaaaaaaaaaaaaaaaaaaaChar40 = 10, + A = 1, + Bcdef = 2, +} + +enum Borderline { + ThisOneHasDiscrimAaaaaaaaaaaaaaaaaaaaaa = 10, + A = 1, + Bcdef = 2, +} + +// Live specimen from #1686 +enum LongWithSmallDiff { + SceneColorimetryEstimates = 0x73636F65, + SceneAppearanceEstimates = 0x73617065, + FocalPlaneColorimetryEstimates = 0x66706365, + ReflectionHardcopyOriginalColorimetry = 0x72686F63, + ReflectionPrintOutputColorimetry = 0x72706F63, +}