Merge pull request #1910 from topecongiro/config-merge_derives

Add merge_derives config option
This commit is contained in:
Nick Cameron 2017-08-25 07:36:04 +12:00 committed by GitHub
commit 1a02c35f9b
6 changed files with 179 additions and 20 deletions

View file

@ -1230,7 +1230,7 @@ Put a match sub-patterns' separator (`|`) in front or back.
- **Default value**: `"Back"`
- **Possible values**: `"Back"`, `"Front"`
#### `"Back"`
#### `"Back"`:
```rust
match m {
@ -1243,7 +1243,7 @@ match m {
}
```
#### `Front`
#### `Front`:
```rust
match m {
@ -1265,6 +1265,29 @@ Maximum width of each line
See also [`error_on_line_overflow`](#error_on_line_overflow).
## `merge_derives`
Merge multiple derives into a single one.
- **Default value**: `true`
- **Possible values**: `true`, `false`
#### `true`:
```rust
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Foo {}
```
#### `false`:
```rust
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum Foo {}
```
## `multiline_closure_forces_block`
Force multiline closure bodies to be wrapped in a block
@ -1272,6 +1295,18 @@ Force multiline closure bodies to be wrapped in a block
- **Default value**: `false`
- **Possible values**: `false`, `true`
#### `true`:
```rust
result.and_then(|maybe_value| {
match maybe_value {
None => ...,
Some(value) => ...,
}
})
```
#### `false`:
```rust
@ -1281,17 +1316,6 @@ result.and_then(|maybe_value| match maybe_value {
})
```
#### `true`:
```rust
result.and_then(|maybe_value| {
match maybe_value {
None => ...,
Some(value) => ...,
}
})
```
## `multiline_match_arm_forces_block`
Force multiline match arm bodies to be wrapped in a block

View file

@ -619,6 +619,7 @@ create_config! {
"Force multiline closure bodies to be wrapped in a block";
multiline_match_arm_forces_block: bool, false,
"Force multiline match arm bodies to be wrapped in a block";
merge_derives: bool, true, "Merge multiple `#[derive(...)]` into a single one";
}
#[cfg(test)]

View file

@ -19,10 +19,10 @@ use config::{Config, IndentStyle};
use rewrite::RewriteContext;
use utils::{first_line_width, last_line_width, mk_sp};
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
/// Formatting tactic for lists. This will be cast down to a
/// DefinitiveListTactic depending on the number and length of the items and
/// their comments.
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum ListTactic {
// One item per row.
Vertical,
@ -144,8 +144,8 @@ impl ListItem {
}
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
/// The definitive formatting tactic for lists.
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum DefinitiveListTactic {
Vertical,
Horizontal,

View file

@ -925,7 +925,10 @@ impl<'a> Rewrite for [ast::Attribute] {
}
let indent = shape.indent.to_string(context.config);
for (i, a) in self.iter().enumerate() {
let mut derive_args = Vec::new();
let mut iter = self.iter().enumerate().peekable();
while let Some((i, a)) = iter.next() {
let a_str = try_opt!(a.rewrite(context, shape));
// Write comments and blank lines between attributes.
@ -952,17 +955,62 @@ impl<'a> Rewrite for [ast::Attribute] {
} else if multi_line {
result.push('\n');
}
result.push_str(&indent);
if derive_args.is_empty() {
result.push_str(&indent);
}
}
// Write the attribute itself.
result.push_str(&a_str);
let mut insert_new_line = true;
if context.config.merge_derives() {
// If the attribute is `#[derive(...)]`, take the arguments.
if let Some(mut args) = get_derive_args(context, a) {
derive_args.append(&mut args);
match iter.peek() {
// If the next attribute is `#[derive(...)]` as well, skip rewriting.
Some(&(_, next_attr)) if is_derive(next_attr) => insert_new_line = false,
// If not, rewrite the merged derives.
_ => {
result.push_str(&format!("#[derive({})]", derive_args.join(", ")));
derive_args.clear();
}
}
} else {
result.push_str(&a_str);
}
} else {
result.push_str(&a_str);
}
if i < self.len() - 1 {
if insert_new_line && i < self.len() - 1 {
result.push('\n');
}
}
Some(result)
}
}
fn is_derive(attr: &ast::Attribute) -> bool {
match attr.meta() {
Some(meta_item) => match meta_item.node {
ast::MetaItemKind::List(..) => meta_item.name.as_str() == "derive",
_ => false,
},
_ => false,
}
}
/// Returns the arguments of `#[derive(...)]`.
fn get_derive_args(context: &RewriteContext, attr: &ast::Attribute) -> Option<Vec<String>> {
attr.meta().and_then(|meta_item| match meta_item.node {
ast::MetaItemKind::List(ref args) if meta_item.name.as_str() == "derive" => {
// Every argument of `derive` should be `NestedMetaItemKind::Literal`.
Some(
args.iter()
.map(|a| context.snippet(a.span))
.collect::<Vec<_>>(),
)
}
_ => None,
})
}

View file

@ -0,0 +1,46 @@
// rustfmt-merge_derives: true
// Merge multiple derives to a single one.
#[bar]
#[derive(Eq, PartialEq)]
#[foo]
#[derive(Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Foo {}
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Bar {}
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum FooBar {}
mod foo {
#[bar]
#[derive(Eq, PartialEq)]
#[foo]
#[derive(Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Foo {}
}
mod bar {
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Bar {}
}
mod foobar {
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum FooBar {}
}

View file

@ -0,0 +1,40 @@
// rustfmt-merge_derives: true
// Merge multiple derives to a single one.
#[bar]
#[derive(Eq, PartialEq)]
#[foo]
#[derive(Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Foo {}
#[derive(Eq, PartialEq, Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Bar {}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum FooBar {}
mod foo {
#[bar]
#[derive(Eq, PartialEq)]
#[foo]
#[derive(Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Foo {}
}
mod bar {
#[derive(Eq, PartialEq, Debug)]
#[foobar]
#[derive(Copy, Clone)]
pub enum Bar {}
}
mod foobar {
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum FooBar {}
}