From 95c2ad37e141a62f184f49dc7a6f12840b67b826 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sun, 26 May 2019 21:15:38 +0900 Subject: [PATCH] Refactor rewrite_where_clause --- src/items.rs | 205 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 136 insertions(+), 69 deletions(-) diff --git a/src/items.rs b/src/items.rs index d642718412f..d39a0bb528b 100644 --- a/src/items.rs +++ b/src/items.rs @@ -693,7 +693,7 @@ pub(crate) fn format_impl( { option.suppress_comma(); option.snuggle(); - option.compress_where(); + option.allow_single_line(); } let misssing_span = mk_sp(self_ty.span.hi(), item.span.hi()); @@ -708,7 +708,6 @@ pub(crate) fn format_impl( where_span_end, self_ty.span.hi(), option, - false, )?; // If there is no where-clause, we may have missing comments between the trait name and @@ -1068,7 +1067,6 @@ pub(crate) fn format_trait( None, pos_before_where, option, - false, )?; // If the where-clause cannot fit on the same line, // put the where-clause on a new line @@ -1376,7 +1374,7 @@ fn format_tuple_struct( result.push_str(&generics_str); let where_budget = context.budget(last_line_width(&result)); - let option = WhereClauseOption::new(true, false); + let option = WhereClauseOption::new(true, WhereClauseSpace::Newline); rewrite_where_clause( context, &generics.where_clause, @@ -1387,7 +1385,6 @@ fn format_tuple_struct( None, body_hi, option, - false, )? } None => "".to_owned(), @@ -1464,7 +1461,6 @@ fn rewrite_type_prefix( None, generics.span.hi(), option, - false, )?; result.push_str(&where_clause_str); @@ -2205,7 +2201,15 @@ fn rewrite_fn_base( let is_args_multi_lined = arg_str.contains('\n'); - let option = WhereClauseOption::new(!has_body, put_args_in_block && ret_str.is_empty()); + let space = if put_args_in_block && ret_str.is_empty() { + WhereClauseSpace::Space + } else { + WhereClauseSpace::Newline + }; + let mut option = WhereClauseOption::new(!has_body, space); + if is_args_multi_lined { + option.veto_single_line(); + } let where_clause_str = rewrite_where_clause( context, where_clause, @@ -2216,7 +2220,6 @@ fn rewrite_fn_base( Some(span.hi()), pos_before_where, option, - is_args_multi_lined, )?; // If there are neither where-clause nor return type, we may be missing comments between // args and `{`. @@ -2244,27 +2247,45 @@ fn rewrite_fn_base( Some((result, force_new_line_for_brace)) } +/// Kind of spaces to put before `where`. +#[derive(Copy, Clone)] +enum WhereClauseSpace { + /// A single space. + Space, + /// A new line. + Newline, + /// Nothing. + None, +} + #[derive(Copy, Clone)] struct WhereClauseOption { suppress_comma: bool, // Force no trailing comma - snuggle: bool, // Do not insert newline before `where` - compress_where: bool, // Try single line where-clause instead of vertical layout + snuggle: WhereClauseSpace, + allow_single_line: bool, // Try single line where-clause instead of vertical layout + veto_single_line: bool, // Disallow a single-line where-clause. } impl WhereClauseOption { - fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption { + fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption { WhereClauseOption { suppress_comma, snuggle, - compress_where: false, + allow_single_line: false, + veto_single_line: false, } } fn snuggled(current: &str) -> WhereClauseOption { WhereClauseOption { suppress_comma: false, - snuggle: last_line_width(current) == 1, - compress_where: false, + snuggle: if last_line_width(current) == 1 { + WhereClauseSpace::Space + } else { + WhereClauseSpace::Newline + }, + allow_single_line: false, + veto_single_line: false, } } @@ -2272,12 +2293,16 @@ fn suppress_comma(&mut self) { self.suppress_comma = true } - fn compress_where(&mut self) { - self.compress_where = true + fn allow_single_line(&mut self) { + self.allow_single_line = true } fn snuggle(&mut self) { - self.snuggle = true + self.snuggle = WhereClauseSpace::Space + } + + fn veto_single_line(&mut self) { + self.veto_single_line = true; } } @@ -2467,25 +2492,104 @@ fn rewrite_where_clause_rfc_style( span_end: Option, span_end_before_where: BytePos, where_clause_option: WhereClauseOption, - is_args_multi_line: bool, ) -> Option { + let (where_keyword, allow_single_line) = rewrite_where_keyword( + context, + where_clause, + shape, + span_end_before_where, + where_clause_option, + )?; + + // 1 = `,` + let clause_shape = shape + .block() + .with_max_width(context.config) + .block_left(context.config.tab_spaces())? + .sub_width(1)?; + let force_single_line = context.config.where_single_line() + && where_clause.predicates.len() == 1 + && !where_clause_option.veto_single_line; + + let preds_str = rewrite_bounds_on_where_clause( + context, + where_clause, + clause_shape, + terminator, + span_end, + where_clause_option, + force_single_line, + )?; + + // 6 = `where ` + let clause_sep = + if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width + || force_single_line + { + Cow::from(" ") + } else { + clause_shape.indent.to_string_with_newline(context.config) + }; + + Some(format!("{}{}{}", where_keyword, clause_sep, preds_str)) +} + +/// Rewrite `where` and comment around it. +fn rewrite_where_keyword( + context: &RewriteContext<'_>, + where_clause: &ast::WhereClause, + shape: Shape, + span_end_before_where: BytePos, + where_clause_option: WhereClauseOption, +) -> Option<(String, bool)> { let block_shape = shape.block().with_max_width(context.config); + // 1 = `,` + let clause_shape = block_shape + .block_left(context.config.tab_spaces())? + .sub_width(1)?; + + let comment_separator = |comment: &str, shape: Shape| { + if comment.is_empty() { + Cow::from("") + } else { + shape.indent.to_string_with_newline(context.config) + } + }; let (span_before, span_after) = missing_span_before_after_where(span_end_before_where, where_clause); let (comment_before, comment_after) = rewrite_comments_before_after_where(context, span_before, span_after, shape)?; - let starting_newline = if where_clause_option.snuggle && comment_before.is_empty() { - Cow::from(" ") - } else { - block_shape.indent.to_string_with_newline(context.config) + let starting_newline = match where_clause_option.snuggle { + WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "), + WhereClauseSpace::None => Cow::from(""), + _ => block_shape.indent.to_string_with_newline(context.config), }; - let clause_shape = block_shape.block_left(context.config.tab_spaces())?; - // 1 = `,` - let clause_shape = clause_shape.sub_width(1)?; - // each clause on one line, trailing comma (except if suppress_comma) + let newline_before_where = comment_separator(&comment_before, shape); + let newline_after_where = comment_separator(&comment_after, clause_shape); + let result = format!( + "{}{}{}where{}{}", + starting_newline, comment_before, newline_before_where, newline_after_where, comment_after + ); + let allow_single_line = where_clause_option.allow_single_line + && comment_before.is_empty() + && comment_after.is_empty(); + + Some((result, allow_single_line)) +} + +/// Rewrite bounds on a where clause. +fn rewrite_bounds_on_where_clause( + context: &RewriteContext<'_>, + where_clause: &ast::WhereClause, + shape: Shape, + terminator: &str, + span_end: Option, + where_clause_option: WhereClauseOption, + force_single_line: bool, +) -> Option { let span_start = where_clause.predicates[0].span().lo(); // If we don't have the start of the next span, then use the end of the // predicates, but that means we miss comments. @@ -2499,64 +2603,30 @@ fn rewrite_where_clause_rfc_style( ",", |pred| pred.span().lo(), |pred| pred.span().hi(), - |pred| pred.rewrite(context, clause_shape), + |pred| pred.rewrite(context, shape), span_start, span_end, false, ); - let where_single_line = context.config.where_single_line() && len == 1 && !is_args_multi_line; - let comma_tactic = if where_clause_option.suppress_comma || where_single_line { + let comma_tactic = if where_clause_option.suppress_comma || force_single_line { SeparatorTactic::Never } else { context.config.trailing_comma() }; - // shape should be vertical only and only if we have `where_single_line` option enabled + // shape should be vertical only and only if we have `force_single_line` option enabled // and the number of items of the where-clause is equal to 1 - let shape_tactic = if where_single_line { + let shape_tactic = if force_single_line { DefinitiveListTactic::Horizontal } else { DefinitiveListTactic::Vertical }; - let fmt = ListFormatting::new(clause_shape, context.config) + let fmt = ListFormatting::new(shape, context.config) .tactic(shape_tactic) .trailing_separator(comma_tactic) .preserve_newline(true); - let preds_str = write_list(&items.collect::>(), &fmt)?; - - let comment_separator = |comment: &str, shape: Shape| { - if comment.is_empty() { - Cow::from("") - } else { - shape.indent.to_string_with_newline(context.config) - } - }; - let newline_before_where = comment_separator(&comment_before, shape); - let newline_after_where = comment_separator(&comment_after, clause_shape); - - // 6 = `where ` - let clause_sep = if where_clause_option.compress_where - && comment_before.is_empty() - && comment_after.is_empty() - && !preds_str.contains('\n') - && 6 + preds_str.len() <= shape.width - || where_single_line - { - Cow::from(" ") - } else { - clause_shape.indent.to_string_with_newline(context.config) - }; - Some(format!( - "{}{}{}where{}{}{}{}", - starting_newline, - comment_before, - newline_before_where, - newline_after_where, - comment_after, - clause_sep, - preds_str - )) + write_list(&items.collect::>(), &fmt) } fn rewrite_where_clause( @@ -2569,7 +2639,6 @@ fn rewrite_where_clause( span_end: Option, span_end_before_where: BytePos, where_clause_option: WhereClauseOption, - is_args_multi_line: bool, ) -> Option { if where_clause.predicates.is_empty() { return Some(String::new()); @@ -2584,7 +2653,6 @@ fn rewrite_where_clause( span_end, span_end_before_where, where_clause_option, - is_args_multi_line, ); } @@ -2742,7 +2810,6 @@ fn format_generics( Some(span.hi()), span_end_before_where, option, - false, )?; result.push_str(&where_clause_str); (