about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-09-24 13:56:52 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-09-25 14:27:42 -0700
commit5c6f8a976f2e3e333d495d1817ed1f624bd78ac6 (patch)
tree90d2fedf58290a82ca5d92c5bcacf53b2630a30e
parentc838351ba673c283564875226a2fc6bad0bc1ea1 (diff)
downloadrust-5c6f8a976f2e3e333d495d1817ed1f624bd78ac6.tar.gz
rust-5c6f8a976f2e3e333d495d1817ed1f624bd78ac6.zip
rustdoc: Linkify all reexports.
This way each component of a reexport path is click-able to the destination that
it's referencing.
-rw-r--r--src/librustc/middle/resolve.rs28
-rw-r--r--src/librustdoc/clean.rs49
-rw-r--r--src/librustdoc/html/format.rs132
-rw-r--r--src/librustdoc/html/render.rs52
4 files changed, 227 insertions, 34 deletions
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 320baf33181..f4772d7adc3 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -2499,6 +2499,26 @@ impl Resolver {
         assert!(import_resolution.outstanding_references >= 1);
         import_resolution.outstanding_references -= 1;
 
+        // record what this import resolves to for later uses in documentation,
+        // this may resolve to either a value or a type, but for documentation
+        // purposes it's good enough to just favor one over the other.
+        match i.value_target {
+            Some(target) => {
+                self.def_map.insert(i.value_id,
+                                    target.bindings.value_def.get_ref().def);
+            }
+            None => {}
+        }
+        match i.type_target {
+            Some(target) => {
+                match target.bindings.type_def.get_ref().type_def {
+                    Some(def) => { self.def_map.insert(i.type_id, def); }
+                    None => {}
+                }
+            }
+            None => {}
+        }
+
         debug!("(resolving single import) successfully resolved import");
         return Success(());
     }
@@ -2626,6 +2646,14 @@ impl Resolver {
             merge_import_resolution(name, name_bindings);
         }
 
+        // Record the destination of this import
+        match containing_module.def_id {
+            Some(did) => {
+                self.def_map.insert(id, DefMod(did));
+            }
+            None => {}
+        }
+
         debug!("(resolving glob import) successfully resolved import");
         return Success(());
     }
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index 8cbe1eed55a..291476c1390 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean.rs
@@ -930,26 +930,45 @@ impl Clean<ViewItemInner> for ast::view_item_ {
 
 #[deriving(Clone, Encodable, Decodable)]
 pub enum ViewPath {
-    SimpleImport(~str, Path, ast::NodeId),
-    GlobImport(Path, ast::NodeId),
-    ImportList(Path, ~[ViewListIdent], ast::NodeId)
+    // use str = source;
+    SimpleImport(~str, ImportSource),
+    // use source::*;
+    GlobImport(ImportSource),
+    // use source::{a, b, c};
+    ImportList(ImportSource, ~[ViewListIdent]),
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct ImportSource {
+    path: Path,
+    did: Option<ast::DefId>,
 }
 
 impl Clean<ViewPath> for ast::view_path {
     fn clean(&self) -> ViewPath {
         match self.node {
-            ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
-            ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
-            ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.clean(), *id),
+            ast::view_path_simple(ref i, ref p, id) =>
+                SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
+            ast::view_path_glob(ref p, id) =>
+                GlobImport(resolve_use_source(p.clean(), id)),
+            ast::view_path_list(ref p, ref pl, id) =>
+                ImportList(resolve_use_source(p.clean(), id), pl.clean()),
         }
     }
 }
 
-pub type ViewListIdent = ~str;
+#[deriving(Clone, Encodable, Decodable)]
+pub struct ViewListIdent {
+    name: ~str,
+    source: Option<ast::DefId>,
+}
 
 impl Clean<ViewListIdent> for ast::path_list_ident {
     fn clean(&self) -> ViewListIdent {
-        self.node.name.clean()
+        ViewListIdent {
+            name: self.node.name.clean(),
+            source: resolve_def(self.node.id),
+        }
     }
 }
 
@@ -1092,6 +1111,18 @@ fn resolve_type(t: &Type) -> Type {
         let cname = cratedata.name.to_owned();
         External(cname + "::" + path, ty)
     } else {
-        ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
+        ResolvedPath {path: path.clone(), typarams: tpbs, id: def_id.node}
     }
 }
+
+fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
+    ImportSource {
+        path: path,
+        did: resolve_def(id),
+    }
+}
+
+fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
+    let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
+    dm.find(&id).map_move(|&d| ast_util::def_id_of_def(d))
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6f05b042dba..7010e7fa4ea 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -97,7 +97,8 @@ impl fmt::Default for clean::Path {
     }
 }
 
-fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
+fn resolved_path(w: &mut io::Writer, id: ast::NodeId,
+                 path: &clean::Path, print_all: bool) {
     // The generics will get written to both the title and link
     let mut generics = ~"";
     let last = path.segments.last();
@@ -119,47 +120,73 @@ fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
     // Did someone say rightward-drift?
     do local_data::get(current_location_key) |loc| {
         let loc = loc.unwrap();
+
+        if print_all {
+            let mut root = match path.segments[0].name.as_slice() {
+                "super" => ~"../",
+                "self" => ~"",
+                _ => "../".repeat(loc.len() - 1),
+            };
+            let amt = path.segments.len() - 1;
+            for seg in path.segments.slice_to(amt).iter() {
+                if "super" == seg.name || "self" == seg.name {
+                    write!(w, "{}::", seg.name);
+                } else {
+                    root.push_str(seg.name);
+                    root.push_str("/");
+                    write!(w, "<a class='mod'
+                                  href='{}index.html'>{}</a>::",
+                           root,
+                           seg.name);
+                }
+            }
+        }
+
         do local_data::get(cache_key) |cache| {
             do cache.unwrap().read |cache| {
                 match cache.paths.find(&id) {
                     // This is a documented path, link to it!
                     Some(&(ref fqp, shortty)) => {
                         let fqn = fqp.connect("::");
-                        let mut same = 0;
-                        for (a, b) in loc.iter().zip(fqp.iter()) {
-                            if *a == *b {
-                                same += 1;
-                            } else {
-                                break;
-                            }
-                        }
+                        let same = loc.iter().zip(fqp.iter())
+                                      .take_while(|&(a, b)| *a == *b).len();
 
                         let mut url = ~"";
-                        for _ in range(same, loc.len()) {
+                        if "super" == path.segments[0].name {
                             url.push_str("../");
+                        } else if "self" != path.segments[0].name {
+                            url.push_str("../".repeat(loc.len() - same));
                         }
-                        if same == fqp.len() {
-                            url.push_str(shortty);
-                            url.push_str(".");
-                            url.push_str(*fqp.last());
-                            url.push_str(".html");
-                        } else {
+                        if same < fqp.len() {
                             let remaining = fqp.slice_from(same);
                             let to_link = remaining.slice_to(remaining.len() - 1);
                             for component in to_link.iter() {
                                 url.push_str(*component);
                                 url.push_str("/");
                             }
-                            url.push_str(shortty);
-                            url.push_str(".");
-                            url.push_str(*remaining.last());
-                            url.push_str(".html");
                         }
-
+                        match shortty {
+                            "mod" => {
+                                url.push_str(*fqp.last());
+                                url.push_str("/index.html");
+                            }
+                            _ => {
+                                url.push_str(shortty);
+                                url.push_str(".");
+                                url.push_str(*fqp.last());
+                                url.push_str(".html");
+                            }
+                        }
                         write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
                                shortty, url, fqn, last.name, generics);
                     }
                     None => {
+                        if print_all {
+                            let amt = path.segments.len() - 1;
+                            for seg in path.segments.iter().take(amt) {
+                                write!(w, "{}::", seg.name);
+                            }
+                        }
                         write!(w, "{}{}", last.name, generics);
                     }
                 };
@@ -178,9 +205,8 @@ impl fmt::Default for clean::Type {
                     }
                 }
             }
-            clean::Unresolved(*) => unreachable!(),
             clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
-                resolved_path(f.buf, id, path);
+                resolved_path(f.buf, id, path, false);
                 match *typarams {
                     Some(ref params) => {
                         f.buf.write("&lt;".as_bytes());
@@ -366,3 +392,63 @@ impl fmt::Default for PuritySpace {
         }
     }
 }
+
+impl fmt::Default for clean::ViewPath {
+    fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) {
+        match *v {
+            clean::SimpleImport(ref name, ref src) => {
+                if *name == src.path.segments.last().name {
+                    write!(f.buf, "use {};", *src);
+                } else {
+                    write!(f.buf, "use {} = {};", *name, *src);
+                }
+            }
+            clean::GlobImport(ref src) => {
+                write!(f.buf, "use {}::*;", *src);
+            }
+            clean::ImportList(ref src, ref names) => {
+                write!(f.buf, "use {}::\\{", *src);
+                for (i, n) in names.iter().enumerate() {
+                    if i > 0 { write!(f.buf, ", "); }
+                    write!(f.buf, "{}", *n);
+                }
+                write!(f.buf, "\\};");
+            }
+        }
+    }
+}
+
+impl fmt::Default for clean::ImportSource {
+    fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
+        match v.did {
+            Some(did) if ast_util::is_local(did) => {
+                resolved_path(f.buf, did.node, &v.path, true);
+            }
+            _ => {
+                for (i, seg) in v.path.segments.iter().enumerate() {
+                    if i > 0 { write!(f.buf, "::") }
+                    write!(f.buf, "{}", seg.name);
+                }
+            }
+        }
+    }
+}
+
+impl fmt::Default for clean::ViewListIdent {
+    fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
+        match v.source {
+            Some(did) if ast_util::is_local(did) => {
+                let path = clean::Path {
+                    global: false,
+                    segments: ~[clean::PathSegment {
+                        name: v.name.clone(),
+                        lifetime: None,
+                        types: ~[],
+                    }]
+                };
+                resolved_path(f.buf, did.node, &path, false);
+            }
+            _ => write!(f.buf, "{}", v.name),
+        }
+    }
+}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 070c0e5d986..790d9bef746 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -288,7 +288,9 @@ impl<'self> DocFolder for Cache {
         } else { false };
         match item.inner {
             clean::StructItem(*) | clean::EnumItem(*) |
-            clean::TypedefItem(*) | clean::TraitItem(*) => {
+            clean::TypedefItem(*) | clean::TraitItem(*) |
+            clean::FunctionItem(*) | clean::ModuleItem(*) |
+            clean::VariantItem(*) => {
                 self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
             }
             _ => {}
@@ -479,6 +481,8 @@ impl Context {
         }
 
         match item.inner {
+            // modules are special because they add a namespace. We also need to
+            // recurse into the items of the module as well.
             clean::ModuleItem(*) => {
                 let name = item.name.get_ref().to_owned();
                 let item = Cell::new(item);
@@ -498,11 +502,29 @@ impl Context {
                     }
                 }
             }
+
+            // Things which don't have names (like impls) don't get special
+            // pages dedicated to them.
             _ if item.name.is_some() => {
                 let dst = self.dst.push(item_path(&item));
                 let writer = dst.open_writer(io::CreateOrTruncate);
                 render(writer.unwrap(), self, &item, true);
+
+                // recurse if necessary
+                let name = item.name.get_ref().clone();
+                match item.inner {
+                    clean::EnumItem(e) => {
+                        let mut it = e.variants.move_iter();
+                        do self.recurse(name) |this| {
+                            for item in it {
+                                f(this, item);
+                            }
+                        }
+                    }
+                    _ => {}
+                }
             }
+
             _ => {}
         }
     }
@@ -696,17 +718,43 @@ fn item_module(w: &mut io::Writer, cx: &Context,
 
                 write!(w, "
                     <tr>
-                        <td><code>{}: {} = </code>{}</td>
+                        <td><code>{}static {}: {} = </code>{}</td>
                         <td class='docblock'>{}&nbsp;</td>
                     </tr>
                 ",
+                VisSpace(myitem.visibility),
                 *myitem.name.get_ref(),
                 s.type_,
                 Initializer(s.expr),
                 Markdown(blank(myitem.doc_value())));
             }
 
+            clean::ViewItemItem(ref item) => {
+                match item.inner {
+                    clean::ExternMod(ref name, ref src, _, _) => {
+                        write!(w, "<tr><td><code>extern mod {}",
+                               name.as_slice());
+                        match *src {
+                            Some(ref src) => write!(w, " = \"{}\"",
+                                                    src.as_slice()),
+                            None => {}
+                        }
+                        write!(w, ";</code></td></tr>");
+                    }
+
+                    clean::Import(ref imports) => {
+                        for import in imports.iter() {
+                            write!(w, "<tr><td><code>{}{}</code></td></tr>",
+                                   VisSpace(myitem.visibility),
+                                   *import);
+                        }
+                    }
+                }
+
+            }
+
             _ => {
+                if myitem.name.is_none() { loop }
                 write!(w, "
                     <tr>
                         <td><a class='{class}' href='{href}'