@@ -14,6 +14,7 @@ use string::{StringFormat, rewrite_string};
14
14
use StructLitStyle ;
15
15
use utils:: { span_after, make_indent} ;
16
16
use visitor:: FmtVisitor ;
17
+ use config:: BlockIndentStyle ;
17
18
18
19
use syntax:: { ast, ptr} ;
19
20
use syntax:: codemap:: { Pos , Span , BytePos , mk_sp} ;
@@ -57,48 +58,16 @@ impl Rewrite for ast::Expr {
57
58
rewrite_tuple_lit ( context, items, self . span , width, offset)
58
59
}
59
60
ast:: Expr_ :: ExprWhile ( ref cond, ref block, label) => {
60
- rewrite_loop ( context,
61
- cond,
62
- block,
63
- label,
64
- None ,
65
- "while " ,
66
- "let " ,
67
- " = " ,
68
- width,
69
- offset)
61
+ Loop :: new_while ( None , cond, block, label) . rewrite ( context, width, offset)
70
62
}
71
63
ast:: Expr_ :: ExprWhileLet ( ref pat, ref cond, ref block, label) => {
72
- rewrite_loop ( context,
73
- cond,
74
- block,
75
- label,
76
- Some ( pat) ,
77
- "while " ,
78
- "let " ,
79
- " = " ,
80
- width,
81
- offset)
64
+ Loop :: new_while ( Some ( pat) , cond, block, label) . rewrite ( context, width, offset)
82
65
}
83
66
ast:: Expr_ :: ExprForLoop ( ref pat, ref cond, ref block, label) => {
84
- rewrite_loop ( context,
85
- cond,
86
- block,
87
- label,
88
- Some ( pat) ,
89
- "for " ,
90
- "" ,
91
- " in " ,
92
- width,
93
- offset)
67
+ Loop :: new_for ( pat, cond, block, label) . rewrite ( context, width, offset)
94
68
}
95
69
ast:: Expr_ :: ExprLoop ( ref block, label) => {
96
- // Of all the loops, this is the only one that does not use
97
- // rewrite_loop!
98
- // FIXME: this drops any comment between "loop" and the block.
99
- block. rewrite ( context, width, offset) . map ( |result| {
100
- format ! ( "{}loop {}" , rewrite_label( label) , result)
101
- } )
70
+ Loop :: new_loop ( block, label) . rewrite ( context, width, offset)
102
71
}
103
72
ast:: Expr_ :: ExprBlock ( ref block) => {
104
73
block. rewrite ( context, width, offset)
@@ -121,7 +90,8 @@ impl Rewrite for ast::Expr {
121
90
width,
122
91
offset)
123
92
}
124
- // We reformat it ourselves because rustc gives us a bad span for ranges
93
+ // We reformat it ourselves because rustc gives us a bad span
94
+ // for ranges, see rust#27162
125
95
ast:: Expr_ :: ExprRange ( ref left, ref right) => {
126
96
rewrite_range ( context,
127
97
left. as_ref ( ) . map ( |e| & * * e) ,
@@ -161,6 +131,91 @@ impl Rewrite for ast::Pat {
161
131
}
162
132
}
163
133
134
+ // Abstraction over for, while and loop expressions
135
+ struct Loop < ' a > {
136
+ cond : Option < & ' a ast:: Expr > ,
137
+ block : & ' a ast:: Block ,
138
+ label : Option < ast:: Ident > ,
139
+ pat : Option < & ' a ast:: Pat > ,
140
+ keyword : & ' a str ,
141
+ matcher : & ' a str ,
142
+ connector : & ' a str ,
143
+ }
144
+
145
+ impl < ' a > Loop < ' a > {
146
+ fn new_loop ( block : & ' a ast:: Block , label : Option < ast:: Ident > ) -> Loop < ' a > {
147
+ Loop {
148
+ cond : None ,
149
+ block : block,
150
+ label : label,
151
+ pat : None ,
152
+ keyword : "loop" ,
153
+ matcher : "" ,
154
+ connector : "" ,
155
+ }
156
+ }
157
+
158
+ fn new_while ( pat : Option < & ' a ast:: Pat > ,
159
+ cond : & ' a ast:: Expr ,
160
+ block : & ' a ast:: Block ,
161
+ label : Option < ast:: Ident > )
162
+ -> Loop < ' a > {
163
+ Loop {
164
+ cond : Some ( cond) ,
165
+ block : block,
166
+ label : label,
167
+ pat : pat,
168
+ keyword : "while " ,
169
+ matcher : match pat {
170
+ Some ( ..) => "let " ,
171
+ None => ""
172
+ } ,
173
+ connector : " =" ,
174
+ }
175
+ }
176
+
177
+ fn new_for ( pat : & ' a ast:: Pat ,
178
+ cond : & ' a ast:: Expr ,
179
+ block : & ' a ast:: Block ,
180
+ label : Option < ast:: Ident > )
181
+ -> Loop < ' a > {
182
+ Loop {
183
+ cond : Some ( cond) ,
184
+ block : block,
185
+ label : label,
186
+ pat : Some ( pat) ,
187
+ keyword : "for " ,
188
+ matcher : "" ,
189
+ connector : " in" ,
190
+ }
191
+ }
192
+ }
193
+
194
+ impl < ' a > Rewrite for Loop < ' a > {
195
+ fn rewrite ( & self , context : & RewriteContext , width : usize , offset : usize ) -> Option < String > {
196
+ let label_string = rewrite_label ( self . label ) ;
197
+ // 2 = " {".len()
198
+ let inner_width = width - self . keyword . len ( ) - 2 - label_string. len ( ) ;
199
+ let inner_offset = offset + self . keyword . len ( ) + label_string. len ( ) ;
200
+
201
+ let pat_expr_string = match self . cond {
202
+ Some ( cond) => try_opt ! ( rewrite_pat_expr( context,
203
+ self . pat,
204
+ cond,
205
+ self . matcher,
206
+ self . connector,
207
+ inner_width,
208
+ inner_offset) ) ,
209
+ None => String :: new ( )
210
+ } ;
211
+
212
+ // FIXME: this drops any comment between "loop" and the block.
213
+ self . block . rewrite ( context, width, offset) . map ( |result| {
214
+ format ! ( "{}{}{} {}" , label_string, self . keyword, pat_expr_string, result)
215
+ } )
216
+ }
217
+ }
218
+
164
219
fn rewrite_label ( label : Option < ast:: Ident > ) -> String {
165
220
match label {
166
221
Some ( ident) => format ! ( "{}: " , ident) ,
@@ -193,36 +248,8 @@ fn rewrite_range(context: &RewriteContext,
193
248
Some ( format ! ( "{}..{}" , left_string, right_string) )
194
249
}
195
250
196
- fn rewrite_loop ( context : & RewriteContext ,
197
- cond : & ast:: Expr ,
198
- block : & ast:: Block ,
199
- label : Option < ast:: Ident > ,
200
- pat : Option < & ast:: Pat > ,
201
- keyword : & str ,
202
- matcher : & str , // FIXME: think of better identifiers
203
- connector : & str ,
204
- width : usize ,
205
- offset : usize )
206
- -> Option < String > {
207
- let label_string = rewrite_label ( label) ;
208
- // 2 = " {"
209
- let inner_width = width - keyword. len ( ) - 2 - label_string. len ( ) ;
210
- let inner_offset = offset + keyword. len ( ) + label_string. len ( ) ;
211
-
212
- let pat_expr_string = try_opt ! ( rewrite_pat_expr( context,
213
- pat,
214
- cond,
215
- matcher,
216
- connector,
217
- inner_width,
218
- inner_offset) ) ;
219
-
220
- // FIXME: this drops any comment between "loop" and the block.
221
- block. rewrite ( context, width, offset) . map ( |result| {
222
- format ! ( "{}{}{} {}" , label_string, keyword, pat_expr_string, result)
223
- } )
224
- }
225
-
251
+ // Rewrites if-else blocks. If let Some(_) = pat, the expression is
252
+ // treated as an if-let-else expression.
226
253
fn rewrite_if_else ( context : & RewriteContext ,
227
254
cond : & ast:: Expr ,
228
255
if_block : & ast:: Block ,
@@ -236,7 +263,7 @@ fn rewrite_if_else(context: &RewriteContext,
236
263
pat,
237
264
cond,
238
265
"let " ,
239
- " = " ,
266
+ " =" ,
240
267
width - 3 - 2 ,
241
268
offset + 3 ) ) ;
242
269
@@ -261,28 +288,49 @@ fn rewrite_pat_expr(context: &RewriteContext,
261
288
width : usize ,
262
289
offset : usize )
263
290
-> Option < String > {
291
+ let pat_offset = offset + matcher. len ( ) ;
264
292
let mut result = match pat {
265
293
Some ( pat) => {
266
294
let pat_string = try_opt ! ( pat. rewrite( context,
267
295
width - connector. len( ) - matcher. len( ) ,
268
- offset + matcher . len ( ) ) ) ;
296
+ pat_offset ) ) ;
269
297
format ! ( "{}{}{}" , matcher, pat_string, connector)
270
298
}
271
299
None => String :: new ( )
272
300
} ;
273
301
274
- // Consider only the last line of the pat string
302
+ // Consider only the last line of the pat string.
275
303
let extra_offset = match result. rfind ( '\n' ) {
276
304
// 1 for newline character
277
305
Some ( idx) => result. len ( ) - idx - 1 - offset,
278
306
None => result. len ( )
279
307
} ;
280
308
281
- let expr_string = try_opt ! ( expr . rewrite ( context ,
282
- width - extra_offset ,
283
- offset + extra_offset) ) ;
309
+ // The expression may (partionally) fit on the current line.
310
+ if width > extra_offset + 1 {
311
+ let mut corrected_offset = extra_offset;
284
312
285
- result. push_str ( & expr_string) ;
313
+ if pat. is_some ( ) {
314
+ result. push ( ' ' ) ;
315
+ corrected_offset += 1 ;
316
+ }
317
+
318
+ let expr_rewrite = expr. rewrite ( context,
319
+ width - corrected_offset,
320
+ offset + corrected_offset) ;
321
+
322
+ if let Some ( expr_string) = expr_rewrite {
323
+ result. push_str ( & expr_string) ;
324
+ return Some ( result) ;
325
+ }
326
+ }
327
+
328
+ // The expression won't fit on the current line, jump to next.
329
+ result. push ( '\n' ) ;
330
+ result. push_str ( & make_indent ( pat_offset) ) ;
331
+
332
+ let expr_rewrite = expr. rewrite ( context, context. config . max_width - pat_offset, pat_offset) ;
333
+ result. push_str ( & & try_opt ! ( expr_rewrite) ) ;
286
334
287
335
Some ( result)
288
336
}
@@ -333,6 +381,8 @@ fn rewrite_call(context: &RewriteContext,
333
381
// 2 is for parens.
334
382
let remaining_width = width - callee_str. len ( ) - 2 ;
335
383
let offset = callee_str. len ( ) + 1 + offset;
384
+ let block_indent = expr_block_indent ( context, offset) ;
385
+ let inner_context = & RewriteContext { block_indent : block_indent, ..* context } ;
336
386
337
387
let items = itemize_list ( context. codemap ,
338
388
Vec :: new ( ) ,
@@ -342,7 +392,7 @@ fn rewrite_call(context: &RewriteContext,
342
392
|item| item. span . lo ,
343
393
|item| item. span . hi ,
344
394
// Take old span when rewrite fails.
345
- |item| item. rewrite ( context , remaining_width, offset)
395
+ |item| item. rewrite ( inner_context , remaining_width, offset)
346
396
. unwrap_or ( context. codemap . span_to_snippet ( item. span )
347
397
. unwrap ( ) ) ,
348
398
callee. span . hi + BytePos ( 1 ) ,
@@ -361,6 +411,14 @@ fn rewrite_call(context: &RewriteContext,
361
411
Some ( format ! ( "{}({})" , callee_str, write_list( & items, & fmt) ) )
362
412
}
363
413
414
+ fn expr_block_indent ( context : & RewriteContext , offset : usize ) -> usize {
415
+ match context. config . expr_indent_style {
416
+ BlockIndentStyle :: Inherit => context. block_indent ,
417
+ BlockIndentStyle :: Tabbed => context. block_indent + context. config . tab_spaces ,
418
+ BlockIndentStyle :: Visual => offset,
419
+ }
420
+ }
421
+
364
422
fn rewrite_paren ( context : & RewriteContext ,
365
423
subexpr : & ast:: Expr ,
366
424
width : usize ,
@@ -391,17 +449,18 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
391
449
}
392
450
393
451
let path_str = pprust:: path_to_string ( path) ;
394
- let ( indent, h_budget, v_budget) = match context. config . struct_lit_style {
452
+ // Foo { a: Foo } - indent is +3, width is -5.
453
+ let h_budget = width. checked_sub ( path_str. len ( ) + 5 ) . unwrap_or ( 0 ) ;
454
+ let ( indent, v_budget) = match context. config . struct_lit_style {
395
455
StructLitStyle :: VisualIndent => {
396
- // Foo { a: Foo } - indent is +3, width is -5.
397
- let budget = width - ( path_str. len ( ) + 5 ) ;
398
- ( offset + path_str. len ( ) + 3 , budget, budget)
456
+ ( offset + path_str. len ( ) + 3 , h_budget)
399
457
}
400
458
StructLitStyle :: BlockIndent => {
401
459
// If we are all on one line, then we'll ignore the indent, and we
402
460
// have a smaller budget.
403
461
let indent = context. block_indent + context. config . tab_spaces ;
404
- ( indent, width - ( path_str. len ( ) + 5 ) , width - indent)
462
+ let v_budget = context. config . max_width . checked_sub ( indent) . unwrap_or ( 0 ) ;
463
+ ( indent, v_budget)
405
464
}
406
465
} ;
407
466
0 commit comments