Add config options for formatting macro matchers and bodies

Closes #2753
This commit is contained in:
Nick Cameron 2018-07-18 12:03:59 +12:00
parent b27d544478
commit 79c5ee8b42
3 changed files with 108 additions and 15 deletions

View File

@ -1006,6 +1006,76 @@ fn main() {
See also [`max_width`](#max_width).
## `format_macro_matchers`
Format the metavariable matching patterns in macros.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No
#### `false` (default):
```rust
macro_rules! foo {
($a: ident : $b: ty) => {
$a(42): $b;
};
($a: ident $b: ident $c: ident) => {
$a = $b + $c;
};
}
```
#### `true`:
```rust
macro_rules! foo {
($a:ident : $b:ty) => {
$a(42): $b;
};
($a:ident $b:ident $c:ident) => {
$a = $b + $c;
};
}
```
See also [`format_macro_bodies`](#format_macro_bodies).
## `format_macro_bodies`
Format the bodies of macros.
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No
#### `true` (default):
```rust
macro_rules! foo {
($a:ident : $b:ty) => {
$a(42): $b;
};
($a:ident $b:ident $c:ident) => {
$a = $b + $c;
};
}
```
#### `false`:
```rust
macro_rules! foo {
($a:ident : $b:ty) => { $a(42): $b; };
($a:ident $b:ident $c:ident) => { $a=$b+$c; };
}
```
See also [`format_macro_matchers`](#format_macro_matchers).
## `hard_tabs`
Use tab characters for indentation, spaces for alignment

View File

@ -42,10 +42,10 @@ create_config! {
tab_spaces: usize, 4, true, "Number of spaces per tab";
newline_style: NewlineStyle, NewlineStyle::Native, true, "Unix or Windows line endings";
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.";
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";
// Comments and strings
// Comments. macros, and strings
wrap_comments: bool, false, false, "Break comments to fit on the line";
comment_width: usize, 80, false,
"Maximum length of comments. No effect unless wrap_comments = true";
@ -53,6 +53,9 @@ create_config! {
license_template_path: String, String::default(), false,
"Beginning of file must match license template";
format_strings: bool, false, false, "Format string literals where necessary";
format_macro_matchers: bool, true, false,
"Format the metavariable matching patterns in macros";
format_macro_bodies: bool, true, false, "Format the bodies of macros";
// Single line expressions and items
empty_item_single_line: bool, true, false,
@ -79,13 +82,13 @@ create_config! {
space_after_colon: bool, true, false, "Leave a space after the colon";
spaces_around_ranges: bool, false, false, "Put spaces around the .. and ..= range operators";
binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
"Where to put a binary operator when a binary expression goes multiline.";
"Where to put a binary operator when a binary expression goes multiline";
// Misc.
remove_nested_parens: bool, true, true, "Remove nested parens.";
combine_control_expr: bool, true, false, "Combine control expressions with function calls.";
remove_nested_parens: bool, true, true, "Remove nested parens";
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.";
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,
@ -101,10 +104,10 @@ create_config! {
match_block_trailing_comma: bool, false, false,
"Put a trailing comma after a block based match arm (non-block arms are not affected)";
blank_lines_upper_bound: usize, 1, false,
"Maximum number of blank lines which can be put between items.";
"Maximum number of blank lines which can be put between items";
blank_lines_lower_bound: usize, 0, false,
"Minimum number of blank lines which must be put between items.";
edition: Edition, Edition::Edition2015, false, "The edition of the parser. (RFC 2052)";
"Minimum number of blank lines which must be put between items";
edition: Edition, Edition::Edition2015, false, "The edition of the parser (RFC 2052)";
// 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";
@ -118,7 +121,7 @@ create_config! {
color: Color, Color::Auto, false,
"What Color option to use when none is supplied: Always, Never, Auto";
required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
"Require a specific version of rustfmt.";
"Require a specific version of rustfmt";
unstable_features: bool, false, false,
"Enables unstable features. Only available on nightly channel";
disable_all_formatting: bool, false, false, "Don't reformat anything";
@ -133,7 +136,7 @@ create_config! {
report_fixme: ReportTactic, ReportTactic::Never, false,
"Report all, none or unnumbered occurrences of FIXME in source file comments";
ignore: IgnoreList, IgnoreList::default(), false,
"Skip formatting the specified files and directories.";
"Skip formatting the specified files and directories";
// Not user-facing
verbose: Verbosity, Verbosity::Normal, false, "How much to information to emit to the user";

View File

@ -938,10 +938,22 @@ fn format_macro_args(
toks: ThinTokenStream,
shape: Shape,
) -> Option<String> {
if !context.config.format_macro_matchers() {
let token_stream: TokenStream = toks.into();
let span = span_for_token_stream(token_stream);
return Some(match span {
Some(span) => context.snippet(span).to_owned(),
None => String::new(),
});
}
let parsed_args = MacroArgParser::new().parse(toks)?;
wrap_macro_args(context, &parsed_args, shape)
}
fn span_for_token_stream(token_stream: TokenStream) -> Option<Span> {
token_stream.trees().next().map(|tt| tt.span())
}
// We should insert a space if the next token is a:
#[derive(Copy, Clone, PartialEq)]
enum SpaceState {
@ -1172,13 +1184,14 @@ impl MacroParser {
TokenTree::Token(_, Token::FatArrow) => {}
_ => return None,
}
let (mut hi, body) = match self.toks.next()? {
let (mut hi, body, whole_body) = match self.toks.next()? {
TokenTree::Token(..) => return None,
TokenTree::Delimited(sp, _) => {
let data = sp.data();
(
data.hi,
Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt),
sp,
)
}
};
@ -1191,6 +1204,7 @@ impl MacroParser {
args_paren_kind,
args,
body,
whole_body,
})
}
}
@ -1207,6 +1221,7 @@ struct MacroBranch {
args_paren_kind: DelimToken,
args: ThinTokenStream,
body: Span,
whole_body: Span,
}
impl MacroBranch {
@ -1229,6 +1244,12 @@ impl MacroBranch {
result += " =>";
}
if !context.config.format_macro_bodies() {
result += " ";
result += context.snippet(self.whole_body);
return Some(result);
}
// The macro body is the most interesting part. It might end up as various
// AST nodes, but also has special variables (e.g, `$foo`) which can't be
// parsed as regular Rust code (and note that these can be escaped using
@ -1237,14 +1258,13 @@ impl MacroBranch {
let old_body = context.snippet(self.body).trim();
let (body_str, substs) = replace_names(old_body)?;
let has_block_body = old_body.starts_with('{');
let mut config = context.config.clone();
config.set().hide_parse_errors(true);
result += " {";
let has_block_body = old_body.starts_with('{');
let body_indent = if has_block_body {
shape.indent
} else {