about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-05-23 20:17:27 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-05-25 01:18:37 -0700
commit8dad7f579e029fd883d64848f4abb12630dcc3e6 (patch)
treefe14ce6ab9aa198a387914d5fc8742d0e9261154
parent9f13db2cb2edfd626006bd86e01351a8b1c23401 (diff)
downloadrust-8dad7f579e029fd883d64848f4abb12630dcc3e6.tar.gz
rust-8dad7f579e029fd883d64848f4abb12630dcc3e6.zip
rustdoc: Get [src] links working for inlined dox
These links work by hyperlinking back to the actual documentation page with a
query parameter which will be recognized and then auto-click the appropriate
[src] link.
-rw-r--r--src/librustdoc/clean.rs47
-rw-r--r--src/librustdoc/html/render.rs71
-rw-r--r--src/librustdoc/html/static/main.js10
3 files changed, 96 insertions, 32 deletions
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index 4ba59647063..ab953419a41 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean.rs
@@ -1575,28 +1575,40 @@ fn try_inline(id: ast::NodeId) -> Option<Vec<Item>> {
     };
     let did = ast_util::def_id_of_def(def);
     if ast_util::is_local(did) { return None }
-    try_inline_def(tcx, def)
+    try_inline_def(&**cx, tcx, def)
 }
 
-fn try_inline_def(tcx: &ty::ctxt, def: ast::Def) -> Option<Vec<Item>> {
+fn try_inline_def(cx: &core::DocContext,
+                  tcx: &ty::ctxt,
+                  def: ast::Def) -> Option<Vec<Item>> {
     let mut ret = Vec::new();
     let did = ast_util::def_id_of_def(def);
     let inner = match def {
-        ast::DefTrait(did) => TraitItem(build_external_trait(tcx, did)),
-        ast::DefFn(did, style) =>
-            FunctionItem(build_external_function(tcx, did, style)),
+        ast::DefTrait(did) => {
+            record_extern_fqn(cx, did, TypeTrait);
+            TraitItem(build_external_trait(tcx, did))
+        }
+        ast::DefFn(did, style) => {
+            record_extern_fqn(cx, did, TypeFunction);
+            FunctionItem(build_external_function(tcx, did, style))
+        }
         ast::DefStruct(did) => {
+            record_extern_fqn(cx, did, TypeStruct);
             ret.extend(build_impls(tcx, did).move_iter());
             StructItem(build_struct(tcx, did))
         }
         ast::DefTy(did) => {
+            record_extern_fqn(cx, did, TypeEnum);
             ret.extend(build_impls(tcx, did).move_iter());
             build_type(tcx, did)
         }
         // Assume that the enum type is reexported next to the variant, and
         // variants don't show up in documentation specially.
         ast::DefVariant(..) => return Some(Vec::new()),
-        ast::DefMod(did) => ModuleItem(build_module(tcx, did)),
+        ast::DefMod(did) => {
+            record_extern_fqn(cx, did, TypeModule);
+            ModuleItem(build_module(cx, tcx, did))
+        }
         _ => return None,
     };
     let fqn = csearch::get_item_path(tcx, did);
@@ -1838,10 +1850,7 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
         core::Typed(ref t) => t,
         core::NotTyped(_) => return did
     };
-    let fqn = csearch::get_item_path(tcx, did);
-    let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
-    debug!("recording {} => {}", did, fqn);
-    cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
+    record_extern_fqn(cx, did, kind);
     match kind {
         TypeTrait => {
             let t = build_external_trait(tcx, did);
@@ -1852,6 +1861,19 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
     return did;
 }
 
+fn record_extern_fqn(cx: &core::DocContext,
+                     did: ast::DefId,
+                     kind: TypeKind) {
+    match cx.maybe_typed {
+        core::Typed(ref tcx) => {
+            let fqn = csearch::get_item_path(tcx, did);
+            let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
+            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
+        }
+        core::NotTyped(..) => {}
+    }
+}
+
 fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
     let def = ty::lookup_trait_def(tcx, did);
     let methods = ty::trait_methods(tcx, did);
@@ -2000,13 +2022,14 @@ fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> Item {
     }
 }
 
-fn build_module(tcx: &ty::ctxt, did: ast::DefId) -> Module {
+fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
+                did: ast::DefId) -> Module {
     let mut items = Vec::new();
 
     csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| {
         match def {
             decoder::DlDef(def) => {
-                match try_inline_def(tcx, def) {
+                match try_inline_def(cx, tcx, def) {
                     Some(i) => items.extend(i.move_iter()),
                     None => {}
                 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 6d6736eac3f..ce7f230ea53 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -141,6 +141,10 @@ pub struct Cache {
     /// necessary.
     pub paths: HashMap<ast::DefId, (Vec<String>, ItemType)>,
 
+    /// Similar to `paths`, but only holds external paths. This is only used for
+    /// generating explicit hyperlinks to other crates.
+    pub external_paths: HashMap<ast::DefId, Vec<StrBuf>>,
+
     /// This map contains information about all known traits of this crate.
     /// Implementations of a crate should inherit the documentation of the
     /// parent trait if no extra documentation is specified, and default methods
@@ -249,7 +253,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     let analysis = ::analysiskey.get();
     let public_items = analysis.as_ref().map(|a| a.public_items.clone());
     let public_items = public_items.unwrap_or(NodeSet::new());
-    let paths = analysis.as_ref().map(|a| {
+    let paths: HashMap<ast::DefId, (Vec<StrBuf>, ItemType)> =
+      analysis.as_ref().map(|a| {
         let paths = a.external_paths.borrow_mut().take_unwrap();
         paths.move_iter().map(|(k, (v, t))| {
             (k, (v, match t {
@@ -265,6 +270,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     }).unwrap_or(HashMap::new());
     let mut cache = Cache {
         impls: HashMap::new(),
+        external_paths: paths.iter().map(|(&k, &(ref v, _))| (k, v.clone()))
+                             .collect(),
         paths: paths,
         implementors: HashMap::new(),
         stack: Vec::new(),
@@ -496,13 +503,15 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
             seen: HashSet::new(),
             cx: &mut cx,
         };
+        // skip all invalid spans
+        folder.seen.insert("".to_strbuf());
         krate = folder.fold_crate(krate);
     }
 
     for &(n, ref e) in krate.externs.iter() {
         cache.extern_locations.insert(n, extern_location(e, &cx.dst));
         let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID };
-        cache.paths.insert(did, (Vec::new(), item_type::Module));
+        cache.paths.insert(did, (vec![e.name.to_strbuf()], item_type::Module));
     }
 
     // And finally render the whole crate's documentation
@@ -1032,23 +1041,38 @@ impl<'a> Item<'a> {
         }
     }
 
-    fn link(&self) -> String {
-        let mut path = Vec::new();
-        clean_srcpath(self.item.source.filename.as_bytes(), |component| {
-            path.push(component.to_owned());
-        });
-        let href = if self.item.source.loline == self.item.source.hiline {
-            format_strbuf!("{}", self.item.source.loline)
+    fn link(&self) -> Option<String> {
+        if ast_util::is_local(self.item.def_id) {
+            let mut path = Vec::new();
+            clean_srcpath(self.item.source.filename.as_bytes(), |component| {
+                path.push(component.to_owned());
+            });
+            let href = if self.item.source.loline == self.item.source.hiline {
+                format!("{}", self.item.source.loline)
+            } else {
+                format!("{}-{}",
+                        self.item.source.loline,
+                        self.item.source.hiline)
+            };
+            Some(format!("{root}src/{krate}/{path}.html\\#{href}",
+                         root = self.cx.root_path,
+                         krate = self.cx.layout.krate,
+                         path = path.connect("/"),
+                         href = href))
         } else {
-            format_strbuf!("{}-{}",
-                           self.item.source.loline,
-                           self.item.source.hiline)
-        };
-        format_strbuf!("{root}src/{krate}/{path}.html\\#{href}",
-                       root = self.cx.root_path,
-                       krate = self.cx.layout.krate,
-                       path = path.connect("/"),
-                       href = href)
+            let cache = cache_key.get().unwrap();
+            let path = cache.external_paths.get(&self.item.def_id);
+            let root = match *cache.extern_locations.get(&self.item.def_id.krate) {
+                Remote(ref s) => s.to_strbuf(),
+                Local => format!("{}/..", self.cx.root_path),
+                Unknown => return None,
+            };
+            Some(format!("{root}/{path}/{file}?gotosrc={goto}",
+                         root = root,
+                         path = path.slice_to(path.len() - 1).connect("/"),
+                         file = item_path(self.item),
+                         goto = self.item.def_id.node))
+        }
     }
 }
 
@@ -1097,8 +1121,15 @@ impl<'a> fmt::Show for Item<'a> {
 
         // Write `src` tag
         if self.cx.include_sources {
-            try!(write!(fmt, "<a class='source' href='{}'>[src]</a>",
-                        self.link()));
+            match self.link() {
+                Some(l) => {
+                    try!(write!(fmt,
+                                "<a class='source' id='src-{}' \
+                                    href='{}'>[src]</a>",
+                                self.item.def_id.node, l));
+                }
+                None => {}
+            }
         }
         try!(write!(fmt, "</h1>\n"));
 
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index c88e6aa5868..ec58162fa92 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -675,4 +675,14 @@
     if (window.pending_implementors) {
         window.register_implementors(window.pending_implementors);
     }
+
+
+    var query = window.location.search.substring(1);
+    var vars = query.split('&');
+    for (var i = 0; i < vars.length; i++) {
+        var pair = vars[i].split('=');
+        if (pair[0] == 'gotosrc') {
+            window.location = $('#src-' + pair[1]).attr('href');
+        }
+    }
 }());