diff --git a/Configurations.md b/Configurations.md index 2a9df314417e..a0e3e63c74e6 100644 --- a/Configurations.md +++ b/Configurations.md @@ -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 diff --git a/src/config/mod.rs b/src/config/mod.rs index baf1982639c0..af344a8720ab 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -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"; diff --git a/src/macros.rs b/src/macros.rs index 76f50b30a545..4f3891fbf495 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -938,10 +938,22 @@ fn format_macro_args( toks: ThinTokenStream, shape: Shape, ) -> Option { + 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 { + 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 {