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);
|
assert!(import_resolution.outstanding_references >= 1);
|
||||||
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");
|
debug!("(resolving single import) successfully resolved import");
|
||||||
return Success(());
|
return Success(());
|
||||||
}
|
}
|
||||||
|
@ -2626,6 +2646,14 @@ impl Resolver {
|
||||||
merge_import_resolution(name, name_bindings);
|
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");
|
debug!("(resolving glob import) successfully resolved import");
|
||||||
return Success(());
|
return Success(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -930,26 +930,45 @@ impl Clean<ViewItemInner> for ast::view_item_ {
|
||||||
|
|
||||||
#[deriving(Clone, Encodable, Decodable)]
|
#[deriving(Clone, Encodable, Decodable)]
|
||||||
pub enum ViewPath {
|
pub enum ViewPath {
|
||||||
SimpleImport(~str, Path, ast::NodeId),
|
// use str = source;
|
||||||
GlobImport(Path, ast::NodeId),
|
SimpleImport(~str, ImportSource),
|
||||||
ImportList(Path, ~[ViewListIdent], ast::NodeId)
|
// 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 {
|
impl Clean<ViewPath> for ast::view_path {
|
||||||
fn clean(&self) -> ViewPath {
|
fn clean(&self) -> ViewPath {
|
||||||
match self.node {
|
match self.node {
|
||||||
ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
|
ast::view_path_simple(ref i, ref p, id) =>
|
||||||
ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
|
SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
|
||||||
ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.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 {
|
impl Clean<ViewListIdent> for ast::path_list_ident {
|
||||||
fn clean(&self) -> ViewListIdent {
|
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();
|
let cname = cratedata.name.to_owned();
|
||||||
External(cname + "::" + path, ty)
|
External(cname + "::" + path, ty)
|
||||||
} else {
|
} 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
|
// The generics will get written to both the title and link
|
||||||
let mut generics = ~"";
|
let mut generics = ~"";
|
||||||
let last = path.segments.last();
|
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?
|
// Did someone say rightward-drift?
|
||||||
do local_data::get(current_location_key) |loc| {
|
do local_data::get(current_location_key) |loc| {
|
||||||
let loc = loc.unwrap();
|
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 local_data::get(cache_key) |cache| {
|
||||||
do cache.unwrap().read |cache| {
|
do cache.unwrap().read |cache| {
|
||||||
match cache.paths.find(&id) {
|
match cache.paths.find(&id) {
|
||||||
// This is a documented path, link to it!
|
// This is a documented path, link to it!
|
||||||
Some(&(ref fqp, shortty)) => {
|
Some(&(ref fqp, shortty)) => {
|
||||||
let fqn = fqp.connect("::");
|
let fqn = fqp.connect("::");
|
||||||
let mut same = 0;
|
let same = loc.iter().zip(fqp.iter())
|
||||||
for (a, b) in loc.iter().zip(fqp.iter()) {
|
.take_while(|&(a, b)| *a == *b).len();
|
||||||
if *a == *b {
|
|
||||||
same += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut url = ~"";
|
let mut url = ~"";
|
||||||
for _ in range(same, loc.len()) {
|
if "super" == path.segments[0].name {
|
||||||
url.push_str("../");
|
url.push_str("../");
|
||||||
|
} else if "self" != path.segments[0].name {
|
||||||
|
url.push_str("../".repeat(loc.len() - same));
|
||||||
}
|
}
|
||||||
if same == fqp.len() {
|
if same < fqp.len() {
|
||||||
url.push_str(shortty);
|
|
||||||
url.push_str(".");
|
|
||||||
url.push_str(*fqp.last());
|
|
||||||
url.push_str(".html");
|
|
||||||
} else {
|
|
||||||
let remaining = fqp.slice_from(same);
|
let remaining = fqp.slice_from(same);
|
||||||
let to_link = remaining.slice_to(remaining.len() - 1);
|
let to_link = remaining.slice_to(remaining.len() - 1);
|
||||||
for component in to_link.iter() {
|
for component in to_link.iter() {
|
||||||
url.push_str(*component);
|
url.push_str(*component);
|
||||||
url.push_str("/");
|
url.push_str("/");
|
||||||
}
|
}
|
||||||
url.push_str(shortty);
|
|
||||||
url.push_str(".");
|
|
||||||
url.push_str(*remaining.last());
|
|
||||||
url.push_str(".html");
|
|
||||||
}
|
}
|
||||||
|
match shortty {
|
||||||
|
"mod" => {
|
||||||
|
url.push_str(*fqp.last());
|
||||||
|
url.push_str("/index.html");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
url.push_str(shortty);
|
||||||
|
url.push_str(".");
|
||||||
|
url.push_str(*fqp.last());
|
||||||
|
url.push_str(".html");
|
||||||
|
}
|
||||||
|
}
|
||||||
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
|
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
|
||||||
shortty, url, fqn, last.name, generics);
|
shortty, url, fqn, last.name, generics);
|
||||||
}
|
}
|
||||||
None => {
|
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);
|
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} => {
|
clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
|
||||||
resolved_path(f.buf, id, path);
|
resolved_path(f.buf, id, path, false);
|
||||||
match *typarams {
|
match *typarams {
|
||||||
Some(ref params) => {
|
Some(ref params) => {
|
||||||
f.buf.write("<".as_bytes());
|
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 };
|
} else { false };
|
||||||
match item.inner {
|
match item.inner {
|
||||||
clean::StructItem(*) | clean::EnumItem(*) |
|
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)));
|
self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -479,6 +481,8 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
match item.inner {
|
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(*) => {
|
clean::ModuleItem(*) => {
|
||||||
let name = item.name.get_ref().to_owned();
|
let name = item.name.get_ref().to_owned();
|
||||||
let item = Cell::new(item);
|
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() => {
|
_ if item.name.is_some() => {
|
||||||
let dst = self.dst.push(item_path(&item));
|
let dst = self.dst.push(item_path(&item));
|
||||||
let writer = dst.open_writer(io::CreateOrTruncate);
|
let writer = dst.open_writer(io::CreateOrTruncate);
|
||||||
render(writer.unwrap(), self, &item, true);
|
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, "
|
write!(w, "
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>{}: {} = </code>{}</td>
|
<td><code>{}static {}: {} = </code>{}</td>
|
||||||
<td class='docblock'>{} </td>
|
<td class='docblock'>{} </td>
|
||||||
</tr>
|
</tr>
|
||||||
",
|
",
|
||||||
|
VisSpace(myitem.visibility),
|
||||||
*myitem.name.get_ref(),
|
*myitem.name.get_ref(),
|
||||||
s.type_,
|
s.type_,
|
||||||
Initializer(s.expr),
|
Initializer(s.expr),
|
||||||
Markdown(blank(myitem.doc_value())));
|
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, "
|
write!(w, "
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class='{class}' href='{href}'
|
<td><a class='{class}' href='{href}'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue