提交 5c6f8a97 编写于 作者: A Alex Crichton

rustdoc: Linkify all reexports.

This way each component of a reexport path is click-able to the destination that
it's referencing.
上级 c838351b
......@@ -2499,6 +2499,26 @@ fn get_binding(this: @mut 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 @@ pub fn resolve_glob_import(@mut self,
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 @@ fn clean(&self) -> ViewItemInner {
#[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 @@ fn fmt(path: &clean::Path, f: &mut fmt::Formatter) {
}
}
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("/");
}
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>{}",
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 @@ fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
}
}
}
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("&lt;".as_bytes());
......@@ -366,3 +392,63 @@ fn fmt(p: &PuritySpace, f: &mut fmt::Formatter) {
}
}
}
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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
} 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 @@ fn render(w: io::file::FileWriter, cx: &mut Context, it: &clean::Item,
}
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 @@ fn render(w: io::file::FileWriter, cx: &mut Context, it: &clean::Item,
}
}
}
// 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 fmt(s: &Initializer<'self>, f: &mut fmt::Formatter) {
write!(w, "
<tr>
<td><code>{}: {} = </code>{}</td>
<td><code>{}static {}: {} = </code>{}</td>
<td class='docblock'>{}&nbsp;</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}'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册