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.
This commit is contained in:
parent
9f13db2cb2
commit
8dad7f579e
@ -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 => {}
|
||||
}
|
||||
|
@ -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 {
|
||||
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_strbuf!("{}", self.item.source.loline)
|
||||
format!("{}", self.item.source.loline)
|
||||
} else {
|
||||
format_strbuf!("{}-{}",
|
||||
format!("{}-{}",
|
||||
self.item.source.loline,
|
||||
self.item.source.hiline)
|
||||
};
|
||||
format_strbuf!("{root}src/{krate}/{path}.html\\#{href}",
|
||||
Some(format!("{root}src/{krate}/{path}.html\\#{href}",
|
||||
root = self.cx.root_path,
|
||||
krate = self.cx.layout.krate,
|
||||
path = path.connect("/"),
|
||||
href = href)
|
||||
href = href))
|
||||
} else {
|
||||
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"));
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
Loading…
Reference in New Issue
Block a user