Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 95c2ad3

Browse files
committed
Refactor rewrite_where_clause
1 parent 264417e commit 95c2ad3

File tree

1 file changed

+136
-69
lines changed

1 file changed

+136
-69
lines changed

src/items.rs

Lines changed: 136 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ pub(crate) fn format_impl(
693693
{
694694
option.suppress_comma();
695695
option.snuggle();
696-
option.compress_where();
696+
option.allow_single_line();
697697
}
698698

699699
let misssing_span = mk_sp(self_ty.span.hi(), item.span.hi());
@@ -708,7 +708,6 @@ pub(crate) fn format_impl(
708708
where_span_end,
709709
self_ty.span.hi(),
710710
option,
711-
false,
712711
)?;
713712

714713
// 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(
10681067
None,
10691068
pos_before_where,
10701069
option,
1071-
false,
10721070
)?;
10731071
// If the where-clause cannot fit on the same line,
10741072
// put the where-clause on a new line
@@ -1376,7 +1374,7 @@ fn format_tuple_struct(
13761374
result.push_str(&generics_str);
13771375

13781376
let where_budget = context.budget(last_line_width(&result));
1379-
let option = WhereClauseOption::new(true, false);
1377+
let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
13801378
rewrite_where_clause(
13811379
context,
13821380
&generics.where_clause,
@@ -1387,7 +1385,6 @@ fn format_tuple_struct(
13871385
None,
13881386
body_hi,
13891387
option,
1390-
false,
13911388
)?
13921389
}
13931390
None => "".to_owned(),
@@ -1464,7 +1461,6 @@ fn rewrite_type_prefix(
14641461
None,
14651462
generics.span.hi(),
14661463
option,
1467-
false,
14681464
)?;
14691465
result.push_str(&where_clause_str);
14701466

@@ -2205,7 +2201,15 @@ fn rewrite_fn_base(
22052201

22062202
let is_args_multi_lined = arg_str.contains('\n');
22072203

2208-
let option = WhereClauseOption::new(!has_body, put_args_in_block && ret_str.is_empty());
2204+
let space = if put_args_in_block && ret_str.is_empty() {
2205+
WhereClauseSpace::Space
2206+
} else {
2207+
WhereClauseSpace::Newline
2208+
};
2209+
let mut option = WhereClauseOption::new(!has_body, space);
2210+
if is_args_multi_lined {
2211+
option.veto_single_line();
2212+
}
22092213
let where_clause_str = rewrite_where_clause(
22102214
context,
22112215
where_clause,
@@ -2216,7 +2220,6 @@ fn rewrite_fn_base(
22162220
Some(span.hi()),
22172221
pos_before_where,
22182222
option,
2219-
is_args_multi_lined,
22202223
)?;
22212224
// If there are neither where-clause nor return type, we may be missing comments between
22222225
// args and `{`.
@@ -2244,40 +2247,62 @@ fn rewrite_fn_base(
22442247
Some((result, force_new_line_for_brace))
22452248
}
22462249

2250+
/// Kind of spaces to put before `where`.
2251+
#[derive(Copy, Clone)]
2252+
enum WhereClauseSpace {
2253+
/// A single space.
2254+
Space,
2255+
/// A new line.
2256+
Newline,
2257+
/// Nothing.
2258+
None,
2259+
}
2260+
22472261
#[derive(Copy, Clone)]
22482262
struct WhereClauseOption {
22492263
suppress_comma: bool, // Force no trailing comma
2250-
snuggle: bool, // Do not insert newline before `where`
2251-
compress_where: bool, // Try single line where-clause instead of vertical layout
2264+
snuggle: WhereClauseSpace,
2265+
allow_single_line: bool, // Try single line where-clause instead of vertical layout
2266+
veto_single_line: bool, // Disallow a single-line where-clause.
22522267
}
22532268

22542269
impl WhereClauseOption {
2255-
fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption {
2270+
fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
22562271
WhereClauseOption {
22572272
suppress_comma,
22582273
snuggle,
2259-
compress_where: false,
2274+
allow_single_line: false,
2275+
veto_single_line: false,
22602276
}
22612277
}
22622278

22632279
fn snuggled(current: &str) -> WhereClauseOption {
22642280
WhereClauseOption {
22652281
suppress_comma: false,
2266-
snuggle: last_line_width(current) == 1,
2267-
compress_where: false,
2282+
snuggle: if last_line_width(current) == 1 {
2283+
WhereClauseSpace::Space
2284+
} else {
2285+
WhereClauseSpace::Newline
2286+
},
2287+
allow_single_line: false,
2288+
veto_single_line: false,
22682289
}
22692290
}
22702291

22712292
fn suppress_comma(&mut self) {
22722293
self.suppress_comma = true
22732294
}
22742295

2275-
fn compress_where(&mut self) {
2276-
self.compress_where = true
2296+
fn allow_single_line(&mut self) {
2297+
self.allow_single_line = true
22772298
}
22782299

22792300
fn snuggle(&mut self) {
2280-
self.snuggle = true
2301+
self.snuggle = WhereClauseSpace::Space
2302+
}
2303+
2304+
fn veto_single_line(&mut self) {
2305+
self.veto_single_line = true;
22812306
}
22822307
}
22832308

@@ -2467,25 +2492,104 @@ fn rewrite_where_clause_rfc_style(
24672492
span_end: Option<BytePos>,
24682493
span_end_before_where: BytePos,
24692494
where_clause_option: WhereClauseOption,
2470-
is_args_multi_line: bool,
24712495
) -> Option<String> {
2496+
let (where_keyword, allow_single_line) = rewrite_where_keyword(
2497+
context,
2498+
where_clause,
2499+
shape,
2500+
span_end_before_where,
2501+
where_clause_option,
2502+
)?;
2503+
2504+
// 1 = `,`
2505+
let clause_shape = shape
2506+
.block()
2507+
.with_max_width(context.config)
2508+
.block_left(context.config.tab_spaces())?
2509+
.sub_width(1)?;
2510+
let force_single_line = context.config.where_single_line()
2511+
&& where_clause.predicates.len() == 1
2512+
&& !where_clause_option.veto_single_line;
2513+
2514+
let preds_str = rewrite_bounds_on_where_clause(
2515+
context,
2516+
where_clause,
2517+
clause_shape,
2518+
terminator,
2519+
span_end,
2520+
where_clause_option,
2521+
force_single_line,
2522+
)?;
2523+
2524+
// 6 = `where `
2525+
let clause_sep =
2526+
if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
2527+
|| force_single_line
2528+
{
2529+
Cow::from(" ")
2530+
} else {
2531+
clause_shape.indent.to_string_with_newline(context.config)
2532+
};
2533+
2534+
Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
2535+
}
2536+
2537+
/// Rewrite `where` and comment around it.
2538+
fn rewrite_where_keyword(
2539+
context: &RewriteContext<'_>,
2540+
where_clause: &ast::WhereClause,
2541+
shape: Shape,
2542+
span_end_before_where: BytePos,
2543+
where_clause_option: WhereClauseOption,
2544+
) -> Option<(String, bool)> {
24722545
let block_shape = shape.block().with_max_width(context.config);
2546+
// 1 = `,`
2547+
let clause_shape = block_shape
2548+
.block_left(context.config.tab_spaces())?
2549+
.sub_width(1)?;
2550+
2551+
let comment_separator = |comment: &str, shape: Shape| {
2552+
if comment.is_empty() {
2553+
Cow::from("")
2554+
} else {
2555+
shape.indent.to_string_with_newline(context.config)
2556+
}
2557+
};
24732558

24742559
let (span_before, span_after) =
24752560
missing_span_before_after_where(span_end_before_where, where_clause);
24762561
let (comment_before, comment_after) =
24772562
rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
24782563

2479-
let starting_newline = if where_clause_option.snuggle && comment_before.is_empty() {
2480-
Cow::from(" ")
2481-
} else {
2482-
block_shape.indent.to_string_with_newline(context.config)
2564+
let starting_newline = match where_clause_option.snuggle {
2565+
WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
2566+
WhereClauseSpace::None => Cow::from(""),
2567+
_ => block_shape.indent.to_string_with_newline(context.config),
24832568
};
24842569

2485-
let clause_shape = block_shape.block_left(context.config.tab_spaces())?;
2486-
// 1 = `,`
2487-
let clause_shape = clause_shape.sub_width(1)?;
2488-
// each clause on one line, trailing comma (except if suppress_comma)
2570+
let newline_before_where = comment_separator(&comment_before, shape);
2571+
let newline_after_where = comment_separator(&comment_after, clause_shape);
2572+
let result = format!(
2573+
"{}{}{}where{}{}",
2574+
starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
2575+
);
2576+
let allow_single_line = where_clause_option.allow_single_line
2577+
&& comment_before.is_empty()
2578+
&& comment_after.is_empty();
2579+
2580+
Some((result, allow_single_line))
2581+
}
2582+
2583+
/// Rewrite bounds on a where clause.
2584+
fn rewrite_bounds_on_where_clause(
2585+
context: &RewriteContext<'_>,
2586+
where_clause: &ast::WhereClause,
2587+
shape: Shape,
2588+
terminator: &str,
2589+
span_end: Option<BytePos>,
2590+
where_clause_option: WhereClauseOption,
2591+
force_single_line: bool,
2592+
) -> Option<String> {
24892593
let span_start = where_clause.predicates[0].span().lo();
24902594
// If we don't have the start of the next span, then use the end of the
24912595
// predicates, but that means we miss comments.
@@ -2499,64 +2603,30 @@ fn rewrite_where_clause_rfc_style(
24992603
",",
25002604
|pred| pred.span().lo(),
25012605
|pred| pred.span().hi(),
2502-
|pred| pred.rewrite(context, clause_shape),
2606+
|pred| pred.rewrite(context, shape),
25032607
span_start,
25042608
span_end,
25052609
false,
25062610
);
2507-
let where_single_line = context.config.where_single_line() && len == 1 && !is_args_multi_line;
2508-
let comma_tactic = if where_clause_option.suppress_comma || where_single_line {
2611+
let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
25092612
SeparatorTactic::Never
25102613
} else {
25112614
context.config.trailing_comma()
25122615
};
25132616

2514-
// shape should be vertical only and only if we have `where_single_line` option enabled
2617+
// shape should be vertical only and only if we have `force_single_line` option enabled
25152618
// and the number of items of the where-clause is equal to 1
2516-
let shape_tactic = if where_single_line {
2619+
let shape_tactic = if force_single_line {
25172620
DefinitiveListTactic::Horizontal
25182621
} else {
25192622
DefinitiveListTactic::Vertical
25202623
};
25212624

2522-
let fmt = ListFormatting::new(clause_shape, context.config)
2625+
let fmt = ListFormatting::new(shape, context.config)
25232626
.tactic(shape_tactic)
25242627
.trailing_separator(comma_tactic)
25252628
.preserve_newline(true);
2526-
let preds_str = write_list(&items.collect::<Vec<_>>(), &fmt)?;
2527-
2528-
let comment_separator = |comment: &str, shape: Shape| {
2529-
if comment.is_empty() {
2530-
Cow::from("")
2531-
} else {
2532-
shape.indent.to_string_with_newline(context.config)
2533-
}
2534-
};
2535-
let newline_before_where = comment_separator(&comment_before, shape);
2536-
let newline_after_where = comment_separator(&comment_after, clause_shape);
2537-
2538-
// 6 = `where `
2539-
let clause_sep = if where_clause_option.compress_where
2540-
&& comment_before.is_empty()
2541-
&& comment_after.is_empty()
2542-
&& !preds_str.contains('\n')
2543-
&& 6 + preds_str.len() <= shape.width
2544-
|| where_single_line
2545-
{
2546-
Cow::from(" ")
2547-
} else {
2548-
clause_shape.indent.to_string_with_newline(context.config)
2549-
};
2550-
Some(format!(
2551-
"{}{}{}where{}{}{}{}",
2552-
starting_newline,
2553-
comment_before,
2554-
newline_before_where,
2555-
newline_after_where,
2556-
comment_after,
2557-
clause_sep,
2558-
preds_str
2559-
))
2629+
write_list(&items.collect::<Vec<_>>(), &fmt)
25602630
}
25612631

25622632
fn rewrite_where_clause(
@@ -2569,7 +2639,6 @@ fn rewrite_where_clause(
25692639
span_end: Option<BytePos>,
25702640
span_end_before_where: BytePos,
25712641
where_clause_option: WhereClauseOption,
2572-
is_args_multi_line: bool,
25732642
) -> Option<String> {
25742643
if where_clause.predicates.is_empty() {
25752644
return Some(String::new());
@@ -2584,7 +2653,6 @@ fn rewrite_where_clause(
25842653
span_end,
25852654
span_end_before_where,
25862655
where_clause_option,
2587-
is_args_multi_line,
25882656
);
25892657
}
25902658

@@ -2742,7 +2810,6 @@ fn format_generics(
27422810
Some(span.hi()),
27432811
span_end_before_where,
27442812
option,
2745-
false,
27462813
)?;
27472814
result.push_str(&where_clause_str);
27482815
(

0 commit comments

Comments
 (0)