auto merge of #14391 : alexcrichton/rust/more-rustdoc-inline, r=huonw
As part of the libstd facade (cc #13851), rustdoc is taught to inline documentation across crate boundaries through the usage of a `pub use` statement. This is done to allow libstd to maintain the facade that it is a standalone library with a defined public interface (allowing us to shuffle around what's underneath it). A preview is available at http://people.mozilla.org/~acrichton/doc/std/index.html
This commit is contained in:
commit
0fca6c6a02
14 changed files with 734 additions and 177 deletions
|
|
@ -41,6 +41,31 @@ pub fn recalibrate() {
|
|||
# }
|
||||
~~~
|
||||
|
||||
Documentation can also be controlled via the `doc` attribute on items. This is
|
||||
implicitly done by the compiler when using the above form of doc comments
|
||||
(converting the slash-based comments to `#[doc]` attributes).
|
||||
|
||||
~~~
|
||||
#[doc = "
|
||||
Calculates the factorial of a number.
|
||||
|
||||
Given the input integer `n`, this function will calculate `n!` and return it.
|
||||
"]
|
||||
pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n)} }
|
||||
# fn main() {}
|
||||
~~~
|
||||
|
||||
The `doc` attribute can also be used to control how rustdoc emits documentation
|
||||
in some cases.
|
||||
|
||||
```
|
||||
// Rustdoc will inline documentation of a `pub use` into this crate when the
|
||||
// `pub use` reaches across crates, but this behavior can also be disabled.
|
||||
#[doc(no_inline)]
|
||||
pub use std::option::Option;
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Doc comments are markdown, and are currently parsed with the
|
||||
[sundown][sundown] library. rustdoc does not yet do any fanciness such as
|
||||
referencing other items inline, like javadoc's `@see`. One exception to this
|
||||
|
|
|
|||
|
|
@ -206,6 +206,9 @@ pub static tag_crate_triple: uint = 0x66;
|
|||
|
||||
pub static tag_dylib_dependency_formats: uint = 0x67;
|
||||
|
||||
pub static tag_method_argument_names: uint = 0x8e;
|
||||
pub static tag_method_argument_name: uint = 0x8f;
|
||||
|
||||
#[deriving(Clone, Show)]
|
||||
pub struct LinkMeta {
|
||||
pub crateid: CrateId,
|
||||
|
|
|
|||
|
|
@ -306,3 +306,10 @@ pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum)
|
|||
let cdata = cstore.get_crate_data(cnum);
|
||||
decoder::get_missing_lang_items(&*cdata)
|
||||
}
|
||||
|
||||
pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId)
|
||||
-> Vec<String>
|
||||
{
|
||||
let cdata = cstore.get_crate_data(did.krate);
|
||||
decoder::get_method_arg_names(&*cdata, did.node)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1309,3 +1309,18 @@ pub fn get_missing_lang_items(cdata: Cmd)
|
|||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<String> {
|
||||
let mut ret = Vec::new();
|
||||
let method_doc = lookup_item(id, cdata.data());
|
||||
match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
|
||||
Some(args_doc) => {
|
||||
reader::tagged_docs(args_doc, tag_method_argument_name, |name_doc| {
|
||||
ret.push(name_doc.as_str_slice().to_strbuf());
|
||||
true
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -536,6 +536,7 @@ fn encode_reexports(ecx: &EncodeContext,
|
|||
fn encode_info_for_mod(ecx: &EncodeContext,
|
||||
ebml_w: &mut Encoder,
|
||||
md: &Mod,
|
||||
attrs: &[Attribute],
|
||||
id: NodeId,
|
||||
path: PathElems,
|
||||
name: Ident,
|
||||
|
|
@ -584,6 +585,7 @@ fn encode_info_for_mod(ecx: &EncodeContext,
|
|||
debug!("(encoding info for module) encoding reexports for {}", id);
|
||||
encode_reexports(ecx, ebml_w, id, path);
|
||||
}
|
||||
encode_attributes(ebml_w, attrs);
|
||||
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
|
@ -774,11 +776,30 @@ fn encode_info_for_method(ecx: &EncodeContext,
|
|||
} else {
|
||||
encode_symbol(ecx, ebml_w, m.def_id.node);
|
||||
}
|
||||
encode_method_argument_names(ebml_w, &*ast_method.decl);
|
||||
}
|
||||
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_method_argument_names(ebml_w: &mut Encoder,
|
||||
decl: &ast::FnDecl) {
|
||||
ebml_w.start_tag(tag_method_argument_names);
|
||||
for arg in decl.inputs.iter() {
|
||||
ebml_w.start_tag(tag_method_argument_name);
|
||||
match arg.pat.node {
|
||||
ast::PatIdent(_, ref name, _) => {
|
||||
let name = name.segments.last().unwrap().identifier;
|
||||
let name = token::get_ident(name);
|
||||
ebml_w.writer.write(name.get().as_bytes());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_inlined_item(ecx: &EncodeContext,
|
||||
ebml_w: &mut Encoder,
|
||||
ii: InlinedItemRef) {
|
||||
|
|
@ -895,7 +916,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_visibility(ebml_w, vis);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemFn(_, fn_style, _, ref generics, _) => {
|
||||
ItemFn(ref decl, fn_style, _, ref generics, _) => {
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
|
|
@ -911,6 +932,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_symbol(ecx, ebml_w, item.id);
|
||||
}
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_method_argument_names(ebml_w, &**decl);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemMod(ref m) => {
|
||||
|
|
@ -918,6 +940,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_info_for_mod(ecx,
|
||||
ebml_w,
|
||||
m,
|
||||
item.attrs.as_slice(),
|
||||
item.id,
|
||||
path,
|
||||
item.ident,
|
||||
|
|
@ -1317,6 +1340,7 @@ fn encode_info_for_items(ecx: &EncodeContext,
|
|||
encode_info_for_mod(ecx,
|
||||
ebml_w,
|
||||
&krate.module,
|
||||
&[],
|
||||
CRATE_NODE_ID,
|
||||
ast_map::Values([].iter()).chain(None),
|
||||
syntax::parse::token::special_idents::invalid,
|
||||
|
|
|
|||
278
src/librustdoc/clean/inline.rs
Normal file
278
src/librustdoc/clean/inline.rs
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Support for inlining external documentation into the current AST.
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
|
||||
use rustc::metadata::csearch;
|
||||
use rustc::metadata::decoder;
|
||||
use rustc::middle::ty;
|
||||
|
||||
use core;
|
||||
use doctree;
|
||||
use clean;
|
||||
|
||||
use super::Clean;
|
||||
|
||||
/// Attempt to inline the definition of a local node id into this AST.
|
||||
///
|
||||
/// This function will fetch the definition of the id specified, and if it is
|
||||
/// from another crate it will attempt to inline the documentation from the
|
||||
/// other crate into this crate.
|
||||
///
|
||||
/// This is primarily used for `pub use` statements which are, in general,
|
||||
/// implementation details. Inlining the documentation should help provide a
|
||||
/// better experience when reading the documentation in this use case.
|
||||
///
|
||||
/// The returned value is `None` if the `id` could not be inlined, and `Some`
|
||||
/// of a vector of items if it was successfully expanded.
|
||||
pub fn try_inline(id: ast::NodeId) -> Option<Vec<clean::Item>> {
|
||||
let cx = ::ctxtkey.get().unwrap();
|
||||
let tcx = match cx.maybe_typed {
|
||||
core::Typed(ref tycx) => tycx,
|
||||
core::NotTyped(_) => return None,
|
||||
};
|
||||
let def = match tcx.def_map.borrow().find(&id) {
|
||||
Some(def) => *def,
|
||||
None => return None,
|
||||
};
|
||||
let did = ast_util::def_id_of_def(def);
|
||||
if ast_util::is_local(did) { return None }
|
||||
try_inline_def(&**cx, tcx, def)
|
||||
}
|
||||
|
||||
fn try_inline_def(cx: &core::DocContext,
|
||||
tcx: &ty::ctxt,
|
||||
def: ast::Def) -> Option<Vec<clean::Item>> {
|
||||
let mut ret = Vec::new();
|
||||
let did = ast_util::def_id_of_def(def);
|
||||
let inner = match def {
|
||||
ast::DefTrait(did) => {
|
||||
record_extern_fqn(cx, did, clean::TypeTrait);
|
||||
clean::TraitItem(build_external_trait(tcx, did))
|
||||
}
|
||||
ast::DefFn(did, style) => {
|
||||
record_extern_fqn(cx, did, clean::TypeFunction);
|
||||
clean::FunctionItem(build_external_function(tcx, did, style))
|
||||
}
|
||||
ast::DefStruct(did) => {
|
||||
record_extern_fqn(cx, did, clean::TypeStruct);
|
||||
ret.extend(build_impls(tcx, did).move_iter());
|
||||
clean::StructItem(build_struct(tcx, did))
|
||||
}
|
||||
ast::DefTy(did) => {
|
||||
record_extern_fqn(cx, did, clean::TypeEnum);
|
||||
ret.extend(build_impls(tcx, did).move_iter());
|
||||
build_type(tcx, did)
|
||||
}
|
||||
// Assume that the enum type is reexported next to the variant, and
|
||||
// variants don't show up in documentation specially.
|
||||
ast::DefVariant(..) => return Some(Vec::new()),
|
||||
ast::DefMod(did) => {
|
||||
record_extern_fqn(cx, did, clean::TypeModule);
|
||||
clean::ModuleItem(build_module(cx, tcx, did))
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let fqn = csearch::get_item_path(tcx, did);
|
||||
ret.push(clean::Item {
|
||||
source: clean::Span::empty(),
|
||||
name: Some(fqn.last().unwrap().to_str().to_strbuf()),
|
||||
attrs: load_attrs(tcx, did),
|
||||
inner: inner,
|
||||
visibility: Some(ast::Public),
|
||||
def_id: did,
|
||||
});
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Attribute> {
|
||||
let mut attrs = Vec::new();
|
||||
csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
|
||||
attrs.extend(v.move_iter().map(|mut a| {
|
||||
// FIXME this isn't quite always true, it's just true about 99% of
|
||||
// the time when dealing with documentation. For example,
|
||||
// this would treat doc comments of the form `#[doc = "foo"]`
|
||||
// incorrectly.
|
||||
if a.name().get() == "doc" && a.value_str().is_some() {
|
||||
a.node.is_sugared_doc = true;
|
||||
}
|
||||
a.clean()
|
||||
}));
|
||||
});
|
||||
attrs
|
||||
}
|
||||
|
||||
/// Record an external fully qualified name in the external_paths cache.
|
||||
///
|
||||
/// These names are used later on by HTML rendering to generate things like
|
||||
/// source links back to the original item.
|
||||
pub fn record_extern_fqn(cx: &core::DocContext,
|
||||
did: ast::DefId,
|
||||
kind: clean::TypeKind) {
|
||||
match cx.maybe_typed {
|
||||
core::Typed(ref tcx) => {
|
||||
let fqn = csearch::get_item_path(tcx, did);
|
||||
let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
|
||||
cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
|
||||
}
|
||||
core::NotTyped(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
|
||||
let def = ty::lookup_trait_def(tcx, did);
|
||||
let methods = ty::trait_methods(tcx, did);
|
||||
clean::Trait {
|
||||
generics: def.generics.clean(),
|
||||
methods: methods.iter().map(|i| i.clean()).collect(),
|
||||
parents: Vec::new(), // FIXME: this is likely wrong
|
||||
}
|
||||
}
|
||||
|
||||
fn build_external_function(tcx: &ty::ctxt,
|
||||
did: ast::DefId,
|
||||
style: ast::FnStyle) -> clean::Function {
|
||||
let t = ty::lookup_item_type(tcx, did);
|
||||
clean::Function {
|
||||
decl: match ty::get(t.ty).sty {
|
||||
ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
|
||||
_ => fail!("bad function"),
|
||||
},
|
||||
generics: t.generics.clean(),
|
||||
fn_style: style,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct {
|
||||
use syntax::parse::token::special_idents::unnamed_field;
|
||||
|
||||
let t = ty::lookup_item_type(tcx, did);
|
||||
let fields = ty::lookup_struct_fields(tcx, did);
|
||||
|
||||
clean::Struct {
|
||||
struct_type: match fields.as_slice() {
|
||||
[] => doctree::Unit,
|
||||
[ref f] if f.name == unnamed_field.name => doctree::Newtype,
|
||||
[ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
|
||||
_ => doctree::Plain,
|
||||
},
|
||||
generics: t.generics.clean(),
|
||||
fields: fields.iter().map(|f| f.clean()).collect(),
|
||||
fields_stripped: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
|
||||
let t = ty::lookup_item_type(tcx, did);
|
||||
match ty::get(t.ty).sty {
|
||||
ty::ty_enum(edid, _) => {
|
||||
return clean::EnumItem(clean::Enum {
|
||||
generics: t.generics.clean(),
|
||||
variants_stripped: false,
|
||||
variants: ty::enum_variants(tcx, edid).clean(),
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
clean::TypedefItem(clean::Typedef {
|
||||
type_: t.ty.clean(),
|
||||
generics: t.generics.clean(),
|
||||
})
|
||||
}
|
||||
|
||||
fn build_impls(tcx: &ty::ctxt,
|
||||
did: ast::DefId) -> Vec<clean::Item> {
|
||||
ty::populate_implementations_for_type_if_necessary(tcx, did);
|
||||
let mut impls = Vec::new();
|
||||
|
||||
match tcx.inherent_impls.borrow().find(&did) {
|
||||
None => {}
|
||||
Some(i) => {
|
||||
impls.extend(i.borrow().iter().map(|&did| { build_impl(tcx, did) }));
|
||||
}
|
||||
}
|
||||
|
||||
impls
|
||||
}
|
||||
|
||||
fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> clean::Item {
|
||||
let associated_trait = csearch::get_impl_trait(tcx, did);
|
||||
let attrs = load_attrs(tcx, did);
|
||||
let ty = ty::lookup_item_type(tcx, did);
|
||||
let methods = csearch::get_impl_methods(&tcx.sess.cstore, did).iter().map(|did| {
|
||||
let mut item = match ty::method(tcx, *did).clean() {
|
||||
clean::Provided(item) => item,
|
||||
clean::Required(item) => item,
|
||||
};
|
||||
item.inner = match item.inner.clone() {
|
||||
clean::TyMethodItem(clean::TyMethod {
|
||||
fn_style, decl, self_, generics
|
||||
}) => {
|
||||
clean::MethodItem(clean::Method {
|
||||
fn_style: fn_style,
|
||||
decl: decl,
|
||||
self_: self_,
|
||||
generics: generics,
|
||||
})
|
||||
}
|
||||
_ => fail!("not a tymethod"),
|
||||
};
|
||||
item
|
||||
}).collect();
|
||||
clean::Item {
|
||||
inner: clean::ImplItem(clean::Impl {
|
||||
derived: clean::detect_derived(attrs.as_slice()),
|
||||
trait_: associated_trait.clean().map(|bound| {
|
||||
match bound {
|
||||
clean::TraitBound(ty) => ty,
|
||||
clean::RegionBound => unreachable!(),
|
||||
}
|
||||
}),
|
||||
for_: ty.ty.clean(),
|
||||
generics: ty.generics.clean(),
|
||||
methods: methods,
|
||||
}),
|
||||
source: clean::Span::empty(),
|
||||
name: None,
|
||||
attrs: attrs,
|
||||
visibility: Some(ast::Inherited),
|
||||
def_id: did,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
|
||||
did: ast::DefId) -> clean::Module {
|
||||
let mut items = Vec::new();
|
||||
|
||||
// FIXME: this doesn't handle reexports inside the module itself.
|
||||
// Should they be handled?
|
||||
csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| {
|
||||
match def {
|
||||
decoder::DlDef(def) => {
|
||||
match try_inline_def(cx, tcx, def) {
|
||||
Some(i) => items.extend(i.move_iter()),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
decoder::DlImpl(did) => items.push(build_impl(tcx, did)),
|
||||
decoder::DlField => fail!("unimplemented field"),
|
||||
}
|
||||
});
|
||||
|
||||
clean::Module {
|
||||
items: items,
|
||||
is_crate: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ use syntax;
|
|||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttributeMethods;
|
||||
use syntax::attr::{AttributeMethods, AttrMetaMethods};
|
||||
use syntax::codemap::Pos;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token;
|
||||
|
|
@ -27,7 +27,7 @@ use rustc::metadata::csearch;
|
|||
use rustc::metadata::decoder;
|
||||
use rustc::middle::ty;
|
||||
|
||||
use std::string::String;
|
||||
use std::rc::Rc;
|
||||
|
||||
use core;
|
||||
use doctree;
|
||||
|
|
@ -37,6 +37,8 @@ use visit_ast;
|
|||
/// Increment this when the `Crate` and related structures change.
|
||||
pub static SCHEMA_VERSION: &'static str = "0.8.2";
|
||||
|
||||
mod inline;
|
||||
|
||||
pub trait Clean<T> {
|
||||
fn clean(&self) -> T;
|
||||
}
|
||||
|
|
@ -53,6 +55,12 @@ impl<T: Clean<U>, U> Clean<U> for @T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
|
||||
fn clean(&self) -> U {
|
||||
(**self).clean()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
|
||||
fn clean(&self) -> Option<U> {
|
||||
match self {
|
||||
|
|
@ -250,7 +258,8 @@ impl Clean<Item> for doctree::Module {
|
|||
self.statics.clean().move_iter().collect(),
|
||||
self.traits.clean().move_iter().collect(),
|
||||
self.impls.clean().move_iter().collect(),
|
||||
self.view_items.clean().move_iter().collect(),
|
||||
self.view_items.clean().move_iter()
|
||||
.flat_map(|s| s.move_iter()).collect(),
|
||||
self.macros.clean().move_iter().collect()
|
||||
);
|
||||
|
||||
|
|
@ -336,6 +345,14 @@ impl attr::AttrMetaMethods for Attribute {
|
|||
None
|
||||
}
|
||||
}
|
||||
impl<'a> attr::AttrMetaMethods for &'a Attribute {
|
||||
fn name(&self) -> InternedString { (**self).name() }
|
||||
fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
|
||||
fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None }
|
||||
fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub struct TyParam {
|
||||
|
|
@ -473,7 +490,7 @@ impl Clean<Option<Vec<TyParamBound>>> for ty::substs {
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
#[deriving(Clone, Encodable, Decodable, Eq)]
|
||||
pub struct Lifetime(String);
|
||||
|
||||
impl Lifetime {
|
||||
|
|
@ -614,7 +631,7 @@ impl Clean<Item> for ast::TypeMethod {
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
#[deriving(Clone, Encodable, Decodable, Eq)]
|
||||
pub enum SelfTy {
|
||||
SelfStatic,
|
||||
SelfValue,
|
||||
|
|
@ -707,18 +724,32 @@ impl Clean<FnDecl> for ast::FnDecl {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<FnDecl> for ty::FnSig {
|
||||
impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
|
||||
fn clean(&self) -> FnDecl {
|
||||
let cx = super::ctxtkey.get().unwrap();
|
||||
let tcx = match cx.maybe_typed {
|
||||
core::Typed(ref tcx) => tcx,
|
||||
core::NotTyped(_) => unreachable!(),
|
||||
};
|
||||
let (did, sig) = *self;
|
||||
let mut names = if did.node != 0 {
|
||||
csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter()
|
||||
} else {
|
||||
Vec::new().move_iter()
|
||||
}.peekable();
|
||||
if names.peek().map(|s| s.as_slice()) == Some("self") {
|
||||
let _ = names.next();
|
||||
}
|
||||
FnDecl {
|
||||
output: self.output.clean(),
|
||||
output: sig.output.clean(),
|
||||
cf: Return,
|
||||
attrs: Vec::new(), // FIXME: this is likely wrong
|
||||
attrs: Vec::new(),
|
||||
inputs: Arguments {
|
||||
values: self.inputs.iter().map(|t| {
|
||||
values: sig.inputs.iter().map(|t| {
|
||||
Argument {
|
||||
type_: t.clean(),
|
||||
id: 0,
|
||||
name: "".to_strbuf(), // FIXME: where are the names?
|
||||
name: names.next().unwrap_or("".to_strbuf()),
|
||||
}
|
||||
}).collect(),
|
||||
},
|
||||
|
|
@ -830,12 +861,8 @@ impl Clean<TraitMethod> for ty::Method {
|
|||
let cx = super::ctxtkey.get().unwrap();
|
||||
let tcx = match cx.maybe_typed {
|
||||
core::Typed(ref tcx) => tcx,
|
||||
core::NotTyped(_) => fail!(),
|
||||
core::NotTyped(_) => unreachable!(),
|
||||
};
|
||||
let mut attrs = Vec::new();
|
||||
csearch::get_item_attrs(&tcx.sess.cstore, self.def_id, |v| {
|
||||
attrs.extend(v.move_iter().map(|i| i.clean()));
|
||||
});
|
||||
let (self_, sig) = match self.explicit_self {
|
||||
ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
|
||||
s => {
|
||||
|
|
@ -857,20 +884,18 @@ impl Clean<TraitMethod> for ty::Method {
|
|||
(s, sig)
|
||||
}
|
||||
};
|
||||
|
||||
m(Item {
|
||||
name: Some(self.ident.clean()),
|
||||
visibility: Some(ast::Inherited),
|
||||
def_id: self.def_id,
|
||||
attrs: attrs,
|
||||
source: Span {
|
||||
filename: "".to_strbuf(),
|
||||
loline: 0, locol: 0, hiline: 0, hicol: 0,
|
||||
},
|
||||
attrs: inline::load_attrs(tcx, self.def_id),
|
||||
source: Span::empty(),
|
||||
inner: TyMethodItem(TyMethod {
|
||||
fn_style: self.fty.fn_style,
|
||||
generics: self.generics.clean(),
|
||||
self_: self_,
|
||||
decl: sig.clean(),
|
||||
decl: (self.def_id, &sig).clean(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -987,13 +1012,13 @@ impl Clean<Type> for ty::t {
|
|||
generics: Generics {
|
||||
lifetimes: Vec::new(), type_params: Vec::new()
|
||||
},
|
||||
decl: fty.sig.clean(),
|
||||
decl: (ast_util::local_def(0), &fty.sig).clean(),
|
||||
abi: fty.abi.to_str().to_strbuf(),
|
||||
}),
|
||||
ty::ty_closure(ref fty) => {
|
||||
let decl = box ClosureDecl {
|
||||
lifetimes: Vec::new(), // FIXME: this looks wrong...
|
||||
decl: fty.sig.clean(),
|
||||
decl: (ast_util::local_def(0), &fty.sig).clean(),
|
||||
onceness: fty.onceness,
|
||||
fn_style: fty.fn_style,
|
||||
bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
|
||||
|
|
@ -1009,7 +1034,7 @@ impl Clean<Type> for ty::t {
|
|||
let cx = super::ctxtkey.get().unwrap();
|
||||
let tcx = match cx.maybe_typed {
|
||||
core::Typed(ref tycx) => tycx,
|
||||
core::NotTyped(_) => fail!(),
|
||||
core::NotTyped(_) => unreachable!(),
|
||||
};
|
||||
let fqn = csearch::get_item_path(tcx, did);
|
||||
let fqn: Vec<String> = fqn.move_iter().map(|i| {
|
||||
|
|
@ -1073,6 +1098,31 @@ impl Clean<Item> for ast::StructField {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for ty::field_ty {
|
||||
fn clean(&self) -> Item {
|
||||
use syntax::parse::token::special_idents::unnamed_field;
|
||||
let name = if self.name == unnamed_field.name {
|
||||
None
|
||||
} else {
|
||||
Some(self.name)
|
||||
};
|
||||
let cx = super::ctxtkey.get().unwrap();
|
||||
let tcx = match cx.maybe_typed {
|
||||
core::Typed(ref tycx) => tycx,
|
||||
core::NotTyped(_) => unreachable!(),
|
||||
};
|
||||
let ty = ty::lookup_item_type(tcx, self.id);
|
||||
Item {
|
||||
name: name.clean(),
|
||||
attrs: inline::load_attrs(tcx, self.id),
|
||||
source: Span::empty(),
|
||||
visibility: Some(self.vis),
|
||||
def_id: self.id,
|
||||
inner: StructFieldItem(TypedStructField(ty.ty.clean())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Visibility = ast::Visibility;
|
||||
|
||||
impl Clean<Option<Visibility>> for ast::Visibility {
|
||||
|
|
@ -1171,6 +1221,53 @@ impl Clean<Item> for doctree::Variant {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for ty::VariantInfo {
|
||||
fn clean(&self) -> Item {
|
||||
// use syntax::parse::token::special_idents::unnamed_field;
|
||||
let cx = super::ctxtkey.get().unwrap();
|
||||
let tcx = match cx.maybe_typed {
|
||||
core::Typed(ref tycx) => tycx,
|
||||
core::NotTyped(_) => fail!("tcx not present"),
|
||||
};
|
||||
let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
|
||||
None | Some([]) if self.args.len() == 0 => CLikeVariant,
|
||||
None | Some([]) => {
|
||||
TupleVariant(self.args.iter().map(|t| t.clean()).collect())
|
||||
}
|
||||
Some(s) => {
|
||||
StructVariant(VariantStruct {
|
||||
struct_type: doctree::Plain,
|
||||
fields_stripped: false,
|
||||
fields: s.iter().zip(self.args.iter()).map(|(name, ty)| {
|
||||
Item {
|
||||
source: Span::empty(),
|
||||
name: Some(name.clean()),
|
||||
attrs: Vec::new(),
|
||||
visibility: Some(ast::Public),
|
||||
// FIXME: this is not accurate, we need an id for
|
||||
// the specific field but we're using the id
|
||||
// for the whole variant. Nothing currently
|
||||
// uses this so we should be good for now.
|
||||
def_id: self.id,
|
||||
inner: StructFieldItem(
|
||||
TypedStructField(ty.clean())
|
||||
)
|
||||
}
|
||||
}).collect()
|
||||
})
|
||||
}
|
||||
};
|
||||
Item {
|
||||
name: Some(self.name.clean()),
|
||||
attrs: inline::load_attrs(tcx, self.id),
|
||||
source: Span::empty(),
|
||||
visibility: Some(ast::Public),
|
||||
def_id: self.id,
|
||||
inner: VariantItem(Variant { kind: kind }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub enum VariantKind {
|
||||
CLikeVariant,
|
||||
|
|
@ -1202,6 +1299,16 @@ pub struct Span {
|
|||
pub hicol: uint,
|
||||
}
|
||||
|
||||
impl Span {
|
||||
fn empty() -> Span {
|
||||
Span {
|
||||
filename: "".to_strbuf(),
|
||||
loline: 0, locol: 0,
|
||||
hiline: 0, hicol: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Span> for syntax::codemap::Span {
|
||||
fn clean(&self) -> Span {
|
||||
let ctxt = super::ctxtkey.get().unwrap();
|
||||
|
|
@ -1273,6 +1380,12 @@ impl Clean<String> for ast::Ident {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<String> for ast::Name {
|
||||
fn clean(&self) -> String {
|
||||
token::get_name(*self).get().to_strbuf()
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub struct Typedef {
|
||||
pub type_: Type,
|
||||
|
|
@ -1345,7 +1458,7 @@ impl Clean<Item> for doctree::Static {
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(Show, Clone, Encodable, Decodable)]
|
||||
#[deriving(Show, Clone, Encodable, Decodable, Eq)]
|
||||
pub enum Mutability {
|
||||
Mutable,
|
||||
Immutable,
|
||||
|
|
@ -1369,19 +1482,12 @@ pub struct Impl {
|
|||
pub derived: bool,
|
||||
}
|
||||
|
||||
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
|
||||
attr::contains_name(attrs, "automatically_derived")
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Impl {
|
||||
fn clean(&self) -> Item {
|
||||
let mut derived = false;
|
||||
for attr in self.attrs.iter() {
|
||||
match attr.node.value.node {
|
||||
ast::MetaWord(ref s) => {
|
||||
if s.get() == "automatically_derived" {
|
||||
derived = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
name: None,
|
||||
attrs: self.attrs.clean(),
|
||||
|
|
@ -1393,7 +1499,7 @@ impl Clean<Item> for doctree::Impl {
|
|||
trait_: self.trait_.clean(),
|
||||
for_: self.for_.clean(),
|
||||
methods: self.methods.clean(),
|
||||
derived: derived,
|
||||
derived: detect_derived(self.attrs.as_slice()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
@ -1404,18 +1510,63 @@ pub struct ViewItem {
|
|||
pub inner: ViewItemInner,
|
||||
}
|
||||
|
||||
impl Clean<Item> for ast::ViewItem {
|
||||
fn clean(&self) -> Item {
|
||||
Item {
|
||||
name: None,
|
||||
attrs: self.attrs.clean().move_iter().collect(),
|
||||
source: self.span.clean(),
|
||||
def_id: ast_util::local_def(0),
|
||||
visibility: self.vis.clean(),
|
||||
inner: ViewItemItem(ViewItem {
|
||||
inner: self.node.clean()
|
||||
}),
|
||||
impl Clean<Vec<Item>> for ast::ViewItem {
|
||||
fn clean(&self) -> Vec<Item> {
|
||||
// We consider inlining the documentation of `pub use` statments, but we
|
||||
// forcefully don't inline if this is not public or if the
|
||||
// #[doc(no_inline)] attribute is present.
|
||||
let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
|
||||
a.name().get() == "doc" && match a.meta_item_list() {
|
||||
Some(l) => attr::contains_name(l, "no_inline"),
|
||||
None => false,
|
||||
}
|
||||
});
|
||||
let convert = |node: &ast::ViewItem_| {
|
||||
Item {
|
||||
name: None,
|
||||
attrs: self.attrs.clean().move_iter().collect(),
|
||||
source: self.span.clean(),
|
||||
def_id: ast_util::local_def(0),
|
||||
visibility: self.vis.clean(),
|
||||
inner: ViewItemItem(ViewItem { inner: node.clean() }),
|
||||
}
|
||||
};
|
||||
let mut ret = Vec::new();
|
||||
match self.node {
|
||||
ast::ViewItemUse(ref path) if !denied => {
|
||||
match path.node {
|
||||
ast::ViewPathGlob(..) => ret.push(convert(&self.node)),
|
||||
ast::ViewPathList(ref a, ref list, ref b) => {
|
||||
// Attempt to inline all reexported items, but be sure
|
||||
// to keep any non-inlineable reexports so they can be
|
||||
// listed in the documentation.
|
||||
let remaining = list.iter().filter(|path| {
|
||||
match inline::try_inline(path.node.id) {
|
||||
Some(items) => {
|
||||
ret.extend(items.move_iter()); false
|
||||
}
|
||||
None => true,
|
||||
}
|
||||
}).map(|a| a.clone()).collect::<Vec<ast::PathListIdent>>();
|
||||
if remaining.len() > 0 {
|
||||
let path = ast::ViewPathList(a.clone(),
|
||||
remaining,
|
||||
b.clone());
|
||||
let path = syntax::codemap::dummy_spanned(path);
|
||||
ret.push(convert(&ast::ViewItemUse(@path)));
|
||||
}
|
||||
}
|
||||
ast::ViewPathSimple(_, _, id) => {
|
||||
match inline::try_inline(id) {
|
||||
Some(items) => ret.extend(items.move_iter()),
|
||||
None => ret.push(convert(&self.node)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ref n => ret.push(convert(n)),
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1630,13 +1781,10 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
|
|||
core::Typed(ref t) => t,
|
||||
core::NotTyped(_) => return did
|
||||
};
|
||||
let fqn = csearch::get_item_path(tcx, did);
|
||||
let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
|
||||
debug!("recording {} => {}", did, fqn);
|
||||
cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
|
||||
inline::record_extern_fqn(cx, did, kind);
|
||||
match kind {
|
||||
TypeTrait => {
|
||||
let t = build_external_trait(tcx, did);
|
||||
let t = inline::build_external_trait(tcx, did);
|
||||
cx.external_traits.borrow_mut().get_mut_ref().insert(did, t);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -1644,16 +1792,6 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
|
|||
return did;
|
||||
}
|
||||
|
||||
fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
|
||||
let def = csearch::get_trait_def(tcx, did);
|
||||
let methods = ty::trait_methods(tcx, did);
|
||||
Trait {
|
||||
generics: def.generics.clean(),
|
||||
methods: methods.iter().map(|i| i.clean()).collect(),
|
||||
parents: Vec::new(), // FIXME: this is likely wrong
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
|
||||
ImportSource {
|
||||
path: path,
|
||||
|
|
@ -99,7 +99,7 @@ impl fmt::Show for clean::TyParamBound {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
clean::RegionBound => {
|
||||
f.write("::".as_bytes())
|
||||
f.write("'static".as_bytes())
|
||||
}
|
||||
clean::TraitBound(ref ty) => {
|
||||
write!(f, "{}", *ty)
|
||||
|
|
@ -150,7 +150,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path,
|
|||
print_all: bool) -> fmt::Result {
|
||||
path(w, p, print_all,
|
||||
|cache, loc| {
|
||||
if ast_util::is_local(did) {
|
||||
if ast_util::is_local(did) || cache.paths.contains_key(&did) {
|
||||
Some(("../".repeat(loc.len())).to_strbuf())
|
||||
} else {
|
||||
match *cache.extern_locations.get(&did.krate) {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
|
|||
extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer,
|
||||
lang: *hoedown_buffer, opaque: *mut libc::c_void) {
|
||||
unsafe {
|
||||
if text.is_null() { return }
|
||||
|
||||
let opaque = opaque as *mut hoedown_html_renderer_state;
|
||||
let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque);
|
||||
slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ pub struct Cache {
|
|||
///
|
||||
/// The values of the map are a list of implementations and documentation
|
||||
/// found on that implementation.
|
||||
pub impls: HashMap<ast::NodeId, Vec<(clean::Impl, Option<String>)>>,
|
||||
pub impls: HashMap<ast::DefId, Vec<(clean::Impl, Option<String>)>>,
|
||||
|
||||
/// Maintains a mapping of local crate node ids to the fully qualified name
|
||||
/// and "short type description" of that node. This is used when generating
|
||||
|
|
@ -141,6 +141,10 @@ pub struct Cache {
|
|||
/// necessary.
|
||||
pub paths: HashMap<ast::DefId, (Vec<String>, ItemType)>,
|
||||
|
||||
/// Similar to `paths`, but only holds external paths. This is only used for
|
||||
/// generating explicit hyperlinks to other crates.
|
||||
pub external_paths: HashMap<ast::DefId, Vec<String>>,
|
||||
|
||||
/// This map contains information about all known traits of this crate.
|
||||
/// Implementations of a crate should inherit the documentation of the
|
||||
/// parent trait if no extra documentation is specified, and default methods
|
||||
|
|
@ -157,9 +161,9 @@ pub struct Cache {
|
|||
|
||||
// Private fields only used when initially crawling a crate to build a cache
|
||||
|
||||
stack: Vec<String> ,
|
||||
parent_stack: Vec<ast::NodeId> ,
|
||||
search_index: Vec<IndexItem> ,
|
||||
stack: Vec<String>,
|
||||
parent_stack: Vec<ast::DefId>,
|
||||
search_index: Vec<IndexItem>,
|
||||
privmod: bool,
|
||||
public_items: NodeSet,
|
||||
|
||||
|
|
@ -198,7 +202,7 @@ struct IndexItem {
|
|||
name: String,
|
||||
path: String,
|
||||
desc: String,
|
||||
parent: Option<ast::NodeId>,
|
||||
parent: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
// TLS keys used to carry information around during rendering.
|
||||
|
|
@ -249,7 +253,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
|
|||
let analysis = ::analysiskey.get();
|
||||
let public_items = analysis.as_ref().map(|a| a.public_items.clone());
|
||||
let public_items = public_items.unwrap_or(NodeSet::new());
|
||||
let paths = analysis.as_ref().map(|a| {
|
||||
let paths: HashMap<ast::DefId, (Vec<String>, ItemType)> =
|
||||
analysis.as_ref().map(|a| {
|
||||
let paths = a.external_paths.borrow_mut().take_unwrap();
|
||||
paths.move_iter().map(|(k, (v, t))| {
|
||||
(k, (v, match t {
|
||||
|
|
@ -265,6 +270,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
|
|||
}).unwrap_or(HashMap::new());
|
||||
let mut cache = Cache {
|
||||
impls: HashMap::new(),
|
||||
external_paths: paths.iter().map(|(&k, &(ref v, _))| (k, v.clone()))
|
||||
.collect(),
|
||||
paths: paths,
|
||||
implementors: HashMap::new(),
|
||||
stack: Vec::new(),
|
||||
|
|
@ -302,7 +309,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
|
|||
path: fqp.slice_to(fqp.len() - 1).connect("::")
|
||||
.to_strbuf(),
|
||||
desc: shorter(item.doc_value()).to_strbuf(),
|
||||
parent: Some(pid),
|
||||
parent: Some(did),
|
||||
});
|
||||
},
|
||||
None => {}
|
||||
|
|
@ -360,9 +367,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
|
|||
|
||||
try!(write!(&mut w, r#"],"paths":["#));
|
||||
|
||||
for (i, &nodeid) in pathid_to_nodeid.iter().enumerate() {
|
||||
let def = ast_util::local_def(nodeid);
|
||||
let &(ref fqp, short) = cache.paths.find(&def).unwrap();
|
||||
for (i, &did) in pathid_to_nodeid.iter().enumerate() {
|
||||
let &(ref fqp, short) = cache.paths.find(&did).unwrap();
|
||||
if i > 0 {
|
||||
try!(write!(&mut w, ","));
|
||||
}
|
||||
|
|
@ -497,13 +503,15 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
|
|||
seen: HashSet::new(),
|
||||
cx: &mut cx,
|
||||
};
|
||||
// skip all invalid spans
|
||||
folder.seen.insert("".to_strbuf());
|
||||
krate = folder.fold_crate(krate);
|
||||
}
|
||||
|
||||
for &(n, ref e) in krate.externs.iter() {
|
||||
cache.extern_locations.insert(n, extern_location(e, &cx.dst));
|
||||
let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID };
|
||||
cache.paths.insert(did, (Vec::new(), item_type::Module));
|
||||
cache.paths.insert(did, (vec![e.name.to_strbuf()], item_type::Module));
|
||||
}
|
||||
|
||||
// And finally render the whole crate's documentation
|
||||
|
|
@ -730,14 +738,13 @@ impl DocFolder for Cache {
|
|||
clean::VariantItem(..) => {
|
||||
(Some(*self.parent_stack.last().unwrap()),
|
||||
Some(self.stack.slice_to(self.stack.len() - 1)))
|
||||
|
||||
}
|
||||
clean::MethodItem(..) => {
|
||||
if self.parent_stack.len() == 0 {
|
||||
(None, None)
|
||||
} else {
|
||||
let last = self.parent_stack.last().unwrap();
|
||||
let did = ast_util::local_def(*last);
|
||||
let did = *last;
|
||||
let path = match self.paths.find(&did) {
|
||||
Some(&(_, item_type::Trait)) =>
|
||||
Some(self.stack.slice_to(self.stack.len() - 1)),
|
||||
|
|
@ -766,9 +773,11 @@ impl DocFolder for Cache {
|
|||
});
|
||||
}
|
||||
(Some(parent), None) if !self.privmod => {
|
||||
// We have a parent, but we don't know where they're
|
||||
// defined yet. Wait for later to index this item.
|
||||
self.orphan_methods.push((parent, item.clone()))
|
||||
if ast_util::is_local(parent) {
|
||||
// We have a parent, but we don't know where they're
|
||||
// defined yet. Wait for later to index this item.
|
||||
self.orphan_methods.push((parent.node, item.clone()))
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -789,19 +798,18 @@ impl DocFolder for Cache {
|
|||
clean::TypedefItem(..) | clean::TraitItem(..) |
|
||||
clean::FunctionItem(..) | clean::ModuleItem(..) |
|
||||
clean::ForeignFunctionItem(..) => {
|
||||
if ast_util::is_local(item.def_id) {
|
||||
// Reexported items mean that the same id can show up twice
|
||||
// in the rustdoc ast that we're looking at. We know,
|
||||
// however, that a reexported item doesn't show up in the
|
||||
// `public_items` map, so we can skip inserting into the
|
||||
// paths map if there was already an entry present and we're
|
||||
// not a public item.
|
||||
let id = item.def_id.node;
|
||||
if !self.paths.contains_key(&item.def_id) ||
|
||||
self.public_items.contains(&id) {
|
||||
self.paths.insert(item.def_id,
|
||||
(self.stack.clone(), shortty(&item)));
|
||||
}
|
||||
// Reexported items mean that the same id can show up twice
|
||||
// in the rustdoc ast that we're looking at. We know,
|
||||
// however, that a reexported item doesn't show up in the
|
||||
// `public_items` map, so we can skip inserting into the
|
||||
// paths map if there was already an entry present and we're
|
||||
// not a public item.
|
||||
let id = item.def_id.node;
|
||||
if !self.paths.contains_key(&item.def_id) ||
|
||||
!ast_util::is_local(item.def_id) ||
|
||||
self.public_items.contains(&id) {
|
||||
self.paths.insert(item.def_id,
|
||||
(self.stack.clone(), shortty(&item)));
|
||||
}
|
||||
}
|
||||
// link variants to their parent enum because pages aren't emitted
|
||||
|
|
@ -817,20 +825,14 @@ impl DocFolder for Cache {
|
|||
// Maintain the parent stack
|
||||
let parent_pushed = match item.inner {
|
||||
clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
|
||||
if ast_util::is_local(item.def_id) {
|
||||
self.parent_stack.push(item.def_id.node);
|
||||
}
|
||||
self.parent_stack.push(item.def_id);
|
||||
true
|
||||
}
|
||||
clean::ImplItem(ref i) => {
|
||||
match i.for_ {
|
||||
clean::ResolvedPath{ did, .. } => {
|
||||
if ast_util::is_local(did) {
|
||||
self.parent_stack.push(did.node);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.parent_stack.push(did);
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
|
|
@ -845,10 +847,8 @@ impl DocFolder for Cache {
|
|||
match item {
|
||||
clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
|
||||
match i.for_ {
|
||||
clean::ResolvedPath { did, .. }
|
||||
if ast_util::is_local(did) =>
|
||||
{
|
||||
let v = self.impls.find_or_insert_with(did.node, |_| {
|
||||
clean::ResolvedPath { did, .. } => {
|
||||
let v = self.impls.find_or_insert_with(did, |_| {
|
||||
Vec::new()
|
||||
});
|
||||
// extract relevant documentation for this impl
|
||||
|
|
@ -1041,23 +1041,62 @@ impl<'a> Item<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn link(&self) -> String {
|
||||
let mut path = Vec::new();
|
||||
clean_srcpath(self.item.source.filename.as_bytes(), |component| {
|
||||
path.push(component.to_owned());
|
||||
});
|
||||
let href = if self.item.source.loline == self.item.source.hiline {
|
||||
format_strbuf!("{}", self.item.source.loline)
|
||||
/// Generate a url appropriate for an `href` attribute back to the source of
|
||||
/// this item.
|
||||
///
|
||||
/// The url generated, when clicked, will redirect the browser back to the
|
||||
/// original source code.
|
||||
///
|
||||
/// If `None` is returned, then a source link couldn't be generated. This
|
||||
/// may happen, for example, with externally inlined items where the source
|
||||
/// of their crate documentation isn't known.
|
||||
fn href(&self) -> Option<String> {
|
||||
// If this item is part of the local crate, then we're guaranteed to
|
||||
// know the span, so we plow forward and generate a proper url. The url
|
||||
// has anchors for the line numbers that we're linking to.
|
||||
if ast_util::is_local(self.item.def_id) {
|
||||
let mut path = Vec::new();
|
||||
clean_srcpath(self.item.source.filename.as_bytes(), |component| {
|
||||
path.push(component.to_owned());
|
||||
});
|
||||
let href = if self.item.source.loline == self.item.source.hiline {
|
||||
format!("{}", self.item.source.loline)
|
||||
} else {
|
||||
format!("{}-{}",
|
||||
self.item.source.loline,
|
||||
self.item.source.hiline)
|
||||
};
|
||||
Some(format!("{root}src/{krate}/{path}.html\\#{href}",
|
||||
root = self.cx.root_path,
|
||||
krate = self.cx.layout.krate,
|
||||
path = path.connect("/"),
|
||||
href = href))
|
||||
|
||||
// If this item is not part of the local crate, then things get a little
|
||||
// trickier. We don't actually know the span of the external item, but
|
||||
// we know that the documentation on the other end knows the span!
|
||||
//
|
||||
// In this case, we generate a link to the *documentation* for this type
|
||||
// in the original crate. There's an extra URL parameter which says that
|
||||
// we want to go somewhere else, and the JS on the destination page will
|
||||
// pick it up and instantly redirect the browser to the source code.
|
||||
//
|
||||
// If we don't know where the external documentation for this crate is
|
||||
// located, then we return `None`.
|
||||
} else {
|
||||
format_strbuf!("{}-{}",
|
||||
self.item.source.loline,
|
||||
self.item.source.hiline)
|
||||
};
|
||||
format_strbuf!("{root}src/{krate}/{path}.html\\#{href}",
|
||||
root = self.cx.root_path,
|
||||
krate = self.cx.layout.krate,
|
||||
path = path.connect("/"),
|
||||
href = href)
|
||||
let cache = cache_key.get().unwrap();
|
||||
let path = cache.external_paths.get(&self.item.def_id);
|
||||
let root = match *cache.extern_locations.get(&self.item.def_id.krate) {
|
||||
Remote(ref s) => s.to_strbuf(),
|
||||
Local => format!("{}/..", self.cx.root_path),
|
||||
Unknown => return None,
|
||||
};
|
||||
Some(format!("{root}/{path}/{file}?gotosrc={goto}",
|
||||
root = root,
|
||||
path = path.slice_to(path.len() - 1).connect("/"),
|
||||
file = item_path(self.item),
|
||||
goto = self.item.def_id.node))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1105,9 +1144,21 @@ impl<'a> fmt::Show for Item<'a> {
|
|||
}
|
||||
|
||||
// Write `src` tag
|
||||
//
|
||||
// When this item is part of a `pub use` in a downstream crate, the
|
||||
// [src] link in the downstream documentation will actually come back to
|
||||
// this page, and this link will be auto-clicked. The `id` attribute is
|
||||
// used to find the link to auto-click.
|
||||
if self.cx.include_sources {
|
||||
try!(write!(fmt, "<a class='source' href='{}'>[src]</a>",
|
||||
self.link()));
|
||||
match self.href() {
|
||||
Some(l) => {
|
||||
try!(write!(fmt,
|
||||
"<a class='source' id='src-{}' \
|
||||
href='{}'>[src]</a>",
|
||||
self.item.def_id.node, l));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
try!(write!(fmt, "</h1>\n"));
|
||||
|
||||
|
|
@ -1266,7 +1317,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
|
|||
try!(write!(f, "<code> = </code>"));
|
||||
if s.contains("\n") {
|
||||
write!(f, "<a href='{}'>[definition]</a>",
|
||||
item.link())
|
||||
item.href())
|
||||
} else {
|
||||
write!(f, "<code>{}</code>", s.as_slice())
|
||||
}
|
||||
|
|
@ -1672,7 +1723,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
|
|||
}
|
||||
|
||||
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
|
||||
match cache_key.get().unwrap().impls.find(&it.def_id.node) {
|
||||
match cache_key.get().unwrap().impls.find(&it.def_id) {
|
||||
Some(v) => {
|
||||
let mut non_trait = v.iter().filter(|p| {
|
||||
p.ref0().trait_.is_none()
|
||||
|
|
|
|||
|
|
@ -675,4 +675,10 @@
|
|||
if (window.pending_implementors) {
|
||||
window.register_implementors(window.pending_implementors);
|
||||
}
|
||||
|
||||
// See documentaiton in html/render.rs for what this is doing.
|
||||
var query = getQueryStringParams();
|
||||
if (query['gotosrc']) {
|
||||
window.location = $('#src-' + query['gotosrc']).attr('href');
|
||||
}
|
||||
}());
|
||||
|
|
|
|||
|
|
@ -152,7 +152,8 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
|||
clean::ImplItem(clean::Impl{
|
||||
for_: clean::ResolvedPath{ did, .. }, ..
|
||||
}) => {
|
||||
if !self.exported_items.contains(&did.node) {
|
||||
if ast_util::is_local(did) &&
|
||||
!self.exported_items.contains(&did.node) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@
|
|||
//!
|
||||
//! ## Intrinsic types and operations
|
||||
//!
|
||||
//! The [`ptr`](../core/ptr/index.html) and [`mem`](../core/mem/index.html)
|
||||
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
|
||||
//! modules deal with unsafe pointers and memory manipulation.
|
||||
//! [`kinds`](../core/kinds/index.html) defines the special built-in traits,
|
||||
//! and [`raw`](../core/raw/index.html) the runtime representation of Rust types.
|
||||
//! [`kinds`](kinds/index.html) defines the special built-in traits,
|
||||
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
|
||||
//! These are some of the lowest-level building blocks in Rust.
|
||||
//!
|
||||
//! ## Math on primitive types and math traits
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
//!
|
||||
//! ## Pervasive types
|
||||
//!
|
||||
//! The [`option`](option/index.html) and [`result`](../core/result/index.html)
|
||||
//! The [`option`](option/index.html) and [`result`](result/index.html)
|
||||
//! modules define optional and error-handling types, `Option` and `Result`.
|
||||
//! [`iter`](../core/iter/index.html) defines Rust's iterator protocol
|
||||
//! [`iter`](iter/index.html) defines Rust's iterator protocol
|
||||
//! along with a wide variety of iterators.
|
||||
//! [`Cell` and `RefCell`](../core/cell/index.html) are for creating types that
|
||||
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
|
||||
//! manage their own mutability.
|
||||
//!
|
||||
//! ## Vectors, slices and strings
|
||||
|
|
|
|||
|
|
@ -38,55 +38,62 @@
|
|||
//! `drop`, `spawn`, and `channel`.
|
||||
|
||||
// Reexported core operators
|
||||
pub use kinds::{Copy, Send, Sized, Share};
|
||||
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
|
||||
pub use ops::{BitAnd, BitOr, BitXor};
|
||||
pub use ops::{Drop, Deref, DerefMut};
|
||||
pub use ops::{Shl, Shr, Index};
|
||||
pub use option::{Option, Some, None};
|
||||
pub use result::{Result, Ok, Err};
|
||||
#[doc(no_inline)] pub use kinds::{Copy, Send, Sized, Share};
|
||||
#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
|
||||
#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor};
|
||||
#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut};
|
||||
#[doc(no_inline)] pub use ops::{Shl, Shr, Index};
|
||||
#[doc(no_inline)] pub use option::{Option, Some, None};
|
||||
#[doc(no_inline)] pub use result::{Result, Ok, Err};
|
||||
|
||||
// Reexported functions
|
||||
pub use from_str::from_str;
|
||||
pub use iter::range;
|
||||
pub use mem::drop;
|
||||
#[doc(no_inline)] pub use from_str::from_str;
|
||||
#[doc(no_inline)] pub use iter::range;
|
||||
#[doc(no_inline)] pub use mem::drop;
|
||||
|
||||
// Reexported types and traits
|
||||
|
||||
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, IntoBytes};
|
||||
pub use c_str::ToCStr;
|
||||
pub use char::Char;
|
||||
pub use clone::Clone;
|
||||
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
|
||||
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
|
||||
pub use iter::{FromIterator, Extendable};
|
||||
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
|
||||
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
|
||||
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
|
||||
pub use num::{Signed, Unsigned};
|
||||
pub use num::{Primitive, Int, Float, FloatMath, ToPrimitive, FromPrimitive};
|
||||
pub use option::Expect;
|
||||
pub use owned::Box;
|
||||
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
|
||||
pub use ptr::RawPtr;
|
||||
pub use io::{Buffer, Writer, Reader, Seek};
|
||||
pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned};
|
||||
pub use str::{StrAllocating};
|
||||
pub use to_str::{ToStr, IntoStr};
|
||||
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
|
||||
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
|
||||
pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
|
||||
pub use slice::{CloneableVector, ImmutableCloneableVector, MutableCloneableVector};
|
||||
pub use slice::{ImmutableVector, MutableVector};
|
||||
pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector, MutableTotalOrdVector};
|
||||
pub use slice::{Vector, VectorVector, OwnedVector, MutableVectorAllocating};
|
||||
pub use string::String;
|
||||
pub use vec::Vec;
|
||||
#[doc(no_inline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
|
||||
#[doc(no_inline)] pub use ascii::IntoBytes;
|
||||
#[doc(no_inline)] pub use c_str::ToCStr;
|
||||
#[doc(no_inline)] pub use char::Char;
|
||||
#[doc(no_inline)] pub use clone::Clone;
|
||||
#[doc(no_inline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd};
|
||||
#[doc(no_inline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv};
|
||||
#[doc(no_inline)] pub use container::{Container, Mutable, Map, MutableMap};
|
||||
#[doc(no_inline)] pub use container::{Set, MutableSet};
|
||||
#[doc(no_inline)] pub use iter::{FromIterator, Extendable, ExactSize};
|
||||
#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator};
|
||||
#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator};
|
||||
#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator};
|
||||
#[doc(no_inline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
|
||||
#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
|
||||
#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
|
||||
#[doc(no_inline)] pub use option::Expect;
|
||||
#[doc(no_inline)] pub use owned::Box;
|
||||
#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath};
|
||||
#[doc(no_inline)] pub use ptr::RawPtr;
|
||||
#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek};
|
||||
#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr};
|
||||
#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating};
|
||||
#[doc(no_inline)] pub use to_str::{ToStr, IntoStr};
|
||||
#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
|
||||
#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
|
||||
#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
|
||||
#[doc(no_inline)] pub use slice::{CloneableVector, ImmutableCloneableVector};
|
||||
#[doc(no_inline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector};
|
||||
#[doc(no_inline)] pub use slice::{ImmutableVector, MutableVector};
|
||||
#[doc(no_inline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector};
|
||||
#[doc(no_inline)] pub use slice::{Vector, VectorVector, OwnedVector};
|
||||
#[doc(no_inline)] pub use slice::MutableVectorAllocating;
|
||||
#[doc(no_inline)] pub use string::String;
|
||||
#[doc(no_inline)] pub use vec::Vec;
|
||||
|
||||
// Reexported runtime types
|
||||
pub use comm::{sync_channel, channel, SyncSender, Sender, Receiver};
|
||||
pub use task::spawn;
|
||||
#[doc(no_inline)] pub use comm::{sync_channel, channel};
|
||||
#[doc(no_inline)] pub use comm::{SyncSender, Sender, Receiver};
|
||||
#[doc(no_inline)] pub use task::spawn;
|
||||
|
||||
// Reexported statics
|
||||
#[cfg(not(test))]
|
||||
pub use gc::GC;
|
||||
#[doc(no_inline)] pub use gc::GC;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue