Skip to content

Commit f8439ce

Browse files
committed
Put operands on its own line when each fits in a single line
1 parent 84e5634 commit f8439ce

File tree

1 file changed

+85
-9
lines changed

1 file changed

+85
-9
lines changed

src/expr.rs

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,18 @@ pub fn format_expr(
8686
rewrite_call(context, &callee_str, args, inner_span, shape)
8787
}
8888
ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span),
89-
ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => {
89+
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
9090
// FIXME: format comments between operands and operator
91-
rewrite_pair(
92-
&**lhs,
93-
&**rhs,
94-
PairParts::new("", &format!(" {} ", context.snippet(op.span)), ""),
95-
context,
96-
shape,
97-
context.config.binop_separator(),
98-
)
91+
rewrite_simple_binaries(context, expr, shape, op).or_else(|| {
92+
rewrite_pair(
93+
&**lhs,
94+
&**rhs,
95+
PairParts::new("", &format!(" {} ", context.snippet(op.span)), ""),
96+
context,
97+
shape,
98+
context.config.binop_separator(),
99+
)
100+
})
99101
}
100102
ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
101103
ast::ExprKind::Struct(ref path, ref fields, ref base) => rewrite_struct_lit(
@@ -352,6 +354,80 @@ pub fn format_expr(
352354
})
353355
}
354356

357+
/// Collect operands that appears in the given binary operator in the opposite order.
358+
/// e.g. `collect_binary_items(e, ||)` for `a && b || c || d` returns `[d, c, a && b]`.
359+
fn collect_binary_items<'a>(mut expr: &'a ast::Expr, binop: ast::BinOp) -> Vec<&'a ast::Expr> {
360+
let mut result = vec![];
361+
let mut prev_lhs = None;
362+
loop {
363+
match expr.node {
364+
ast::ExprKind::Binary(inner_binop, ref lhs, ref rhs)
365+
if inner_binop.node == binop.node =>
366+
{
367+
result.push(&**rhs);
368+
expr = lhs;
369+
prev_lhs = Some(lhs);
370+
}
371+
_ => {
372+
if let Some(lhs) = prev_lhs {
373+
result.push(lhs);
374+
}
375+
break;
376+
}
377+
}
378+
}
379+
result
380+
}
381+
382+
/// Rewrites a binary expression whose operands fits within a single line.
383+
fn rewrite_simple_binaries(
384+
context: &RewriteContext,
385+
expr: &ast::Expr,
386+
shape: Shape,
387+
op: ast::BinOp,
388+
) -> Option<String> {
389+
let op_str = context.snippet(op.span);
390+
391+
// 2 = spaces around a binary operator.
392+
let sep_overhead = op_str.len() + 2;
393+
let nested_overhead = sep_overhead - 1;
394+
395+
let nested_shape = (match context.config.indent_style() {
396+
IndentStyle::Visual => shape.visual_indent(0),
397+
IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
398+
}).with_max_width(context.config);
399+
let nested_shape = match context.config.binop_separator() {
400+
SeparatorPlace::Back => nested_shape.sub_width(nested_overhead)?,
401+
SeparatorPlace::Front => nested_shape.offset_left(nested_overhead)?,
402+
};
403+
404+
let opt_rewrites: Option<Vec<_>> = collect_binary_items(expr, op)
405+
.iter()
406+
.rev()
407+
.map(|e| e.rewrite(context, nested_shape))
408+
.collect();
409+
if let Some(rewrites) = opt_rewrites {
410+
if rewrites.iter().all(|e| ::utils::is_single_line(e)) {
411+
let total_width = rewrites.iter().map(|s| s.len()).sum::<usize>()
412+
+ sep_overhead * (rewrites.len() - 1);
413+
414+
let sep_str = if total_width <= shape.width {
415+
format!(" {} ", op_str)
416+
} else {
417+
let indent_str = nested_shape.indent.to_string_with_newline(context.config);
418+
match context.config.binop_separator() {
419+
SeparatorPlace::Back => format!(" {}{}", op_str.trim_right(), indent_str),
420+
SeparatorPlace::Front => format!("{}{} ", indent_str, op_str.trim_left()),
421+
}
422+
};
423+
424+
return wrap_str(rewrites.join(&sep_str), context.config.max_width(), shape);
425+
}
426+
}
427+
428+
None
429+
}
430+
355431
#[derive(new, Clone, Copy)]
356432
pub struct PairParts<'a> {
357433
prefix: &'a str,

0 commit comments

Comments
 (0)