]> git.lizzy.rs Git - rust.git/blobdiff - src/imports.rs
Remove BlockIndentStyle::Inherit
[rust.git] / src / imports.rs
index ed74d828a9cb0fd9eecb1512050a3eb00d3fa4a5..cafba0bb2c5aa6ab18b9e73ef7c9816803584603 100644 (file)
@@ -8,12 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use Indent;
+use Shape;
 use utils;
 use syntax::codemap::{self, BytePos, Span};
 use codemap::SpanUtils;
 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, definitive_tactic};
-use types::rewrite_path;
+use types::{rewrite_path, PathContext};
 use rewrite::{Rewrite, RewriteContext};
 use visitor::FmtVisitor;
 use std::cmp::{self, Ordering};
@@ -29,7 +29,10 @@ fn path_of(a: &ast::ViewPath_) -> &ast::Path {
 }
 
 fn compare_path_segments(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
-    a.identifier.name.as_str().cmp(&b.identifier.name.as_str())
+    a.identifier
+        .name
+        .as_str()
+        .cmp(&b.identifier.name.as_str())
 }
 
 fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering {
@@ -43,8 +46,14 @@ fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering {
 }
 
 fn compare_path_list_items(a: &ast::PathListItem, b: &ast::PathListItem) -> Ordering {
-    let a_name_str = a.node.name.name.as_str();
-    let b_name_str = b.node.name.name.as_str();
+    let a_name_str = &*a.node
+                           .name
+                           .name
+                           .as_str();
+    let b_name_str = &*b.node
+                           .name
+                           .name
+                           .as_str();
     let name_ordering = if a_name_str == "self" {
         if b_name_str == "self" {
             Ordering::Equal
@@ -123,31 +132,56 @@ fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option<Ordering> {
 // TODO (some day) remove unused imports, expand globs, compress many single
 // imports into a list import.
 
+fn rewrite_view_path_prefix(path: &ast::Path,
+                            context: &RewriteContext,
+                            shape: Shape)
+                            -> Option<String> {
+    let path_str = if path.segments
+           .last()
+           .unwrap()
+           .identifier
+           .to_string() == "self" && path.segments.len() > 1 {
+        let path = &ast::Path {
+                        span: path.span.clone(),
+                        segments: path.segments[..path.segments.len() - 1].to_owned(),
+                    };
+        try_opt!(rewrite_path(context, PathContext::Import, None, path, shape))
+    } else {
+        try_opt!(rewrite_path(context, PathContext::Import, None, path, shape))
+    };
+    Some(path_str)
+}
+
 impl Rewrite for ast::ViewPath {
     // Returns an empty string when the ViewPath is empty (like foo::bar::{})
-    fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         match self.node {
             ast::ViewPath_::ViewPathList(_, ref path_list) if path_list.is_empty() => {
                 Some(String::new())
             }
             ast::ViewPath_::ViewPathList(ref path, ref path_list) => {
-                rewrite_use_list(width, offset, path, path_list, self.span, context)
+                rewrite_use_list(shape, path, path_list, self.span, context)
             }
-            ast::ViewPath_::ViewPathGlob(_) => {
-                // FIXME convert to list?
-                None
+            ast::ViewPath_::ViewPathGlob(ref path) => {
+                // 4 = "::*".len()
+                let prefix_shape = try_opt!(shape.sub_width(3));
+                let path_str = try_opt!(rewrite_view_path_prefix(path, context, prefix_shape));
+                Some(format!("{}::*", path_str))
             }
             ast::ViewPath_::ViewPathSimple(ident, ref path) => {
                 let ident_str = ident.to_string();
                 // 4 = " as ".len()
-                let budget = try_opt!(width.checked_sub(ident_str.len() + 4));
-                let path_str = try_opt!(rewrite_path(context, false, None, path, budget, offset));
+                let prefix_shape = try_opt!(shape.sub_width(ident_str.len() + 4));
+                let path_str = try_opt!(rewrite_view_path_prefix(path, context, prefix_shape));
 
-                Some(if path.segments.last().unwrap().identifier == ident {
-                    path_str
-                } else {
-                    format!("{} as {}", path_str, ident_str)
-                })
+                Some(if path.segments
+                            .last()
+                            .unwrap()
+                            .identifier == ident {
+                         path_str
+                     } else {
+                         format!("{} as {}", path_str, ident_str)
+                     })
             }
         }
     }
@@ -158,17 +192,24 @@ pub fn format_imports(&mut self, use_items: &[ptr::P<ast::Item>]) {
         // Find the location immediately before the first use item in the run. This must not lie
         // before the current `self.last_pos`
         let pos_before_first_use_item = use_items.first()
-            .map(|p_i| cmp::max(self.last_pos, p_i.span.lo))
+            .map(|p_i| {
+                cmp::max(self.last_pos,
+                         p_i.attrs
+                             .iter()
+                             .map(|attr| attr.span.lo)
+                             .min()
+                             .unwrap_or(p_i.span.lo))
+            })
             .unwrap_or(self.last_pos);
         // Construct a list of pairs, each containing a `use` item and the start of span before
         // that `use` item.
         let mut last_pos_of_prev_use_item = pos_before_first_use_item;
         let mut ordered_use_items = use_items.iter()
             .map(|p_i| {
-                let new_item = (&*p_i, last_pos_of_prev_use_item);
-                last_pos_of_prev_use_item = p_i.span.hi;
-                new_item
-            })
+                     let new_item = (&*p_i, last_pos_of_prev_use_item);
+                     last_pos_of_prev_use_item = p_i.span.hi;
+                     new_item
+                 })
             .collect::<Vec<_>>();
         let pos_after_last_use_item = last_pos_of_prev_use_item;
         // Order the imports by view-path & other import path properties
@@ -210,8 +251,7 @@ pub fn format_import(&mut self, vis: &ast::Visibility, vp: &ast::ViewPath, span:
         offset.alignment += vis.len() + "use ".len();
         // 1 = ";"
         match vp.rewrite(&self.get_context(),
-                         self.config.max_width - offset.width() - 1,
-                         offset) {
+                         Shape::legacy(self.config.max_width - offset.width() - 1, offset)) {
             Some(ref s) if s.is_empty() => {
                 // Format up to last newline
                 let prev_span = codemap::mk_sp(self.last_pos, source!(self, span).lo);
@@ -236,13 +276,22 @@ pub fn format_import(&mut self, vis: &ast::Visibility, vp: &ast::ViewPath, span:
     }
 }
 
-fn rewrite_single_use_list(path_str: Option<String>, vpi: &ast::PathListItem) -> String {
-    let path_item_str = match path_str {
-        Some(ref path_str) if vpi.node.name.to_string() == "self" => path_str.to_owned(),
-        Some(path_str) => format!("{}::{}", path_str, vpi.node.name),
-        None => vpi.node.name.to_string(),
+fn rewrite_single_use_list(path_str: String, vpi: &ast::PathListItem) -> String {
+    let mut item_str = vpi.node.name.to_string();
+    if item_str == "self" {
+        item_str = "".to_owned();
+    }
+    let path_item_str = if path_str.is_empty() {
+        if item_str.is_empty() {
+            "self".to_owned()
+        } else {
+            item_str
+        }
+    } else if item_str.is_empty() {
+        path_str
+    } else {
+        format!("{}::{}", path_str, item_str)
     };
-
     append_alias(path_item_str, vpi)
 }
 
@@ -259,35 +308,23 @@ fn append_alias(path_item_str: String, vpi: &ast::PathListItem) -> String {
 
 // Pretty prints a multi-item import.
 // Assumes that path_list.len() > 0.
-pub fn rewrite_use_list(width: usize,
-                        offset: Indent,
+pub fn rewrite_use_list(shape: Shape,
                         path: &ast::Path,
                         path_list: &[ast::PathListItem],
                         span: Span,
                         context: &RewriteContext)
                         -> Option<String> {
     // Returns a different option to distinguish `::foo` and `foo`
-    let opt_path_str = if !path.to_string().is_empty() {
-        Some(path.to_string())
-    } else if path.global {
-        // path is absolute, we return an empty String to avoid a double `::`
-        Some(String::new())
-    } else {
-        None
-    };
+    let path_str = try_opt!(rewrite_path(context, PathContext::Import, None, path, shape));
 
     match path_list.len() {
         0 => unreachable!(),
-        1 => return Some(rewrite_single_use_list(opt_path_str, &path_list[0])),
+        1 => return Some(rewrite_single_use_list(path_str, &path_list[0])),
         _ => (),
     }
 
-    // 2 = ::
-    let path_separation_w = if opt_path_str.is_some() { 2 } else { 0 };
-    // 1 = {
-    let supp_indent = path.to_string().len() + path_separation_w + 1;
-    // 1 = }
-    let remaining_width = width.checked_sub(supp_indent + 1).unwrap_or(0);
+    // 2 = {}
+    let remaining_width = shape.width.checked_sub(path_str.len() + 2).unwrap_or(0);
 
     let mut items = {
         // Dummy value, see explanation below.
@@ -314,6 +351,8 @@ pub fn rewrite_use_list(width: usize,
         items[1..].sort_by(|a, b| a.item.cmp(&b.item));
     }
 
+    let colons_offset = if path_str.is_empty() { 0 } else { 2 };
+
     let tactic = definitive_tactic(&items[first_index..],
                                    ::lists::ListTactic::Mixed,
                                    remaining_width);
@@ -321,20 +360,21 @@ pub fn rewrite_use_list(width: usize,
         tactic: tactic,
         separator: ",",
         trailing_separator: SeparatorTactic::Never,
-        indent: offset + supp_indent,
         // FIXME This is too conservative, and will not use all width
         // available
         // (loose 1 column (";"))
-        width: remaining_width,
+        shape: Shape::legacy(remaining_width,
+                             shape.indent + path_str.len() + 1 + colons_offset),
         ends_with_newline: false,
         config: context.config,
     };
     let list_str = try_opt!(write_list(&items[first_index..], &fmt));
 
-    Some(match opt_path_str {
-        Some(opt_path_str) => format!("{}::{{{}}}", opt_path_str, list_str),
-        None => format!("{{{}}}", list_str),
-    })
+    Some(if path_str.is_empty() {
+             format!("{{{}}}", list_str)
+         } else {
+             format!("{}::{{{}}}", path_str, list_str)
+         })
 }
 
 // Returns true when self item was found.