1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Rustdoc's HTML Rendering module
13 //! This modules contains the bulk of the logic necessary for rendering a
14 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
15 //! rendering process is largely driven by the `format!` syntax extension to
16 //! perform all I/O into files and streams.
18 //! The rendering process is largely driven by the `Context` and `Cache`
19 //! structures. The cache is pre-populated by crawling the crate in question,
20 //! and then it is shared among the various rendering tasks. The cache is meant
21 //! to be a fairly large structure not implementing `Clone` (because it's shared
22 //! among tasks). The context, however, should be a lightweight structure. This
23 //! is cloned per-task and contains information about what is currently being
26 //! In order to speed up rendering (mostly because of markdown rendering), the
27 //! rendering process has been parallelized. This parallelization is only
28 //! exposed through the `crate` method on the context, and then also from the
29 //! fact that the shared cache is stored in TLS (and must be accessed as such).
31 //! In addition to rendering the crate itself, this module is also responsible
32 //! for creating the corresponding search index and source file renderings.
33 //! These tasks are not parallelized (they haven't been a bottleneck yet), and
34 //! both occur before the crate is rendered.
35 pub use self::ExternalLocation::*;
37 use std::cell::RefCell;
38 use std::cmp::Ordering;
39 use std::collections::{HashMap, HashSet};
40 use std::default::Default;
42 use std::old_io::fs::PathExtensions;
43 use std::old_io::{fs, File, BufferedWriter, BufferedReader};
45 use std::iter::repeat;
49 use externalfiles::ExternalHtml;
52 use serialize::json::ToJson;
55 use rustc::util::nodemap::NodeSet;
60 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability};
61 use html::format::{ConciseStability, TyParamBounds, WhereClause};
63 use html::item_type::ItemType;
65 use html::markdown::Markdown;
67 use html::escape::Escape;
68 use stability_summary;
70 /// A pair of name and its optional document.
71 #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
72 pub struct NameDoc(String, Option<String>);
74 /// Major driving force in all rustdoc rendering. This contains information
75 /// about where in the tree-like hierarchy rendering is occurring and controls
76 /// how the current page is being rendered.
78 /// It is intended that this context is a lightweight object which can be fairly
79 /// easily cloned because it is cloned per work-job (about once per item in the
83 /// Current hierarchy of components leading down to what's currently being
85 pub current: Vec<String>,
86 /// String representation of how to get back to the root path of the 'doc/'
87 /// folder in terms of a relative URL.
88 pub root_path: String,
89 /// The path to the crate root source minus the file name.
90 /// Used for simplifying paths to the highlighted source code files.
92 /// The current destination folder of where HTML artifacts should be placed.
93 /// This changes as the context descends into the module hierarchy.
95 /// This describes the layout of each page, and is not modified after
96 /// creation of the context (contains info like the favicon and added html).
97 pub layout: layout::Layout,
98 /// This map is a list of what should be displayed on the sidebar of the
99 /// current page. The key is the section header (traits, modules,
100 /// functions), and the value is the list of containers belonging to this
101 /// header. This map will change depending on the surrounding context of the
103 pub sidebar: HashMap<String, Vec<NameDoc>>,
104 /// This flag indicates whether [src] links should be generated or not. If
105 /// the source files are present in the html rendering, then this will be
107 pub include_sources: bool,
108 /// A flag, which when turned off, will render pages which redirect to the
109 /// real location of an item. This is used to allow external links to
110 /// publicly reused items to redirect to the right location.
111 pub render_redirect_pages: bool,
112 /// All the passes that were run on this crate.
113 pub passes: HashSet<String>,
116 /// Indicates where an external crate can be found.
117 pub enum ExternalLocation {
118 /// Remote URL root of the external crate
120 /// This external crate can be found in the local doc/ folder
122 /// The external crate could not be found.
126 /// Metadata about an implementor of a trait.
127 pub struct Implementor {
128 pub def_id: ast::DefId,
129 pub generics: clean::Generics,
130 pub trait_: clean::Type,
131 pub for_: clean::Type,
132 pub stability: Option<clean::Stability>,
135 /// Metadata about implementations for a type.
138 pub impl_: clean::Impl,
139 pub dox: Option<String>,
140 pub stability: Option<clean::Stability>,
143 /// This cache is used to store information about the `clean::Crate` being
144 /// rendered in order to provide more useful documentation. This contains
145 /// information like all implementors of a trait, all traits a type implements,
146 /// documentation for all known traits, etc.
148 /// This structure purposefully does not implement `Clone` because it's intended
149 /// to be a fairly large and expensive structure to clone. Instead this adheres
150 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
154 /// Mapping of typaram ids to the name of the type parameter. This is used
155 /// when pretty-printing a type (so pretty printing doesn't have to
156 /// painfully maintain a context like this)
157 pub typarams: HashMap<ast::DefId, String>,
159 /// Maps a type id to all known implementations for that type. This is only
160 /// recognized for intra-crate `ResolvedPath` types, and is used to print
161 /// out extra documentation on the page of an enum/struct.
163 /// The values of the map are a list of implementations and documentation
164 /// found on that implementation.
165 pub impls: HashMap<ast::DefId, Vec<Impl>>,
167 /// Maintains a mapping of local crate node ids to the fully qualified name
168 /// and "short type description" of that node. This is used when generating
169 /// URLs when a type is being linked to. External paths are not located in
170 /// this map because the `External` type itself has all the information
172 pub paths: HashMap<ast::DefId, (Vec<String>, ItemType)>,
174 /// Similar to `paths`, but only holds external paths. This is only used for
175 /// generating explicit hyperlinks to other crates.
176 pub external_paths: HashMap<ast::DefId, Vec<String>>,
178 /// This map contains information about all known traits of this crate.
179 /// Implementations of a crate should inherit the documentation of the
180 /// parent trait if no extra documentation is specified, and default methods
181 /// should show up in documentation about trait implementations.
182 pub traits: HashMap<ast::DefId, clean::Trait>,
184 /// When rendering traits, it's often useful to be able to list all
185 /// implementors of the trait, and this mapping is exactly, that: a mapping
186 /// of trait ids to the list of known implementors of the trait
187 pub implementors: HashMap<ast::DefId, Vec<Implementor>>,
189 /// Cache of where external crate documentation can be found.
190 pub extern_locations: HashMap<ast::CrateNum, ExternalLocation>,
192 /// Cache of where documentation for primitives can be found.
193 pub primitive_locations: HashMap<clean::PrimitiveType, ast::CrateNum>,
195 /// Set of definitions which have been inlined from external crates.
196 pub inlined: HashSet<ast::DefId>,
198 // Private fields only used when initially crawling a crate to build a cache
201 parent_stack: Vec<ast::DefId>,
202 search_index: Vec<IndexItem>,
205 public_items: NodeSet,
207 // In rare case where a structure is defined in one module but implemented
208 // in another, if the implementing module is parsed before defining module,
209 // then the fully qualified name of the structure isn't presented in `paths`
210 // yet when its implementation methods are being indexed. Caches such methods
211 // and their parent id here and indexes them at the end of crate parsing.
212 orphan_methods: Vec<(ast::NodeId, clean::Item)>,
215 /// Helper struct to render all source code to HTML pages
216 struct SourceCollector<'a> {
219 /// Processed source-file paths
220 seen: HashSet<String>,
221 /// Root destination to place all HTML output into
225 /// Wrapper struct to render the source code of a file. This will do things like
226 /// adding line numbers to the left-hand side.
227 struct Source<'a>(&'a str);
229 // Helper structs for rendering items/sidebars and carrying along contextual
235 item: &'a clean::Item,
238 struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
240 /// Struct representing one entry in the JS search index. These are all emitted
241 /// by hand to a large JS file at the end of cache-creation.
247 parent: Option<ast::DefId>,
250 // TLS keys used to carry information around during rendering.
252 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
253 thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> =
254 RefCell::new(Vec::new()));
256 /// Generates the documentation for `crate` into the directory `dst`
257 pub fn run(mut krate: clean::Crate,
258 external_html: &ExternalHtml,
260 passes: HashSet<String>) -> old_io::IoResult<()> {
261 let mut cx = Context {
263 src_root: krate.src.dir_path(),
266 root_path: String::new(),
267 sidebar: HashMap::new(),
268 layout: layout::Layout {
269 logo: "".to_string(),
270 favicon: "".to_string(),
271 external_html: external_html.clone(),
272 krate: krate.name.clone(),
273 playground_url: "".to_string(),
275 include_sources: true,
276 render_redirect_pages: false,
279 try!(mkdir(&cx.dst));
281 // Crawl the crate attributes looking for attributes which control how we're
282 // going to emit HTML
283 let default: &[_] = &[];
284 match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) {
288 clean::NameValue(ref x, ref s)
289 if "html_favicon_url" == *x => {
290 cx.layout.favicon = s.to_string();
292 clean::NameValue(ref x, ref s)
293 if "html_logo_url" == *x => {
294 cx.layout.logo = s.to_string();
296 clean::NameValue(ref x, ref s)
297 if "html_playground_url" == *x => {
298 cx.layout.playground_url = s.to_string();
299 markdown::PLAYGROUND_KRATE.with(|slot| {
300 if slot.borrow().is_none() {
301 let name = krate.name.clone();
302 *slot.borrow_mut() = Some(Some(name));
307 if "html_no_source" == *x => {
308 cx.include_sources = false;
317 // Crawl the crate to build various caches used for the output
318 let analysis = ::ANALYSISKEY.with(|a| a.clone());
319 let analysis = analysis.borrow();
320 let public_items = analysis.as_ref().map(|a| a.public_items.clone());
321 let public_items = public_items.unwrap_or(NodeSet());
322 let paths: HashMap<ast::DefId, (Vec<String>, ItemType)> =
323 analysis.as_ref().map(|a| {
324 let paths = a.external_paths.borrow_mut().take().unwrap();
325 paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))).collect()
326 }).unwrap_or(HashMap::new());
327 let mut cache = Cache {
328 impls: HashMap::new(),
329 external_paths: paths.iter().map(|(&k, v)| (k, v.0.clone()))
332 implementors: HashMap::new(),
334 parent_stack: Vec::new(),
335 search_index: Vec::new(),
336 extern_locations: HashMap::new(),
337 primitive_locations: HashMap::new(),
338 remove_priv: cx.passes.contains("strip-private"),
340 public_items: public_items,
341 orphan_methods: Vec::new(),
342 traits: analysis.as_ref().map(|a| {
343 a.external_traits.borrow_mut().take().unwrap()
344 }).unwrap_or(HashMap::new()),
345 typarams: analysis.as_ref().map(|a| {
346 a.external_typarams.borrow_mut().take().unwrap()
347 }).unwrap_or(HashMap::new()),
348 inlined: analysis.as_ref().map(|a| {
349 a.inlined.borrow_mut().take().unwrap()
350 }).unwrap_or(HashSet::new()),
352 cache.stack.push(krate.name.clone());
353 krate = cache.fold_crate(krate);
355 // Cache where all our extern crates are located
356 for &(n, ref e) in &krate.externs {
357 cache.extern_locations.insert(n, extern_location(e, &cx.dst));
358 let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID };
359 cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
362 // Cache where all known primitives have their documentation located.
364 // Favor linking to as local extern as possible, so iterate all crates in
365 // reverse topological order.
366 for &(n, ref e) in krate.externs.iter().rev() {
367 for &prim in &e.primitives {
368 cache.primitive_locations.insert(prim, n);
371 for &prim in &krate.primitives {
372 cache.primitive_locations.insert(prim, ast::LOCAL_CRATE);
375 // Build our search index
376 let index = try!(build_index(&krate, &mut cache));
378 // Freeze the cache now that the index has been built. Put an Arc into TLS
379 // for future parallelization opportunities
380 let cache = Arc::new(cache);
381 CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
382 CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
384 try!(write_shared(&cx, &krate, &*cache, index));
385 let krate = try!(render_sources(&mut cx, krate));
387 // Crawl the crate, building a summary of the stability levels.
388 let summary = stability_summary::build(&krate);
390 // And finally render the whole crate's documentation
391 cx.krate(krate, summary)
394 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> old_io::IoResult<String> {
395 // Build the search index from the collected metadata
396 let mut nodeid_to_pathid = HashMap::new();
397 let mut pathid_to_nodeid = Vec::new();
399 let Cache { ref mut search_index,
401 ref mut paths, .. } = *cache;
403 // Attach all orphan methods to the type's definition if the type
404 // has since been learned.
405 for &(pid, ref item) in orphan_methods {
406 let did = ast_util::local_def(pid);
407 match paths.get(&did) {
408 Some(&(ref fqp, _)) => {
409 search_index.push(IndexItem {
411 name: item.name.clone().unwrap(),
412 path: fqp[..fqp.len() - 1].connect("::"),
413 desc: shorter(item.doc_value()).to_string(),
421 // Reduce `NodeId` in paths into smaller sequential numbers,
422 // and prune the paths that do not appear in the index.
423 for item in &*search_index {
426 if !nodeid_to_pathid.contains_key(&nodeid) {
427 let pathid = pathid_to_nodeid.len();
428 nodeid_to_pathid.insert(nodeid, pathid);
429 pathid_to_nodeid.push(nodeid);
435 assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len());
438 // Collect the index into a string
439 let mut w = Vec::new();
440 try!(write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name));
442 let mut lastpath = "".to_string();
443 for (i, item) in cache.search_index.iter().enumerate() {
444 // Omit the path if it is same to that of the prior item.
446 if lastpath == item.path {
449 lastpath = item.path.to_string();
454 try!(write!(&mut w, ","));
456 try!(write!(&mut w, r#"[{},"{}","{}",{}"#,
457 item.ty as uint, item.name, path,
458 item.desc.to_json().to_string()));
461 let pathid = *nodeid_to_pathid.get(&nodeid).unwrap();
462 try!(write!(&mut w, ",{}", pathid));
466 try!(write!(&mut w, "]"));
469 try!(write!(&mut w, r#"],"paths":["#));
471 for (i, &did) in pathid_to_nodeid.iter().enumerate() {
472 let &(ref fqp, short) = cache.paths.get(&did).unwrap();
474 try!(write!(&mut w, ","));
476 try!(write!(&mut w, r#"[{},"{}"]"#,
477 short as uint, *fqp.last().unwrap()));
480 try!(write!(&mut w, "]}};"));
482 Ok(String::from_utf8(w).unwrap())
485 fn write_shared(cx: &Context,
486 krate: &clean::Crate,
488 search_index: String) -> old_io::IoResult<()> {
489 // Write out the shared files. Note that these are shared among all rustdoc
490 // docs placed in the output directory, so this needs to be a synchronized
491 // operation with respect to all other rustdocs running around.
492 try!(mkdir(&cx.dst));
493 let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
495 // Add all the static files. These may already exist, but we just
496 // overwrite them anyway to make sure that they're fresh and up-to-date.
497 try!(write(cx.dst.join("jquery.js"),
498 include_bytes!("static/jquery-2.1.0.min.js")));
499 try!(write(cx.dst.join("main.js"), include_bytes!("static/main.js")));
500 try!(write(cx.dst.join("playpen.js"), include_bytes!("static/playpen.js")));
501 try!(write(cx.dst.join("main.css"), include_bytes!("static/main.css")));
502 try!(write(cx.dst.join("normalize.css"),
503 include_bytes!("static/normalize.css")));
504 try!(write(cx.dst.join("FiraSans-Regular.woff"),
505 include_bytes!("static/FiraSans-Regular.woff")));
506 try!(write(cx.dst.join("FiraSans-Medium.woff"),
507 include_bytes!("static/FiraSans-Medium.woff")));
508 try!(write(cx.dst.join("Heuristica-Italic.woff"),
509 include_bytes!("static/Heuristica-Italic.woff")));
510 try!(write(cx.dst.join("SourceSerifPro-Regular.woff"),
511 include_bytes!("static/SourceSerifPro-Regular.woff")));
512 try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
513 include_bytes!("static/SourceSerifPro-Bold.woff")));
514 try!(write(cx.dst.join("SourceCodePro-Regular.woff"),
515 include_bytes!("static/SourceCodePro-Regular.woff")));
516 try!(write(cx.dst.join("SourceCodePro-Semibold.woff"),
517 include_bytes!("static/SourceCodePro-Semibold.woff")));
519 fn collect(path: &Path, krate: &str,
520 key: &str) -> old_io::IoResult<Vec<String>> {
521 let mut ret = Vec::new();
523 for line in BufferedReader::new(File::open(path)).lines() {
524 let line = try!(line);
525 if !line.starts_with(key) {
528 if line.starts_with(&format!("{}['{}']", key, krate)) {
531 ret.push(line.to_string());
537 // Update the search index
538 let dst = cx.dst.join("search-index.js");
539 let all_indexes = try!(collect(&dst, &krate.name, "searchIndex"));
540 let mut w = try!(File::create(&dst));
541 try!(writeln!(&mut w, "var searchIndex = {{}};"));
542 try!(writeln!(&mut w, "{}", search_index));
543 for index in &all_indexes {
544 try!(writeln!(&mut w, "{}", *index));
546 try!(writeln!(&mut w, "initSearch(searchIndex);"));
548 // Update the list of all implementors for traits
549 let dst = cx.dst.join("implementors");
551 for (&did, imps) in &cache.implementors {
552 // Private modules can leak through to this phase of rustdoc, which
553 // could contain implementations for otherwise private types. In some
554 // rare cases we could find an implementation for an item which wasn't
555 // indexed, so we just skip this step in that case.
557 // FIXME: this is a vague explanation for why this can't be a `get`, in
558 // theory it should be...
559 let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) {
564 let mut mydst = dst.clone();
565 for part in &remote_path[..remote_path.len() - 1] {
569 mydst.push(format!("{}.{}.js",
570 remote_item_type.to_static_str(),
571 remote_path[remote_path.len() - 1]));
572 let all_implementors = try!(collect(&mydst, &krate.name,
575 try!(mkdir(&mydst.dir_path()));
576 let mut f = BufferedWriter::new(try!(File::create(&mydst)));
577 try!(writeln!(&mut f, "(function() {{var implementors = {{}};"));
579 for implementor in &all_implementors {
580 try!(write!(&mut f, "{}", *implementor));
583 try!(write!(&mut f, r"implementors['{}'] = [", krate.name));
585 // If the trait and implementation are in the same crate, then
586 // there's no need to emit information about it (there's inlining
587 // going on). If they're in different crates then the crate defining
588 // the trait will be interested in our implementation.
589 if imp.def_id.krate == did.krate { continue }
590 try!(write!(&mut f, r#""{}impl{} {} for {}","#,
591 ConciseStability(&imp.stability),
592 imp.generics, imp.trait_, imp.for_));
594 try!(writeln!(&mut f, r"];"));
595 try!(writeln!(&mut f, "{}", r"
596 if (window.register_implementors) {
597 window.register_implementors(implementors);
599 window.pending_implementors = implementors;
602 try!(writeln!(&mut f, r"}})()"));
607 fn render_sources(cx: &mut Context,
608 krate: clean::Crate) -> old_io::IoResult<clean::Crate> {
609 info!("emitting source files");
610 let dst = cx.dst.join("src");
612 let dst = dst.join(&krate.name);
614 let mut folder = SourceCollector {
616 seen: HashSet::new(),
619 // skip all invalid spans
620 folder.seen.insert("".to_string());
621 Ok(folder.fold_crate(krate))
624 /// Writes the entire contents of a string to a destination, not attempting to
625 /// catch any errors.
626 fn write(dst: Path, contents: &[u8]) -> old_io::IoResult<()> {
627 File::create(&dst).write_all(contents)
630 /// Makes a directory on the filesystem, failing the task if an error occurs and
631 /// skipping if the directory already exists.
632 fn mkdir(path: &Path) -> old_io::IoResult<()> {
634 fs::mkdir(path, old_io::USER_RWX)
640 /// Returns a documentation-level item type from the item.
641 fn shortty(item: &clean::Item) -> ItemType {
642 ItemType::from_item(item)
645 /// Takes a path to a source file and cleans the path to it. This canonicalizes
646 /// things like ".." to components which preserve the "top down" hierarchy of a
647 /// static HTML tree.
648 // FIXME (#9639): The closure should deal with &[u8] instead of &str
649 // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
650 fn clean_srcpath<F>(src_root: &Path, src: &[u8], mut f: F) where
653 let p = Path::new(src);
655 // make it relative, if possible
656 let p = p.path_relative_from(src_root).unwrap_or(p);
658 if p.as_vec() != b"." {
659 for c in p.str_components().map(|x|x.unwrap()) {
669 /// Attempts to find where an external crate is located, given that we're
670 /// rendering in to the specified source destination.
671 fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
672 // See if there's documentation generated into the local directory
673 let local_location = dst.join(&e.name);
674 if local_location.is_dir() {
678 // Failing that, see if there's an attribute specifying where to find this
680 for attr in &e.attrs {
682 clean::List(ref x, ref list) if "doc" == *x => {
685 clean::NameValue(ref x, ref s)
686 if "html_root_url" == *x => {
687 if s.ends_with("/") {
688 return Remote(s.to_string());
690 return Remote(format!("{}/", s));
700 // Well, at least we tried.
704 impl<'a> DocFolder for SourceCollector<'a> {
705 fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
706 // If we're including source files, and we haven't seen this file yet,
707 // then we need to render it out to the filesystem
708 if self.cx.include_sources && !self.seen.contains(&item.source.filename) {
710 // If it turns out that we couldn't read this file, then we probably
711 // can't read any of the files (generating html output from json or
712 // something like that), so just don't include sources for the
713 // entire crate. The other option is maintaining this mapping on a
714 // per-file basis, but that's probably not worth it...
716 .include_sources = match self.emit_source(&item.source .filename) {
719 println!("warning: source code was requested to be rendered, \
720 but processing `{}` had an error: {}",
721 item.source.filename, e);
722 println!(" skipping rendering of source code");
726 self.seen.insert(item.source.filename.clone());
729 self.fold_item_recur(item)
733 impl<'a> SourceCollector<'a> {
734 /// Renders the given filename into its corresponding HTML source file.
735 fn emit_source(&mut self, filename: &str) -> old_io::IoResult<()> {
736 let p = Path::new(filename);
738 // If we couldn't open this file, then just returns because it
739 // probably means that it's some standard library macro thing and we
740 // can't have the source to it anyway.
741 let contents = match File::open(&p).read_to_end() {
743 // macros from other libraries get special filenames which we can
745 Err(..) if filename.starts_with("<") &&
746 filename.ends_with("macros>") => return Ok(()),
747 Err(e) => return Err(e)
749 let contents = str::from_utf8(&contents).unwrap();
751 // Remove the utf-8 BOM if any
752 let contents = if contents.starts_with("\u{feff}") {
758 // Create the intermediate directories
759 let mut cur = self.dst.clone();
760 let mut root_path = String::from_str("../../");
761 clean_srcpath(&self.cx.src_root, p.dirname(), |component| {
763 mkdir(&cur).unwrap();
764 root_path.push_str("../");
767 let mut fname = p.filename().expect("source has no filename").to_vec();
768 fname.extend(".html".bytes());
770 let mut w = BufferedWriter::new(try!(File::create(&cur)));
772 let title = format!("{} -- source", cur.filename_display());
773 let desc = format!("Source to the Rust file `{}`.", filename);
774 let page = layout::Page {
777 root_path: &root_path,
779 keywords: get_basic_keywords(),
781 try!(layout::render(&mut w as &mut Writer, &self.cx.layout,
782 &page, &(""), &Source(contents)));
788 impl DocFolder for Cache {
789 fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
790 // If this is a private module, we don't want it in the search index.
791 let orig_privmod = match item.inner {
792 clean::ModuleItem(..) => {
793 let prev = self.privmod;
794 self.privmod = prev || (self.remove_priv && item.visibility != Some(ast::Public));
800 // Register any generics to their corresponding string. This is used
801 // when pretty-printing types
803 clean::StructItem(ref s) => self.generics(&s.generics),
804 clean::EnumItem(ref e) => self.generics(&e.generics),
805 clean::FunctionItem(ref f) => self.generics(&f.generics),
806 clean::TypedefItem(ref t) => self.generics(&t.generics),
807 clean::TraitItem(ref t) => self.generics(&t.generics),
808 clean::ImplItem(ref i) => self.generics(&i.generics),
809 clean::TyMethodItem(ref i) => self.generics(&i.generics),
810 clean::MethodItem(ref i) => self.generics(&i.generics),
811 clean::ForeignFunctionItem(ref f) => self.generics(&f.generics),
815 // Propagate a trait methods' documentation to all implementors of the
817 if let clean::TraitItem(ref t) = item.inner {
818 self.traits.insert(item.def_id, t.clone());
821 // Collect all the implementors of traits.
822 if let clean::ImplItem(ref i) = item.inner {
824 Some(clean::ResolvedPath{ did, .. }) => {
825 let v = self.implementors.entry(did).get().unwrap_or_else(
826 |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
829 generics: i.generics.clone(),
830 trait_: i.trait_.as_ref().unwrap().clone(),
831 for_: i.for_.clone(),
832 stability: item.stability.clone(),
835 Some(..) | None => {}
839 // Index this method for searching later on
840 if let Some(ref s) = item.name {
841 let (parent, is_method) = match item.inner {
842 clean::TyMethodItem(..) |
843 clean::StructFieldItem(..) |
844 clean::VariantItem(..) => {
845 ((Some(*self.parent_stack.last().unwrap()),
846 Some(&self.stack[..self.stack.len() - 1])),
849 clean::MethodItem(..) => {
850 if self.parent_stack.len() == 0 {
851 ((None, None), false)
853 let last = self.parent_stack.last().unwrap();
855 let path = match self.paths.get(&did) {
856 Some(&(_, ItemType::Trait)) =>
857 Some(&self.stack[..self.stack.len() - 1]),
858 // The current stack not necessarily has correlation for
859 // where the type was defined. On the other hand,
860 // `paths` always has the right information if present.
861 Some(&(ref fqp, ItemType::Struct)) |
862 Some(&(ref fqp, ItemType::Enum)) =>
863 Some(&fqp[..fqp.len() - 1]),
864 Some(..) => Some(&*self.stack),
867 ((Some(*last), path), true)
870 _ => ((None, Some(&*self.stack)), false)
872 let hidden_field = match item.inner {
873 clean::StructFieldItem(clean::HiddenStructField) => true,
878 (parent, Some(path)) if is_method || (!self.privmod && !hidden_field) => {
879 self.search_index.push(IndexItem {
882 path: path.connect("::").to_string(),
883 desc: shorter(item.doc_value()).to_string(),
887 (Some(parent), None) if is_method || (!self.privmod && !hidden_field)=> {
888 if ast_util::is_local(parent) {
889 // We have a parent, but we don't know where they're
890 // defined yet. Wait for later to index this item.
891 self.orphan_methods.push((parent.node, item.clone()))
898 // Keep track of the fully qualified path for this item.
899 let pushed = if item.name.is_some() {
900 let n = item.name.as_ref().unwrap();
902 self.stack.push(n.to_string());
907 clean::StructItem(..) | clean::EnumItem(..) |
908 clean::TypedefItem(..) | clean::TraitItem(..) |
909 clean::FunctionItem(..) | clean::ModuleItem(..) |
910 clean::ForeignFunctionItem(..) if !self.privmod => {
911 // Reexported items mean that the same id can show up twice
912 // in the rustdoc ast that we're looking at. We know,
913 // however, that a reexported item doesn't show up in the
914 // `public_items` map, so we can skip inserting into the
915 // paths map if there was already an entry present and we're
916 // not a public item.
917 let id = item.def_id.node;
918 if !self.paths.contains_key(&item.def_id) ||
919 !ast_util::is_local(item.def_id) ||
920 self.public_items.contains(&id) {
921 self.paths.insert(item.def_id,
922 (self.stack.clone(), shortty(&item)));
925 // link variants to their parent enum because pages aren't emitted
927 clean::VariantItem(..) if !self.privmod => {
928 let mut stack = self.stack.clone();
930 self.paths.insert(item.def_id, (stack, ItemType::Enum));
933 clean::PrimitiveItem(..) if item.visibility.is_some() => {
934 self.paths.insert(item.def_id, (self.stack.clone(),
941 // Maintain the parent stack
942 let parent_pushed = match item.inner {
943 clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
944 self.parent_stack.push(item.def_id);
947 clean::ImplItem(ref i) => {
949 clean::ResolvedPath{ did, .. } => {
950 self.parent_stack.push(did);
959 // Once we've recursively found all the generics, then hoard off all the
960 // implementations elsewhere
961 let ret = match self.fold_item_recur(item) {
964 clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
965 use clean::{Primitive, Vector, ResolvedPath, BorrowedRef};
966 use clean::{FixedVector, Slice, Tuple, PrimitiveTuple};
968 // extract relevant documentation for this impl
969 let dox = match attrs.into_iter().find(|a| {
971 clean::NameValue(ref x, _)
978 Some(clean::NameValue(_, dox)) => Some(dox),
979 Some(..) | None => None,
982 // Figure out the id of this impl. This may map to a
983 // primitive rather than always to a struct/enum.
984 let did = match i.for_ {
985 ResolvedPath { did, .. } => Some(did),
987 // References to primitives are picked up as well to
988 // recognize implementations for &str, this may not
989 // be necessary in a DST world.
991 BorrowedRef { type_: box Primitive(p), ..} =>
993 Some(ast_util::local_def(p.to_node_id()))
996 // In a DST world, we may only need
997 // Vector/FixedVector, but for now we also pick up
998 // borrowed references
999 Vector(..) | FixedVector(..) |
1000 BorrowedRef{ type_: box Vector(..), .. } |
1001 BorrowedRef{ type_: box FixedVector(..), .. } =>
1003 Some(ast_util::local_def(Slice.to_node_id()))
1007 let id = PrimitiveTuple.to_node_id();
1008 Some(ast_util::local_def(id))
1014 if let Some(did) = did {
1015 let v = self.impls.entry(did).get().unwrap_or_else(
1016 |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
1020 stability: item.stability.clone(),
1033 if pushed { self.stack.pop().unwrap(); }
1034 if parent_pushed { self.parent_stack.pop().unwrap(); }
1035 self.privmod = orig_privmod;
1041 fn generics(&mut self, generics: &clean::Generics) {
1042 for typ in &generics.type_params {
1043 self.typarams.insert(typ.did, typ.name.clone());
1049 /// Recurse in the directory structure and change the "root path" to make
1050 /// sure it always points to the top (relatively)
1051 fn recurse<T, F>(&mut self, s: String, f: F) -> T where
1052 F: FnOnce(&mut Context) -> T,
1055 panic!("Unexpected empty destination: {:?}", self.current);
1057 let prev = self.dst.clone();
1059 self.root_path.push_str("../");
1060 self.current.push(s);
1062 info!("Recursing into {}", self.dst.display());
1064 mkdir(&self.dst).unwrap();
1067 info!("Recursed; leaving {}", self.dst.display());
1069 // Go back to where we were at
1071 let len = self.root_path.len();
1072 self.root_path.truncate(len - 3);
1073 self.current.pop().unwrap();
1078 /// Main method for rendering a crate.
1080 /// This currently isn't parallelized, but it'd be pretty easy to add
1081 /// parallelization to this function.
1082 fn krate(mut self, mut krate: clean::Crate,
1083 stability: stability_summary::ModuleSummary) -> old_io::IoResult<()> {
1084 let mut item = match krate.module.take() {
1086 None => return Ok(())
1088 item.name = Some(krate.name);
1090 // render stability dashboard
1091 try!(self.recurse(stability.name.clone(), |this| {
1092 let json_dst = &this.dst.join("stability.json");
1093 let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
1094 try!(write!(&mut json_out, "{}", json::as_json(&stability)));
1096 let mut title = stability.name.clone();
1097 title.push_str(" - Stability dashboard");
1098 let desc = format!("API stability overview for the Rust `{}` crate.",
1100 let page = layout::Page {
1102 root_path: &this.root_path,
1105 keywords: get_basic_keywords(),
1107 let html_dst = &this.dst.join("stability.html");
1108 let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
1109 layout::render(&mut html_out, &this.layout, &page,
1110 &Sidebar{ cx: this, item: &item },
1114 // render the crate documentation
1115 let mut work = vec!((self, item));
1118 Some((mut cx, item)) => try!(cx.item(item, |cx, item| {
1119 work.push((cx.clone(), item));
1128 /// Non-parallelized version of rendering an item. This will take the input
1129 /// item, render its contents, and then invoke the specified closure with
1130 /// all sub-items which need to be rendered.
1132 /// The rendering driver uses this closure to queue up more work.
1133 fn item<F>(&mut self, item: clean::Item, mut f: F) -> old_io::IoResult<()> where
1134 F: FnMut(&mut Context, clean::Item),
1136 fn render(w: old_io::File, cx: &Context, it: &clean::Item,
1137 pushname: bool) -> old_io::IoResult<()> {
1138 info!("Rendering an item to {}", w.path().display());
1139 // A little unfortunate that this is done like this, but it sure
1140 // does make formatting *a lot* nicer.
1141 CURRENT_LOCATION_KEY.with(|slot| {
1142 *slot.borrow_mut() = cx.current.clone();
1145 let mut title = cx.current.connect("::");
1147 if title.len() > 0 {
1148 title.push_str("::");
1150 title.push_str(it.name.as_ref().unwrap());
1152 title.push_str(" - Rust");
1153 let tyname = shortty(it).to_static_str();
1154 let is_crate = match it.inner {
1155 clean::ModuleItem(clean::Module { items: _, is_crate: true }) => true,
1158 let desc = if is_crate {
1159 format!("API documentation for the Rust `{}` crate.",
1162 format!("API documentation for the Rust `{}` {} in crate `{}`.",
1163 it.name.as_ref().unwrap(), tyname, cx.layout.krate)
1165 let keywords = make_item_keywords(it);
1166 let page = layout::Page {
1168 root_path: &cx.root_path,
1171 keywords: &keywords,
1174 markdown::reset_headers();
1176 // We have a huge number of calls to write, so try to alleviate some
1177 // of the pain by using a buffered writer instead of invoking the
1178 // write syscall all the time.
1179 let mut writer = BufferedWriter::new(w);
1180 if !cx.render_redirect_pages {
1181 try!(layout::render(&mut writer, &cx.layout, &page,
1182 &Sidebar{ cx: cx, item: it },
1183 &Item{ cx: cx, item: it }));
1185 let mut url = repeat("../").take(cx.current.len())
1186 .collect::<String>();
1187 match cache().paths.get(&it.def_id) {
1188 Some(&(ref names, _)) => {
1189 for name in &names[..names.len() - 1] {
1193 url.push_str(&item_path(it));
1194 try!(layout::redirect(&mut writer, &url));
1202 // Private modules may survive the strip-private pass if they
1203 // contain impls for public types. These modules can also
1204 // contain items such as publicly reexported structures.
1206 // External crates will provide links to these structures, so
1207 // these modules are recursed into, but not rendered normally (a
1208 // flag on the context).
1209 if !self.render_redirect_pages {
1210 self.render_redirect_pages = self.ignore_private_item(&item);
1214 // modules are special because they add a namespace. We also need to
1215 // recurse into the items of the module as well.
1216 clean::ModuleItem(..) => {
1217 let name = item.name.as_ref().unwrap().to_string();
1218 let mut item = Some(item);
1219 self.recurse(name, |this| {
1220 let item = item.take().unwrap();
1221 let dst = this.dst.join("index.html");
1222 let dst = try!(File::create(&dst));
1223 try!(render(dst, this, &item, false));
1225 let m = match item.inner {
1226 clean::ModuleItem(m) => m,
1229 this.sidebar = this.build_sidebar(&m);
1230 for item in m.items {
1237 // Things which don't have names (like impls) don't get special
1238 // pages dedicated to them.
1239 _ if item.name.is_some() => {
1240 let dst = self.dst.join(item_path(&item));
1241 let dst = try!(File::create(&dst));
1242 render(dst, self, &item, true)
1249 fn build_sidebar(&self, m: &clean::Module) -> HashMap<String, Vec<NameDoc>> {
1250 let mut map = HashMap::new();
1251 for item in &m.items {
1252 if self.ignore_private_item(item) { continue }
1254 // avoid putting foreign items to the sidebar.
1255 if let &clean::ForeignFunctionItem(..) = &item.inner { continue }
1256 if let &clean::ForeignStaticItem(..) = &item.inner { continue }
1258 let short = shortty(item).to_static_str();
1259 let myname = match item.name {
1261 Some(ref s) => s.to_string(),
1263 let short = short.to_string();
1264 let v = map.entry(short).get().unwrap_or_else(
1265 |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
1266 v.push(NameDoc(myname, Some(shorter_line(item.doc_value()))));
1269 for (_, items) in &mut map {
1275 fn ignore_private_item(&self, it: &clean::Item) -> bool {
1277 clean::ModuleItem(ref m) => {
1278 (m.items.len() == 0 && it.doc_value().is_none()) ||
1279 (self.passes.contains("strip-private") && it.visibility != Some(ast::Public))
1281 clean::PrimitiveItem(..) => it.visibility != Some(ast::Public),
1288 fn ismodule(&self) -> bool {
1289 match self.item.inner {
1290 clean::ModuleItem(..) => true, _ => false
1294 /// Generate a url appropriate for an `href` attribute back to the source of
1297 /// The url generated, when clicked, will redirect the browser back to the
1298 /// original source code.
1300 /// If `None` is returned, then a source link couldn't be generated. This
1301 /// may happen, for example, with externally inlined items where the source
1302 /// of their crate documentation isn't known.
1303 fn href(&self, cx: &Context) -> Option<String> {
1304 // If this item is part of the local crate, then we're guaranteed to
1305 // know the span, so we plow forward and generate a proper url. The url
1306 // has anchors for the line numbers that we're linking to.
1307 if ast_util::is_local(self.item.def_id) {
1308 let mut path = Vec::new();
1309 clean_srcpath(&cx.src_root, self.item.source.filename.as_bytes(),
1311 path.push(component.to_string());
1313 let href = if self.item.source.loline == self.item.source.hiline {
1314 format!("{}", self.item.source.loline)
1317 self.item.source.loline,
1318 self.item.source.hiline)
1320 Some(format!("{root}src/{krate}/{path}.html#{href}",
1321 root = self.cx.root_path,
1322 krate = self.cx.layout.krate,
1323 path = path.connect("/"),
1326 // If this item is not part of the local crate, then things get a little
1327 // trickier. We don't actually know the span of the external item, but
1328 // we know that the documentation on the other end knows the span!
1330 // In this case, we generate a link to the *documentation* for this type
1331 // in the original crate. There's an extra URL parameter which says that
1332 // we want to go somewhere else, and the JS on the destination page will
1333 // pick it up and instantly redirect the browser to the source code.
1335 // If we don't know where the external documentation for this crate is
1336 // located, then we return `None`.
1338 let cache = cache();
1339 let path = &cache.external_paths[self.item.def_id];
1340 let root = match cache.extern_locations[self.item.def_id.krate] {
1341 Remote(ref s) => s.to_string(),
1342 Local => self.cx.root_path.clone(),
1343 Unknown => return None,
1345 Some(format!("{root}{path}/{file}?gotosrc={goto}",
1347 path = path[..path.len() - 1].connect("/"),
1348 file = item_path(self.item),
1349 goto = self.item.def_id.node))
1355 impl<'a> fmt::Display for Item<'a> {
1356 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1357 // Write the breadcrumb trail header for the top
1358 try!(write!(fmt, "\n<h1 class='fqn'><span class='in-band'>"));
1359 match self.item.inner {
1360 clean::ModuleItem(ref m) => if m.is_crate {
1361 try!(write!(fmt, "Crate "));
1363 try!(write!(fmt, "Module "));
1365 clean::FunctionItem(..) => try!(write!(fmt, "Function ")),
1366 clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
1367 clean::StructItem(..) => try!(write!(fmt, "Struct ")),
1368 clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
1369 clean::PrimitiveItem(..) => try!(write!(fmt, "Primitive Type ")),
1372 let is_primitive = match self.item.inner {
1373 clean::PrimitiveItem(..) => true,
1377 let cur = &self.cx.current;
1378 let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
1379 for (i, component) in cur.iter().enumerate().take(amt) {
1380 try!(write!(fmt, "<a href='{}index.html'>{}</a>::<wbr>",
1381 repeat("../").take(cur.len() - i - 1)
1382 .collect::<String>(),
1386 try!(write!(fmt, "<a class='{}' href=''>{}</a>",
1387 shortty(self.item), self.item.name.as_ref().unwrap()));
1389 // Write stability level
1390 try!(write!(fmt, "<wbr>{}", Stability(&self.item.stability)));
1392 try!(write!(fmt, "</span>")); // in-band
1393 // Links to out-of-band information, i.e. src and stability dashboard
1394 try!(write!(fmt, "<span class='out-of-band'>"));
1396 // Write stability dashboard link
1397 match self.item.inner {
1398 clean::ModuleItem(ref m) if m.is_crate => {
1399 try!(write!(fmt, "<a href='stability.html'>[stability]</a> "));
1405 r##"<span id='render-detail'>
1406 <a id="collapse-all" href="#">[-]
1407 </a> <a id="expand-all" href="#">[+]</a>
1412 // When this item is part of a `pub use` in a downstream crate, the
1413 // [src] link in the downstream documentation will actually come back to
1414 // this page, and this link will be auto-clicked. The `id` attribute is
1415 // used to find the link to auto-click.
1416 if self.cx.include_sources && !is_primitive {
1417 match self.href(self.cx) {
1419 try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
1420 self.item.def_id.node, l));
1426 try!(write!(fmt, "</span>")); // out-of-band
1428 try!(write!(fmt, "</h1>\n"));
1430 match self.item.inner {
1431 clean::ModuleItem(ref m) => {
1432 item_module(fmt, self.cx, self.item, &m.items)
1434 clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
1435 item_function(fmt, self.item, f),
1436 clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
1437 clean::StructItem(ref s) => item_struct(fmt, self.item, s),
1438 clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
1439 clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
1440 clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
1441 clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p),
1442 clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
1443 item_static(fmt, self.item, i),
1444 clean::ConstantItem(ref c) => item_constant(fmt, self.item, c),
1450 fn item_path(item: &clean::Item) -> String {
1452 clean::ModuleItem(..) => {
1453 format!("{}/index.html", item.name.as_ref().unwrap())
1456 format!("{}.{}.html",
1457 shortty(item).to_static_str(),
1458 *item.name.as_ref().unwrap())
1463 fn full_path(cx: &Context, item: &clean::Item) -> String {
1464 let mut s = cx.current.connect("::");
1466 s.push_str(item.name.as_ref().unwrap());
1470 fn shorter<'a>(s: Option<&'a str>) -> &'a str {
1472 Some(s) => match s.find_str("\n\n") {
1473 Some(pos) => &s[..pos],
1481 fn shorter_line(s: Option<&str>) -> String {
1482 shorter(s).replace("\n", " ")
1485 fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
1486 match item.doc_value() {
1488 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1495 fn item_module(w: &mut fmt::Formatter, cx: &Context,
1496 item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
1497 try!(document(w, item));
1499 let mut indices = (0..items.len()).filter(|i| {
1500 !cx.ignore_private_item(&items[*i])
1501 }).collect::<Vec<uint>>();
1503 // the order of item types in the listing
1504 fn reorder(ty: ItemType) -> u8 {
1506 ItemType::ExternCrate => 0,
1507 ItemType::Import => 1,
1508 ItemType::Primitive => 2,
1509 ItemType::Module => 3,
1510 ItemType::Macro => 4,
1511 ItemType::Struct => 5,
1512 ItemType::Enum => 6,
1513 ItemType::Constant => 7,
1514 ItemType::Static => 8,
1515 ItemType::Trait => 9,
1516 ItemType::Function => 10,
1517 ItemType::Typedef => 12,
1522 fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
1523 let ty1 = shortty(i1);
1524 let ty2 = shortty(i2);
1526 return i1.name.cmp(&i2.name);
1528 (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2))
1531 indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
1533 debug!("{:?}", indices);
1534 let mut curty = None;
1535 for &idx in &indices {
1536 let myitem = &items[idx];
1538 let myty = Some(shortty(myitem));
1539 if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
1540 // Put `extern crate` and `use` re-exports in the same section.
1542 } else if myty != curty {
1543 if curty.is_some() {
1544 try!(write!(w, "</table>"));
1547 let (short, name) = match myty.unwrap() {
1548 ItemType::ExternCrate |
1549 ItemType::Import => ("reexports", "Reexports"),
1550 ItemType::Module => ("modules", "Modules"),
1551 ItemType::Struct => ("structs", "Structs"),
1552 ItemType::Enum => ("enums", "Enums"),
1553 ItemType::Function => ("functions", "Functions"),
1554 ItemType::Typedef => ("types", "Type Definitions"),
1555 ItemType::Static => ("statics", "Statics"),
1556 ItemType::Constant => ("constants", "Constants"),
1557 ItemType::Trait => ("traits", "Traits"),
1558 ItemType::Impl => ("impls", "Implementations"),
1559 ItemType::TyMethod => ("tymethods", "Type Methods"),
1560 ItemType::Method => ("methods", "Methods"),
1561 ItemType::StructField => ("fields", "Struct Fields"),
1562 ItemType::Variant => ("variants", "Variants"),
1563 ItemType::Macro => ("macros", "Macros"),
1564 ItemType::Primitive => ("primitives", "Primitive Types"),
1565 ItemType::AssociatedType => ("associated-types", "Associated Types"),
1568 "<h2 id='{id}' class='section-header'>\
1569 <a href=\"#{id}\">{name}</a></h2>\n<table>",
1570 id = short, name = name));
1573 match myitem.inner {
1574 clean::ExternCrateItem(ref name, ref src) => {
1577 try!(write!(w, "<tr><td><code>{}extern crate \"{}\" as {};",
1578 VisSpace(myitem.visibility),
1583 try!(write!(w, "<tr><td><code>{}extern crate {};",
1584 VisSpace(myitem.visibility), name))
1587 try!(write!(w, "</code></td></tr>"));
1590 clean::ImportItem(ref import) => {
1591 try!(write!(w, "<tr><td><code>{}{}</code></td></tr>",
1592 VisSpace(myitem.visibility), *import));
1596 if myitem.name.is_none() { continue }
1599 <td>{stab}<a class='{class}' href='{href}'
1600 title='{title}'>{}</a></td>
1601 <td class='docblock short'>{}</td>
1604 *myitem.name.as_ref().unwrap(),
1605 Markdown(shorter(myitem.doc_value())),
1606 class = shortty(myitem),
1607 href = item_path(myitem),
1608 title = full_path(cx, myitem),
1609 stab = ConciseStability(&myitem.stability)));
1614 write!(w, "</table>")
1617 struct Initializer<'a>(&'a str);
1619 impl<'a> fmt::Display for Initializer<'a> {
1620 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1621 let Initializer(s) = *self;
1622 if s.len() == 0 { return Ok(()); }
1623 try!(write!(f, "<code> = </code>"));
1624 write!(f, "<code>{}</code>", s)
1628 fn item_constant(w: &mut fmt::Formatter, it: &clean::Item,
1629 c: &clean::Constant) -> fmt::Result {
1630 try!(write!(w, "<pre class='rust const'>{vis}const \
1631 {name}: {typ}{init}</pre>",
1632 vis = VisSpace(it.visibility),
1633 name = it.name.as_ref().unwrap(),
1635 init = Initializer(&c.expr)));
1639 fn item_static(w: &mut fmt::Formatter, it: &clean::Item,
1640 s: &clean::Static) -> fmt::Result {
1641 try!(write!(w, "<pre class='rust static'>{vis}static {mutability}\
1642 {name}: {typ}{init}</pre>",
1643 vis = VisSpace(it.visibility),
1644 mutability = MutableSpace(s.mutability),
1645 name = it.name.as_ref().unwrap(),
1647 init = Initializer(&s.expr)));
1651 fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
1652 f: &clean::Function) -> fmt::Result {
1653 try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}fn \
1654 {name}{generics}{decl}{where_clause}</pre>",
1655 vis = VisSpace(it.visibility),
1656 unsafety = UnsafetySpace(f.unsafety),
1657 name = it.name.as_ref().unwrap(),
1658 generics = f.generics,
1659 where_clause = WhereClause(&f.generics),
1664 fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1665 t: &clean::Trait) -> fmt::Result {
1666 let mut bounds = String::new();
1667 if t.bounds.len() > 0 {
1668 if bounds.len() > 0 {
1671 bounds.push_str(": ");
1672 for (i, p) in t.bounds.iter().enumerate() {
1673 if i > 0 { bounds.push_str(" + "); }
1674 bounds.push_str(&format!("{}", *p));
1678 // Output the trait definition
1679 try!(write!(w, "<pre class='rust trait'>{}{}trait {}{}{}{} ",
1680 VisSpace(it.visibility),
1681 UnsafetySpace(t.unsafety),
1682 it.name.as_ref().unwrap(),
1685 WhereClause(&t.generics)));
1687 let types = t.items.iter().filter(|m| m.is_type()).collect::<Vec<_>>();
1688 let required = t.items.iter().filter(|m| m.is_req()).collect::<Vec<_>>();
1689 let provided = t.items.iter().filter(|m| m.is_def()).collect::<Vec<_>>();
1691 if t.items.len() == 0 {
1692 try!(write!(w, "{{ }}"));
1694 try!(write!(w, "{{\n"));
1696 try!(write!(w, " "));
1697 try!(render_method(w, t.item()));
1698 try!(write!(w, ";\n"));
1700 if types.len() > 0 && required.len() > 0 {
1701 try!(w.write_str("\n"));
1703 for m in &required {
1704 try!(write!(w, " "));
1705 try!(render_method(w, m.item()));
1706 try!(write!(w, ";\n"));
1708 if required.len() > 0 && provided.len() > 0 {
1709 try!(w.write_str("\n"));
1711 for m in &provided {
1712 try!(write!(w, " "));
1713 try!(render_method(w, m.item()));
1714 try!(write!(w, " {{ ... }}\n"));
1716 try!(write!(w, "}}"));
1718 try!(write!(w, "</pre>"));
1720 // Trait documentation
1721 try!(document(w, it));
1723 fn trait_item(w: &mut fmt::Formatter, m: &clean::TraitMethod)
1725 try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>",
1727 *m.item().name.as_ref().unwrap(),
1728 ConciseStability(&m.item().stability)));
1729 try!(render_method(w, m.item()));
1730 try!(write!(w, "</code></h3>"));
1731 try!(document(w, m.item()));
1735 if types.len() > 0 {
1737 <h2 id='associated-types'>Associated Types</h2>
1738 <div class='methods'>
1741 try!(trait_item(w, *t));
1743 try!(write!(w, "</div>"));
1746 // Output the documentation for each function individually
1747 if required.len() > 0 {
1749 <h2 id='required-methods'>Required Methods</h2>
1750 <div class='methods'>
1752 for m in &required {
1753 try!(trait_item(w, *m));
1755 try!(write!(w, "</div>"));
1757 if provided.len() > 0 {
1759 <h2 id='provided-methods'>Provided Methods</h2>
1760 <div class='methods'>
1762 for m in &provided {
1763 try!(trait_item(w, *m));
1765 try!(write!(w, "</div>"));
1768 let cache = cache();
1770 <h2 id='implementors'>Implementors</h2>
1771 <ul class='item-list' id='implementors-list'>
1773 match cache.implementors.get(&it.def_id) {
1774 Some(implementors) => {
1775 for i in implementors {
1776 try!(writeln!(w, "<li>{}<code>impl{} {} for {}{}</code></li>",
1777 ConciseStability(&i.stability),
1778 i.generics, i.trait_, i.for_, WhereClause(&i.generics)));
1783 try!(write!(w, "</ul>"));
1784 try!(write!(w, r#"<script type="text/javascript" async
1785 src="{root_path}/implementors/{path}/{ty}.{name}.js">
1787 root_path = repeat("..").take(cx.current.len()).collect::<Vec<_>>().connect("/"),
1788 path = if ast_util::is_local(it.def_id) {
1789 cx.current.connect("/")
1791 let path = &cache.external_paths[it.def_id];
1792 path[..path.len() - 1].connect("/")
1794 ty = shortty(it).to_static_str(),
1795 name = *it.name.as_ref().unwrap()));
1799 fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
1800 typ: &clean::TyParam) -> fmt::Result {
1801 try!(write!(w, "type {}", it.name.as_ref().unwrap()));
1802 if typ.bounds.len() > 0 {
1803 try!(write!(w, ": {}", TyParamBounds(&*typ.bounds)))
1805 if let Some(ref default) = typ.default {
1806 try!(write!(w, " = {}", default));
1811 fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
1812 fn method(w: &mut fmt::Formatter, it: &clean::Item, unsafety: ast::Unsafety,
1813 g: &clean::Generics, selfty: &clean::SelfTy,
1814 d: &clean::FnDecl) -> fmt::Result {
1815 write!(w, "{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
1816 {generics}{decl}{where_clause}",
1818 ast::Unsafety::Unsafe => "unsafe ",
1822 name = it.name.as_ref().unwrap(),
1824 decl = Method(selfty, d),
1825 where_clause = WhereClause(g))
1828 clean::TyMethodItem(ref m) => {
1829 method(w, meth, m.unsafety, &m.generics, &m.self_, &m.decl)
1831 clean::MethodItem(ref m) => {
1832 method(w, meth, m.unsafety, &m.generics, &m.self_, &m.decl)
1834 clean::AssociatedTypeItem(ref typ) => {
1835 assoc_type(w, meth, typ)
1837 _ => panic!("render_method called on non-method")
1841 fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
1842 s: &clean::Struct) -> fmt::Result {
1843 try!(write!(w, "<pre class='rust struct'>"));
1844 try!(render_struct(w,
1851 try!(write!(w, "</pre>"));
1853 try!(document(w, it));
1854 let mut fields = s.fields.iter().filter(|f| {
1856 clean::StructFieldItem(clean::HiddenStructField) => false,
1857 clean::StructFieldItem(clean::TypedStructField(..)) => true,
1861 if let doctree::Plain = s.struct_type {
1862 if fields.peek().is_some() {
1863 try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
1864 for field in fields {
1865 try!(write!(w, "<tr><td id='structfield.{name}'>\
1866 {stab}<code>{name}</code></td><td>",
1867 stab = ConciseStability(&field.stability),
1868 name = field.name.as_ref().unwrap()));
1869 try!(document(w, field));
1870 try!(write!(w, "</td></tr>"));
1872 try!(write!(w, "</table>"));
1875 render_methods(w, it)
1878 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
1879 e: &clean::Enum) -> fmt::Result {
1880 try!(write!(w, "<pre class='rust enum'>{}enum {}{}{}",
1881 VisSpace(it.visibility),
1882 it.name.as_ref().unwrap(),
1884 WhereClause(&e.generics)));
1885 if e.variants.len() == 0 && !e.variants_stripped {
1886 try!(write!(w, " {{}}"));
1888 try!(write!(w, " {{\n"));
1889 for v in &e.variants {
1890 try!(write!(w, " "));
1891 let name = v.name.as_ref().unwrap();
1893 clean::VariantItem(ref var) => {
1895 clean::CLikeVariant => try!(write!(w, "{}", name)),
1896 clean::TupleVariant(ref tys) => {
1897 try!(write!(w, "{}(", name));
1898 for (i, ty) in tys.iter().enumerate() {
1900 try!(write!(w, ", "))
1902 try!(write!(w, "{}", *ty));
1904 try!(write!(w, ")"));
1906 clean::StructVariant(ref s) => {
1907 try!(render_struct(w,
1919 try!(write!(w, ",\n"));
1922 if e.variants_stripped {
1923 try!(write!(w, " // some variants omitted\n"));
1925 try!(write!(w, "}}"));
1927 try!(write!(w, "</pre>"));
1929 try!(document(w, it));
1930 if e.variants.len() > 0 {
1931 try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
1932 for variant in &e.variants {
1933 try!(write!(w, "<tr><td id='variant.{name}'>{stab}<code>{name}</code></td><td>",
1934 stab = ConciseStability(&variant.stability),
1935 name = variant.name.as_ref().unwrap()));
1936 try!(document(w, variant));
1937 match variant.inner {
1938 clean::VariantItem(ref var) => {
1940 clean::StructVariant(ref s) => {
1941 let fields = s.fields.iter().filter(|f| {
1943 clean::StructFieldItem(ref t) => match *t {
1944 clean::HiddenStructField => false,
1945 clean::TypedStructField(..) => true,
1950 try!(write!(w, "<h3 class='fields'>Fields</h3>\n
1952 for field in fields {
1953 try!(write!(w, "<tr><td \
1954 id='variant.{v}.field.{f}'>\
1955 <code>{f}</code></td><td>",
1956 v = variant.name.as_ref().unwrap(),
1957 f = field.name.as_ref().unwrap()));
1958 try!(document(w, field));
1959 try!(write!(w, "</td></tr>"));
1961 try!(write!(w, "</table>"));
1968 try!(write!(w, "</td></tr>"));
1970 try!(write!(w, "</table>"));
1973 try!(render_methods(w, it));
1977 fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
1978 g: Option<&clean::Generics>,
1979 ty: doctree::StructType,
1980 fields: &[clean::Item],
1982 structhead: bool) -> fmt::Result {
1983 try!(write!(w, "{}{}{}",
1984 VisSpace(it.visibility),
1985 if structhead {"struct "} else {""},
1986 it.name.as_ref().unwrap()));
1988 Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))),
1993 try!(write!(w, " {{\n{}", tab));
1994 let mut fields_stripped = false;
1995 for field in fields {
1997 clean::StructFieldItem(clean::HiddenStructField) => {
1998 fields_stripped = true;
2000 clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
2001 try!(write!(w, " {}{}: {},\n{}",
2002 VisSpace(field.visibility),
2003 field.name.as_ref().unwrap(),
2007 _ => unreachable!(),
2011 if fields_stripped {
2012 try!(write!(w, " // some fields omitted\n{}", tab));
2014 try!(write!(w, "}}"));
2016 doctree::Tuple | doctree::Newtype => {
2017 try!(write!(w, "("));
2018 for (i, field) in fields.iter().enumerate() {
2020 try!(write!(w, ", "));
2023 clean::StructFieldItem(clean::HiddenStructField) => {
2024 try!(write!(w, "_"))
2026 clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
2027 try!(write!(w, "{}{}", VisSpace(field.visibility), *ty))
2032 try!(write!(w, ");"));
2035 try!(write!(w, ";"));
2041 fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
2042 match cache().impls.get(&it.def_id) {
2044 let (non_trait, traits): (Vec<_>, _) = v.iter().cloned()
2045 .partition(|i| i.impl_.trait_.is_none());
2046 if non_trait.len() > 0 {
2047 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
2048 for i in &non_trait {
2049 try!(render_impl(w, i));
2052 if traits.len() > 0 {
2053 try!(write!(w, "<h2 id='implementations'>Trait \
2054 Implementations</h2>"));
2055 let (derived, manual): (Vec<_>, _) = traits.into_iter()
2056 .partition(|i| i.impl_.derived);
2058 try!(render_impl(w, i));
2060 if derived.len() > 0 {
2061 try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
2064 try!(render_impl(w, i));
2074 fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
2075 try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
2076 ConciseStability(&i.stability),
2078 match i.impl_.polarity {
2079 Some(clean::ImplPolarity::Negative) => try!(write!(w, "!")),
2082 match i.impl_.trait_ {
2083 Some(ref ty) => try!(write!(w, "{} for ", *ty)),
2086 try!(write!(w, "{}{}</code></h3>", i.impl_.for_, WhereClause(&i.impl_.generics)));
2089 try!(write!(w, "<div class='docblock'>{}</div>",
2095 fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool)
2098 clean::MethodItem(..) | clean::TyMethodItem(..) => {
2099 try!(write!(w, "<h4 id='method.{}' class='{}'>{}<code>",
2100 *item.name.as_ref().unwrap(),
2102 ConciseStability(&item.stability)));
2103 try!(render_method(w, item));
2104 try!(write!(w, "</code></h4>\n"));
2106 clean::TypedefItem(ref tydef) => {
2107 let name = item.name.as_ref().unwrap();
2108 try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>",
2111 ConciseStability(&item.stability)));
2112 try!(write!(w, "type {} = {}", name, tydef.type_));
2113 try!(write!(w, "</code></h4>\n"));
2115 clean::AssociatedTypeItem(ref typaram) => {
2116 let name = item.name.as_ref().unwrap();
2117 try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>",
2120 ConciseStability(&item.stability)));
2121 try!(assoc_type(w, item, typaram));
2122 try!(write!(w, "</code></h4>\n"));
2124 _ => panic!("can't make docs for trait item with name {:?}", item.name)
2126 match item.doc_value() {
2128 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
2131 Some(..) | None => Ok(())
2135 try!(write!(w, "<div class='impl-items'>"));
2136 for trait_item in &i.impl_.items {
2137 try!(doctraititem(w, trait_item, true));
2140 fn render_default_methods(w: &mut fmt::Formatter,
2142 i: &clean::Impl) -> fmt::Result {
2143 for trait_item in &t.items {
2144 let n = trait_item.item().name.clone();
2145 match i.items.iter().find(|m| { m.name == n }) {
2146 Some(..) => continue,
2150 try!(doctraititem(w, trait_item.item(), false));
2155 // If we've implemented a trait, then also emit documentation for all
2156 // default methods which weren't overridden in the implementation block.
2157 // FIXME: this also needs to be done for associated types, whenever defaults
2159 match i.impl_.trait_ {
2160 Some(clean::ResolvedPath { did, .. }) => {
2162 match cache().traits.get(&did) {
2163 Some(t) => try!(render_default_methods(w, t, &i.impl_)),
2169 Some(..) | None => {}
2171 try!(write!(w, "</div>"));
2175 fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
2176 t: &clean::Typedef) -> fmt::Result {
2177 try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
2178 it.name.as_ref().unwrap(),
2185 impl<'a> fmt::Display for Sidebar<'a> {
2186 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2189 try!(write!(fmt, "<p class='location'>"));
2190 let len = cx.current.len() - if it.is_mod() {1} else {0};
2191 for (i, name) in cx.current.iter().take(len).enumerate() {
2193 try!(write!(fmt, "::<wbr>"));
2195 try!(write!(fmt, "<a href='{}index.html'>{}</a>",
2196 &cx.root_path[..(cx.current.len() - i - 1) * 3],
2199 try!(write!(fmt, "</p>"));
2201 fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
2202 cur: &clean::Item, cx: &Context) -> fmt::Result {
2203 let items = match cx.sidebar.get(short) {
2204 Some(items) => items,
2205 None => return Ok(())
2207 try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
2208 for &NameDoc(ref name, ref doc) in items {
2209 let curty = shortty(cur).to_static_str();
2210 let class = if cur.name.as_ref().unwrap() == name &&
2211 short == curty { "current" } else { "" };
2212 try!(write!(w, "<a class='{ty} {class}' href='{href}{path}' \
2213 title='{title}'>{name}</a>",
2216 href = if curty == "mod" {"../"} else {""},
2217 path = if short == "mod" {
2218 format!("{}/index.html", name)
2220 format!("{}.{}.html", short, name)
2222 title = Escape(doc.as_ref().unwrap()),
2225 try!(write!(w, "</div>"));
2229 try!(block(fmt, "mod", "Modules", it, cx));
2230 try!(block(fmt, "struct", "Structs", it, cx));
2231 try!(block(fmt, "enum", "Enums", it, cx));
2232 try!(block(fmt, "trait", "Traits", it, cx));
2233 try!(block(fmt, "fn", "Functions", it, cx));
2234 try!(block(fmt, "macro", "Macros", it, cx));
2239 impl<'a> fmt::Display for Source<'a> {
2240 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2241 let Source(s) = *self;
2242 let lines = s.lines().count();
2244 let mut tmp = lines;
2249 try!(write!(fmt, "<pre class=\"line-numbers\">"));
2250 for i in 1..lines + 1 {
2251 try!(write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols));
2253 try!(write!(fmt, "</pre>"));
2254 try!(write!(fmt, "{}", highlight::highlight(s, None, None)));
2259 fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
2260 t: &clean::Macro) -> fmt::Result {
2261 try!(w.write_str(&highlight::highlight(&t.source,
2267 fn item_primitive(w: &mut fmt::Formatter,
2269 _p: &clean::PrimitiveType) -> fmt::Result {
2270 try!(document(w, it));
2271 render_methods(w, it)
2274 fn get_basic_keywords() -> &'static str {
2275 "rust, rustlang, rust-lang"
2278 fn make_item_keywords(it: &clean::Item) -> String {
2279 format!("{}, {}", get_basic_keywords(), it.name.as_ref().unwrap())
2282 pub fn cache() -> Arc<Cache> {
2283 CACHE_KEY.with(|c| c.borrow().clone())