From 90b6b87b43394f69b9296769ef9f575074cbef3a Mon Sep 17 00:00:00 2001 From: ruin Date: Fri, 16 Jun 2017 14:55:24 -0500 Subject: [PATCH 01/11] Commit draft of match_align_arms --- src/config.rs | 9 +- src/expr.rs | 195 ++++++++++++------ src/items.rs | 132 +++++------- src/lib.rs | 9 + .../source/configs-match_align_arms-always.rs | 38 ++++ .../source/configs-match_align_arms-never.rs | 25 +++ .../configs-match_align_arms-preserve.rs | 25 +++ .../target/configs-match_align_arms-always.rs | 38 ++++ .../target/configs-match_align_arms-never.rs | 25 +++ .../configs-match_align_arms-preserve.rs | 25 +++ 10 files changed, 384 insertions(+), 137 deletions(-) create mode 100644 tests/source/configs-match_align_arms-always.rs create mode 100644 tests/source/configs-match_align_arms-never.rs create mode 100644 tests/source/configs-match_align_arms-preserve.rs create mode 100644 tests/target/configs-match_align_arms-always.rs create mode 100644 tests/target/configs-match_align_arms-never.rs create mode 100644 tests/target/configs-match_align_arms-preserve.rs diff --git a/src/config.rs b/src/config.rs index 153fad178cc..bae23a7823e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -93,6 +93,12 @@ configuration_option_enum! { TypeDensity: Wide, } +configuration_option_enum! { MatchAlignArms: + Always, + Preserve, + Never, +} + impl Density { pub fn to_list_tactic(self) -> ListTactic { @@ -598,7 +604,8 @@ create_config! { "What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage"; condense_wildcard_suffixes: bool, false, "Replace strings of _ wildcards by a single .. in \ tuple patterns"; - combine_control_expr: bool, true, "Combine control expressions with funciton calls." + combine_control_expr: bool, true, "Combine control expressions with funciton calls."; + match_align_arms: MatchAlignArms, MatchAlignArms::Never, "Align match arms" } #[cfg(test)] diff --git a/src/expr.rs b/src/expr.rs index 892e6ef905e..87da763be29 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -23,7 +23,7 @@ use utils::{extra_offset, last_line_width, wrap_str, binary_search, first_line_w semicolon_for_stmt, trimmed_last_line_width, left_most_sub_expr, stmt_expr, colon_spaces, contains_skip, mk_sp}; use visitor::FmtVisitor; -use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style}; +use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style, MatchAlignArms}; use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed}; use types::{rewrite_path, PathContext, can_be_overflowed_type}; use items::{span_lo_for_arg, span_hi_for_arg}; @@ -360,8 +360,9 @@ where // This is needed in case of line break not caused by a // shortage of space, but by end-of-line comments, for example. if !rhs_result.contains('\n') { - let lhs_shape = - try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width(infix.len())); + let lhs_shape = try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width( + infix.len(), + )); let lhs_result = lhs.rewrite(context, lhs_shape); if let Some(lhs_result) = lhs_result { let mut result = format!("{}{}{}", prefix, lhs_result, infix); @@ -450,11 +451,9 @@ where let nested_shape = match context.config.array_layout() { IndentStyle::Block => shape.block().block_indent(context.config.tab_spaces()), IndentStyle::Visual => { - try_opt!( - shape - .visual_indent(bracket_size) - .sub_width(bracket_size * 2) - ) + try_opt!(shape.visual_indent(bracket_size).sub_width( + bracket_size * 2, + )) } }; @@ -477,9 +476,9 @@ where } } - let has_long_item = items - .iter() - .any(|li| li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false)); + let has_long_item = items.iter().any(|li| { + li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false) + }); let tactic = match context.config.array_layout() { IndentStyle::Block => { @@ -755,14 +754,14 @@ fn and_one_line(x: Option) -> Option { fn nop_block_collapse(block_str: Option, budget: usize) -> Option { debug!("nop_block_collapse {:?} {}", block_str, budget); - block_str.map(|block_str| { - if block_str.starts_with('{') && budget >= 2 && - (block_str[1..].find(|c: char| !c.is_whitespace()).unwrap() == block_str.len() - 2) - { - "{}".to_owned() - } else { - block_str.to_owned() - } + block_str.map(|block_str| if block_str.starts_with('{') && budget >= 2 && + (block_str[1..] + .find(|c: char| !c.is_whitespace()) + .unwrap() == block_str.len() - 2) + { + "{}".to_owned() + } else { + block_str.to_owned() }) } @@ -1479,13 +1478,61 @@ fn rewrite_match( }; let mut result = format!("match {}{}{{", cond_str, block_sep); - let arm_shape = if context.config.indent_match_arms() { - shape.block_indent(context.config.tab_spaces()) - } else { - shape.block_indent(0) - }; + let mut arm_shapes = Vec::new(); + + let mut furthest_arrow_pos = 0; + let mut furthest_pat_pos = 0; + let mut should_preserve_align = true; + if let Some(arm) = arms.first() { + furthest_arrow_pos = arm_arrow_pos(arm); + furthest_pat_pos = arm_pat_end_pos_relative(arm); + } - let arm_indent_str = arm_shape.indent.to_string(context.config); + for arm in arms.iter() { + let arrow_pos = arm_arrow_pos(arm); + let pat_pos = arm_pat_end_pos_relative(arm); + + if arrow_pos != furthest_arrow_pos { + should_preserve_align = false; + } + + if arrow_pos > furthest_arrow_pos { + furthest_arrow_pos = arrow_pos; + } + + if pat_pos > furthest_pat_pos { + furthest_pat_pos = pat_pos; + } + } + + for arm in arms.iter() { + let alignment = match context.config.match_align_arms() { + MatchAlignArms::Always => { + if should_preserve_align { + arm_arrow_spacing(arm) + } else { + furthest_pat_pos - arm_pat_end_pos_relative(arm) + } + } + MatchAlignArms::Preserve => { + if should_preserve_align { + arm_arrow_spacing(arm) + } else { + 0 + } + } + MatchAlignArms::Never => 0, + }; + + let mut arm_shape = if context.config.indent_match_arms() { + shape.block_indent(context.config.tab_spaces()) + } else { + shape.block_indent(0) + }; + + arm_shape.alignment = alignment; + arm_shapes.push(arm_shape); + } let open_brace_pos = context.codemap.span_after( mk_sp(cond.span.hi, arm_start_pos(&arms[0])), @@ -1493,6 +1540,9 @@ fn rewrite_match( ); for (i, arm) in arms.iter().enumerate() { + let arm_shape = arm_shapes[i]; + let arm_indent_str = arm_shape.indent.to_string(context.config); + // Make sure we get the stuff between arms. let missed_str = if i == 0 { context.snippet(mk_sp(open_brace_pos, arm_start_pos(arm))) @@ -1519,14 +1569,17 @@ fn rewrite_match( result.push_str(arm_comma(context.config, &arm.body)); } } + let last_arm_shape = arm_shapes[arms.len() - 1]; + let last_arm_indent_str = last_arm_shape.indent.to_string(context.config); + // BytePos(1) = closing match brace. let last_span = mk_sp(arm_end_pos(&arms[arms.len() - 1]), span.hi - BytePos(1)); let last_comment = context.snippet(last_span); let comment = try_opt!(rewrite_match_arm_comment( context, &last_comment, - arm_shape, - &arm_indent_str, + last_arm_shape, + &last_arm_indent_str, )); result.push_str(&comment); result.push('\n'); @@ -1552,6 +1605,24 @@ fn arm_end_pos(arm: &ast::Arm) -> BytePos { arm.body.span.hi } +fn arm_pat_end_pos_relative(arm: &ast::Arm) -> usize { + let &ast::Arm { ref pats, .. } = arm; + (pats[pats.len() - 1].span.hi - pats[0].span.lo).0 as usize +} + +fn arm_arrow_pos(arm: &ast::Arm) -> usize { + let &ast::Arm { ref body, ref pats, .. } = arm; + let pat_start_pos = pats[0].span.lo; + // 3 = `=> `.len() + (body.span.lo - pat_start_pos).0 as usize - 3 +} + +fn arm_arrow_spacing(arm: &ast::Arm) -> usize { + let pat_end_rel = arm_pat_end_pos_relative(arm); + let arrow_pos = arm_arrow_pos(arm); + arrow_pos - pat_end_rel - 1 +} + fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str { if config.match_block_trailing_comma() { "," @@ -1653,6 +1724,11 @@ impl Rewrite for ast::Arm { let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config); + let mut alignment_str = String::with_capacity(shape.alignment); + for _ in 0..shape.alignment { + alignment_str.push(' '); + } + let pat_width = extra_offset(&pats_str, shape); // Let's try and get the arm body on the same line as the condition. // 4 = ` => `.len() @@ -1681,9 +1757,10 @@ impl Rewrite for ast::Arm { }; return Some(format!( - "{}{} =>{}{}{}", + "{}{} {}=>{}{}{}", attr_str.trim_left(), pats_str, + alignment_str, block_sep, body_str, comma @@ -1700,10 +1777,9 @@ impl Rewrite for ast::Arm { body.rewrite(context, body_shape), body_shape.width, )); - let indent_str = shape - .indent - .block_indent(context.config) - .to_string(context.config); + let indent_str = shape.indent.block_indent(context.config).to_string( + context.config, + ); let (body_prefix, body_suffix) = if context.config.wrap_match_arms() { if context.config.match_block_trailing_comma() { ("{", "},") @@ -1723,9 +1799,10 @@ impl Rewrite for ast::Arm { if context.config.wrap_match_arms() { Some(format!( - "{}{} =>{}{}{}\n{}{}", + "{}{} {}=>{}{}{}\n{}{}", attr_str.trim_left(), pats_str, + alignment_str, block_sep, indent_str, next_line_body, @@ -1734,9 +1811,10 @@ impl Rewrite for ast::Arm { )) } else { Some(format!( - "{}{} =>{}{}{}{}", + "{}{} {}=>{}{}{}{}", attr_str.trim_left(), pats_str, + alignment_str, block_sep, indent_str, next_line_body, @@ -1765,13 +1843,13 @@ fn rewrite_guard( if let Some(ref guard) = *guard { // First try to fit the guard string on the same line as the pattern. // 4 = ` if `, 5 = ` => {` - if let Some(cond_shape) = shape - .shrink_left(pattern_width + 4) - .and_then(|s| s.sub_width(5)) + if let Some(cond_shape) = shape.shrink_left(pattern_width + 4).and_then( + |s| s.sub_width(5), + ) { - if let Some(cond_str) = guard - .rewrite(context, cond_shape) - .and_then(|s| s.rewrite(context, cond_shape)) + if let Some(cond_str) = guard.rewrite(context, cond_shape).and_then(|s| { + s.rewrite(context, cond_shape) + }) { if !cond_str.contains('\n') { return Some(format!(" if {}", cond_str)); @@ -1789,10 +1867,9 @@ fn rewrite_guard( if let Some(cond_str) = guard.rewrite(context, cond_shape) { return Some(format!( "\n{}if {}", - shape - .indent - .block_indent(context.config) - .to_string(context.config), + shape.indent.block_indent(context.config).to_string( + context.config, + ), cond_str )); } @@ -1824,8 +1901,9 @@ fn rewrite_pat_expr( } else { format!("{} ", matcher) }; - let pat_shape = - try_opt!(try_opt!(shape.offset_left(matcher.len())).sub_width(connector.len())); + let pat_shape = try_opt!(try_opt!(shape.offset_left(matcher.len())).sub_width( + connector.len(), + )); pat_string = try_opt!(pat.rewrite(context, pat_shape)); format!("{}{}{}", matcher, pat_string, connector) } @@ -1938,9 +2016,9 @@ where width: callee_max_width, ..shape }; - let callee_str = callee - .rewrite(context, callee_shape) - .ok_or(Ordering::Greater)?; + let callee_str = callee.rewrite(context, callee_shape).ok_or( + Ordering::Greater, + )?; rewrite_call_inner( context, @@ -2048,9 +2126,9 @@ where ); } - let args_shape = shape - .sub_width(last_line_width(&callee_str)) - .ok_or(Ordering::Less)?; + let args_shape = shape.sub_width(last_line_width(&callee_str)).ok_or( + Ordering::Less, + )?; Ok(format!( "{}{}", callee_str, @@ -2066,8 +2144,9 @@ where fn need_block_indent(s: &str, shape: Shape) -> bool { s.lines().skip(1).any(|s| { - s.find(|c| !char::is_whitespace(c)) - .map_or(false, |w| w + 1 < shape.indent.width()) + s.find(|c| !char::is_whitespace(c)).map_or(false, |w| { + w + 1 < shape.indent.width() + }) }) } @@ -2205,6 +2284,7 @@ fn last_arg_shape( width: try_opt!(max_width.checked_sub(overhead)), indent: arg_indent, offset: 0, + alignment: 0, }) } @@ -2435,10 +2515,9 @@ fn rewrite_struct_lit<'a>( return Some(format!("{} {{}}", path_str)); } - let field_iter = fields - .into_iter() - .map(StructLitField::Regular) - .chain(base.into_iter().map(StructLitField::Base)); + let field_iter = fields.into_iter().map(StructLitField::Regular).chain( + base.into_iter().map(StructLitField::Base), + ); // Foo { a: Foo } - indent is +3, width is -5. let (h_shape, v_shape) = try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, 2)); diff --git a/src/items.rs b/src/items.rs index 1eb85771fd6..b4deec6153c 100644 --- a/src/items.rs +++ b/src/items.rs @@ -149,8 +149,9 @@ impl<'a> FmtVisitor<'a> { self.format_missing_no_indent(item.span.hi - BytePos(1)); self.block_indent = self.block_indent.block_unindent(self.config); - self.buffer - .push_str(&self.block_indent.to_string(self.config)); + self.buffer.push_str( + &self.block_indent.to_string(self.config), + ); } else { for item in &item.body { self.format_body_element(item); @@ -423,8 +424,9 @@ impl<'a> FmtVisitor<'a> { self.block_indent = self.block_indent.block_unindent(self.config); if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) { - self.buffer - .push_str(&self.block_indent.to_string(self.config)); + self.buffer.push_str( + &self.block_indent.to_string(self.config), + ); } self.buffer.push_str("}"); self.last_pos = span.hi; @@ -497,6 +499,7 @@ impl<'a> FmtVisitor<'a> { width: context.config.max_width(), indent: self.block_indent, offset: self.block_indent.alignment, + alignment: 0, }; let missing_comment = rewrite_missing_comment_on_field( &context, @@ -682,15 +685,13 @@ fn format_impl_ref_and_type( item: &ast::Item, offset: Indent, ) -> Option { - if let ast::ItemKind::Impl( - unsafety, - polarity, - _, - ref generics, - ref trait_ref, - ref self_ty, - _, - ) = item.node + if let ast::ItemKind::Impl(unsafety, + polarity, + _, + ref generics, + ref trait_ref, + ref self_ty, + _) = item.node { let mut result = String::new(); @@ -953,12 +954,9 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) Density::Tall }; - let where_budget = try_opt!( - context - .config - .max_width() - .checked_sub(last_line_width(&result)) - ); + let where_budget = try_opt!(context.config.max_width().checked_sub( + last_line_width(&result), + )); let where_clause_str = try_opt!(rewrite_where_clause( context, &generics.where_clause, @@ -1101,12 +1099,9 @@ fn format_struct_struct( let item_indent = offset.block_indent(context.config); // 1 = "," - let item_budget = try_opt!( - context - .config - .max_width() - .checked_sub(item_indent.width() + 1) - ); + let item_budget = try_opt!(context.config.max_width().checked_sub( + item_indent.width() + 1, + )); let items = itemize_list( context.codemap, @@ -1148,9 +1143,9 @@ fn format_struct_struct( Some(format!( "{}\n{}{}\n{}}}", result, - offset - .block_indent(context.config) - .to_string(context.config), + offset.block_indent(context.config).to_string( + context.config, + ), items_str, offset.to_string(context.config) )) @@ -1185,12 +1180,9 @@ fn format_tuple_struct( let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); - let where_budget = try_opt!( - context - .config - .max_width() - .checked_sub(last_line_width(&result)) - ); + let where_budget = try_opt!(context.config.max_width().checked_sub( + last_line_width(&result), + )); try_opt!(rewrite_where_clause( context, &generics.where_clause, @@ -1236,12 +1228,9 @@ fn format_tuple_struct( } }; // 3 = `();` - let item_budget = try_opt!( - context - .config - .max_width() - .checked_sub(item_indent.width() + 3) - ); + let item_budget = try_opt!(context.config.max_width().checked_sub( + item_indent.width() + 3, + )); let items = itemize_list( context.codemap, @@ -1331,12 +1320,9 @@ pub fn rewrite_type_alias( let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); - let where_budget = try_opt!( - context - .config - .max_width() - .checked_sub(last_line_width(&result)) - ); + let where_budget = try_opt!(context.config.max_width().checked_sub( + last_line_width(&result), + )); let where_clause_str = try_opt!(rewrite_where_clause( context, &generics.where_clause, @@ -1371,12 +1357,9 @@ pub fn rewrite_type_alias( let type_indent = indent.block_indent(context.config); result.push('\n'); result.push_str(&type_indent.to_string(context.config)); - let budget = try_opt!( - context - .config - .max_width() - .checked_sub(type_indent.width() + ";".len()) - ); + let budget = try_opt!(context.config.max_width().checked_sub( + type_indent.width() + ";".len(), + )); ty.rewrite(context, Shape::legacy(budget, type_indent)) }) ); @@ -1572,6 +1555,7 @@ pub fn rewrite_static( width: context.config.max_width(), indent: offset, offset: offset.alignment, + alignment: 0, }, ) }) @@ -1979,10 +1963,9 @@ fn rewrite_fn_base( } // If the last line of args contains comment, we cannot put the closing paren // on the same line. - if arg_str - .lines() - .last() - .map_or(false, |last_line| last_line.contains("//")) + if arg_str.lines().last().map_or(false, |last_line| { + last_line.contains("//") + }) { args_last_line_contains_comment = true; result.push('\n'); @@ -2055,13 +2038,12 @@ fn rewrite_fn_base( let snippet_hi = span.hi; let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi)); // Try to preserve the layout of the original snippet. - let original_starts_with_newline = - snippet - .find(|c| c != ' ') - .map_or(false, |i| snippet[i..].starts_with('\n')); - let original_ends_with_newline = snippet - .rfind(|c| c != ' ') - .map_or(false, |i| snippet[i..].ends_with('\n')); + let original_starts_with_newline = snippet.find(|c| c != ' ').map_or(false, |i| { + snippet[i..].starts_with('\n') + }); + let original_ends_with_newline = snippet.rfind(|c| c != ' ').map_or(false, |i| { + snippet[i..].ends_with('\n') + }); let snippet = snippet.trim(); if !snippet.is_empty() { result.push(if original_starts_with_newline { @@ -2088,12 +2070,9 @@ fn rewrite_fn_base( } || (put_args_in_block && ret_str.is_empty()); if where_clause.predicates.len() == 1 && should_compress_where { - let budget = try_opt!( - context - .config - .max_width() - .checked_sub(last_line_width(&result)) - ); + let budget = try_opt!(context.config.max_width().checked_sub( + last_line_width(&result), + )); if let Some(where_clause_str) = rewrite_where_clause( context, @@ -2484,9 +2463,9 @@ pub fn wrap_generics_with_angle_brackets( "<\n{}{}\n{}>", list_offset.to_string(context.config), list_str, - list_offset - .block_unindent(context.config) - .to_string(context.config) + list_offset.block_unindent(context.config).to_string( + context.config, + ) ) } else if context.config.spaces_within_angle_brackets() { format!("< {} >", list_str) @@ -2693,12 +2672,9 @@ fn format_generics( let mut result = try_opt!(rewrite_generics(context, generics, shape, span)); if !generics.where_clause.predicates.is_empty() || result.contains('\n') { - let budget = try_opt!( - context - .config - .max_width() - .checked_sub(last_line_width(&result)) - ); + let budget = try_opt!(context.config.max_width().checked_sub( + last_line_width(&result), + )); let where_clause_str = try_opt!(rewrite_where_clause( context, &generics.where_clause, diff --git a/src/lib.rs b/src/lib.rs index 62d4df502d1..61ea5210616 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,6 +222,8 @@ pub struct Shape { // Indentation + any already emitted text on the first line of the current // statement. pub offset: usize, + // Alignment to other structures + pub alignment: usize, } impl Shape { @@ -245,6 +247,7 @@ impl Shape { width: width, indent: indent, offset: indent.alignment, + alignment: 0, } } @@ -253,6 +256,7 @@ impl Shape { width: config.max_width().checked_sub(indent.width()).unwrap_or(0), indent: indent, offset: indent.alignment, + alignment: 0, } } @@ -271,6 +275,7 @@ impl Shape { width: width, indent: indent, offset: offset, + alignment: 0, } } @@ -280,6 +285,7 @@ impl Shape { width: self.width, indent: Indent::new(self.indent.block_indent, alignment), offset: alignment, + alignment: 0, } } @@ -289,12 +295,14 @@ impl Shape { width: self.width, indent: Indent::new(self.indent.block_indent + extra_width, 0), offset: 0, + alignment: 0, } } else { Shape { width: self.width, indent: self.indent + extra_width, offset: self.indent.alignment + extra_width, + alignment: 0, } } } @@ -329,6 +337,7 @@ impl Shape { width: try_opt!(self.width.checked_sub(width)), indent: self.indent + width, offset: self.offset + width, + alignment: 0, }) } diff --git a/tests/source/configs-match_align_arms-always.rs b/tests/source/configs-match_align_arms-always.rs new file mode 100644 index 00000000000..c918e9899f4 --- /dev/null +++ b/tests/source/configs-match_align_arms-always.rs @@ -0,0 +1,38 @@ +// rustfmt-match_align_arms: Always +// Align match arms + +fn main() { + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => { + lorem(); + ipsum(); + } + Lorem::Sit => { + lorem(); + ipsum(); + } + Lorem::Amet => (), + } +} diff --git a/tests/source/configs-match_align_arms-never.rs b/tests/source/configs-match_align_arms-never.rs new file mode 100644 index 00000000000..370d8683982 --- /dev/null +++ b/tests/source/configs-match_align_arms-never.rs @@ -0,0 +1,25 @@ +// rustfmt-match_align_arms: Never +// Align match arms + +fn main() { + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } +} diff --git a/tests/source/configs-match_align_arms-preserve.rs b/tests/source/configs-match_align_arms-preserve.rs new file mode 100644 index 00000000000..9ff14a27f6f --- /dev/null +++ b/tests/source/configs-match_align_arms-preserve.rs @@ -0,0 +1,25 @@ +// rustfmt-match_align_arms: Preserve +// Align match arms + +fn main() { + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } +} diff --git a/tests/target/configs-match_align_arms-always.rs b/tests/target/configs-match_align_arms-always.rs new file mode 100644 index 00000000000..adae6f38452 --- /dev/null +++ b/tests/target/configs-match_align_arms-always.rs @@ -0,0 +1,38 @@ +// rustfmt-match_align_arms: Always +// Align match arms + +fn main() { + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => { + lorem(); + ipsum(); + } + Lorem::Sit => { + lorem(); + ipsum(); + } + Lorem::Amet => (), + } +} diff --git a/tests/target/configs-match_align_arms-never.rs b/tests/target/configs-match_align_arms-never.rs new file mode 100644 index 00000000000..968726fd599 --- /dev/null +++ b/tests/target/configs-match_align_arms-never.rs @@ -0,0 +1,25 @@ +// rustfmt-match_align_arms: Never +// Align match arms + +fn main() { + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } +} diff --git a/tests/target/configs-match_align_arms-preserve.rs b/tests/target/configs-match_align_arms-preserve.rs new file mode 100644 index 00000000000..8c99c4c0c98 --- /dev/null +++ b/tests/target/configs-match_align_arms-preserve.rs @@ -0,0 +1,25 @@ +// rustfmt-match_align_arms: Preserve +// Align match arms + +fn main() { + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } + + match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), + } +} From 71a6d8a38d8be0616e6aac29d21b87f9261d592c Mon Sep 17 00:00:00 2001 From: ruin Date: Fri, 16 Jun 2017 15:03:37 -0500 Subject: [PATCH 02/11] Add documentation for match_align_arms --- Configurations.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Configurations.md b/Configurations.md index 82f50dc6672..893319f452e 100644 --- a/Configurations.md +++ b/Configurations.md @@ -916,6 +916,70 @@ match lorem { See also: [`match_block_trailing_comma`](#match_block_trailing_comma), [`wrap_match_arms`](#wrap_match_arms). +## `match_align_arms` + +Aligns the arms of a `match` statement to be flush with each other. `"Preserve"` will not re-format match arms that have already been aligned manually. + +- **Default value**: `"Preserve"` +- **Possible values**: `"Always"`, `"Preserve"`, `"Never"` + +#### `"Never"`: + +```rust +match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), +} + +match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), +} +``` + +#### `"Preserve"`: + +```rust +match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), +} + +match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), +} +``` + +#### `"Always"`: + +```rust +match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), +} + +match lorem { + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), +} +``` + +See also: [`indent_match_arms`](#indent_match_arms), [`wrap_match_arms`](#wrap_match_arms). + + ## `item_brace_style` Brace style for structs and enums From 6d2b674ac3a2acdb9da1d6cb01c73f8d6a7e4cbc Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 16 Jun 2017 15:06:37 -0500 Subject: [PATCH 03/11] Update Configurations.md --- Configurations.md | 99 +++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/Configurations.md b/Configurations.md index 893319f452e..6e1e97dce91 100644 --- a/Configurations.md +++ b/Configurations.md @@ -916,6 +916,55 @@ match lorem { See also: [`match_block_trailing_comma`](#match_block_trailing_comma), [`wrap_match_arms`](#wrap_match_arms). +## `item_brace_style` + +Brace style for structs and enums + +- **Default value**: `"SameLineWhere"` +- **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"` + +#### `"AlwaysNextLine"`: + +```rust +struct Lorem +{ + ipsum: bool, +} + +struct Dolor + where T: Eq +{ + sit: T, +} +``` + +#### `"PreferSameLine"`: + +```rust +struct Lorem { + ipsum: bool, +} + +struct Dolor + where T: Eq { + sit: T, +} +``` + +#### `"SameLineWhere"`: + +```rust +struct Lorem { + ipsum: bool, +} + +struct Dolor + where T: Eq +{ + sit: T, +} +``` + ## `match_align_arms` Aligns the arms of a `match` statement to be flush with each other. `"Preserve"` will not re-format match arms that have already been aligned manually. @@ -979,56 +1028,6 @@ match lorem { See also: [`indent_match_arms`](#indent_match_arms), [`wrap_match_arms`](#wrap_match_arms). - -## `item_brace_style` - -Brace style for structs and enums - -- **Default value**: `"SameLineWhere"` -- **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"` - -#### `"AlwaysNextLine"`: - -```rust -struct Lorem -{ - ipsum: bool, -} - -struct Dolor - where T: Eq -{ - sit: T, -} -``` - -#### `"PreferSameLine"`: - -```rust -struct Lorem { - ipsum: bool, -} - -struct Dolor - where T: Eq { - sit: T, -} -``` - -#### `"SameLineWhere"`: - -```rust -struct Lorem { - ipsum: bool, -} - -struct Dolor - where T: Eq -{ - sit: T, -} -``` - ## `match_block_trailing_comma` Put a trailing comma after a block based match arm (non-block arms are not affected) From 9ddfb2c104b269219c3c8fe279306c480d97c1ed Mon Sep 17 00:00:00 2001 From: ruin Date: Fri, 16 Jun 2017 15:56:28 -0500 Subject: [PATCH 04/11] Reformat using own debug release --- src/expr.rs | 173 ++++++++++++++++++++++++--------------------------- src/items.rs | 130 ++++++++++++++++++++++---------------- 2 files changed, 161 insertions(+), 142 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 87da763be29..92f90dbb8dd 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -157,9 +157,8 @@ fn format_expr( ast::ExprKind::Loop(..) | ast::ExprKind::While(..) | ast::ExprKind::WhileLet(..) => { - to_control_flow(expr, expr_type).and_then(|control_flow| { - control_flow.rewrite(context, shape) - }) + to_control_flow(expr, expr_type) + .and_then(|control_flow| control_flow.rewrite(context, shape)) } ast::ExprKind::Block(ref block) => block.rewrite(context, shape), ast::ExprKind::Match(ref cond, ref arms) => { @@ -360,9 +359,8 @@ where // This is needed in case of line break not caused by a // shortage of space, but by end-of-line comments, for example. if !rhs_result.contains('\n') { - let lhs_shape = try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width( - infix.len(), - )); + let lhs_shape = + try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width(infix.len())); let lhs_result = lhs.rewrite(context, lhs_shape); if let Some(lhs_result) = lhs_result { let mut result = format!("{}{}{}", prefix, lhs_result, infix); @@ -451,9 +449,11 @@ where let nested_shape = match context.config.array_layout() { IndentStyle::Block => shape.block().block_indent(context.config.tab_spaces()), IndentStyle::Visual => { - try_opt!(shape.visual_indent(bracket_size).sub_width( - bracket_size * 2, - )) + try_opt!( + shape + .visual_indent(bracket_size) + .sub_width(bracket_size * 2) + ) } }; @@ -476,9 +476,9 @@ where } } - let has_long_item = items.iter().any(|li| { - li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false) - }); + let has_long_item = items + .iter() + .any(|li| li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false)); let tactic = match context.config.array_layout() { IndentStyle::Block => { @@ -754,14 +754,14 @@ fn and_one_line(x: Option) -> Option { fn nop_block_collapse(block_str: Option, budget: usize) -> Option { debug!("nop_block_collapse {:?} {}", block_str, budget); - block_str.map(|block_str| if block_str.starts_with('{') && budget >= 2 && - (block_str[1..] - .find(|c: char| !c.is_whitespace()) - .unwrap() == block_str.len() - 2) - { - "{}".to_owned() - } else { - block_str.to_owned() + block_str.map(|block_str| { + if block_str.starts_with('{') && budget >= 2 && + (block_str[1..].find(|c: char| !c.is_whitespace()).unwrap() == block_str.len() - 2) + { + "{}".to_owned() + } else { + block_str.to_owned() + } }) } @@ -938,16 +938,12 @@ fn to_control_flow<'a>(expr: &'a ast::Expr, expr_type: ExprType) -> Option { Some(ControlFlow::new_for(pat, cond, block, label, expr.span)) } - ast::ExprKind::Loop(ref block, label) => Some( - ControlFlow::new_loop(block, label, expr.span), - ), - ast::ExprKind::While(ref cond, ref block, label) => Some(ControlFlow::new_while( - None, - cond, - block, - label, - expr.span, - )), + ast::ExprKind::Loop(ref block, label) => { + Some(ControlFlow::new_loop(block, label, expr.span)) + } + ast::ExprKind::While(ref cond, ref block, label) => { + Some(ControlFlow::new_while(None, cond, block, label, expr.span)) + } ast::ExprKind::WhileLet(ref pat, ref cond, ref block, label) => { Some(ControlFlow::new_while( Some(pat), @@ -1208,23 +1204,20 @@ impl<'a> ControlFlow<'a> { }; Some(( - format!( - "{}{}{}{}{}", - label_string, - self.keyword, - between_kwd_cond_comment.as_ref().map_or( - if pat_expr_string.is_empty() || - pat_expr_string.starts_with('\n') - { - "" - } else { - " " - }, - |s| &**s, - ), - pat_expr_string, - after_cond_comment.as_ref().map_or(block_sep, |s| &**s) - ), + format!("{}{}{}{}{}", + label_string, + self.keyword, + between_kwd_cond_comment + .as_ref() + .map_or(if pat_expr_string.is_empty() || + pat_expr_string.starts_with('\n') { + "" + } else { + " " + }, + |s| &**s), + pat_expr_string, + after_cond_comment.as_ref().map_or(block_sep, |s| &**s)), used_width, )) } @@ -1478,8 +1471,6 @@ fn rewrite_match( }; let mut result = format!("match {}{}{{", cond_str, block_sep); - let mut arm_shapes = Vec::new(); - let mut furthest_arrow_pos = 0; let mut furthest_pat_pos = 0; let mut should_preserve_align = true; @@ -1505,7 +1496,18 @@ fn rewrite_match( } } - for arm in arms.iter() { + let open_brace_pos = context.codemap.span_after( + mk_sp(cond.span.hi, arm_start_pos(&arms[0])), + "{", + ); + + let mut arm_shape = if context.config.indent_match_arms() { + shape.block_indent(context.config.tab_spaces()) + } else { + shape.block_indent(0) + }; + + for (i, arm) in arms.iter().enumerate() { let alignment = match context.config.match_align_arms() { MatchAlignArms::Always => { if should_preserve_align { @@ -1524,23 +1526,14 @@ fn rewrite_match( MatchAlignArms::Never => 0, }; - let mut arm_shape = if context.config.indent_match_arms() { + arm_shape = if context.config.indent_match_arms() { shape.block_indent(context.config.tab_spaces()) } else { shape.block_indent(0) }; arm_shape.alignment = alignment; - arm_shapes.push(arm_shape); - } - let open_brace_pos = context.codemap.span_after( - mk_sp(cond.span.hi, arm_start_pos(&arms[0])), - "{", - ); - - for (i, arm) in arms.iter().enumerate() { - let arm_shape = arm_shapes[i]; let arm_indent_str = arm_shape.indent.to_string(context.config); // Make sure we get the stuff between arms. @@ -1569,8 +1562,7 @@ fn rewrite_match( result.push_str(arm_comma(context.config, &arm.body)); } } - let last_arm_shape = arm_shapes[arms.len() - 1]; - let last_arm_indent_str = last_arm_shape.indent.to_string(context.config); + let last_arm_indent_str = arm_shape.indent.to_string(context.config); // BytePos(1) = closing match brace. let last_span = mk_sp(arm_end_pos(&arms[arms.len() - 1]), span.hi - BytePos(1)); @@ -1578,7 +1570,7 @@ fn rewrite_match( let comment = try_opt!(rewrite_match_arm_comment( context, &last_comment, - last_arm_shape, + arm_shape, &last_arm_indent_str, )); result.push_str(&comment); @@ -1777,9 +1769,10 @@ impl Rewrite for ast::Arm { body.rewrite(context, body_shape), body_shape.width, )); - let indent_str = shape.indent.block_indent(context.config).to_string( - context.config, - ); + let indent_str = shape + .indent + .block_indent(context.config) + .to_string(context.config); let (body_prefix, body_suffix) = if context.config.wrap_match_arms() { if context.config.match_block_trailing_comma() { ("{", "},") @@ -1843,13 +1836,13 @@ fn rewrite_guard( if let Some(ref guard) = *guard { // First try to fit the guard string on the same line as the pattern. // 4 = ` if `, 5 = ` => {` - if let Some(cond_shape) = shape.shrink_left(pattern_width + 4).and_then( - |s| s.sub_width(5), - ) + if let Some(cond_shape) = shape + .shrink_left(pattern_width + 4) + .and_then(|s| s.sub_width(5)) { - if let Some(cond_str) = guard.rewrite(context, cond_shape).and_then(|s| { - s.rewrite(context, cond_shape) - }) + if let Some(cond_str) = guard + .rewrite(context, cond_shape) + .and_then(|s| s.rewrite(context, cond_shape)) { if !cond_str.contains('\n') { return Some(format!(" if {}", cond_str)); @@ -1867,9 +1860,10 @@ fn rewrite_guard( if let Some(cond_str) = guard.rewrite(context, cond_shape) { return Some(format!( "\n{}if {}", - shape.indent.block_indent(context.config).to_string( - context.config, - ), + shape + .indent + .block_indent(context.config) + .to_string(context.config), cond_str )); } @@ -1901,9 +1895,8 @@ fn rewrite_pat_expr( } else { format!("{} ", matcher) }; - let pat_shape = try_opt!(try_opt!(shape.offset_left(matcher.len())).sub_width( - connector.len(), - )); + let pat_shape = + try_opt!(try_opt!(shape.offset_left(matcher.len())).sub_width(connector.len())); pat_string = try_opt!(pat.rewrite(context, pat_shape)); format!("{}{}{}", matcher, pat_string, connector) } @@ -2016,9 +2009,9 @@ where width: callee_max_width, ..shape }; - let callee_str = callee.rewrite(context, callee_shape).ok_or( - Ordering::Greater, - )?; + let callee_str = callee + .rewrite(context, callee_shape) + .ok_or(Ordering::Greater)?; rewrite_call_inner( context, @@ -2126,9 +2119,9 @@ where ); } - let args_shape = shape.sub_width(last_line_width(&callee_str)).ok_or( - Ordering::Less, - )?; + let args_shape = shape + .sub_width(last_line_width(&callee_str)) + .ok_or(Ordering::Less)?; Ok(format!( "{}{}", callee_str, @@ -2144,9 +2137,8 @@ where fn need_block_indent(s: &str, shape: Shape) -> bool { s.lines().skip(1).any(|s| { - s.find(|c| !char::is_whitespace(c)).map_or(false, |w| { - w + 1 < shape.indent.width() - }) + s.find(|c| !char::is_whitespace(c)) + .map_or(false, |w| w + 1 < shape.indent.width()) }) } @@ -2515,9 +2507,10 @@ fn rewrite_struct_lit<'a>( return Some(format!("{} {{}}", path_str)); } - let field_iter = fields.into_iter().map(StructLitField::Regular).chain( - base.into_iter().map(StructLitField::Base), - ); + let field_iter = fields + .into_iter() + .map(StructLitField::Regular) + .chain(base.into_iter().map(StructLitField::Base)); // Foo { a: Foo } - indent is +3, width is -5. let (h_shape, v_shape) = try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, 2)); diff --git a/src/items.rs b/src/items.rs index b4deec6153c..6154ee83cd4 100644 --- a/src/items.rs +++ b/src/items.rs @@ -149,9 +149,8 @@ impl<'a> FmtVisitor<'a> { self.format_missing_no_indent(item.span.hi - BytePos(1)); self.block_indent = self.block_indent.block_unindent(self.config); - self.buffer.push_str( - &self.block_indent.to_string(self.config), - ); + self.buffer + .push_str(&self.block_indent.to_string(self.config)); } else { for item in &item.body { self.format_body_element(item); @@ -424,9 +423,8 @@ impl<'a> FmtVisitor<'a> { self.block_indent = self.block_indent.block_unindent(self.config); if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) { - self.buffer.push_str( - &self.block_indent.to_string(self.config), - ); + self.buffer + .push_str(&self.block_indent.to_string(self.config)); } self.buffer.push_str("}"); self.last_pos = span.hi; @@ -685,13 +683,15 @@ fn format_impl_ref_and_type( item: &ast::Item, offset: Indent, ) -> Option { - if let ast::ItemKind::Impl(unsafety, - polarity, - _, - ref generics, - ref trait_ref, - ref self_ty, - _) = item.node + if let ast::ItemKind::Impl( + unsafety, + polarity, + _, + ref generics, + ref trait_ref, + ref self_ty, + _, + ) = item.node { let mut result = String::new(); @@ -954,9 +954,12 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) Density::Tall }; - let where_budget = try_opt!(context.config.max_width().checked_sub( - last_line_width(&result), - )); + let where_budget = try_opt!( + context + .config + .max_width() + .checked_sub(last_line_width(&result)) + ); let where_clause_str = try_opt!(rewrite_where_clause( context, &generics.where_clause, @@ -1099,9 +1102,12 @@ fn format_struct_struct( let item_indent = offset.block_indent(context.config); // 1 = "," - let item_budget = try_opt!(context.config.max_width().checked_sub( - item_indent.width() + 1, - )); + let item_budget = try_opt!( + context + .config + .max_width() + .checked_sub(item_indent.width() + 1) + ); let items = itemize_list( context.codemap, @@ -1143,9 +1149,9 @@ fn format_struct_struct( Some(format!( "{}\n{}{}\n{}}}", result, - offset.block_indent(context.config).to_string( - context.config, - ), + offset + .block_indent(context.config) + .to_string(context.config), items_str, offset.to_string(context.config) )) @@ -1180,9 +1186,12 @@ fn format_tuple_struct( let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); - let where_budget = try_opt!(context.config.max_width().checked_sub( - last_line_width(&result), - )); + let where_budget = try_opt!( + context + .config + .max_width() + .checked_sub(last_line_width(&result)) + ); try_opt!(rewrite_where_clause( context, &generics.where_clause, @@ -1228,9 +1237,12 @@ fn format_tuple_struct( } }; // 3 = `();` - let item_budget = try_opt!(context.config.max_width().checked_sub( - item_indent.width() + 3, - )); + let item_budget = try_opt!( + context + .config + .max_width() + .checked_sub(item_indent.width() + 3) + ); let items = itemize_list( context.codemap, @@ -1320,9 +1332,12 @@ pub fn rewrite_type_alias( let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); - let where_budget = try_opt!(context.config.max_width().checked_sub( - last_line_width(&result), - )); + let where_budget = try_opt!( + context + .config + .max_width() + .checked_sub(last_line_width(&result)) + ); let where_clause_str = try_opt!(rewrite_where_clause( context, &generics.where_clause, @@ -1357,9 +1372,12 @@ pub fn rewrite_type_alias( let type_indent = indent.block_indent(context.config); result.push('\n'); result.push_str(&type_indent.to_string(context.config)); - let budget = try_opt!(context.config.max_width().checked_sub( - type_indent.width() + ";".len(), - )); + let budget = try_opt!( + context + .config + .max_width() + .checked_sub(type_indent.width() + ";".len()) + ); ty.rewrite(context, Shape::legacy(budget, type_indent)) }) ); @@ -1963,9 +1981,10 @@ fn rewrite_fn_base( } // If the last line of args contains comment, we cannot put the closing paren // on the same line. - if arg_str.lines().last().map_or(false, |last_line| { - last_line.contains("//") - }) + if arg_str + .lines() + .last() + .map_or(false, |last_line| last_line.contains("//")) { args_last_line_contains_comment = true; result.push('\n'); @@ -2038,12 +2057,13 @@ fn rewrite_fn_base( let snippet_hi = span.hi; let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi)); // Try to preserve the layout of the original snippet. - let original_starts_with_newline = snippet.find(|c| c != ' ').map_or(false, |i| { - snippet[i..].starts_with('\n') - }); - let original_ends_with_newline = snippet.rfind(|c| c != ' ').map_or(false, |i| { - snippet[i..].ends_with('\n') - }); + let original_starts_with_newline = + snippet + .find(|c| c != ' ') + .map_or(false, |i| snippet[i..].starts_with('\n')); + let original_ends_with_newline = snippet + .rfind(|c| c != ' ') + .map_or(false, |i| snippet[i..].ends_with('\n')); let snippet = snippet.trim(); if !snippet.is_empty() { result.push(if original_starts_with_newline { @@ -2070,9 +2090,12 @@ fn rewrite_fn_base( } || (put_args_in_block && ret_str.is_empty()); if where_clause.predicates.len() == 1 && should_compress_where { - let budget = try_opt!(context.config.max_width().checked_sub( - last_line_width(&result), - )); + let budget = try_opt!( + context + .config + .max_width() + .checked_sub(last_line_width(&result)) + ); if let Some(where_clause_str) = rewrite_where_clause( context, @@ -2463,9 +2486,9 @@ pub fn wrap_generics_with_angle_brackets( "<\n{}{}\n{}>", list_offset.to_string(context.config), list_str, - list_offset.block_unindent(context.config).to_string( - context.config, - ) + list_offset + .block_unindent(context.config) + .to_string(context.config) ) } else if context.config.spaces_within_angle_brackets() { format!("< {} >", list_str) @@ -2672,9 +2695,12 @@ fn format_generics( let mut result = try_opt!(rewrite_generics(context, generics, shape, span)); if !generics.where_clause.predicates.is_empty() || result.contains('\n') { - let budget = try_opt!(context.config.max_width().checked_sub( - last_line_width(&result), - )); + let budget = try_opt!( + context + .config + .max_width() + .checked_sub(last_line_width(&result)) + ); let where_clause_str = try_opt!(rewrite_where_clause( context, &generics.where_clause, From 0243a3d4dab1650d13097086684a93610ab1da4a Mon Sep 17 00:00:00 2001 From: ruin Date: Sat, 17 Jun 2017 13:00:21 -0500 Subject: [PATCH 05/11] Always align match arms to minimum spacing possible --- src/expr.rs | 14 ++------------ tests/target/configs-match_align_arms-always.rs | 8 ++++---- tests/target/configs-match_align_arms-preserve.rs | 8 ++++---- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 92f90dbb8dd..27e84371355 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1510,15 +1510,11 @@ fn rewrite_match( for (i, arm) in arms.iter().enumerate() { let alignment = match context.config.match_align_arms() { MatchAlignArms::Always => { - if should_preserve_align { - arm_arrow_spacing(arm) - } else { - furthest_pat_pos - arm_pat_end_pos_relative(arm) - } + furthest_pat_pos - arm_pat_end_pos_relative(arm) } MatchAlignArms::Preserve => { if should_preserve_align { - arm_arrow_spacing(arm) + furthest_pat_pos - arm_pat_end_pos_relative(arm) } else { 0 } @@ -1609,12 +1605,6 @@ fn arm_arrow_pos(arm: &ast::Arm) -> usize { (body.span.lo - pat_start_pos).0 as usize - 3 } -fn arm_arrow_spacing(arm: &ast::Arm) -> usize { - let pat_end_rel = arm_pat_end_pos_relative(arm); - let arrow_pos = arm_arrow_pos(arm); - arrow_pos - pat_end_rel - 1 -} - fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str { if config.match_block_trailing_comma() { "," diff --git a/tests/target/configs-match_align_arms-always.rs b/tests/target/configs-match_align_arms-always.rs index adae6f38452..bde862ca836 100644 --- a/tests/target/configs-match_align_arms-always.rs +++ b/tests/target/configs-match_align_arms-always.rs @@ -17,10 +17,10 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), } match lorem { diff --git a/tests/target/configs-match_align_arms-preserve.rs b/tests/target/configs-match_align_arms-preserve.rs index 8c99c4c0c98..2390500b39d 100644 --- a/tests/target/configs-match_align_arms-preserve.rs +++ b/tests/target/configs-match_align_arms-preserve.rs @@ -17,9 +17,9 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => (), + Lorem::Dolor => (), + Lorem::Sit => (), + Lorem::Amet => (), } } From 2957836ff45515018e2467351bfe9cf95d46045e Mon Sep 17 00:00:00 2001 From: ruin Date: Sat, 17 Jun 2017 13:30:28 -0500 Subject: [PATCH 06/11] Add conservative formatting option for match_align_arms --- Configurations.md | 77 ++++++++++++++----- src/config.rs | 6 +- src/expr.rs | 39 +++++----- .../source/configs-match_align_arms-always.rs | 14 +--- ... configs-match_align_arms-conservative.rs} | 16 ++-- .../source/configs-match_align_arms-never.rs | 13 +++- .../target/configs-match_align_arms-always.rs | 14 +--- ... configs-match_align_arms-conservative.rs} | 20 +++-- .../target/configs-match_align_arms-never.rs | 13 +++- 9 files changed, 131 insertions(+), 81 deletions(-) rename tests/source/{configs-match_align_arms-preserve.rs => configs-match_align_arms-conservative.rs} (52%) rename tests/target/{configs-match_align_arms-preserve.rs => configs-match_align_arms-conservative.rs} (52%) diff --git a/Configurations.md b/Configurations.md index 6e1e97dce91..b2e8662f7da 100644 --- a/Configurations.md +++ b/Configurations.md @@ -965,46 +965,80 @@ struct Dolor } ``` -## `match_align_arms` -Aligns the arms of a `match` statement to be flush with each other. `"Preserve"` will not re-format match arms that have already been aligned manually. +## `match_arm_align_threshold` -- **Default value**: `"Preserve"` -- **Possible values**: `"Always"`, `"Preserve"`, `"Never"` +Maximum number of spaces between `match` statement patterns for the arms to be aligned by `match_align_arms`. -#### `"Never"`: +- **Default value**: `10` +- **Possible values**: any positive integer +**Note:** A value of `0` results in match arm alignment being applied regardless of the spacing between match arm patterns. + +#### Difference in width shorter than `match_arm_align_threshold`: ```rust match lorem { Lorem::Ipsum => (), Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Sit => (), + Lorem::Amet => (), } +``` + +#### Difference in width longer than `match_arm_align_threshold`: + +See [`match_align_arms`](#match_align_arms). + +## `match_align_arms` + +Aligns the arms of a `match` statement to be flush with each other. `"Conservative"` will only format match arms with a maximum of `match_arm_align_threshold` spaces between patterns. + +- **Default value**: `"Conservative"` +- **Possible values**: `"Always"`, `"Conservative"`, `"Never"` + +#### `"Never"`: +```rust match lorem { Lorem::Ipsum => (), Lorem::Dolor => (), Lorem::Sit => (), Lorem::Amet => (), } + +match lorem { + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } +} ``` -#### `"Preserve"`: +#### `"Conservative"`: ```rust match lorem { Lorem::Ipsum => (), Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Sit => (), + Lorem::Amet => (), } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } } ``` @@ -1019,14 +1053,19 @@ match lorem { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } } ``` -See also: [`indent_match_arms`](#indent_match_arms), [`wrap_match_arms`](#wrap_match_arms). +See also: [`match_arm_align_threshold`](#match_arm_align_threshold), [`indent_match_arms`](#indent_match_arms), [`wrap_match_arms`](#wrap_match_arms). ## `match_block_trailing_comma` diff --git a/src/config.rs b/src/config.rs index bae23a7823e..1f645baafce 100644 --- a/src/config.rs +++ b/src/config.rs @@ -95,7 +95,7 @@ configuration_option_enum! { TypeDensity: configuration_option_enum! { MatchAlignArms: Always, - Preserve, + Conservative, Never, } @@ -605,7 +605,9 @@ create_config! { condense_wildcard_suffixes: bool, false, "Replace strings of _ wildcards by a single .. in \ tuple patterns"; combine_control_expr: bool, true, "Combine control expressions with funciton calls."; - match_align_arms: MatchAlignArms, MatchAlignArms::Never, "Align match arms" + match_align_arms: MatchAlignArms, MatchAlignArms::Never, "Align match arms"; + match_arm_align_threshold: usize, 10, "Maximum spacing between match arm patterns before \ + falling back on non-alignment" } #[cfg(test)] diff --git a/src/expr.rs b/src/expr.rs index 27e84371355..45736f400c5 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1471,28 +1471,25 @@ fn rewrite_match( }; let mut result = format!("match {}{}{{", cond_str, block_sep); - let mut furthest_arrow_pos = 0; - let mut furthest_pat_pos = 0; - let mut should_preserve_align = true; + let mut min_pat_pos = 0; + let mut max_pat_pos = 0; + let mut realign_if_conservative = true; if let Some(arm) = arms.first() { - furthest_arrow_pos = arm_arrow_pos(arm); - furthest_pat_pos = arm_pat_end_pos_relative(arm); + min_pat_pos = arm_pat_end_pos_relative(arm); + max_pat_pos = min_pat_pos; } for arm in arms.iter() { - let arrow_pos = arm_arrow_pos(arm); let pat_pos = arm_pat_end_pos_relative(arm); - if arrow_pos != furthest_arrow_pos { - should_preserve_align = false; + if max_pat_pos - min_pat_pos > context.config.match_arm_align_threshold() { + realign_if_conservative = false; } - if arrow_pos > furthest_arrow_pos { - furthest_arrow_pos = arrow_pos; - } - - if pat_pos > furthest_pat_pos { - furthest_pat_pos = pat_pos; + if pat_pos > max_pat_pos { + max_pat_pos = pat_pos; + } else if pat_pos < min_pat_pos { + min_pat_pos = pat_pos; } } @@ -1510,11 +1507,11 @@ fn rewrite_match( for (i, arm) in arms.iter().enumerate() { let alignment = match context.config.match_align_arms() { MatchAlignArms::Always => { - furthest_pat_pos - arm_pat_end_pos_relative(arm) + max_pat_pos - arm_pat_end_pos_relative(arm) } - MatchAlignArms::Preserve => { - if should_preserve_align { - furthest_pat_pos - arm_pat_end_pos_relative(arm) + MatchAlignArms::Conservative => { + if realign_if_conservative { + max_pat_pos - arm_pat_end_pos_relative(arm) } else { 0 } @@ -1605,6 +1602,12 @@ fn arm_arrow_pos(arm: &ast::Arm) -> usize { (body.span.lo - pat_start_pos).0 as usize - 3 } +fn arm_arrow_spacing(arm: &ast::Arm) -> usize { + let pat_end_rel = arm_pat_end_pos_relative(arm); + let arrow_pos = arm_arrow_pos(arm); + arrow_pos - pat_end_rel - 1 +} + fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str { if config.match_block_trailing_comma() { "," diff --git a/tests/source/configs-match_align_arms-always.rs b/tests/source/configs-match_align_arms-always.rs index c918e9899f4..08277d8680b 100644 --- a/tests/source/configs-match_align_arms-always.rs +++ b/tests/source/configs-match_align_arms-always.rs @@ -17,22 +17,14 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => { + Lorem::Ipsum => { lorem(); ipsum(); } - Lorem::Sit => { + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { lorem(); ipsum(); } - Lorem::Amet => (), } } diff --git a/tests/source/configs-match_align_arms-preserve.rs b/tests/source/configs-match_align_arms-conservative.rs similarity index 52% rename from tests/source/configs-match_align_arms-preserve.rs rename to tests/source/configs-match_align_arms-conservative.rs index 9ff14a27f6f..9fb5446e5b2 100644 --- a/tests/source/configs-match_align_arms-preserve.rs +++ b/tests/source/configs-match_align_arms-conservative.rs @@ -1,4 +1,5 @@ -// rustfmt-match_align_arms: Preserve +// rustfmt-match_align_arms: Conservative +// rustfmt-match_arm_align_threshold: 10 // Align match arms fn main() { @@ -17,9 +18,14 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } } } diff --git a/tests/source/configs-match_align_arms-never.rs b/tests/source/configs-match_align_arms-never.rs index 370d8683982..6e03238b500 100644 --- a/tests/source/configs-match_align_arms-never.rs +++ b/tests/source/configs-match_align_arms-never.rs @@ -17,9 +17,14 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } } } diff --git a/tests/target/configs-match_align_arms-always.rs b/tests/target/configs-match_align_arms-always.rs index bde862ca836..b68c026f5f1 100644 --- a/tests/target/configs-match_align_arms-always.rs +++ b/tests/target/configs-match_align_arms-always.rs @@ -17,22 +17,14 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => { + Lorem::Ipsum => { lorem(); ipsum(); } - Lorem::Sit => { + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { lorem(); ipsum(); } - Lorem::Amet => (), } } diff --git a/tests/target/configs-match_align_arms-preserve.rs b/tests/target/configs-match_align_arms-conservative.rs similarity index 52% rename from tests/target/configs-match_align_arms-preserve.rs rename to tests/target/configs-match_align_arms-conservative.rs index 2390500b39d..172a8f329c3 100644 --- a/tests/target/configs-match_align_arms-preserve.rs +++ b/tests/target/configs-match_align_arms-conservative.rs @@ -1,12 +1,13 @@ -// rustfmt-match_align_arms: Preserve +// rustfmt-match_align_arms: Conservative +// rustfmt-match_arm_align_threshold: 10 // Align match arms fn main() { match lorem { Lorem::Ipsum => (), Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Sit => (), + Lorem::Amet => (), } match lorem { @@ -17,9 +18,14 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } } } diff --git a/tests/target/configs-match_align_arms-never.rs b/tests/target/configs-match_align_arms-never.rs index 968726fd599..f5a43b59fc6 100644 --- a/tests/target/configs-match_align_arms-never.rs +++ b/tests/target/configs-match_align_arms-never.rs @@ -17,9 +17,14 @@ fn main() { } match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Ipsum => { + lorem(); + ipsum(); + } + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { + lorem(); + ipsum(); + } } } From 844353d737f5d92e373271384423aba53f8de836 Mon Sep 17 00:00:00 2001 From: ruin Date: Sat, 17 Jun 2017 13:32:27 -0500 Subject: [PATCH 07/11] remove unused arm functions --- src/expr.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 45736f400c5..06177816942 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1595,19 +1595,6 @@ fn arm_pat_end_pos_relative(arm: &ast::Arm) -> usize { (pats[pats.len() - 1].span.hi - pats[0].span.lo).0 as usize } -fn arm_arrow_pos(arm: &ast::Arm) -> usize { - let &ast::Arm { ref body, ref pats, .. } = arm; - let pat_start_pos = pats[0].span.lo; - // 3 = `=> `.len() - (body.span.lo - pat_start_pos).0 as usize - 3 -} - -fn arm_arrow_spacing(arm: &ast::Arm) -> usize { - let pat_end_rel = arm_pat_end_pos_relative(arm); - let arrow_pos = arm_arrow_pos(arm); - arrow_pos - pat_end_rel - 1 -} - fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str { if config.match_block_trailing_comma() { "," From 607bb2e9d4751ecaa862606dd471e76834904ef0 Mon Sep 17 00:00:00 2001 From: ruin Date: Sat, 17 Jun 2017 13:38:54 -0500 Subject: [PATCH 08/11] Remove redundant tests --- tests/source/configs-match_align_arms-always.rs | 11 ++--------- tests/source/configs-match_align_arms-conservative.rs | 11 ++--------- tests/target/configs-match_align_arms-always.rs | 7 ------- tests/target/configs-match_align_arms-conservative.rs | 7 ------- 4 files changed, 4 insertions(+), 32 deletions(-) diff --git a/tests/source/configs-match_align_arms-always.rs b/tests/source/configs-match_align_arms-always.rs index 08277d8680b..33c45ceb93c 100644 --- a/tests/source/configs-match_align_arms-always.rs +++ b/tests/source/configs-match_align_arms-always.rs @@ -2,18 +2,11 @@ // Align match arms fn main() { - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - match lorem { Lorem::Ipsum => (), Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Sit => (), + Lorem::Amet => (), } match lorem { diff --git a/tests/source/configs-match_align_arms-conservative.rs b/tests/source/configs-match_align_arms-conservative.rs index 9fb5446e5b2..7b5c3830804 100644 --- a/tests/source/configs-match_align_arms-conservative.rs +++ b/tests/source/configs-match_align_arms-conservative.rs @@ -3,18 +3,11 @@ // Align match arms fn main() { - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - match lorem { Lorem::Ipsum => (), Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), + Lorem::Sit => (), + Lorem::Amet => (), } match lorem { diff --git a/tests/target/configs-match_align_arms-always.rs b/tests/target/configs-match_align_arms-always.rs index b68c026f5f1..9debc04e547 100644 --- a/tests/target/configs-match_align_arms-always.rs +++ b/tests/target/configs-match_align_arms-always.rs @@ -9,13 +9,6 @@ fn main() { Lorem::Amet => (), } - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - match lorem { Lorem::Ipsum => { lorem(); diff --git a/tests/target/configs-match_align_arms-conservative.rs b/tests/target/configs-match_align_arms-conservative.rs index 172a8f329c3..57f76a6f4ec 100644 --- a/tests/target/configs-match_align_arms-conservative.rs +++ b/tests/target/configs-match_align_arms-conservative.rs @@ -10,13 +10,6 @@ fn main() { Lorem::Amet => (), } - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - match lorem { Lorem::Ipsum => { lorem(); From a48ad144f743e62db6e991d8c061731a8ec59f9c Mon Sep 17 00:00:00 2001 From: ruin Date: Sun, 18 Jun 2017 14:13:10 -0500 Subject: [PATCH 09/11] Use only "match_arm_align_threshold" to control match arm alignment --- Configurations.md | 74 ++----------------- src/config.rs | 12 +-- src/expr.rs | 31 ++++---- .../source/configs-match_align_arms-never.rs | 30 -------- ...onfigs-match_arm_align_threshold-above.rs} | 12 +-- ...onfigs-match_arm_align_threshold-below.rs} | 13 +--- .../target/configs-match_align_arms-never.rs | 30 -------- ...onfigs-match_arm_align_threshold-above.rs} | 8 -- ...onfigs-match_arm_align_threshold-below.rs} | 9 +-- 9 files changed, 31 insertions(+), 188 deletions(-) delete mode 100644 tests/source/configs-match_align_arms-never.rs rename tests/{target/configs-match_align_arms-conservative.rs => source/configs-match_arm_align_threshold-above.rs} (53%) rename tests/source/{configs-match_align_arms-always.rs => configs-match_arm_align_threshold-below.rs} (50%) delete mode 100644 tests/target/configs-match_align_arms-never.rs rename tests/{source/configs-match_align_arms-conservative.rs => target/configs-match_arm_align_threshold-above.rs} (64%) rename tests/target/{configs-match_align_arms-always.rs => configs-match_arm_align_threshold-below.rs} (67%) diff --git a/Configurations.md b/Configurations.md index b2e8662f7da..a9067d11dfb 100644 --- a/Configurations.md +++ b/Configurations.md @@ -968,67 +968,30 @@ struct Dolor ## `match_arm_align_threshold` -Maximum number of spaces between `match` statement patterns for the arms to be aligned by `match_align_arms`. +Maximum number of spaces between `match` statement patterns for the arms to be aligned with each other. -- **Default value**: `10` +- **Default value**: `0` - **Possible values**: any positive integer -**Note:** A value of `0` results in match arm alignment being applied regardless of the spacing between match arm patterns. +**Note:** A value greater than or equal to `max_width` results in match arm alignment being applied regardless of the spacing between match arm patterns. A value of `0` will never align match arms. #### Difference in width shorter than `match_arm_align_threshold`: ```rust match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), -} -``` - -#### Difference in width longer than `match_arm_align_threshold`: - -See [`match_align_arms`](#match_align_arms). - -## `match_align_arms` - -Aligns the arms of a `match` statement to be flush with each other. `"Conservative"` will only format match arms with a maximum of `match_arm_align_threshold` spaces between patterns. - -- **Default value**: `"Conservative"` -- **Possible values**: `"Always"`, `"Conservative"`, `"Never"` - -#### `"Never"`: - -```rust -match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), -} - -match lorem { - Lorem::Ipsum => { + Lorem::Ipsum => { lorem(); ipsum(); } Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { + Lorem::Eiusmod => { lorem(); ipsum(); } } ``` -#### `"Conservative"`: - +#### Difference in width longer than `match_arm_align_threshold`: ```rust -match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), -} - match lorem { Lorem::Ipsum => { lorem(); @@ -1042,30 +1005,7 @@ match lorem { } ``` -#### `"Always"`: - -```rust -match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), -} - -match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { - lorem(); - ipsum(); - } -} -``` - -See also: [`match_arm_align_threshold`](#match_arm_align_threshold), [`indent_match_arms`](#indent_match_arms), [`wrap_match_arms`](#wrap_match_arms). +See also: [`indent_match_arms`](#indent_match_arms), [`wrap_match_arms`](#wrap_match_arms). ## `match_block_trailing_comma` diff --git a/src/config.rs b/src/config.rs index 1f645baafce..481d88c328f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -93,13 +93,6 @@ configuration_option_enum! { TypeDensity: Wide, } -configuration_option_enum! { MatchAlignArms: - Always, - Conservative, - Never, -} - - impl Density { pub fn to_list_tactic(self) -> ListTactic { match self { @@ -605,9 +598,8 @@ create_config! { condense_wildcard_suffixes: bool, false, "Replace strings of _ wildcards by a single .. in \ tuple patterns"; combine_control_expr: bool, true, "Combine control expressions with funciton calls."; - match_align_arms: MatchAlignArms, MatchAlignArms::Never, "Align match arms"; - match_arm_align_threshold: usize, 10, "Maximum spacing between match arm patterns before \ - falling back on non-alignment" + match_arm_align_threshold: usize, 0, "Maximum difference in width between match arms for \ + them to be aligned. 0 means never align." } #[cfg(test)] diff --git a/src/expr.rs b/src/expr.rs index 06177816942..219e50e79a4 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -23,7 +23,7 @@ use utils::{extra_offset, last_line_width, wrap_str, binary_search, first_line_w semicolon_for_stmt, trimmed_last_line_width, left_most_sub_expr, stmt_expr, colon_spaces, contains_skip, mk_sp}; use visitor::FmtVisitor; -use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style, MatchAlignArms}; +use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style}; use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed}; use types::{rewrite_path, PathContext, can_be_overflowed_type}; use items::{span_lo_for_arg, span_hi_for_arg}; @@ -1473,7 +1473,12 @@ fn rewrite_match( let mut min_pat_pos = 0; let mut max_pat_pos = 0; - let mut realign_if_conservative = true; + let mut should_align_arms = true; + + if context.config.match_arm_align_threshold() == 0 { + should_align_arms = false; + } + if let Some(arm) = arms.first() { min_pat_pos = arm_pat_end_pos_relative(arm); max_pat_pos = min_pat_pos; @@ -1483,7 +1488,7 @@ fn rewrite_match( let pat_pos = arm_pat_end_pos_relative(arm); if max_pat_pos - min_pat_pos > context.config.match_arm_align_threshold() { - realign_if_conservative = false; + should_align_arms = false; } if pat_pos > max_pat_pos { @@ -1493,6 +1498,10 @@ fn rewrite_match( } } + if context.config.match_arm_align_threshold() >= context.config.max_width() { + should_align_arms = true; + } + let open_brace_pos = context.codemap.span_after( mk_sp(cond.span.hi, arm_start_pos(&arms[0])), "{", @@ -1505,18 +1514,10 @@ fn rewrite_match( }; for (i, arm) in arms.iter().enumerate() { - let alignment = match context.config.match_align_arms() { - MatchAlignArms::Always => { - max_pat_pos - arm_pat_end_pos_relative(arm) - } - MatchAlignArms::Conservative => { - if realign_if_conservative { - max_pat_pos - arm_pat_end_pos_relative(arm) - } else { - 0 - } - } - MatchAlignArms::Never => 0, + let alignment = if should_align_arms { + max_pat_pos - arm_pat_end_pos_relative(arm) + } else { + 0 }; arm_shape = if context.config.indent_match_arms() { diff --git a/tests/source/configs-match_align_arms-never.rs b/tests/source/configs-match_align_arms-never.rs deleted file mode 100644 index 6e03238b500..00000000000 --- a/tests/source/configs-match_align_arms-never.rs +++ /dev/null @@ -1,30 +0,0 @@ -// rustfmt-match_align_arms: Never -// Align match arms - -fn main() { - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { - lorem(); - ipsum(); - } - } -} diff --git a/tests/target/configs-match_align_arms-conservative.rs b/tests/source/configs-match_arm_align_threshold-above.rs similarity index 53% rename from tests/target/configs-match_align_arms-conservative.rs rename to tests/source/configs-match_arm_align_threshold-above.rs index 57f76a6f4ec..acef540f5c7 100644 --- a/tests/target/configs-match_align_arms-conservative.rs +++ b/tests/source/configs-match_arm_align_threshold-above.rs @@ -1,22 +1,14 @@ -// rustfmt-match_align_arms: Conservative // rustfmt-match_arm_align_threshold: 10 // Align match arms fn main() { match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => { + Lorem::Ipsum => { lorem(); ipsum(); } Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { + Lorem::Eiusmod => { lorem(); ipsum(); } diff --git a/tests/source/configs-match_align_arms-always.rs b/tests/source/configs-match_arm_align_threshold-below.rs similarity index 50% rename from tests/source/configs-match_align_arms-always.rs rename to tests/source/configs-match_arm_align_threshold-below.rs index 33c45ceb93c..8078c73cb1e 100644 --- a/tests/source/configs-match_align_arms-always.rs +++ b/tests/source/configs-match_arm_align_threshold-below.rs @@ -1,21 +1,14 @@ -// rustfmt-match_align_arms: Always +// rustfmt-match_arm_align_threshold: 100 // Align match arms fn main() { match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => { + Lorem::Ipsum => { lorem(); ipsum(); } Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { + Lorem::Eiusmod => { lorem(); ipsum(); } diff --git a/tests/target/configs-match_align_arms-never.rs b/tests/target/configs-match_align_arms-never.rs deleted file mode 100644 index f5a43b59fc6..00000000000 --- a/tests/target/configs-match_align_arms-never.rs +++ /dev/null @@ -1,30 +0,0 @@ -// rustfmt-match_align_arms: Never -// Align match arms - -fn main() { - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - - match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { - lorem(); - ipsum(); - } - } -} diff --git a/tests/source/configs-match_align_arms-conservative.rs b/tests/target/configs-match_arm_align_threshold-above.rs similarity index 64% rename from tests/source/configs-match_align_arms-conservative.rs rename to tests/target/configs-match_arm_align_threshold-above.rs index 7b5c3830804..6bf7bd48af5 100644 --- a/tests/source/configs-match_align_arms-conservative.rs +++ b/tests/target/configs-match_arm_align_threshold-above.rs @@ -1,15 +1,7 @@ -// rustfmt-match_align_arms: Conservative // rustfmt-match_arm_align_threshold: 10 // Align match arms fn main() { - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - match lorem { Lorem::Ipsum => { lorem(); diff --git a/tests/target/configs-match_align_arms-always.rs b/tests/target/configs-match_arm_align_threshold-below.rs similarity index 67% rename from tests/target/configs-match_align_arms-always.rs rename to tests/target/configs-match_arm_align_threshold-below.rs index 9debc04e547..d7b5b143027 100644 --- a/tests/target/configs-match_align_arms-always.rs +++ b/tests/target/configs-match_arm_align_threshold-below.rs @@ -1,14 +1,7 @@ -// rustfmt-match_align_arms: Always +// rustfmt-match_arm_align_threshold: 100 // Align match arms fn main() { - match lorem { - Lorem::Ipsum => (), - Lorem::Dolor => (), - Lorem::Sit => (), - Lorem::Amet => (), - } - match lorem { Lorem::Ipsum => { lorem(); From eead0872b12272f2b91e9d068a3e9213e09f3f48 Mon Sep 17 00:00:00 2001 From: Ian Pickering Date: Mon, 19 Jun 2017 13:22:45 -0500 Subject: [PATCH 10/11] Add extra tests --- src/expr.rs | 19 ++++++++++++++----- ...configs-match_arm_align_threshold-above.rs | 12 +++++++----- ...configs-match_arm_align_threshold-below.rs | 13 ++++++++----- ...configs-match_arm_align_threshold-above.rs | 10 ++++++---- ...configs-match_arm_align_threshold-below.rs | 14 ++++++++------ 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 219e50e79a4..494e3a2ec4c 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1480,12 +1480,12 @@ fn rewrite_match( } if let Some(arm) = arms.first() { - min_pat_pos = arm_pat_end_pos_relative(arm); + min_pat_pos = arm_pat_end_pos_relative(arm, shape.indent.block_indent, context); max_pat_pos = min_pat_pos; } for arm in arms.iter() { - let pat_pos = arm_pat_end_pos_relative(arm); + let pat_pos = arm_pat_end_pos_relative(arm, shape.indent.block_indent, context); if max_pat_pos - min_pat_pos > context.config.match_arm_align_threshold() { should_align_arms = false; @@ -1515,7 +1515,7 @@ fn rewrite_match( for (i, arm) in arms.iter().enumerate() { let alignment = if should_align_arms { - max_pat_pos - arm_pat_end_pos_relative(arm) + max_pat_pos - arm_pat_end_pos_relative(arm, shape.indent.block_indent, context) } else { 0 }; @@ -1591,9 +1591,18 @@ fn arm_end_pos(arm: &ast::Arm) -> BytePos { arm.body.span.hi } -fn arm_pat_end_pos_relative(arm: &ast::Arm) -> usize { +fn arm_pat_end_pos_relative(arm: &ast::Arm, indent: usize, context: &RewriteContext) -> usize { let &ast::Arm { ref pats, .. } = arm; - (pats[pats.len() - 1].span.hi - pats[0].span.lo).0 as usize + let mut len = indent; + let wrap_width = context.config.max_width(); + for pat in pats.iter() { + let pat_width = (pat.span.hi - pat.span.lo).0 as usize; + len += pat_width; + if len + indent > wrap_width { + len = pat_width; + } + } + len } fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str { diff --git a/tests/source/configs-match_arm_align_threshold-above.rs b/tests/source/configs-match_arm_align_threshold-above.rs index acef540f5c7..03eea4e1543 100644 --- a/tests/source/configs-match_arm_align_threshold-above.rs +++ b/tests/source/configs-match_arm_align_threshold-above.rs @@ -3,14 +3,16 @@ fn main() { match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Ipsum => (), + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), Lorem::Eiusmod => { lorem(); ipsum(); } + Lorem::Donec | Lorem::Hendrerit | Lorem::Tempor | Lorem::Tellus | Lorem::Proin | + Lorem::Quam | Lorem::Nisl => (), + Lorem::DonecHendrerit | + Lorem::TemporTellusProinQuamNislTinciduntEtMattisEgetConvallisNecPurusCumSociis => (), + Lorem::Natoque if lorem() => (), } } diff --git a/tests/source/configs-match_arm_align_threshold-below.rs b/tests/source/configs-match_arm_align_threshold-below.rs index 8078c73cb1e..62ca3228f68 100644 --- a/tests/source/configs-match_arm_align_threshold-below.rs +++ b/tests/source/configs-match_arm_align_threshold-below.rs @@ -3,14 +3,17 @@ fn main() { match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Ipsum => (), + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), Lorem::Eiusmod => { lorem(); ipsum(); } + Lorem::Donec | Lorem::Hendrerit | Lorem::Tempor | Lorem::Tellus | Lorem::Proin | + Lorem::Quam | Lorem::Nisl => (), + Lorem::DonecHendrerit | + Lorem::TemporTellusProinQuamNislTinciduntEtMattisEgetConvallisNecPurusCumSociis => (), + Lorem::Natoque if lorem() => (), } } + diff --git a/tests/target/configs-match_arm_align_threshold-above.rs b/tests/target/configs-match_arm_align_threshold-above.rs index 6bf7bd48af5..d2fa407bd6a 100644 --- a/tests/target/configs-match_arm_align_threshold-above.rs +++ b/tests/target/configs-match_arm_align_threshold-above.rs @@ -3,14 +3,16 @@ fn main() { match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } + Lorem::Ipsum => (), Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), Lorem::Eiusmod => { lorem(); ipsum(); } + Lorem::Donec | Lorem::Hendrerit | Lorem::Tempor | Lorem::Tellus | Lorem::Proin | + Lorem::Quam | Lorem::Nisl => (), + Lorem::DonecHendrerit | + Lorem::TemporTellusProinQuamNislTinciduntEtMattisEgetConvallisNecPurusCumSociis => (), + Lorem::Natoque if lorem() => (), } } diff --git a/tests/target/configs-match_arm_align_threshold-below.rs b/tests/target/configs-match_arm_align_threshold-below.rs index d7b5b143027..a4e2365744b 100644 --- a/tests/target/configs-match_arm_align_threshold-below.rs +++ b/tests/target/configs-match_arm_align_threshold-below.rs @@ -3,14 +3,16 @@ fn main() { match lorem { - Lorem::Ipsum => { - lorem(); - ipsum(); - } - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { + Lorem::Ipsum => (), + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { lorem(); ipsum(); } + Lorem::Donec | Lorem::Hendrerit | Lorem::Tempor | Lorem::Tellus | Lorem::Proin | + Lorem::Quam | Lorem::Nisl => (), + Lorem::DonecHendrerit | + Lorem::TemporTellusProinQuamNislTinciduntEtMattisEgetConvallisNecPurusCumSociis => (), + Lorem::Natoque if lorem() => (), } } From 99336c318bc1a4b87cbcdc60f8dbb5358deb0a77 Mon Sep 17 00:00:00 2001 From: Ian Pickering Date: Mon, 19 Jun 2017 13:27:01 -0500 Subject: [PATCH 11/11] fix test --- .../configs-match_arm_align_threshold-below.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/target/configs-match_arm_align_threshold-below.rs b/tests/target/configs-match_arm_align_threshold-below.rs index a4e2365744b..408e7abeb68 100644 --- a/tests/target/configs-match_arm_align_threshold-below.rs +++ b/tests/target/configs-match_arm_align_threshold-below.rs @@ -3,16 +3,16 @@ fn main() { match lorem { - Lorem::Ipsum => (), - Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), - Lorem::Eiusmod => { + Lorem::Ipsum => (), + Lorem::DolorSitAmetConsecteturAdipiscingElitSedDo => (), + Lorem::Eiusmod => { lorem(); ipsum(); } Lorem::Donec | Lorem::Hendrerit | Lorem::Tempor | Lorem::Tellus | Lorem::Proin | - Lorem::Quam | Lorem::Nisl => (), + Lorem::Quam | Lorem::Nisl => (), Lorem::DonecHendrerit | - Lorem::TemporTellusProinQuamNislTinciduntEtMattisEgetConvallisNecPurusCumSociis => (), - Lorem::Natoque if lorem() => (), + Lorem::TemporTellusProinQuamNislTinciduntEtMattisEgetConvallisNecPurusCumSociis => (), + Lorem::Natoque if lorem() => (), } }