8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use std:: cmp:: { self , Ordering } ;
11
+ use std:: cmp:: Ordering ;
12
12
13
13
use syntax:: { ast, ptr} ;
14
14
use syntax:: codemap:: { BytePos , Span } ;
15
15
16
- use Shape ;
16
+ use { Shape , Spanned } ;
17
17
use codemap:: SpanUtils ;
18
+ use comment:: combine_strs_with_missing_comments;
18
19
use config:: IndentStyle ;
19
20
use lists:: { definitive_tactic, itemize_list, write_list, DefinitiveListTactic , ListFormatting ,
20
21
ListItem , Separator , SeparatorPlace , SeparatorTactic } ;
21
22
use rewrite:: { Rewrite , RewriteContext } ;
22
23
use types:: { rewrite_path, PathContext } ;
23
- use utils;
24
- use visitor:: FmtVisitor ;
24
+ use utils:: { format_visibility , mk_sp } ;
25
+ use visitor:: { rewrite_extern_crate , FmtVisitor } ;
25
26
26
27
fn path_of ( a : & ast:: ViewPath_ ) -> & ast:: Path {
27
28
match * a {
@@ -185,95 +186,115 @@ impl Rewrite for ast::ViewPath {
185
186
}
186
187
}
187
188
188
- impl < ' a > FmtVisitor < ' a > {
189
- pub fn format_imports ( & mut self , use_items : & [ ptr:: P < ast:: Item > ] ) {
190
- // Find the location immediately before the first use item in the run. This must not lie
191
- // before the current `self.last_pos`
192
- let pos_before_first_use_item = use_items
193
- . first ( )
194
- . map ( |p_i| {
195
- cmp:: max (
196
- self . last_pos ,
197
- p_i. attrs
198
- . iter ( )
199
- . map ( |attr| attr. span . lo ( ) )
200
- . min ( )
201
- . unwrap_or ( p_i. span . lo ( ) ) ,
202
- )
203
- } )
204
- . unwrap_or ( self . last_pos ) ;
205
- // Construct a list of pairs, each containing a `use` item and the start of span before
206
- // that `use` item.
207
- let mut last_pos_of_prev_use_item = pos_before_first_use_item;
208
- let mut ordered_use_items = use_items
209
- . iter ( )
210
- . map ( |p_i| {
211
- let new_item = ( & * p_i, last_pos_of_prev_use_item) ;
212
- last_pos_of_prev_use_item = p_i. span . hi ( ) ;
213
- new_item
214
- } )
215
- . collect :: < Vec < _ > > ( ) ;
216
- let pos_after_last_use_item = last_pos_of_prev_use_item;
217
- // Order the imports by view-path & other import path properties
218
- ordered_use_items. sort_by ( |a, b| {
219
- compare_use_items ( & self . get_context ( ) , a. 0 , b. 0 ) . unwrap ( )
220
- } ) ;
221
- // First, output the span before the first import
222
- let prev_span_str = self . snippet ( utils:: mk_sp ( self . last_pos , pos_before_first_use_item) ) ;
223
- // Look for purely trailing space at the start of the prefix snippet before a linefeed, or
224
- // a prefix that's entirely horizontal whitespace.
225
- let prefix_span_start = match prev_span_str. find ( '\n' ) {
226
- Some ( offset) if prev_span_str[ ..offset] . trim ( ) . is_empty ( ) => {
227
- self . last_pos + BytePos ( offset as u32 )
228
- }
229
- None if prev_span_str. trim ( ) . is_empty ( ) => pos_before_first_use_item,
230
- _ => self . last_pos ,
231
- } ;
232
- // Look for indent (the line part preceding the use is all whitespace) and excise that
233
- // from the prefix
234
- let span_end = match prev_span_str. rfind ( '\n' ) {
235
- Some ( offset) if prev_span_str[ offset..] . trim ( ) . is_empty ( ) => {
236
- self . last_pos + BytePos ( offset as u32 )
189
+ // Rewrite `use foo;` WITHOUT attributes.
190
+ fn rewrite_import (
191
+ context : & RewriteContext ,
192
+ vis : & ast:: Visibility ,
193
+ vp : & ast:: ViewPath ,
194
+ attrs : & [ ast:: Attribute ] ,
195
+ shape : Shape ,
196
+ ) -> Option < String > {
197
+ let vis = format_visibility ( vis) ;
198
+ // 4 = `use `, 1 = `;`
199
+ let rw = shape
200
+ . offset_left ( vis. len ( ) + 4 )
201
+ . and_then ( |shape| shape. sub_width ( 1 ) )
202
+ . and_then ( |shape| match vp. node {
203
+ // If we have an empty path list with no attributes, we erase it
204
+ ast:: ViewPath_ :: ViewPathList ( _, ref path_list)
205
+ if path_list. is_empty ( ) && attrs. is_empty ( ) =>
206
+ {
207
+ Some ( "" . into ( ) )
237
208
}
238
- _ => pos_before_first_use_item,
239
- } ;
209
+ _ => vp. rewrite ( context, shape) ,
210
+ } ) ;
211
+ match rw {
212
+ Some ( ref s) if !s. is_empty ( ) => Some ( format ! ( "{}use {};" , vis, s) ) ,
213
+ _ => rw,
214
+ }
215
+ }
240
216
241
- self . last_pos = prefix_span_start;
242
- self . format_missing ( span_end) ;
243
- for ordered in ordered_use_items {
244
- // Fake out the formatter by setting `self.last_pos` to the appropriate location before
245
- // each item before visiting it.
246
- self . last_pos = ordered. 1 ;
247
- self . visit_item ( ordered. 0 ) ;
217
+ fn rewrite_imports (
218
+ context : & RewriteContext ,
219
+ use_items : & [ ptr:: P < ast:: Item > ] ,
220
+ shape : Shape ,
221
+ span : Span ,
222
+ ) -> Option < String > {
223
+ let items = itemize_list (
224
+ context. codemap ,
225
+ use_items. iter ( ) ,
226
+ "" ,
227
+ |item| item. span ( ) . lo ( ) ,
228
+ |item| item. span ( ) . hi ( ) ,
229
+ |item| {
230
+ let attrs_str = try_opt ! ( item. attrs. rewrite( context, shape) ) ;
231
+
232
+ let missed_span = if item. attrs . is_empty ( ) {
233
+ mk_sp ( item. span . lo ( ) , item. span . lo ( ) )
234
+ } else {
235
+ mk_sp ( item. attrs . last ( ) . unwrap ( ) . span . hi ( ) , item. span . lo ( ) )
236
+ } ;
237
+
238
+ let item_str = match item. node {
239
+ ast:: ItemKind :: Use ( ref vp) => {
240
+ try_opt ! ( rewrite_import( context, & item. vis, vp, & item. attrs, shape) )
241
+ }
242
+ ast:: ItemKind :: ExternCrate ( ..) => try_opt ! ( rewrite_extern_crate( context, item) ) ,
243
+ _ => return None ,
244
+ } ;
245
+
246
+ combine_strs_with_missing_comments (
247
+ context,
248
+ & attrs_str,
249
+ & item_str,
250
+ missed_span,
251
+ shape,
252
+ false ,
253
+ )
254
+ } ,
255
+ span. lo ( ) ,
256
+ span. hi ( ) ,
257
+ false ,
258
+ ) ;
259
+ let mut item_pair_vec: Vec < _ > = items. zip ( use_items. iter ( ) ) . collect ( ) ;
260
+ item_pair_vec. sort_by ( |a, b| compare_use_items ( context, a. 1 , b. 1 ) . unwrap ( ) ) ;
261
+ let item_vec: Vec < _ > = item_pair_vec. into_iter ( ) . map ( |pair| pair. 0 ) . collect ( ) ;
262
+
263
+ let fmt = ListFormatting {
264
+ tactic : DefinitiveListTactic :: Vertical ,
265
+ separator : "" ,
266
+ trailing_separator : SeparatorTactic :: Never ,
267
+ separator_place : SeparatorPlace :: Back ,
268
+ shape : shape,
269
+ ends_with_newline : true ,
270
+ preserve_newline : false ,
271
+ config : context. config ,
272
+ } ;
273
+
274
+ write_list ( & item_vec, & fmt)
275
+ }
276
+
277
+ impl < ' a > FmtVisitor < ' a > {
278
+ pub fn format_imports ( & mut self , use_items : & [ ptr:: P < ast:: Item > ] ) {
279
+ if use_items. is_empty ( ) {
280
+ return ;
248
281
}
249
- self . last_pos = pos_after_last_use_item;
282
+
283
+ let lo = use_items. first ( ) . unwrap ( ) . span ( ) . lo ( ) ;
284
+ let hi = use_items. last ( ) . unwrap ( ) . span ( ) . hi ( ) ;
285
+ let span = mk_sp ( lo, hi) ;
286
+ let rw = rewrite_imports ( & self . get_context ( ) , use_items, self . shape ( ) , span) ;
287
+ self . push_rewrite ( span, rw) ;
250
288
}
251
289
252
- pub fn format_import (
253
- & mut self ,
254
- vis : & ast:: Visibility ,
255
- vp : & ast:: ViewPath ,
256
- span : Span ,
257
- attrs : & [ ast:: Attribute ] ,
258
- ) {
259
- let vis = utils:: format_visibility ( vis) ;
260
- // 4 = `use `, 1 = `;`
261
- let rw = self . shape ( )
262
- . offset_left ( vis. len ( ) + 4 )
263
- . and_then ( |shape| shape. sub_width ( 1 ) )
264
- . and_then ( |shape| match vp. node {
265
- // If we have an empty path list with no attributes, we erase it
266
- ast:: ViewPath_ :: ViewPathList ( _, ref path_list)
267
- if path_list. is_empty ( ) && attrs. is_empty ( ) =>
268
- {
269
- Some ( "" . into ( ) )
270
- }
271
- _ => vp. rewrite ( & self . get_context ( ) , shape) ,
272
- } ) ;
290
+ pub fn format_import ( & mut self , item : & ast:: Item , vp : & ast:: ViewPath ) {
291
+ let span = item. span ;
292
+ let shape = self . shape ( ) ;
293
+ let rw = rewrite_import ( & self . get_context ( ) , & item. vis , vp, & item. attrs , shape) ;
273
294
match rw {
274
295
Some ( ref s) if s. is_empty ( ) => {
275
296
// Format up to last newline
276
- let prev_span = utils :: mk_sp ( self . last_pos , source ! ( self , span) . lo ( ) ) ;
297
+ let prev_span = mk_sp ( self . last_pos , source ! ( self , span) . lo ( ) ) ;
277
298
let span_end = match self . snippet ( prev_span) . rfind ( '\n' ) {
278
299
Some ( offset) => self . last_pos + BytePos ( offset as u32 ) ,
279
300
None => source ! ( self , span) . lo ( ) ,
@@ -282,7 +303,6 @@ impl<'a> FmtVisitor<'a> {
282
303
self . last_pos = source ! ( self , span) . hi ( ) ;
283
304
}
284
305
Some ( ref s) => {
285
- let s = format ! ( "{}use {};" , vis, s) ;
286
306
self . format_missing_with_indent ( source ! ( self , span) . lo ( ) ) ;
287
307
self . buffer . push_str ( & s) ;
288
308
self . last_pos = source ! ( self , span) . hi ( ) ;
0 commit comments