@@ -98,40 +98,31 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
98
98
if chain_only_try ( & subexpr_list) {
99
99
return rewrite_try ( & parent, subexpr_list. len ( ) , context, shape) ;
100
100
}
101
- let trailing_try_num = subexpr_list
102
- . iter ( )
103
- . take_while ( |e| match e. node {
104
- ast:: ExprKind :: Try ( ..) => true ,
105
- _ => false ,
106
- } )
107
- . count ( ) ;
101
+ let suffix_try_num = subexpr_list. iter ( ) . take_while ( |e| is_try ( e) ) . count ( ) ;
102
+ let prefix_try_num = subexpr_list. iter ( ) . rev ( ) . take_while ( |e| is_try ( e) ) . count ( ) ;
108
103
109
104
// Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
110
105
let parent_shape = if is_block_expr ( context, & parent, "\n " ) {
111
106
match context. config . chain_indent ( ) {
112
107
IndentStyle :: Visual => shape. visual_indent ( 0 ) ,
113
- IndentStyle :: Block => shape. block ( ) ,
108
+ IndentStyle :: Block => shape,
114
109
}
115
110
} else {
116
111
shape
117
112
} ;
118
- let parent_rewrite = try_opt ! ( parent. rewrite( context, parent_shape) ) ;
113
+ let parent_rewrite = try_opt ! (
114
+ parent
115
+ . rewrite( context, parent_shape)
116
+ . map( |parent_rw| parent_rw + & repeat_try( prefix_try_num) )
117
+ ) ;
119
118
let parent_rewrite_contains_newline = parent_rewrite. contains ( '\n' ) ;
120
119
let is_small_parent = parent_rewrite. len ( ) <= context. config . tab_spaces ( ) ;
121
120
122
121
// Decide how to layout the rest of the chain. `extend` is true if we can
123
122
// put the first non-parent item on the same line as the parent.
124
- let first_subexpr_is_try = subexpr_list. last ( ) . map_or ( false , is_try) ;
125
123
let ( nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable ( & parent) {
126
- let nested_shape = if first_subexpr_is_try {
127
- parent_shape
128
- . block_indent ( context. config . tab_spaces ( ) )
129
- . with_max_width ( context. config )
130
- } else {
131
- chain_indent ( context, shape. add_offset ( parent_rewrite. len ( ) ) )
132
- } ;
133
124
(
134
- nested_shape ,
125
+ chain_indent ( context , shape . add_offset ( parent_rewrite . len ( ) ) ) ,
135
126
context. config . chain_indent ( ) == IndentStyle :: Visual || is_small_parent,
136
127
)
137
128
} else if is_block_expr ( context, & parent, & parent_rewrite) {
@@ -142,13 +133,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
142
133
// brace.
143
134
IndentStyle :: Visual => ( parent_shape, false ) ,
144
135
}
145
- } else if parent_rewrite_contains_newline {
146
- ( chain_indent ( context, parent_shape) , false )
147
136
} else {
148
137
(
149
- shape
150
- . block_indent ( context. config . tab_spaces ( ) )
151
- . with_max_width ( context. config ) ,
138
+ chain_indent ( context, shape. add_offset ( parent_rewrite. len ( ) ) ) ,
152
139
false ,
153
140
)
154
141
} ;
@@ -171,95 +158,60 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
171
158
other_child_shape
172
159
) ;
173
160
174
- let child_shape_iter = Some ( first_child_shape) . into_iter ( ) . chain (
175
- :: std:: iter:: repeat ( other_child_shape) . take ( subexpr_list. len ( ) - 1 ) ,
176
- ) ;
177
- let iter = subexpr_list. iter ( ) . rev ( ) . zip ( child_shape_iter) ;
161
+ let child_shape_iter = Some ( first_child_shape)
162
+ . into_iter ( )
163
+ . chain ( iter:: repeat ( other_child_shape) ) ;
164
+ let subexpr_num = subexpr_list. len ( ) ;
165
+ let last_subexpr = & subexpr_list[ suffix_try_num] ;
166
+ let subexpr_list = & subexpr_list[ suffix_try_num..subexpr_num - prefix_try_num] ;
167
+ let iter = subexpr_list. iter ( ) . skip ( 1 ) . rev ( ) . zip ( child_shape_iter) ;
178
168
let mut rewrites = try_opt ! (
179
169
iter. map( |( e, shape) | {
180
170
rewrite_chain_subexpr( e, total_span, context, shape)
181
171
} ) . collect:: <Option <Vec <_>>>( )
182
172
) ;
183
173
184
174
// Total of all items excluding the last.
185
- let last_non_try_index = rewrites. len ( ) - ( 1 + trailing_try_num) ;
186
- let almost_total = rewrites[ ..last_non_try_index]
187
- . iter ( )
188
- . fold ( 0 , |a, b| a + first_line_width ( b) ) + parent_rewrite. len ( ) ;
189
- let one_line_len =
190
- rewrites. iter ( ) . fold ( 0 , |a, r| a + first_line_width ( r) ) + parent_rewrite. len ( ) ;
191
-
192
- let one_line_budget = min ( shape. width , context. config . chain_one_line_max ( ) ) ;
193
- let veto_single_line = if one_line_len > one_line_budget {
194
- if rewrites. len ( ) > 1 {
195
- true
196
- } else if rewrites. len ( ) == 1 {
197
- context. config . chain_split_single_child ( ) || one_line_len > shape. width
198
- } else {
199
- false
200
- }
201
- } else if context. config . take_source_hints ( ) && subexpr_list. len ( ) > 1 {
202
- // Look at the source code. Unless all chain elements start on the same
203
- // line, we won't consider putting them on a single line either.
204
- let last_span = context. snippet ( mk_sp ( subexpr_list[ 1 ] . span . hi , total_span. hi ) ) ;
205
- let first_span = context. snippet ( subexpr_list[ 1 ] . span ) ;
206
- let last_iter = last_span. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) ;
207
-
208
- first_span. chars ( ) . chain ( last_iter) . any ( |c| c == '\n' )
175
+ let extend_last_subexr = last_line_extendable ( & parent_rewrite) && rewrites. is_empty ( ) ;
176
+ let almost_total = if extend_last_subexr {
177
+ last_line_width ( & parent_rewrite)
209
178
} else {
210
- false
179
+ rewrites . iter ( ) . fold ( 0 , |a , b| a + b . len ( ) ) + parent_rewrite . len ( )
211
180
} ;
212
-
213
- let mut fits_single_line = !veto_single_line && almost_total <= shape. width ;
214
- if fits_single_line {
215
- let len = rewrites. len ( ) ;
216
- let ( init, last) = rewrites. split_at_mut ( len - ( 1 + trailing_try_num) ) ;
217
- fits_single_line = init. iter ( ) . all ( |s| !s. contains ( '\n' ) ) ;
218
-
219
- if fits_single_line {
220
- fits_single_line = match expr. node {
221
- ref e @ ast:: ExprKind :: MethodCall ( ..) => {
222
- if rewrite_method_call_with_overflow (
223
- e,
224
- & mut last[ 0 ] ,
225
- almost_total,
226
- total_span,
227
- context,
228
- shape,
229
- ) {
230
- // If the first line of the last method does not fit into a single line
231
- // after the others, allow new lines.
232
- almost_total + first_line_width ( & last[ 0 ] ) < context. config . max_width ( )
233
- } else {
234
- false
181
+ let one_line_budget = if rewrites. is_empty ( ) && !context. config . chain_split_single_child ( ) {
182
+ shape. width
183
+ } else {
184
+ min ( shape. width , context. config . chain_one_line_max ( ) )
185
+ } ;
186
+ let all_in_one_line = !parent_rewrite_contains_newline &&
187
+ rewrites. iter ( ) . all ( |s| !s. contains ( '\n' ) ) &&
188
+ almost_total < one_line_budget;
189
+ let rewrite_last = || rewrite_chain_subexpr ( last_subexpr, total_span, context, nested_shape) ;
190
+ let ( last_subexpr_str, fits_single_line) = try_opt ! ( if all_in_one_line || extend_last_subexr {
191
+ parent_shape. offset_left( almost_total) . map( |shape| {
192
+ if let Some ( rw) = rewrite_chain_subexpr( last_subexpr, total_span, context, shape) {
193
+ let line_count = rw. lines( ) . count( ) ;
194
+ let fits_single_line = almost_total + first_line_width( & rw) <= one_line_budget;
195
+ if ( line_count >= 5 && fits_single_line) || extend_last_subexr {
196
+ ( Some ( rw) , true )
197
+ } else {
198
+ match rewrite_last( ) {
199
+ Some ( ref new_rw) if !fits_single_line => ( Some ( new_rw. clone( ) ) , false ) ,
200
+ Some ( ref new_rw) if new_rw. lines( ) . count( ) >= line_count => {
201
+ ( Some ( rw) , fits_single_line)
202
+ }
203
+ new_rw @ Some ( ..) => ( new_rw, false ) ,
204
+ _ => ( Some ( rw) , fits_single_line) ,
235
205
}
236
206
}
237
- _ => !last[ 0 ] . contains ( '\n' ) ,
207
+ } else {
208
+ ( rewrite_last( ) , false )
238
209
}
239
- }
240
- }
241
-
242
- // Try overflowing the last element if we are using block indent and it goes multi line
243
- // or it fits in a single line but goes over the max width.
244
- if !fits_single_line && context. use_block_indent ( ) {
245
- let ( init, last) = rewrites. split_at_mut ( last_non_try_index) ;
246
- let almost_single_line = init. iter ( ) . all ( |s| !s. contains ( '\n' ) ) ;
247
- if almost_single_line && last[ 0 ] . contains ( '\n' ) {
248
- let overflow_shape = Shape {
249
- width : one_line_budget,
250
- ..parent_shape
251
- } ;
252
- fits_single_line = rewrite_last_child_with_overflow (
253
- context,
254
- & subexpr_list[ trailing_try_num] ,
255
- overflow_shape,
256
- total_span,
257
- almost_total,
258
- one_line_budget,
259
- & mut last[ 0 ] ,
260
- ) ;
261
- }
262
- }
210
+ } )
211
+ } else {
212
+ Some ( ( rewrite_last( ) , false ) )
213
+ } ) ;
214
+ rewrites. push ( try_opt ! ( last_subexpr_str) ) ;
263
215
264
216
let connector = if fits_single_line && !parent_rewrite_contains_newline {
265
217
// Yay, we can put everything on one line.
@@ -272,52 +224,42 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
272
224
format ! ( "\n {}" , nested_shape. indent. to_string( context. config) )
273
225
} ;
274
226
275
- let first_connector = choose_first_connector (
276
- context ,
277
- & parent_rewrite ,
278
- & rewrites [ 0 ] ,
279
- & connector ,
280
- & subexpr_list ,
281
- extend ,
282
- ) ;
227
+ let first_connector = if is_small_parent || fits_single_line ||
228
+ last_line_extendable ( & parent_rewrite ) ||
229
+ context . config . chain_indent ( ) == IndentStyle :: Visual
230
+ {
231
+ ""
232
+ } else {
233
+ connector . as_str ( )
234
+ } ;
283
235
284
- if is_small_parent && rewrites. len ( ) > 1 {
236
+ let result = if is_small_parent && rewrites. len ( ) > 1 {
285
237
let second_connector = choose_first_connector (
286
238
context,
287
239
& rewrites[ 0 ] ,
288
240
& rewrites[ 1 ] ,
289
241
& connector,
290
- & subexpr_list[ 0 ..subexpr_list . len ( ) - 1 ] ,
242
+ & subexpr_list[ ..subexpr_num - 1 ] ,
291
243
false ,
292
244
) ;
293
- wrap_str (
294
- format ! (
295
- "{}{}{}{}{}" ,
296
- parent_rewrite,
297
- first_connector,
298
- rewrites[ 0 ] ,
299
- second_connector,
300
- join_rewrites(
301
- & rewrites[ 1 ..] ,
302
- & subexpr_list[ 0 ..subexpr_list. len( ) - 1 ] ,
303
- & connector,
304
- )
305
- ) ,
306
- context. config . max_width ( ) ,
307
- shape,
245
+ format ! (
246
+ "{}{}{}{}{}" ,
247
+ parent_rewrite,
248
+ first_connector,
249
+ rewrites[ 0 ] ,
250
+ second_connector,
251
+ join_rewrites( & rewrites[ 1 ..] , & subexpr_list[ ..subexpr_num - 1 ] , & connector)
308
252
)
309
253
} else {
310
- wrap_str (
311
- format ! (
312
- "{}{}{}" ,
313
- parent_rewrite,
314
- first_connector,
315
- join_rewrites( & rewrites, & subexpr_list, & connector)
316
- ) ,
317
- context. config . max_width ( ) ,
318
- shape,
254
+ format ! (
255
+ "{}{}{}" ,
256
+ parent_rewrite,
257
+ first_connector,
258
+ join_rewrites( & rewrites, & subexpr_list, & connector)
319
259
)
320
- }
260
+ } ;
261
+ let result = format ! ( "{}{}" , result, repeat_try( suffix_try_num) ) ;
262
+ wrap_str ( result, context. config . max_width ( ) , shape)
321
263
}
322
264
323
265
fn is_extendable_parent ( context : & RewriteContext , parent_str : & str ) -> bool {
@@ -335,38 +277,18 @@ fn chain_only_try(exprs: &[ast::Expr]) -> bool {
335
277
336
278
// Try to rewrite and replace the last non-try child. Return `true` if
337
279
// replacing succeeds.
338
- fn rewrite_last_child_with_overflow (
339
- context : & RewriteContext ,
340
- expr : & ast:: Expr ,
341
- shape : Shape ,
342
- span : Span ,
343
- almost_total : usize ,
344
- one_line_budget : usize ,
345
- last_child : & mut String ,
346
- ) -> bool {
347
- if let Some ( shape) = shape. shrink_left ( almost_total) {
348
- if let Some ( ref mut rw) = rewrite_chain_subexpr ( expr, span, context, shape) {
349
- if almost_total + first_line_width ( rw) <= one_line_budget && rw. lines ( ) . count ( ) > 3 {
350
- :: std:: mem:: swap ( last_child, rw) ;
351
- return true ;
352
- }
353
- }
354
- }
355
- false
280
+ fn repeat_try ( try_count : usize ) -> String {
281
+ iter:: repeat ( "?" ) . take ( try_count) . collect :: < String > ( )
356
282
}
357
283
358
- pub fn rewrite_try (
284
+ fn rewrite_try (
359
285
expr : & ast:: Expr ,
360
286
try_count : usize ,
361
287
context : & RewriteContext ,
362
288
shape : Shape ,
363
289
) -> Option < String > {
364
290
let sub_expr = try_opt ! ( expr. rewrite( context, try_opt!( shape. sub_width( try_count) ) ) ) ;
365
- Some ( format ! (
366
- "{}{}" ,
367
- sub_expr,
368
- iter:: repeat( "?" ) . take( try_count) . collect:: <String >( )
369
- ) )
291
+ Some ( format ! ( "{}{}" , sub_expr, repeat_try( try_count) ) )
370
292
}
371
293
372
294
fn join_rewrites ( rewrites : & [ String ] , subexps : & [ ast:: Expr ] , connector : & str ) -> String {
@@ -426,47 +348,9 @@ fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> (ast::Expr,
426
348
fn chain_indent ( context : & RewriteContext , shape : Shape ) -> Shape {
427
349
match context. config . chain_indent ( ) {
428
350
IndentStyle :: Visual => shape. visual_indent ( 0 ) ,
429
- IndentStyle :: Block => shape. block_indent ( context. config . tab_spaces ( ) ) ,
430
- }
431
- }
432
-
433
- fn rewrite_method_call_with_overflow (
434
- expr_kind : & ast:: ExprKind ,
435
- last : & mut String ,
436
- almost_total : usize ,
437
- total_span : Span ,
438
- context : & RewriteContext ,
439
- shape : Shape ,
440
- ) -> bool {
441
- if let & ast:: ExprKind :: MethodCall ( ref segment, ref expressions) = expr_kind {
442
- let shape = match shape. shrink_left ( almost_total) {
443
- Some ( b) => b,
444
- None => return false ,
445
- } ;
446
- let types = match segment. parameters {
447
- Some ( ref params) => match * * params {
448
- ast:: PathParameters :: AngleBracketed ( ref data) => & data. types [ ..] ,
449
- _ => & [ ] ,
450
- } ,
451
- _ => & [ ] ,
452
- } ;
453
- let mut last_rewrite = rewrite_method_call (
454
- segment. identifier ,
455
- types,
456
- expressions,
457
- total_span,
458
- context,
459
- shape,
460
- ) ;
461
-
462
- if let Some ( ref mut s) = last_rewrite {
463
- :: std:: mem:: swap ( s, last) ;
464
- true
465
- } else {
466
- false
467
- }
468
- } else {
469
- unreachable ! ( ) ;
351
+ IndentStyle :: Block => shape
352
+ . block_indent ( context. config . tab_spaces ( ) )
353
+ . with_max_width ( context. config ) ,
470
354
}
471
355
}
472
356
0 commit comments