Skip to content

Commit 5c6f8a9

Browse files
committed
rustdoc: Linkify all reexports.
This way each component of a reexport path is click-able to the destination that it's referencing.
1 parent c838351 commit 5c6f8a9

File tree

4 files changed

+227
-34
lines changed

4 files changed

+227
-34
lines changed

src/librustc/middle/resolve.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,26 @@ impl Resolver {
24992499
assert!(import_resolution.outstanding_references >= 1);
25002500
import_resolution.outstanding_references -= 1;
25012501

2502+
// record what this import resolves to for later uses in documentation,
2503+
// this may resolve to either a value or a type, but for documentation
2504+
// purposes it's good enough to just favor one over the other.
2505+
match i.value_target {
2506+
Some(target) => {
2507+
self.def_map.insert(i.value_id,
2508+
target.bindings.value_def.get_ref().def);
2509+
}
2510+
None => {}
2511+
}
2512+
match i.type_target {
2513+
Some(target) => {
2514+
match target.bindings.type_def.get_ref().type_def {
2515+
Some(def) => { self.def_map.insert(i.type_id, def); }
2516+
None => {}
2517+
}
2518+
}
2519+
None => {}
2520+
}
2521+
25022522
debug!("(resolving single import) successfully resolved import");
25032523
return Success(());
25042524
}
@@ -2626,6 +2646,14 @@ impl Resolver {
26262646
merge_import_resolution(name, name_bindings);
26272647
}
26282648

2649+
// Record the destination of this import
2650+
match containing_module.def_id {
2651+
Some(did) => {
2652+
self.def_map.insert(id, DefMod(did));
2653+
}
2654+
None => {}
2655+
}
2656+
26292657
debug!("(resolving glob import) successfully resolved import");
26302658
return Success(());
26312659
}

src/librustdoc/clean.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -930,26 +930,45 @@ impl Clean<ViewItemInner> for ast::view_item_ {
930930

931931
#[deriving(Clone, Encodable, Decodable)]
932932
pub enum ViewPath {
933-
SimpleImport(~str, Path, ast::NodeId),
934-
GlobImport(Path, ast::NodeId),
935-
ImportList(Path, ~[ViewListIdent], ast::NodeId)
933+
// use str = source;
934+
SimpleImport(~str, ImportSource),
935+
// use source::*;
936+
GlobImport(ImportSource),
937+
// use source::{a, b, c};
938+
ImportList(ImportSource, ~[ViewListIdent]),
939+
}
940+
941+
#[deriving(Clone, Encodable, Decodable)]
942+
pub struct ImportSource {
943+
path: Path,
944+
did: Option<ast::DefId>,
936945
}
937946

938947
impl Clean<ViewPath> for ast::view_path {
939948
fn clean(&self) -> ViewPath {
940949
match self.node {
941-
ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
942-
ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
943-
ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.clean(), *id),
950+
ast::view_path_simple(ref i, ref p, id) =>
951+
SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
952+
ast::view_path_glob(ref p, id) =>
953+
GlobImport(resolve_use_source(p.clean(), id)),
954+
ast::view_path_list(ref p, ref pl, id) =>
955+
ImportList(resolve_use_source(p.clean(), id), pl.clean()),
944956
}
945957
}
946958
}
947959

948-
pub type ViewListIdent = ~str;
960+
#[deriving(Clone, Encodable, Decodable)]
961+
pub struct ViewListIdent {
962+
name: ~str,
963+
source: Option<ast::DefId>,
964+
}
949965

950966
impl Clean<ViewListIdent> for ast::path_list_ident {
951967
fn clean(&self) -> ViewListIdent {
952-
self.node.name.clean()
968+
ViewListIdent {
969+
name: self.node.name.clean(),
970+
source: resolve_def(self.node.id),
971+
}
953972
}
954973
}
955974

@@ -1092,6 +1111,18 @@ fn resolve_type(t: &Type) -> Type {
10921111
let cname = cratedata.name.to_owned();
10931112
External(cname + "::" + path, ty)
10941113
} else {
1095-
ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
1114+
ResolvedPath {path: path.clone(), typarams: tpbs, id: def_id.node}
10961115
}
10971116
}
1117+
1118+
fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
1119+
ImportSource {
1120+
path: path,
1121+
did: resolve_def(id),
1122+
}
1123+
}
1124+
1125+
fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
1126+
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
1127+
dm.find(&id).map_move(|&d| ast_util::def_id_of_def(d))
1128+
}

src/librustdoc/html/format.rs

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ impl fmt::Default for clean::Path {
9797
}
9898
}
9999

100-
fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
100+
fn resolved_path(w: &mut io::Writer, id: ast::NodeId,
101+
path: &clean::Path, print_all: bool) {
101102
// The generics will get written to both the title and link
102103
let mut generics = ~"";
103104
let last = path.segments.last();
@@ -119,47 +120,73 @@ fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
119120
// Did someone say rightward-drift?
120121
do local_data::get(current_location_key) |loc| {
121122
let loc = loc.unwrap();
123+
124+
if print_all {
125+
let mut root = match path.segments[0].name.as_slice() {
126+
"super" => ~"../",
127+
"self" => ~"",
128+
_ => "../".repeat(loc.len() - 1),
129+
};
130+
let amt = path.segments.len() - 1;
131+
for seg in path.segments.slice_to(amt).iter() {
132+
if "super" == seg.name || "self" == seg.name {
133+
write!(w, "{}::", seg.name);
134+
} else {
135+
root.push_str(seg.name);
136+
root.push_str("/");
137+
write!(w, "<a class='mod'
138+
href='{}index.html'>{}</a>::",
139+
root,
140+
seg.name);
141+
}
142+
}
143+
}
144+
122145
do local_data::get(cache_key) |cache| {
123146
do cache.unwrap().read |cache| {
124147
match cache.paths.find(&id) {
125148
// This is a documented path, link to it!
126149
Some(&(ref fqp, shortty)) => {
127150
let fqn = fqp.connect("::");
128-
let mut same = 0;
129-
for (a, b) in loc.iter().zip(fqp.iter()) {
130-
if *a == *b {
131-
same += 1;
132-
} else {
133-
break;
134-
}
135-
}
151+
let same = loc.iter().zip(fqp.iter())
152+
.take_while(|&(a, b)| *a == *b).len();
136153

137154
let mut url = ~"";
138-
for _ in range(same, loc.len()) {
155+
if "super" == path.segments[0].name {
139156
url.push_str("../");
157+
} else if "self" != path.segments[0].name {
158+
url.push_str("../".repeat(loc.len() - same));
140159
}
141-
if same == fqp.len() {
142-
url.push_str(shortty);
143-
url.push_str(".");
144-
url.push_str(*fqp.last());
145-
url.push_str(".html");
146-
} else {
160+
if same < fqp.len() {
147161
let remaining = fqp.slice_from(same);
148162
let to_link = remaining.slice_to(remaining.len() - 1);
149163
for component in to_link.iter() {
150164
url.push_str(*component);
151165
url.push_str("/");
152166
}
153-
url.push_str(shortty);
154-
url.push_str(".");
155-
url.push_str(*remaining.last());
156-
url.push_str(".html");
157167
}
158-
168+
match shortty {
169+
"mod" => {
170+
url.push_str(*fqp.last());
171+
url.push_str("/index.html");
172+
}
173+
_ => {
174+
url.push_str(shortty);
175+
url.push_str(".");
176+
url.push_str(*fqp.last());
177+
url.push_str(".html");
178+
}
179+
}
159180
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
160181
shortty, url, fqn, last.name, generics);
161182
}
162183
None => {
184+
if print_all {
185+
let amt = path.segments.len() - 1;
186+
for seg in path.segments.iter().take(amt) {
187+
write!(w, "{}::", seg.name);
188+
}
189+
}
163190
write!(w, "{}{}", last.name, generics);
164191
}
165192
};
@@ -178,9 +205,8 @@ impl fmt::Default for clean::Type {
178205
}
179206
}
180207
}
181-
clean::Unresolved(*) => unreachable!(),
182208
clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
183-
resolved_path(f.buf, id, path);
209+
resolved_path(f.buf, id, path, false);
184210
match *typarams {
185211
Some(ref params) => {
186212
f.buf.write("&lt;".as_bytes());
@@ -366,3 +392,63 @@ impl fmt::Default for PuritySpace {
366392
}
367393
}
368394
}
395+
396+
impl fmt::Default for clean::ViewPath {
397+
fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) {
398+
match *v {
399+
clean::SimpleImport(ref name, ref src) => {
400+
if *name == src.path.segments.last().name {
401+
write!(f.buf, "use {};", *src);
402+
} else {
403+
write!(f.buf, "use {} = {};", *name, *src);
404+
}
405+
}
406+
clean::GlobImport(ref src) => {
407+
write!(f.buf, "use {}::*;", *src);
408+
}
409+
clean::ImportList(ref src, ref names) => {
410+
write!(f.buf, "use {}::\\{", *src);
411+
for (i, n) in names.iter().enumerate() {
412+
if i > 0 { write!(f.buf, ", "); }
413+
write!(f.buf, "{}", *n);
414+
}
415+
write!(f.buf, "\\};");
416+
}
417+
}
418+
}
419+
}
420+
421+
impl fmt::Default for clean::ImportSource {
422+
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
423+
match v.did {
424+
Some(did) if ast_util::is_local(did) => {
425+
resolved_path(f.buf, did.node, &v.path, true);
426+
}
427+
_ => {
428+
for (i, seg) in v.path.segments.iter().enumerate() {
429+
if i > 0 { write!(f.buf, "::") }
430+
write!(f.buf, "{}", seg.name);
431+
}
432+
}
433+
}
434+
}
435+
}
436+
437+
impl fmt::Default for clean::ViewListIdent {
438+
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
439+
match v.source {
440+
Some(did) if ast_util::is_local(did) => {
441+
let path = clean::Path {
442+
global: false,
443+
segments: ~[clean::PathSegment {
444+
name: v.name.clone(),
445+
lifetime: None,
446+
types: ~[],
447+
}]
448+
};
449+
resolved_path(f.buf, did.node, &path, false);
450+
}
451+
_ => write!(f.buf, "{}", v.name),
452+
}
453+
}
454+
}

src/librustdoc/html/render.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,9 @@ impl<'self> DocFolder for Cache {
288288
} else { false };
289289
match item.inner {
290290
clean::StructItem(*) | clean::EnumItem(*) |
291-
clean::TypedefItem(*) | clean::TraitItem(*) => {
291+
clean::TypedefItem(*) | clean::TraitItem(*) |
292+
clean::FunctionItem(*) | clean::ModuleItem(*) |
293+
clean::VariantItem(*) => {
292294
self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
293295
}
294296
_ => {}
@@ -479,6 +481,8 @@ impl Context {
479481
}
480482

481483
match item.inner {
484+
// modules are special because they add a namespace. We also need to
485+
// recurse into the items of the module as well.
482486
clean::ModuleItem(*) => {
483487
let name = item.name.get_ref().to_owned();
484488
let item = Cell::new(item);
@@ -498,11 +502,29 @@ impl Context {
498502
}
499503
}
500504
}
505+
506+
// Things which don't have names (like impls) don't get special
507+
// pages dedicated to them.
501508
_ if item.name.is_some() => {
502509
let dst = self.dst.push(item_path(&item));
503510
let writer = dst.open_writer(io::CreateOrTruncate);
504511
render(writer.unwrap(), self, &item, true);
512+
513+
// recurse if necessary
514+
let name = item.name.get_ref().clone();
515+
match item.inner {
516+
clean::EnumItem(e) => {
517+
let mut it = e.variants.move_iter();
518+
do self.recurse(name) |this| {
519+
for item in it {
520+
f(this, item);
521+
}
522+
}
523+
}
524+
_ => {}
525+
}
505526
}
527+
506528
_ => {}
507529
}
508530
}
@@ -696,17 +718,43 @@ fn item_module(w: &mut io::Writer, cx: &Context,
696718

697719
write!(w, "
698720
<tr>
699-
<td><code>{}: {} = </code>{}</td>
721+
<td><code>{}static {}: {} = </code>{}</td>
700722
<td class='docblock'>{}&nbsp;</td>
701723
</tr>
702724
",
725+
VisSpace(myitem.visibility),
703726
*myitem.name.get_ref(),
704727
s.type_,
705728
Initializer(s.expr),
706729
Markdown(blank(myitem.doc_value())));
707730
}
708731

732+
clean::ViewItemItem(ref item) => {
733+
match item.inner {
734+
clean::ExternMod(ref name, ref src, _, _) => {
735+
write!(w, "<tr><td><code>extern mod {}",
736+
name.as_slice());
737+
match *src {
738+
Some(ref src) => write!(w, " = \"{}\"",
739+
src.as_slice()),
740+
None => {}
741+
}
742+
write!(w, ";</code></td></tr>");
743+
}
744+
745+
clean::Import(ref imports) => {
746+
for import in imports.iter() {
747+
write!(w, "<tr><td><code>{}{}</code></td></tr>",
748+
VisSpace(myitem.visibility),
749+
*import);
750+
}
751+
}
752+
}
753+
754+
}
755+
709756
_ => {
757+
if myitem.name.is_none() { loop }
710758
write!(w, "
711759
<tr>
712760
<td><a class='{class}' href='{href}'

0 commit comments

Comments
 (0)