@@ -86,16 +86,18 @@ pub fn format_expr(
86
86
rewrite_call ( context, & callee_str, args, inner_span, shape)
87
87
}
88
88
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) => {
90
90
// 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
+ } )
99
101
}
100
102
ast:: ExprKind :: Unary ( ref op, ref subexpr) => rewrite_unary_op ( context, op, subexpr, shape) ,
101
103
ast:: ExprKind :: Struct ( ref path, ref fields, ref base) => rewrite_struct_lit (
@@ -352,6 +354,80 @@ pub fn format_expr(
352
354
} )
353
355
}
354
356
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
+
355
431
#[ derive( new, Clone , Copy ) ]
356
432
pub struct PairParts < ' a > {
357
433
prefix : & ' a str ,
@@ -398,8 +474,10 @@ where
398
474
. map ( |first_line| first_line. ends_with ( '{' ) )
399
475
. unwrap_or ( false ) ;
400
476
if !rhs_result. contains ( '\n' ) || allow_same_line {
401
- let one_line_width = last_line_width ( & lhs_result) + pp. infix . len ( )
402
- + first_line_width ( rhs_result) + pp. suffix . len ( ) ;
477
+ let one_line_width = last_line_width ( & lhs_result)
478
+ + pp. infix . len ( )
479
+ + first_line_width ( rhs_result)
480
+ + pp. suffix . len ( ) ;
403
481
if one_line_width <= shape. width {
404
482
return Some ( format ! (
405
483
"{}{}{}{}" ,
@@ -482,7 +560,9 @@ fn rewrite_empty_block(
482
560
let user_str = user_str. trim ( ) ;
483
561
if user_str. starts_with ( '{' ) && user_str. ends_with ( '}' ) {
484
562
let comment_str = user_str[ 1 ..user_str. len ( ) - 1 ] . trim ( ) ;
485
- if block. stmts . is_empty ( ) && !comment_str. contains ( '\n' ) && !comment_str. starts_with ( "//" )
563
+ if block. stmts . is_empty ( )
564
+ && !comment_str. contains ( '\n' )
565
+ && !comment_str. starts_with ( "//" )
486
566
&& comment_str. len ( ) + 4 <= shape. width
487
567
{
488
568
return Some ( format ! ( "{}{{ {} }}" , prefix, comment_str) ) ;
@@ -1165,8 +1245,10 @@ pub fn is_simple_block(
1165
1245
attrs : Option < & [ ast:: Attribute ] > ,
1166
1246
codemap : & CodeMap ,
1167
1247
) -> bool {
1168
- ( block. stmts . len ( ) == 1 && stmt_is_expr ( & block. stmts [ 0 ] )
1169
- && !block_contains_comment ( block, codemap) && attrs. map_or ( true , |a| a. is_empty ( ) ) )
1248
+ ( block. stmts . len ( ) == 1
1249
+ && stmt_is_expr ( & block. stmts [ 0 ] )
1250
+ && !block_contains_comment ( block, codemap)
1251
+ && attrs. map_or ( true , |a| a. is_empty ( ) ) )
1170
1252
}
1171
1253
1172
1254
/// Checks whether a block contains at most one statement or expression, and no
@@ -1176,7 +1258,8 @@ pub fn is_simple_block_stmt(
1176
1258
attrs : Option < & [ ast:: Attribute ] > ,
1177
1259
codemap : & CodeMap ,
1178
1260
) -> bool {
1179
- block. stmts . len ( ) <= 1 && !block_contains_comment ( block, codemap)
1261
+ block. stmts . len ( ) <= 1
1262
+ && !block_contains_comment ( block, codemap)
1180
1263
&& attrs. map_or ( true , |a| a. is_empty ( ) )
1181
1264
}
1182
1265
@@ -1187,7 +1270,8 @@ pub fn is_empty_block(
1187
1270
attrs : Option < & [ ast:: Attribute ] > ,
1188
1271
codemap : & CodeMap ,
1189
1272
) -> bool {
1190
- block. stmts . is_empty ( ) && !block_contains_comment ( block, codemap)
1273
+ block. stmts . is_empty ( )
1274
+ && !block_contains_comment ( block, codemap)
1191
1275
&& attrs. map_or ( true , |a| inner_attributes ( a) . is_empty ( ) )
1192
1276
}
1193
1277
@@ -1702,7 +1786,8 @@ pub fn wrap_struct_field(
1702
1786
one_line_width : usize ,
1703
1787
) -> String {
1704
1788
if context. config . indent_style ( ) == IndentStyle :: Block
1705
- && ( fields_str. contains ( '\n' ) || !context. config . struct_lit_single_line ( )
1789
+ && ( fields_str. contains ( '\n' )
1790
+ || !context. config . struct_lit_single_line ( )
1706
1791
|| fields_str. len ( ) > one_line_width)
1707
1792
{
1708
1793
format ! (
@@ -2028,7 +2113,8 @@ fn choose_rhs<R: Rewrite>(
2028
2113
}
2029
2114
2030
2115
pub fn prefer_next_line ( orig_rhs : & str , next_line_rhs : & str , rhs_tactics : RhsTactics ) -> bool {
2031
- rhs_tactics == RhsTactics :: ForceNextLine || !next_line_rhs. contains ( '\n' )
2116
+ rhs_tactics == RhsTactics :: ForceNextLine
2117
+ || !next_line_rhs. contains ( '\n' )
2032
2118
|| count_newlines ( orig_rhs) > count_newlines ( next_line_rhs) + 1
2033
2119
}
2034
2120
0 commit comments