Skip to content

Commit d06043b

Browse files
committed
rustdoc: Generate hyperlinks between crates
The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
1 parent f00d72b commit d06043b

File tree

6 files changed

+253
-124
lines changed

6 files changed

+253
-124
lines changed

src/libextra/extra.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ Rust extras are part of the standard Rust distribution.
2626
url = "https://github.com/mozilla/rust/tree/master/src/libextra")];
2727

2828
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
29-
html_favicon_url = "http://www.rust-lang.org/favicon.ico")];
29+
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
30+
html_root_url = "http://static.rust-lang.org/doc/master")];
3031

3132
#[comment = "Rust extras"];
3233
#[license = "MIT/ASL2"];

src/librustdoc/clean.rs

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@ use its = syntax::parse::token::ident_to_str;
1515

1616
use syntax;
1717
use syntax::ast;
18+
use syntax::ast_map;
1819
use syntax::ast_util;
1920
use syntax::attr;
2021
use syntax::attr::AttributeMethods;
2122

23+
use rustc::metadata::cstore;
24+
use rustc::metadata::csearch;
25+
use rustc::metadata::decoder;
26+
2227
use std;
28+
use std::hashmap::HashMap;
29+
2330
use doctree;
2431
use visit_ast;
2532
use std::local_data;
@@ -61,19 +68,44 @@ impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
6168
pub struct Crate {
6269
name: ~str,
6370
module: Option<Item>,
71+
externs: HashMap<ast::CrateNum, ExternalCrate>,
6472
}
6573

6674
impl Clean<Crate> for visit_ast::RustdocVisitor {
6775
fn clean(&self) -> Crate {
6876
use syntax::attr::{find_linkage_metas, last_meta_item_value_str_by_name};
69-
let maybe_meta = last_meta_item_value_str_by_name(find_linkage_metas(self.attrs), "name");
77+
let maybe_meta = last_meta_item_value_str_by_name(
78+
find_linkage_metas(self.attrs), "name");
79+
let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
80+
81+
let mut externs = HashMap::new();
82+
do cstore::iter_crate_data(cx.sess.cstore) |n, meta| {
83+
externs.insert(n, meta.clean());
84+
}
7085

7186
Crate {
7287
name: match maybe_meta {
7388
Some(x) => x.to_owned(),
74-
None => fail2!("rustdoc_ng requires a \\#[link(name=\"foo\")] crate attribute"),
89+
None => fail2!("rustdoc requires a \\#[link(name=\"foo\")] \
90+
crate attribute"),
7591
},
7692
module: Some(self.module.clean()),
93+
externs: externs,
94+
}
95+
}
96+
}
97+
98+
#[deriving(Clone, Encodable, Decodable)]
99+
pub struct ExternalCrate {
100+
name: ~str,
101+
attrs: ~[Attribute],
102+
}
103+
104+
impl Clean<ExternalCrate> for cstore::crate_metadata {
105+
fn clean(&self) -> ExternalCrate {
106+
ExternalCrate {
107+
name: self.name.to_owned(),
108+
attrs: decoder::get_crate_attributes(self.data).clean()
77109
}
78110
}
79111
}
@@ -542,7 +574,15 @@ pub enum Type {
542574
ResolvedPath {
543575
path: Path,
544576
typarams: Option<~[TyParamBound]>,
545-
did: ast::DefId
577+
id: ast::NodeId,
578+
},
579+
/// Same as above, but only external variants
580+
ExternalPath {
581+
path: Path,
582+
typarams: Option<~[TyParamBound]>,
583+
fqn: ~[~str],
584+
kind: TypeKind,
585+
crate: ast::CrateNum,
546586
},
547587
// I have no idea how to usefully use this.
548588
TyParamBinder(ast::NodeId),
@@ -572,6 +612,14 @@ pub enum Type {
572612
// region, raw, other boxes, mutable
573613
}
574614

615+
#[deriving(Clone, Encodable, Decodable)]
616+
pub enum TypeKind {
617+
TypeStruct,
618+
TypeEnum,
619+
TypeTrait,
620+
TypeFunction,
621+
}
622+
575623
impl Clean<Type> for ast::Ty {
576624
fn clean(&self) -> Type {
577625
use syntax::ast::*;
@@ -1099,26 +1147,12 @@ fn name_from_pat(p: &ast::Pat) -> ~str {
10991147
}
11001148
}
11011149

1102-
fn remove_comment_tags(s: &str) -> ~str {
1103-
if s.starts_with("/") {
1104-
match s.slice(0,3) {
1105-
&"///" => return s.slice(3, s.len()).trim().to_owned(),
1106-
&"/**" | &"/*!" => return s.slice(3, s.len() - 2).trim().to_owned(),
1107-
_ => return s.trim().to_owned()
1108-
}
1109-
} else {
1110-
return s.to_owned();
1111-
}
1112-
}
1113-
11141150
/// Given a Type, resolve it using the def_map
11151151
fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
11161152
id: ast::NodeId) -> Type {
1117-
use syntax::ast::*;
1118-
1119-
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
1153+
let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
11201154
debug2!("searching for {:?} in defmap", id);
1121-
let d = match dm.find(&id) {
1155+
let d = match cx.tycx.def_map.find(&id) {
11221156
Some(k) => k,
11231157
None => {
11241158
let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
@@ -1128,28 +1162,41 @@ fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
11281162
}
11291163
};
11301164

1131-
let def_id = match *d {
1132-
DefFn(i, _) => i,
1133-
DefSelf(i) | DefSelfTy(i) => return Self(i),
1134-
DefTy(i) => i,
1135-
DefTrait(i) => {
1165+
let (def_id, kind) = match *d {
1166+
ast::DefFn(i, _) => (i, TypeFunction),
1167+
ast::DefSelf(i) | ast::DefSelfTy(i) => return Self(i),
1168+
ast::DefTy(i) => (i, TypeEnum),
1169+
ast::DefTrait(i) => {
11361170
debug2!("saw DefTrait in def_to_id");
1137-
i
1171+
(i, TypeTrait)
11381172
},
1139-
DefPrimTy(p) => match p {
1140-
ty_str => return String,
1141-
ty_bool => return Bool,
1173+
ast::DefPrimTy(p) => match p {
1174+
ast::ty_str => return String,
1175+
ast::ty_bool => return Bool,
11421176
_ => return Primitive(p)
11431177
},
1144-
DefTyParam(i, _) => return Generic(i.node),
1145-
DefStruct(i) => i,
1146-
DefTyParamBinder(i) => {
1178+
ast::DefTyParam(i, _) => return Generic(i.node),
1179+
ast::DefStruct(i) => (i, TypeStruct),
1180+
ast::DefTyParamBinder(i) => {
11471181
debug2!("found a typaram_binder, what is it? {}", i);
11481182
return TyParamBinder(i);
11491183
},
11501184
x => fail2!("resolved type maps to a weird def {:?}", x),
11511185
};
1152-
ResolvedPath{ path: path, typarams: tpbs, did: def_id }
1186+
if ast_util::is_local(def_id) {
1187+
ResolvedPath{ path: path, typarams: tpbs, id: def_id.node }
1188+
} else {
1189+
let fqn = csearch::get_item_path(cx.tycx, def_id);
1190+
let fqn = fqn.move_iter().map(|i| {
1191+
match i {
1192+
ast_map::path_mod(id) |
1193+
ast_map::path_name(id) |
1194+
ast_map::path_pretty_name(id, _) => id.clean()
1195+
}
1196+
}).to_owned_vec();
1197+
ExternalPath{ path: path, typarams: tpbs, fqn: fqn, kind: kind,
1198+
crate: def_id.crate }
1199+
}
11531200
}
11541201

11551202
fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {

0 commit comments

Comments
 (0)