Skip to content

Commit

Permalink
Add option to vertically align enum discriminants.
Browse files Browse the repository at this point in the history
  • Loading branch information
moxian committed Sep 26, 2018
1 parent 90692a5 commit cc22869
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 3 deletions.
46 changes: 46 additions & 0 deletions Configurations.md
Expand Up @@ -885,6 +885,52 @@ impl Lorem {
See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_style).


## `enum_discrim_align_threshold`

The maximum diff of width between enum variants to have discriminants aligned with each other.
Variants without discriminants would be ignored for the purpose of alignment.

- **Default value** : 0
- **Possible values**: any positive integer
- **Stable**: No

#### `0` (default):

```rust
enum Foo {
A = 0,
Bb = 1,
RandomLongVariantWithoutDiscriminant,
Ccc = 71,
}

enum Bar {
A = 0,
Bb = 1,
ThisOneisWithDiscriminantAndPreventsAlignment = 10,
Ccc = 71,
}
```

#### `20`:

```rust
enum Foo {
A = 0,
Bb = 1,
RandomLongVariantWithoutDiscriminant,
Ccc = 2,
}

enum Bar {
A = 0,
Bb = 1,
ThisOneisWithDiscriminantAndPreventsAlignment = 10,
Ccc = 71,
}
```


## `fn_single_line`

Put single-expression functions on a single line
Expand Down
2 changes: 2 additions & 0 deletions src/config/mod.rs
Expand Up @@ -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,
Expand Down
33 changes: 30 additions & 3 deletions src/items.rs
Expand Up @@ -500,6 +500,24 @@ 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 it does not result in too much padding
let pad_discrim_ident_to;
let diff_threshold = 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();
let shortest_w_discr = *discr_ident_lens.iter().min().unwrap_or(&0);
let longest_w_discr = *discr_ident_lens.iter().max().unwrap_or(&0);
if longest_w_discr > shortest_w_discr + diff_threshold {
pad_discrim_ident_to = 0;
} else {
pad_discrim_ident_to = longest_w_discr;
}

let itemize_list_with = |one_line_width: usize| {
itemize_list(
self.snippet_provider,
Expand All @@ -514,7 +532,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,
Expand Down Expand Up @@ -543,7 +561,12 @@ impl<'a> FmtVisitor<'a> {
}

// Variant of an enum.
fn format_variant(&self, field: &ast::Variant, one_line_width: usize) -> Option<String> {
fn format_variant(
&self,
field: &ast::Variant,
one_line_width: usize,
pad_discrim_ident_to: usize,
) -> Option<String> {
if contains_skip(&field.node.attrs) {
let lo = field.node.attrs[0].span.lo();
let span = mk_sp(lo, field.span.hi());
Expand All @@ -570,7 +593,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()
Expand Down
28 changes: 28 additions & 0 deletions tests/source/configs/enum_discrim_align_threshold/20.rs
@@ -0,0 +1,28 @@
// rustfmt-enum_discrim_align_threshold: 20

enum Standard {
A = 1,
Bcdef = 2,
}

enum Mixed {
ThisIsAFairlyLongEnumVariantWithoutDiscrim,
A = 1,
ThisIsAFairlyLongEnumVariantWithoutDiscrim2,
Bcdef = 2,
}

enum TooLong {
ThisOneHasDiscrimAaaaaaaaaaaaaaaaaaaaaaaaaaaa = 10,
A = 1,
Bcdef = 2,
}

// Live specimen from #1686
enum LongWithSmallDiff {
SceneColorimetryEstimates = 0x73636F65,
SceneAppearanceEstimates = 0x73617065,
FocalPlaneColorimetryEstimates = 0x66706365,
ReflectionHardcopyOriginalColorimetry = 0x72686F63,
ReflectionPrintOutputColorimetry = 0x72706F63,
}
28 changes: 28 additions & 0 deletions tests/target/configs/enum_discrim_align_threshold/20.rs
@@ -0,0 +1,28 @@
// rustfmt-enum_discrim_align_threshold: 20

enum Standard {
A = 1,
Bcdef = 2,
}

enum Mixed {
ThisIsAFairlyLongEnumVariantWithoutDiscrim,
A = 1,
ThisIsAFairlyLongEnumVariantWithoutDiscrim2,
Bcdef = 2,
}

enum TooLong {
ThisOneHasDiscrimAaaaaaaaaaaaaaaaaaaaaaaaaaaa = 10,
A = 1,
Bcdef = 2,
}

// Live specimen from #1686
enum LongWithSmallDiff {
SceneColorimetryEstimates = 0x73636F65,
SceneAppearanceEstimates = 0x73617065,
FocalPlaneColorimetryEstimates = 0x66706365,
ReflectionHardcopyOriginalColorimetry = 0x72686F63,
ReflectionPrintOutputColorimetry = 0x72706F63,
}

0 comments on commit cc22869

Please sign in to comment.