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> { }; 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> { +fn try_inline_def(cx: &core::DocContext, + tcx: &ty::ctxt, + def: ast::Def) -> Option> { 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, ItemType)>, + /// Similar to `paths`, but only holds external paths. This is only used for + /// generating explicit hyperlinks to other crates. + pub external_paths: HashMap>, + /// 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, 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 { + 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, "[src]", - self.link())); + match self.link() { + Some(l) => { + try!(write!(fmt, + "[src]", + self.item.def_id.node, l)); + } + None => {} + } } try!(write!(fmt, "\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'); + } + } }());