|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | use Indent;
|
| 12 | +use utils; |
| 13 | +use syntax::codemap::{self, BytePos, Span}; |
12 | 14 | use codemap::SpanUtils;
|
13 | 15 | use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, definitive_tactic};
|
14 | 16 | use types::rewrite_path;
|
15 | 17 | use rewrite::{Rewrite, RewriteContext};
|
| 18 | +use visitor::FmtVisitor; |
| 19 | +use std::cmp::Ordering; |
16 | 20 |
|
17 |
| -use syntax::ast; |
18 |
| -use syntax::codemap::Span; |
| 21 | +use syntax::{ast, ptr}; |
| 22 | + |
| 23 | +fn path_of(a: &ast::ViewPath_) -> &ast::Path { |
| 24 | + match a { |
| 25 | + &ast::ViewPath_::ViewPathSimple(_, ref p) => p, |
| 26 | + &ast::ViewPath_::ViewPathGlob(ref p) => p, |
| 27 | + &ast::ViewPath_::ViewPathList(ref p, _) => p, |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +fn compare_path_segments(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { |
| 32 | + a.identifier.name.as_str().cmp(&b.identifier.name.as_str()) |
| 33 | +} |
| 34 | + |
| 35 | +fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering { |
| 36 | + for segment in a.segments.iter().zip(b.segments.iter()) { |
| 37 | + let ord = compare_path_segments(segment.0, segment.1); |
| 38 | + if ord != Ordering::Equal { |
| 39 | + return ord; |
| 40 | + } |
| 41 | + } |
| 42 | + a.segments.len().cmp(&b.segments.len()) |
| 43 | +} |
| 44 | + |
| 45 | +fn compare_path_list_items(a: &ast::PathListItem, b: &ast::PathListItem) -> Ordering { |
| 46 | + let name_ordering = match a.node.name() { |
| 47 | + Some(a_name) => { |
| 48 | + match b.node.name() { |
| 49 | + Some(b_name) => a_name.name.as_str().cmp(&b_name.name.as_str()), |
| 50 | + None => Ordering::Greater, |
| 51 | + } |
| 52 | + } |
| 53 | + None => { |
| 54 | + match b.node.name() { |
| 55 | + Some(_) => Ordering::Less, |
| 56 | + None => Ordering::Equal, |
| 57 | + } |
| 58 | + } |
| 59 | + }; |
| 60 | + if name_ordering == Ordering::Equal { |
| 61 | + match a.node.rename() { |
| 62 | + Some(a_rename) => { |
| 63 | + match b.node.rename() { |
| 64 | + Some(b_rename) => a_rename.name.as_str().cmp(&b_rename.name.as_str()), |
| 65 | + None => Ordering::Greater, |
| 66 | + } |
| 67 | + } |
| 68 | + None => { |
| 69 | + match b.node.name() { |
| 70 | + Some(_) => Ordering::Less, |
| 71 | + None => Ordering::Equal, |
| 72 | + } |
| 73 | + } |
| 74 | + } |
| 75 | + } else { |
| 76 | + name_ordering |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +fn compare_path_list_item_lists(a_items: &Vec<ast::PathListItem>, |
| 81 | + b_items: &Vec<ast::PathListItem>) |
| 82 | + -> Ordering { |
| 83 | + let mut a = a_items.clone(); |
| 84 | + let mut b = b_items.clone(); |
| 85 | + a.sort_by(|a, b| compare_path_list_items(a, b)); |
| 86 | + b.sort_by(|a, b| compare_path_list_items(a, b)); |
| 87 | + for comparison_pair in a.iter().zip(b.iter()) { |
| 88 | + let ord = compare_path_list_items(comparison_pair.0, comparison_pair.1); |
| 89 | + if ord != Ordering::Equal { |
| 90 | + return ord; |
| 91 | + } |
| 92 | + } |
| 93 | + a.len().cmp(&b.len()) |
| 94 | +} |
| 95 | + |
| 96 | +fn compare_view_path_types(a: &ast::ViewPath_, b: &ast::ViewPath_) -> Ordering { |
| 97 | + use syntax::ast::ViewPath_::*; |
| 98 | + match (a, b) { |
| 99 | + (&ViewPathSimple(..), &ViewPathSimple(..)) => Ordering::Equal, |
| 100 | + (&ViewPathSimple(..), _) => Ordering::Less, |
| 101 | + (&ViewPathGlob(_), &ViewPathSimple(..)) => Ordering::Greater, |
| 102 | + (&ViewPathGlob(_), &ViewPathGlob(_)) => Ordering::Equal, |
| 103 | + (&ViewPathGlob(_), &ViewPathList(..)) => Ordering::Less, |
| 104 | + (&ViewPathList(_, ref a_items), &ViewPathList(_, ref b_items)) => { |
| 105 | + compare_path_list_item_lists(a_items, b_items) |
| 106 | + } |
| 107 | + (&ViewPathList(..), _) => Ordering::Greater, |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +fn compare_view_paths(a: &ast::ViewPath_, b: &ast::ViewPath_) -> Ordering { |
| 112 | + match compare_paths(path_of(a), path_of(b)) { |
| 113 | + Ordering::Equal => compare_view_path_types(a, b), |
| 114 | + cmp => cmp, |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option<Ordering> { |
| 119 | + match (&a.node, &b.node) { |
| 120 | + (&ast::ItemKind::Use(ref a_vp), &ast::ItemKind::Use(ref b_vp)) => { |
| 121 | + Some(compare_view_paths(&a_vp.node, &b_vp.node)) |
| 122 | + } |
| 123 | + _ => None, |
| 124 | + } |
| 125 | +} |
19 | 126 |
|
20 | 127 | // TODO (some day) remove unused imports, expand globs, compress many single
|
21 | 128 | // imports into a list import.
|
@@ -50,6 +157,63 @@ impl Rewrite for ast::ViewPath {
|
50 | 157 | }
|
51 | 158 | }
|
52 | 159 |
|
| 160 | +impl<'a> FmtVisitor<'a> { |
| 161 | + pub fn format_imports(&mut self, use_items: &[ptr::P<ast::Item>]) { |
| 162 | + let mut last_pos = |
| 163 | + use_items.first().map(|p_i| p_i.span.lo - BytePos(1)).unwrap_or(self.last_pos); |
| 164 | + let prefix = codemap::mk_sp(self.last_pos, last_pos); |
| 165 | + let mut ordered_use_items = use_items.iter() |
| 166 | + .map(|p_i| { |
| 167 | + let new_item = (&*p_i, last_pos); |
| 168 | + last_pos = p_i.span.hi; |
| 169 | + new_item |
| 170 | + }) |
| 171 | + .collect::<Vec<_>>(); |
| 172 | + // Order the imports by view-path & other import path properties |
| 173 | + ordered_use_items.sort_by(|a, b| compare_use_items(a.0, b.0).unwrap()); |
| 174 | + // First, output the span before the first import |
| 175 | + self.format_missing(prefix.hi); |
| 176 | + for ordered in ordered_use_items { |
| 177 | + // Fake out the formatter by setting `self.last_pos` to the appropriate location before |
| 178 | + // each item before visiting it. |
| 179 | + self.last_pos = ordered.1; |
| 180 | + self.visit_item(&ordered.0); |
| 181 | + } |
| 182 | + self.last_pos = last_pos; |
| 183 | + } |
| 184 | + |
| 185 | + pub fn format_import(&mut self, vis: &ast::Visibility, vp: &ast::ViewPath, span: Span) { |
| 186 | + let vis = utils::format_visibility(vis); |
| 187 | + let mut offset = self.block_indent; |
| 188 | + offset.alignment += vis.len() + "use ".len(); |
| 189 | + // 1 = ";" |
| 190 | + match vp.rewrite(&self.get_context(), |
| 191 | + self.config.max_width - offset.width() - 1, |
| 192 | + offset) { |
| 193 | + Some(ref s) if s.is_empty() => { |
| 194 | + // Format up to last newline |
| 195 | + let prev_span = codemap::mk_sp(self.last_pos, source!(self, span).lo); |
| 196 | + let span_end = match self.snippet(prev_span).rfind('\n') { |
| 197 | + Some(offset) => self.last_pos + BytePos(offset as u32), |
| 198 | + None => source!(self, span).lo, |
| 199 | + }; |
| 200 | + self.format_missing(span_end); |
| 201 | + self.last_pos = source!(self, span).hi; |
| 202 | + } |
| 203 | + Some(ref s) => { |
| 204 | + let s = format!("{}use {};", vis, s); |
| 205 | + self.format_missing_with_indent(source!(self, span).lo); |
| 206 | + self.buffer.push_str(&s); |
| 207 | + self.last_pos = source!(self, span).hi; |
| 208 | + } |
| 209 | + None => { |
| 210 | + self.format_missing_with_indent(source!(self, span).lo); |
| 211 | + self.format_missing(source!(self, span).hi); |
| 212 | + } |
| 213 | + } |
| 214 | + } |
| 215 | +} |
| 216 | + |
53 | 217 | fn rewrite_single_use_list(path_str: String, vpi: &ast::PathListItem) -> String {
|
54 | 218 | let path_item_str = if let ast::PathListItemKind::Ident { name, .. } = vpi.node {
|
55 | 219 | // A name.
|
@@ -138,7 +302,7 @@ pub fn rewrite_use_list(width: usize,
|
138 | 302 | let has_self = move_self_to_front(&mut items);
|
139 | 303 | let first_index = if has_self { 0 } else { 1 };
|
140 | 304 |
|
141 |
| - if context.config.reorder_imports { |
| 305 | + if context.config.reorder_imported_names { |
142 | 306 | items[1..].sort_by(|a, b| a.item.cmp(&b.item));
|
143 | 307 | }
|
144 | 308 |
|
|
0 commit comments