rustdoc: Linkify all reexports.
This way each component of a reexport path is click-able to the destination that it's referencing.
This commit is contained in:
parent
c838351ba6
commit
5c6f8a976f
4 changed files with 227 additions and 34 deletions
|
@ -2499,6 +2499,26 @@ impl Resolver {
|
|||
assert!(import_resolution.outstanding_references >= 1);
|
||||
import_resolution.outstanding_references -= 1;
|
||||
|
||||
// record what this import resolves to for later uses in documentation,
|
||||
// this may resolve to either a value or a type, but for documentation
|
||||
// purposes it's good enough to just favor one over the other.
|
||||
match i.value_target {
|
||||
Some(target) => {
|
||||
self.def_map.insert(i.value_id,
|
||||
target.bindings.value_def.get_ref().def);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
match i.type_target {
|
||||
Some(target) => {
|
||||
match target.bindings.type_def.get_ref().type_def {
|
||||
Some(def) => { self.def_map.insert(i.type_id, def); }
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
debug!("(resolving single import) successfully resolved import");
|
||||
return Success(());
|
||||
}
|
||||
|
@ -2626,6 +2646,14 @@ impl Resolver {
|
|||
merge_import_resolution(name, name_bindings);
|
||||
}
|
||||
|
||||
// Record the destination of this import
|
||||
match containing_module.def_id {
|
||||
Some(did) => {
|
||||
self.def_map.insert(id, DefMod(did));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
debug!("(resolving glob import) successfully resolved import");
|
||||
return Success(());
|
||||
}
|
||||
|
|
|
@ -930,26 +930,45 @@ impl Clean<ViewItemInner> for ast::view_item_ {
|
|||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub enum ViewPath {
|
||||
SimpleImport(~str, Path, ast::NodeId),
|
||||
GlobImport(Path, ast::NodeId),
|
||||
ImportList(Path, ~[ViewListIdent], ast::NodeId)
|
||||
// use str = source;
|
||||
SimpleImport(~str, ImportSource),
|
||||
// use source::*;
|
||||
GlobImport(ImportSource),
|
||||
// use source::{a, b, c};
|
||||
ImportList(ImportSource, ~[ViewListIdent]),
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub struct ImportSource {
|
||||
path: Path,
|
||||
did: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
impl Clean<ViewPath> for ast::view_path {
|
||||
fn clean(&self) -> ViewPath {
|
||||
match self.node {
|
||||
ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
|
||||
ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
|
||||
ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.clean(), *id),
|
||||
ast::view_path_simple(ref i, ref p, id) =>
|
||||
SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
|
||||
ast::view_path_glob(ref p, id) =>
|
||||
GlobImport(resolve_use_source(p.clean(), id)),
|
||||
ast::view_path_list(ref p, ref pl, id) =>
|
||||
ImportList(resolve_use_source(p.clean(), id), pl.clean()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ViewListIdent = ~str;
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub struct ViewListIdent {
|
||||
name: ~str,
|
||||
source: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
impl Clean<ViewListIdent> for ast::path_list_ident {
|
||||
fn clean(&self) -> ViewListIdent {
|
||||
self.node.name.clean()
|
||||
ViewListIdent {
|
||||
name: self.node.name.clean(),
|
||||
source: resolve_def(self.node.id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1092,6 +1111,18 @@ fn resolve_type(t: &Type) -> Type {
|
|||
let cname = cratedata.name.to_owned();
|
||||
External(cname + "::" + path, ty)
|
||||
} else {
|
||||
ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
|
||||
ResolvedPath {path: path.clone(), typarams: tpbs, id: def_id.node}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
|
||||
ImportSource {
|
||||
path: path,
|
||||
did: resolve_def(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
|
||||
let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
|
||||
dm.find(&id).map_move(|&d| ast_util::def_id_of_def(d))
|
||||
}
|
||||
|
|
|
@ -97,7 +97,8 @@ impl fmt::Default for clean::Path {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
|
||||
fn resolved_path(w: &mut io::Writer, id: ast::NodeId,
|
||||
path: &clean::Path, print_all: bool) {
|
||||
// The generics will get written to both the title and link
|
||||
let mut generics = ~"";
|
||||
let last = path.segments.last();
|
||||
|
@ -119,47 +120,73 @@ fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
|
|||
// Did someone say rightward-drift?
|
||||
do local_data::get(current_location_key) |loc| {
|
||||
let loc = loc.unwrap();
|
||||
|
||||
if print_all {
|
||||
let mut root = match path.segments[0].name.as_slice() {
|
||||
"super" => ~"../",
|
||||
"self" => ~"",
|
||||
_ => "../".repeat(loc.len() - 1),
|
||||
};
|
||||
let amt = path.segments.len() - 1;
|
||||
for seg in path.segments.slice_to(amt).iter() {
|
||||
if "super" == seg.name || "self" == seg.name {
|
||||
write!(w, "{}::", seg.name);
|
||||
} else {
|
||||
root.push_str(seg.name);
|
||||
root.push_str("/");
|
||||
write!(w, "<a class='mod'
|
||||
href='{}index.html'>{}</a>::",
|
||||
root,
|
||||
seg.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do local_data::get(cache_key) |cache| {
|
||||
do cache.unwrap().read |cache| {
|
||||
match cache.paths.find(&id) {
|
||||
// This is a documented path, link to it!
|
||||
Some(&(ref fqp, shortty)) => {
|
||||
let fqn = fqp.connect("::");
|
||||
let mut same = 0;
|
||||
for (a, b) in loc.iter().zip(fqp.iter()) {
|
||||
if *a == *b {
|
||||
same += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let same = loc.iter().zip(fqp.iter())
|
||||
.take_while(|&(a, b)| *a == *b).len();
|
||||
|
||||
let mut url = ~"";
|
||||
for _ in range(same, loc.len()) {
|
||||
if "super" == path.segments[0].name {
|
||||
url.push_str("../");
|
||||
} else if "self" != path.segments[0].name {
|
||||
url.push_str("../".repeat(loc.len() - same));
|
||||
}
|
||||
if same == fqp.len() {
|
||||
url.push_str(shortty);
|
||||
url.push_str(".");
|
||||
url.push_str(*fqp.last());
|
||||
url.push_str(".html");
|
||||
} else {
|
||||
if same < fqp.len() {
|
||||
let remaining = fqp.slice_from(same);
|
||||
let to_link = remaining.slice_to(remaining.len() - 1);
|
||||
for component in to_link.iter() {
|
||||
url.push_str(*component);
|
||||
url.push_str("/");
|
||||
}
|
||||
}
|
||||
match shortty {
|
||||
"mod" => {
|
||||
url.push_str(*fqp.last());
|
||||
url.push_str("/index.html");
|
||||
}
|
||||
_ => {
|
||||
url.push_str(shortty);
|
||||
url.push_str(".");
|
||||
url.push_str(*remaining.last());
|
||||
url.push_str(*fqp.last());
|
||||
url.push_str(".html");
|
||||
}
|
||||
|
||||
}
|
||||
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
|
||||
shortty, url, fqn, last.name, generics);
|
||||
}
|
||||
None => {
|
||||
if print_all {
|
||||
let amt = path.segments.len() - 1;
|
||||
for seg in path.segments.iter().take(amt) {
|
||||
write!(w, "{}::", seg.name);
|
||||
}
|
||||
}
|
||||
write!(w, "{}{}", last.name, generics);
|
||||
}
|
||||
};
|
||||
|
@ -178,9 +205,8 @@ impl fmt::Default for clean::Type {
|
|||
}
|
||||
}
|
||||
}
|
||||
clean::Unresolved(*) => unreachable!(),
|
||||
clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
|
||||
resolved_path(f.buf, id, path);
|
||||
resolved_path(f.buf, id, path, false);
|
||||
match *typarams {
|
||||
Some(ref params) => {
|
||||
f.buf.write("<".as_bytes());
|
||||
|
@ -366,3 +392,63 @@ impl fmt::Default for PuritySpace {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for clean::ViewPath {
|
||||
fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) {
|
||||
match *v {
|
||||
clean::SimpleImport(ref name, ref src) => {
|
||||
if *name == src.path.segments.last().name {
|
||||
write!(f.buf, "use {};", *src);
|
||||
} else {
|
||||
write!(f.buf, "use {} = {};", *name, *src);
|
||||
}
|
||||
}
|
||||
clean::GlobImport(ref src) => {
|
||||
write!(f.buf, "use {}::*;", *src);
|
||||
}
|
||||
clean::ImportList(ref src, ref names) => {
|
||||
write!(f.buf, "use {}::\\{", *src);
|
||||
for (i, n) in names.iter().enumerate() {
|
||||
if i > 0 { write!(f.buf, ", "); }
|
||||
write!(f.buf, "{}", *n);
|
||||
}
|
||||
write!(f.buf, "\\};");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for clean::ImportSource {
|
||||
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
|
||||
match v.did {
|
||||
Some(did) if ast_util::is_local(did) => {
|
||||
resolved_path(f.buf, did.node, &v.path, true);
|
||||
}
|
||||
_ => {
|
||||
for (i, seg) in v.path.segments.iter().enumerate() {
|
||||
if i > 0 { write!(f.buf, "::") }
|
||||
write!(f.buf, "{}", seg.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Default for clean::ViewListIdent {
|
||||
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
|
||||
match v.source {
|
||||
Some(did) if ast_util::is_local(did) => {
|
||||
let path = clean::Path {
|
||||
global: false,
|
||||
segments: ~[clean::PathSegment {
|
||||
name: v.name.clone(),
|
||||
lifetime: None,
|
||||
types: ~[],
|
||||
}]
|
||||
};
|
||||
resolved_path(f.buf, did.node, &path, false);
|
||||
}
|
||||
_ => write!(f.buf, "{}", v.name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,7 +288,9 @@ impl<'self> DocFolder for Cache {
|
|||
} else { false };
|
||||
match item.inner {
|
||||
clean::StructItem(*) | clean::EnumItem(*) |
|
||||
clean::TypedefItem(*) | clean::TraitItem(*) => {
|
||||
clean::TypedefItem(*) | clean::TraitItem(*) |
|
||||
clean::FunctionItem(*) | clean::ModuleItem(*) |
|
||||
clean::VariantItem(*) => {
|
||||
self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
|
||||
}
|
||||
_ => {}
|
||||
|
@ -479,6 +481,8 @@ impl Context {
|
|||
}
|
||||
|
||||
match item.inner {
|
||||
// modules are special because they add a namespace. We also need to
|
||||
// recurse into the items of the module as well.
|
||||
clean::ModuleItem(*) => {
|
||||
let name = item.name.get_ref().to_owned();
|
||||
let item = Cell::new(item);
|
||||
|
@ -498,11 +502,29 @@ impl Context {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Things which don't have names (like impls) don't get special
|
||||
// pages dedicated to them.
|
||||
_ if item.name.is_some() => {
|
||||
let dst = self.dst.push(item_path(&item));
|
||||
let writer = dst.open_writer(io::CreateOrTruncate);
|
||||
render(writer.unwrap(), self, &item, true);
|
||||
|
||||
// recurse if necessary
|
||||
let name = item.name.get_ref().clone();
|
||||
match item.inner {
|
||||
clean::EnumItem(e) => {
|
||||
let mut it = e.variants.move_iter();
|
||||
do self.recurse(name) |this| {
|
||||
for item in it {
|
||||
f(this, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -696,17 +718,43 @@ fn item_module(w: &mut io::Writer, cx: &Context,
|
|||
|
||||
write!(w, "
|
||||
<tr>
|
||||
<td><code>{}: {} = </code>{}</td>
|
||||
<td><code>{}static {}: {} = </code>{}</td>
|
||||
<td class='docblock'>{} </td>
|
||||
</tr>
|
||||
",
|
||||
VisSpace(myitem.visibility),
|
||||
*myitem.name.get_ref(),
|
||||
s.type_,
|
||||
Initializer(s.expr),
|
||||
Markdown(blank(myitem.doc_value())));
|
||||
}
|
||||
|
||||
clean::ViewItemItem(ref item) => {
|
||||
match item.inner {
|
||||
clean::ExternMod(ref name, ref src, _, _) => {
|
||||
write!(w, "<tr><td><code>extern mod {}",
|
||||
name.as_slice());
|
||||
match *src {
|
||||
Some(ref src) => write!(w, " = \"{}\"",
|
||||
src.as_slice()),
|
||||
None => {}
|
||||
}
|
||||
write!(w, ";</code></td></tr>");
|
||||
}
|
||||
|
||||
clean::Import(ref imports) => {
|
||||
for import in imports.iter() {
|
||||
write!(w, "<tr><td><code>{}{}</code></td></tr>",
|
||||
VisSpace(myitem.visibility),
|
||||
*import);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_ => {
|
||||
if myitem.name.is_none() { loop }
|
||||
write!(w, "
|
||||
<tr>
|
||||
<td><a class='{class}' href='{href}'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue