]> git.lizzy.rs Git - rust.git/blobdiff - src/imports.rs
Remove BlockIndentStyle::Inherit
[rust.git] / src / imports.rs
index bc343307272b24ff86e3f1d75bb3fa0459aacab5..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};
 use syntax::{ast, ptr};
 
 fn path_of(a: &ast::ViewPath_) -> &ast::Path {
-    match a {
-        &ast::ViewPath_::ViewPathSimple(_, ref p) => p,
-        &ast::ViewPath_::ViewPathGlob(ref p) => p,
-        &ast::ViewPath_::ViewPathList(ref p, _) => p,
+    match *a {
+        ast::ViewPath_::ViewPathSimple(_, ref p) => p,
+        ast::ViewPath_::ViewPathGlob(ref p) => p,
+        ast::ViewPath_::ViewPathList(ref p, _) => p,
     }
 }
 
 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,34 +46,36 @@ fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering {
 }
 
 fn compare_path_list_items(a: &ast::PathListItem, b: &ast::PathListItem) -> Ordering {
-    let name_ordering = match a.node.name() {
-        Some(a_name) => {
-            match b.node.name() {
-                Some(b_name) => a_name.name.as_str().cmp(&b_name.name.as_str()),
-                None => Ordering::Greater,
-            }
+    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
+        } else {
+            Ordering::Less
         }
-        None => {
-            match b.node.name() {
-                Some(_) => Ordering::Less,
-                None => Ordering::Equal,
-            }
+    } else {
+        if b_name_str == "self" {
+            Ordering::Greater
+        } else {
+            a_name_str.cmp(&b_name_str)
         }
     };
     if name_ordering == Ordering::Equal {
-        match a.node.rename() {
+        match a.node.rename {
             Some(a_rename) => {
-                match b.node.rename() {
+                match b.node.rename {
                     Some(b_rename) => a_rename.name.as_str().cmp(&b_rename.name.as_str()),
                     None => Ordering::Greater,
                 }
             }
-            None => {
-                match b.node.name() {
-                    Some(_) => Ordering::Less,
-                    None => Ordering::Equal,
-                }
-            }
+            None => Ordering::Less,
         }
     } else {
         name_ordering
@@ -127,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)
+                     })
             }
         }
     }
@@ -162,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
@@ -203,7 +240,7 @@ pub fn format_imports(&mut self, use_items: &[ptr::P<ast::Item>]) {
             // Fake out the formatter by setting `self.last_pos` to the appropriate location before
             // each item before visiting it.
             self.last_pos = ordered.1;
-            self.visit_item(&ordered.0);
+            self.visit_item(ordered.0);
         }
         self.last_pos = pos_after_last_use_item;
     }
@@ -214,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);
@@ -240,76 +276,55 @@ 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 = if let ast::PathListItemKind::Ident { name, .. } = vpi.node {
-        // A name.
-        match path_str {
-            Some(path_str) => format!("{}::{}", path_str, name),
-            None => 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 {
-        // `self`.
-        match path_str {
-            Some(path_str) => path_str,
-            // This catches the import: use {self}, which is a compiler error, so we just
-            // leave it alone.
-            None => "{self}".to_owned(),
-        }
+        format!("{}::{}", path_str, item_str)
     };
-
     append_alias(path_item_str, vpi)
 }
 
 fn rewrite_path_item(vpi: &&ast::PathListItem) -> Option<String> {
-    let path_item_str = match vpi.node {
-        ast::PathListItemKind::Ident { name, .. } => name.to_string(),
-        ast::PathListItemKind::Mod { .. } => "self".to_owned(),
-    };
-
-    Some(append_alias(path_item_str, vpi))
+    Some(append_alias(vpi.node.name.to_string(), vpi))
 }
 
 fn append_alias(path_item_str: String, vpi: &ast::PathListItem) -> String {
-    match vpi.node {
-        ast::PathListItemKind::Ident { rename: Some(rename), .. } |
-        ast::PathListItemKind::Mod { rename: Some(rename), .. } => {
-            format!("{} as {}", path_item_str, rename)
-        }
-        _ => path_item_str,
+    match vpi.node.rename {
+        Some(rename) => format!("{} as {}", path_item_str, rename),
+        None => path_item_str,
     }
 }
 
 // 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.
@@ -336,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);
@@ -343,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.