]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render.rs
Merge pull request #20510 from tshepang/patch-6
[rust.git] / src / librustdoc / html / render.rs
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.
4 //
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.
10
11 //! Rustdoc's HTML Rendering module
12 //!
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.
17 //!
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
24 //! rendered.
25 //!
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).
30 //!
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::*;
36
37 use std::cell::RefCell;
38 use std::cmp::Ordering::{self, Less, Greater, Equal};
39 use std::collections::hash_map::Entry::{Occupied, Vacant};
40 use std::collections::{HashMap, HashSet};
41 use std::default::Default;
42 use std::fmt;
43 use std::io::fs::PathExtensions;
44 use std::io::{fs, File, BufferedWriter, BufferedReader};
45 use std::io;
46 use std::iter::repeat;
47 use std::str;
48 use std::sync::Arc;
49
50 use externalfiles::ExternalHtml;
51
52 use serialize::json;
53 use serialize::json::ToJson;
54 use syntax::ast;
55 use syntax::ast_util;
56 use rustc::util::nodemap::NodeSet;
57
58 use clean;
59 use doctree;
60 use fold::DocFolder;
61 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability};
62 use html::format::{ConciseStability, TyParamBounds, WhereClause};
63 use html::highlight;
64 use html::item_type::ItemType;
65 use html::layout;
66 use html::markdown::Markdown;
67 use html::markdown;
68 use stability_summary;
69
70 /// Major driving force in all rustdoc rendering. This contains information
71 /// about where in the tree-like hierarchy rendering is occurring and controls
72 /// how the current page is being rendered.
73 ///
74 /// It is intended that this context is a lightweight object which can be fairly
75 /// easily cloned because it is cloned per work-job (about once per item in the
76 /// rustdoc tree).
77 #[derive(Clone)]
78 pub struct Context {
79     /// Current hierarchy of components leading down to what's currently being
80     /// rendered
81     pub current: Vec<String>,
82     /// String representation of how to get back to the root path of the 'doc/'
83     /// folder in terms of a relative URL.
84     pub root_path: String,
85     /// The path to the crate root source minus the file name.
86     /// Used for simplifying paths to the highlighted source code files.
87     pub src_root: Path,
88     /// The current destination folder of where HTML artifacts should be placed.
89     /// This changes as the context descends into the module hierarchy.
90     pub dst: Path,
91     /// This describes the layout of each page, and is not modified after
92     /// creation of the context (contains info like the favicon and added html).
93     pub layout: layout::Layout,
94     /// This map is a list of what should be displayed on the sidebar of the
95     /// current page. The key is the section header (traits, modules,
96     /// functions), and the value is the list of containers belonging to this
97     /// header. This map will change depending on the surrounding context of the
98     /// page.
99     pub sidebar: HashMap<String, Vec<String>>,
100     /// This flag indicates whether [src] links should be generated or not. If
101     /// the source files are present in the html rendering, then this will be
102     /// `true`.
103     pub include_sources: bool,
104     /// A flag, which when turned off, will render pages which redirect to the
105     /// real location of an item. This is used to allow external links to
106     /// publicly reused items to redirect to the right location.
107     pub render_redirect_pages: bool,
108     /// All the passes that were run on this crate.
109     pub passes: HashSet<String>,
110 }
111
112 /// Indicates where an external crate can be found.
113 pub enum ExternalLocation {
114     /// Remote URL root of the external crate
115     Remote(String),
116     /// This external crate can be found in the local doc/ folder
117     Local,
118     /// The external crate could not be found.
119     Unknown,
120 }
121
122 /// Metadata about an implementor of a trait.
123 pub struct Implementor {
124     pub def_id: ast::DefId,
125     pub generics: clean::Generics,
126     pub trait_: clean::Type,
127     pub for_: clean::Type,
128     pub stability: Option<clean::Stability>,
129 }
130
131 /// Metadata about implementations for a type.
132 #[derive(Clone)]
133 pub struct Impl {
134     pub impl_: clean::Impl,
135     pub dox: Option<String>,
136     pub stability: Option<clean::Stability>,
137 }
138
139 /// This cache is used to store information about the `clean::Crate` being
140 /// rendered in order to provide more useful documentation. This contains
141 /// information like all implementors of a trait, all traits a type implements,
142 /// documentation for all known traits, etc.
143 ///
144 /// This structure purposefully does not implement `Clone` because it's intended
145 /// to be a fairly large and expensive structure to clone. Instead this adheres
146 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
147 /// rendering tasks.
148 #[derive(Default)]
149 pub struct Cache {
150     /// Mapping of typaram ids to the name of the type parameter. This is used
151     /// when pretty-printing a type (so pretty printing doesn't have to
152     /// painfully maintain a context like this)
153     pub typarams: HashMap<ast::DefId, String>,
154
155     /// Maps a type id to all known implementations for that type. This is only
156     /// recognized for intra-crate `ResolvedPath` types, and is used to print
157     /// out extra documentation on the page of an enum/struct.
158     ///
159     /// The values of the map are a list of implementations and documentation
160     /// found on that implementation.
161     pub impls: HashMap<ast::DefId, Vec<Impl>>,
162
163     /// Maintains a mapping of local crate node ids to the fully qualified name
164     /// and "short type description" of that node. This is used when generating
165     /// URLs when a type is being linked to. External paths are not located in
166     /// this map because the `External` type itself has all the information
167     /// necessary.
168     pub paths: HashMap<ast::DefId, (Vec<String>, ItemType)>,
169
170     /// Similar to `paths`, but only holds external paths. This is only used for
171     /// generating explicit hyperlinks to other crates.
172     pub external_paths: HashMap<ast::DefId, Vec<String>>,
173
174     /// This map contains information about all known traits of this crate.
175     /// Implementations of a crate should inherit the documentation of the
176     /// parent trait if no extra documentation is specified, and default methods
177     /// should show up in documentation about trait implementations.
178     pub traits: HashMap<ast::DefId, clean::Trait>,
179
180     /// When rendering traits, it's often useful to be able to list all
181     /// implementors of the trait, and this mapping is exactly, that: a mapping
182     /// of trait ids to the list of known implementors of the trait
183     pub implementors: HashMap<ast::DefId, Vec<Implementor>>,
184
185     /// Cache of where external crate documentation can be found.
186     pub extern_locations: HashMap<ast::CrateNum, ExternalLocation>,
187
188     /// Cache of where documentation for primitives can be found.
189     pub primitive_locations: HashMap<clean::PrimitiveType, ast::CrateNum>,
190
191     /// Set of definitions which have been inlined from external crates.
192     pub inlined: HashSet<ast::DefId>,
193
194     // Private fields only used when initially crawling a crate to build a cache
195
196     stack: Vec<String>,
197     parent_stack: Vec<ast::DefId>,
198     search_index: Vec<IndexItem>,
199     privmod: bool,
200     remove_priv: bool,
201     public_items: NodeSet,
202
203     // In rare case where a structure is defined in one module but implemented
204     // in another, if the implementing module is parsed before defining module,
205     // then the fully qualified name of the structure isn't presented in `paths`
206     // yet when its implementation methods are being indexed. Caches such methods
207     // and their parent id here and indexes them at the end of crate parsing.
208     orphan_methods: Vec<(ast::NodeId, clean::Item)>,
209 }
210
211 /// Helper struct to render all source code to HTML pages
212 struct SourceCollector<'a> {
213     cx: &'a mut Context,
214
215     /// Processed source-file paths
216     seen: HashSet<String>,
217     /// Root destination to place all HTML output into
218     dst: Path,
219 }
220
221 /// Wrapper struct to render the source code of a file. This will do things like
222 /// adding line numbers to the left-hand side.
223 struct Source<'a>(&'a str);
224
225 // Helper structs for rendering items/sidebars and carrying along contextual
226 // information
227
228 #[derive(Copy)]
229 struct Item<'a> {
230     cx: &'a Context,
231     item: &'a clean::Item,
232 }
233
234 struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
235
236 /// Struct representing one entry in the JS search index. These are all emitted
237 /// by hand to a large JS file at the end of cache-creation.
238 struct IndexItem {
239     ty: ItemType,
240     name: String,
241     path: String,
242     desc: String,
243     parent: Option<ast::DefId>,
244 }
245
246 // TLS keys used to carry information around during rendering.
247
248 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
249 thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> =
250                     RefCell::new(Vec::new()));
251
252 /// Generates the documentation for `crate` into the directory `dst`
253 pub fn run(mut krate: clean::Crate,
254            external_html: &ExternalHtml,
255            dst: Path,
256            passes: HashSet<String>) -> io::IoResult<()> {
257     let mut cx = Context {
258         dst: dst,
259         src_root: krate.src.dir_path(),
260         passes: passes,
261         current: Vec::new(),
262         root_path: String::new(),
263         sidebar: HashMap::new(),
264         layout: layout::Layout {
265             logo: "".to_string(),
266             favicon: "".to_string(),
267             external_html: external_html.clone(),
268             krate: krate.name.clone(),
269             playground_url: "".to_string(),
270         },
271         include_sources: true,
272         render_redirect_pages: false,
273     };
274
275     try!(mkdir(&cx.dst));
276
277     // Crawl the crate attributes looking for attributes which control how we're
278     // going to emit HTML
279     let default: &[_] = &[];
280     match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) {
281         Some(attrs) => {
282             for attr in attrs.iter() {
283                 match *attr {
284                     clean::NameValue(ref x, ref s)
285                             if "html_favicon_url" == *x => {
286                         cx.layout.favicon = s.to_string();
287                     }
288                     clean::NameValue(ref x, ref s)
289                             if "html_logo_url" == *x => {
290                         cx.layout.logo = s.to_string();
291                     }
292                     clean::NameValue(ref x, ref s)
293                             if "html_playground_url" == *x => {
294                         cx.layout.playground_url = s.to_string();
295                         markdown::PLAYGROUND_KRATE.with(|slot| {
296                             if slot.borrow().is_none() {
297                                 let name = krate.name.clone();
298                                 *slot.borrow_mut() = Some(Some(name));
299                             }
300                         });
301                     }
302                     clean::Word(ref x)
303                             if "html_no_source" == *x => {
304                         cx.include_sources = false;
305                     }
306                     _ => {}
307                 }
308             }
309         }
310         None => {}
311     }
312
313     // Crawl the crate to build various caches used for the output
314     let analysis = ::ANALYSISKEY.with(|a| a.clone());
315     let analysis = analysis.borrow();
316     let public_items = analysis.as_ref().map(|a| a.public_items.clone());
317     let public_items = public_items.unwrap_or(NodeSet::new());
318     let paths: HashMap<ast::DefId, (Vec<String>, ItemType)> =
319       analysis.as_ref().map(|a| {
320         let paths = a.external_paths.borrow_mut().take().unwrap();
321         paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))).collect()
322       }).unwrap_or(HashMap::new());
323     let mut cache = Cache {
324         impls: HashMap::new(),
325         external_paths: paths.iter().map(|(&k, v)| (k, v.0.clone()))
326                              .collect(),
327         paths: paths,
328         implementors: HashMap::new(),
329         stack: Vec::new(),
330         parent_stack: Vec::new(),
331         search_index: Vec::new(),
332         extern_locations: HashMap::new(),
333         primitive_locations: HashMap::new(),
334         remove_priv: cx.passes.contains("strip-private"),
335         privmod: false,
336         public_items: public_items,
337         orphan_methods: Vec::new(),
338         traits: analysis.as_ref().map(|a| {
339             a.external_traits.borrow_mut().take().unwrap()
340         }).unwrap_or(HashMap::new()),
341         typarams: analysis.as_ref().map(|a| {
342             a.external_typarams.borrow_mut().take().unwrap()
343         }).unwrap_or(HashMap::new()),
344         inlined: analysis.as_ref().map(|a| {
345             a.inlined.borrow_mut().take().unwrap()
346         }).unwrap_or(HashSet::new()),
347     };
348     cache.stack.push(krate.name.clone());
349     krate = cache.fold_crate(krate);
350
351     // Cache where all our extern crates are located
352     for &(n, ref e) in krate.externs.iter() {
353         cache.extern_locations.insert(n, extern_location(e, &cx.dst));
354         let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID };
355         cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
356     }
357
358     // Cache where all known primitives have their documentation located.
359     //
360     // Favor linking to as local extern as possible, so iterate all crates in
361     // reverse topological order.
362     for &(n, ref e) in krate.externs.iter().rev() {
363         for &prim in e.primitives.iter() {
364             cache.primitive_locations.insert(prim, n);
365         }
366     }
367     for &prim in krate.primitives.iter() {
368         cache.primitive_locations.insert(prim, ast::LOCAL_CRATE);
369     }
370
371     // Build our search index
372     let index = try!(build_index(&krate, &mut cache));
373
374     // Freeze the cache now that the index has been built. Put an Arc into TLS
375     // for future parallelization opportunities
376     let cache = Arc::new(cache);
377     CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
378     CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
379
380     try!(write_shared(&cx, &krate, &*cache, index));
381     let krate = try!(render_sources(&mut cx, krate));
382
383     // Crawl the crate, building a summary of the stability levels.
384     let summary = stability_summary::build(&krate);
385
386     // And finally render the whole crate's documentation
387     cx.krate(krate, summary)
388 }
389
390 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult<String> {
391     // Build the search index from the collected metadata
392     let mut nodeid_to_pathid = HashMap::new();
393     let mut pathid_to_nodeid = Vec::new();
394     {
395         let Cache { ref mut search_index,
396                     ref orphan_methods,
397                     ref mut paths, .. } = *cache;
398
399         // Attach all orphan methods to the type's definition if the type
400         // has since been learned.
401         for &(pid, ref item) in orphan_methods.iter() {
402             let did = ast_util::local_def(pid);
403             match paths.get(&did) {
404                 Some(&(ref fqp, _)) => {
405                     search_index.push(IndexItem {
406                         ty: shortty(item),
407                         name: item.name.clone().unwrap(),
408                         path: fqp[..fqp.len() - 1].connect("::"),
409                         desc: shorter(item.doc_value()).to_string(),
410                         parent: Some(did),
411                     });
412                 },
413                 None => {}
414             }
415         };
416
417         // Reduce `NodeId` in paths into smaller sequential numbers,
418         // and prune the paths that do not appear in the index.
419         for item in search_index.iter() {
420             match item.parent {
421                 Some(nodeid) => {
422                     if !nodeid_to_pathid.contains_key(&nodeid) {
423                         let pathid = pathid_to_nodeid.len();
424                         nodeid_to_pathid.insert(nodeid, pathid);
425                         pathid_to_nodeid.push(nodeid);
426                     }
427                 }
428                 None => {}
429             }
430         }
431         assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len());
432     }
433
434     // Collect the index into a string
435     let mut w = Vec::new();
436     try!(write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name));
437
438     let mut lastpath = "".to_string();
439     for (i, item) in cache.search_index.iter().enumerate() {
440         // Omit the path if it is same to that of the prior item.
441         let path;
442         if lastpath == item.path {
443             path = "";
444         } else {
445             lastpath = item.path.to_string();
446             path = item.path.as_slice();
447         };
448
449         if i > 0 {
450             try!(write!(&mut w, ","));
451         }
452         try!(write!(&mut w, r#"[{},"{}","{}",{}"#,
453                     item.ty as uint, item.name, path,
454                     item.desc.to_json().to_string()));
455         match item.parent {
456             Some(nodeid) => {
457                 let pathid = *nodeid_to_pathid.get(&nodeid).unwrap();
458                 try!(write!(&mut w, ",{}", pathid));
459             }
460             None => {}
461         }
462         try!(write!(&mut w, "]"));
463     }
464
465     try!(write!(&mut w, r#"],"paths":["#));
466
467     for (i, &did) in pathid_to_nodeid.iter().enumerate() {
468         let &(ref fqp, short) = cache.paths.get(&did).unwrap();
469         if i > 0 {
470             try!(write!(&mut w, ","));
471         }
472         try!(write!(&mut w, r#"[{},"{}"]"#,
473                     short as uint, *fqp.last().unwrap()));
474     }
475
476     try!(write!(&mut w, "]}};"));
477
478     Ok(String::from_utf8(w).unwrap())
479 }
480
481 fn write_shared(cx: &Context,
482                 krate: &clean::Crate,
483                 cache: &Cache,
484                 search_index: String) -> io::IoResult<()> {
485     // Write out the shared files. Note that these are shared among all rustdoc
486     // docs placed in the output directory, so this needs to be a synchronized
487     // operation with respect to all other rustdocs running around.
488     try!(mkdir(&cx.dst));
489     let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
490
491     // Add all the static files. These may already exist, but we just
492     // overwrite them anyway to make sure that they're fresh and up-to-date.
493     try!(write(cx.dst.join("jquery.js"),
494                include_bytes!("static/jquery-2.1.0.min.js")));
495     try!(write(cx.dst.join("main.js"), include_bytes!("static/main.js")));
496     try!(write(cx.dst.join("playpen.js"), include_bytes!("static/playpen.js")));
497     try!(write(cx.dst.join("main.css"), include_bytes!("static/main.css")));
498     try!(write(cx.dst.join("normalize.css"),
499                include_bytes!("static/normalize.css")));
500     try!(write(cx.dst.join("FiraSans-Regular.woff"),
501                include_bytes!("static/FiraSans-Regular.woff")));
502     try!(write(cx.dst.join("FiraSans-Medium.woff"),
503                include_bytes!("static/FiraSans-Medium.woff")));
504     try!(write(cx.dst.join("Heuristica-Italic.woff"),
505                include_bytes!("static/Heuristica-Italic.woff")));
506     try!(write(cx.dst.join("SourceSerifPro-Regular.woff"),
507                include_bytes!("static/SourceSerifPro-Regular.woff")));
508     try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
509                include_bytes!("static/SourceSerifPro-Bold.woff")));
510     try!(write(cx.dst.join("SourceCodePro-Regular.woff"),
511                include_bytes!("static/SourceCodePro-Regular.woff")));
512     try!(write(cx.dst.join("SourceCodePro-Semibold.woff"),
513                include_bytes!("static/SourceCodePro-Semibold.woff")));
514
515     fn collect(path: &Path, krate: &str,
516                key: &str) -> io::IoResult<Vec<String>> {
517         let mut ret = Vec::new();
518         if path.exists() {
519             for line in BufferedReader::new(File::open(path)).lines() {
520                 let line = try!(line);
521                 if !line.starts_with(key) {
522                     continue
523                 }
524                 if line.starts_with(
525                         format!("{}['{}']", key, krate).as_slice()) {
526                     continue
527                 }
528                 ret.push(line.to_string());
529             }
530         }
531         return Ok(ret);
532     }
533
534     // Update the search index
535     let dst = cx.dst.join("search-index.js");
536     let all_indexes = try!(collect(&dst, krate.name.as_slice(),
537                                    "searchIndex"));
538     let mut w = try!(File::create(&dst));
539     try!(writeln!(&mut w, "var searchIndex = {{}};"));
540     try!(writeln!(&mut w, "{}", search_index));
541     for index in all_indexes.iter() {
542         try!(writeln!(&mut w, "{}", *index));
543     }
544     try!(writeln!(&mut w, "initSearch(searchIndex);"));
545
546     // Update the list of all implementors for traits
547     let dst = cx.dst.join("implementors");
548     try!(mkdir(&dst));
549     for (&did, imps) in cache.implementors.iter() {
550         // Private modules can leak through to this phase of rustdoc, which
551         // could contain implementations for otherwise private types. In some
552         // rare cases we could find an implementation for an item which wasn't
553         // indexed, so we just skip this step in that case.
554         //
555         // FIXME: this is a vague explanation for why this can't be a `get`, in
556         //        theory it should be...
557         let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) {
558             Some(p) => p,
559             None => continue,
560         };
561
562         let mut mydst = dst.clone();
563         for part in remote_path[..remote_path.len() - 1].iter() {
564             mydst.push(part.as_slice());
565             try!(mkdir(&mydst));
566         }
567         mydst.push(format!("{}.{}.js",
568                            remote_item_type.to_static_str(),
569                            remote_path[remote_path.len() - 1]));
570         let all_implementors = try!(collect(&mydst, krate.name.as_slice(),
571                                             "implementors"));
572
573         try!(mkdir(&mydst.dir_path()));
574         let mut f = BufferedWriter::new(try!(File::create(&mydst)));
575         try!(writeln!(&mut f, "(function() {{var implementors = {{}};"));
576
577         for implementor in all_implementors.iter() {
578             try!(write!(&mut f, "{}", *implementor));
579         }
580
581         try!(write!(&mut f, r"implementors['{}'] = [", krate.name));
582         for imp in imps.iter() {
583             // If the trait and implementation are in the same crate, then
584             // there's no need to emit information about it (there's inlining
585             // going on). If they're in different crates then the crate defining
586             // the trait will be interested in our implementation.
587             if imp.def_id.krate == did.krate { continue }
588             try!(write!(&mut f, r#""{}impl{} {} for {}","#,
589                         ConciseStability(&imp.stability),
590                         imp.generics, imp.trait_, imp.for_));
591         }
592         try!(writeln!(&mut f, r"];"));
593         try!(writeln!(&mut f, "{}", r"
594             if (window.register_implementors) {
595                 window.register_implementors(implementors);
596             } else {
597                 window.pending_implementors = implementors;
598             }
599         "));
600         try!(writeln!(&mut f, r"}})()"));
601     }
602     Ok(())
603 }
604
605 fn render_sources(cx: &mut Context,
606                   krate: clean::Crate) -> io::IoResult<clean::Crate> {
607     info!("emitting source files");
608     let dst = cx.dst.join("src");
609     try!(mkdir(&dst));
610     let dst = dst.join(krate.name.as_slice());
611     try!(mkdir(&dst));
612     let mut folder = SourceCollector {
613         dst: dst,
614         seen: HashSet::new(),
615         cx: cx,
616     };
617     // skip all invalid spans
618     folder.seen.insert("".to_string());
619     Ok(folder.fold_crate(krate))
620 }
621
622 /// Writes the entire contents of a string to a destination, not attempting to
623 /// catch any errors.
624 fn write(dst: Path, contents: &[u8]) -> io::IoResult<()> {
625     File::create(&dst).write(contents)
626 }
627
628 /// Makes a directory on the filesystem, failing the task if an error occurs and
629 /// skipping if the directory already exists.
630 fn mkdir(path: &Path) -> io::IoResult<()> {
631     if !path.exists() {
632         fs::mkdir(path, io::USER_RWX)
633     } else {
634         Ok(())
635     }
636 }
637
638 /// Returns a documentation-level item type from the item.
639 fn shortty(item: &clean::Item) -> ItemType {
640     ItemType::from_item(item)
641 }
642
643 /// Takes a path to a source file and cleans the path to it. This canonicalizes
644 /// things like ".." to components which preserve the "top down" hierarchy of a
645 /// static HTML tree.
646 // FIXME (#9639): The closure should deal with &[u8] instead of &str
647 // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
648 fn clean_srcpath<F>(src_root: &Path, src: &[u8], mut f: F) where
649     F: FnMut(&str),
650 {
651     let p = Path::new(src);
652
653     // make it relative, if possible
654     let p = p.path_relative_from(src_root).unwrap_or(p);
655
656     if p.as_vec() != b"." {
657         for c in p.str_components().map(|x|x.unwrap()) {
658             if ".." == c {
659                 f("up");
660             } else {
661                 f(c.as_slice())
662             }
663         }
664     }
665 }
666
667 /// Attempts to find where an external crate is located, given that we're
668 /// rendering in to the specified source destination.
669 fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
670     // See if there's documentation generated into the local directory
671     let local_location = dst.join(e.name.as_slice());
672     if local_location.is_dir() {
673         return Local;
674     }
675
676     // Failing that, see if there's an attribute specifying where to find this
677     // external crate
678     for attr in e.attrs.iter() {
679         match *attr {
680             clean::List(ref x, ref list) if "doc" == *x => {
681                 for attr in list.iter() {
682                     match *attr {
683                         clean::NameValue(ref x, ref s)
684                                 if "html_root_url" == *x => {
685                             if s.ends_with("/") {
686                                 return Remote(s.to_string());
687                             }
688                             return Remote(format!("{}/", s));
689                         }
690                         _ => {}
691                     }
692                 }
693             }
694             _ => {}
695         }
696     }
697
698     // Well, at least we tried.
699     return Unknown;
700 }
701
702 impl<'a> DocFolder for SourceCollector<'a> {
703     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
704         // If we're including source files, and we haven't seen this file yet,
705         // then we need to render it out to the filesystem
706         if self.cx.include_sources && !self.seen.contains(&item.source.filename) {
707
708             // If it turns out that we couldn't read this file, then we probably
709             // can't read any of the files (generating html output from json or
710             // something like that), so just don't include sources for the
711             // entire crate. The other option is maintaining this mapping on a
712             // per-file basis, but that's probably not worth it...
713             self.cx
714                 .include_sources = match self.emit_source(item.source
715                                                               .filename
716                                                               .as_slice()) {
717                 Ok(()) => true,
718                 Err(e) => {
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");
723                     false
724                 }
725             };
726             self.seen.insert(item.source.filename.clone());
727         }
728
729         self.fold_item_recur(item)
730     }
731 }
732
733 impl<'a> SourceCollector<'a> {
734     /// Renders the given filename into its corresponding HTML source file.
735     fn emit_source(&mut self, filename: &str) -> io::IoResult<()> {
736         let p = Path::new(filename);
737
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() {
742             Ok(r) => r,
743             // macros from other libraries get special filenames which we can
744             // safely ignore
745             Err(..) if filename.starts_with("<") &&
746                        filename.ends_with("macros>") => return Ok(()),
747             Err(e) => return Err(e)
748         };
749         let contents = str::from_utf8(contents.as_slice()).unwrap();
750
751         // Remove the utf-8 BOM if any
752         let contents = if contents.starts_with("\u{feff}") {
753             contents.slice_from(3)
754         } else {
755             contents
756         };
757
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| {
762             cur.push(component);
763             mkdir(&cur).unwrap();
764             root_path.push_str("../");
765         });
766
767         let mut fname = p.filename().expect("source has no filename").to_vec();
768         fname.extend(".html".bytes());
769         cur.push(fname);
770         let mut w = BufferedWriter::new(try!(File::create(&cur)));
771
772         let title = format!("{} -- source", cur.filename_display());
773         let desc = format!("Source to the Rust file `{}`.", filename);
774         let page = layout::Page {
775             title: title.as_slice(),
776             ty: "source",
777             root_path: root_path.as_slice(),
778             description: desc.as_slice(),
779             keywords: get_basic_keywords(),
780         };
781         try!(layout::render(&mut w as &mut Writer, &self.cx.layout,
782                             &page, &(""), &Source(contents)));
783         try!(w.flush());
784         return Ok(());
785     }
786 }
787
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));
795                 prev
796             }
797             _ => self.privmod,
798         };
799
800         // Register any generics to their corresponding string. This is used
801         // when pretty-printing types
802         match item.inner {
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),
812             _ => {}
813         }
814
815         // Propagate a trait methods' documentation to all implementors of the
816         // trait
817         if let clean::TraitItem(ref t) = item.inner {
818             self.traits.insert(item.def_id, t.clone());
819         }
820
821         // Collect all the implementors of traits.
822         if let clean::ImplItem(ref i) = item.inner {
823             match i.trait_ {
824                 Some(clean::ResolvedPath{ did, .. }) => {
825                     let v = match self.implementors.entry(did) {
826                         Vacant(entry) => entry.set(Vec::with_capacity(1)),
827                         Occupied(entry) => entry.into_mut(),
828                     };
829                     v.push(Implementor {
830                         def_id: item.def_id,
831                         generics: i.generics.clone(),
832                         trait_: i.trait_.as_ref().unwrap().clone(),
833                         for_: i.for_.clone(),
834                         stability: item.stability.clone(),
835                     });
836                 }
837                 Some(..) | None => {}
838             }
839         }
840
841         // Index this method for searching later on
842         if let Some(ref s) = item.name {
843             let (parent, is_method) = match item.inner {
844                 clean::TyMethodItem(..) |
845                 clean::StructFieldItem(..) |
846                 clean::VariantItem(..) => {
847                     ((Some(*self.parent_stack.last().unwrap()),
848                       Some(self.stack[..self.stack.len() - 1])),
849                      false)
850                 }
851                 clean::MethodItem(..) => {
852                     if self.parent_stack.len() == 0 {
853                         ((None, None), false)
854                     } else {
855                         let last = self.parent_stack.last().unwrap();
856                         let did = *last;
857                         let path = match self.paths.get(&did) {
858                             Some(&(_, ItemType::Trait)) =>
859                                 Some(self.stack[..self.stack.len() - 1]),
860                             // The current stack not necessarily has correlation for
861                             // where the type was defined. On the other hand,
862                             // `paths` always has the right information if present.
863                             Some(&(ref fqp, ItemType::Struct)) |
864                             Some(&(ref fqp, ItemType::Enum)) =>
865                                 Some(fqp[..fqp.len() - 1]),
866                             Some(..) => Some(self.stack.as_slice()),
867                             None => None
868                         };
869                         ((Some(*last), path), true)
870                     }
871                 }
872                 _ => ((None, Some(self.stack.as_slice())), false)
873             };
874             let hidden_field = match item.inner {
875                 clean::StructFieldItem(clean::HiddenStructField) => true,
876                 _ => false
877             };
878
879             match parent {
880                 (parent, Some(path)) if is_method || (!self.privmod && !hidden_field) => {
881                     self.search_index.push(IndexItem {
882                         ty: shortty(&item),
883                         name: s.to_string(),
884                         path: path.connect("::").to_string(),
885                         desc: shorter(item.doc_value()).to_string(),
886                         parent: parent,
887                     });
888                 }
889                 (Some(parent), None) if is_method || (!self.privmod && !hidden_field)=> {
890                     if ast_util::is_local(parent) {
891                         // We have a parent, but we don't know where they're
892                         // defined yet. Wait for later to index this item.
893                         self.orphan_methods.push((parent.node, item.clone()))
894                     }
895                 }
896                 _ => {}
897             }
898         }
899
900         // Keep track of the fully qualified path for this item.
901         let pushed = if item.name.is_some() {
902             let n = item.name.as_ref().unwrap();
903             if n.len() > 0 {
904                 self.stack.push(n.to_string());
905                 true
906             } else { false }
907         } else { false };
908         match item.inner {
909             clean::StructItem(..) | clean::EnumItem(..) |
910             clean::TypedefItem(..) | clean::TraitItem(..) |
911             clean::FunctionItem(..) | clean::ModuleItem(..) |
912             clean::ForeignFunctionItem(..) if !self.privmod => {
913                 // Reexported items mean that the same id can show up twice
914                 // in the rustdoc ast that we're looking at. We know,
915                 // however, that a reexported item doesn't show up in the
916                 // `public_items` map, so we can skip inserting into the
917                 // paths map if there was already an entry present and we're
918                 // not a public item.
919                 let id = item.def_id.node;
920                 if !self.paths.contains_key(&item.def_id) ||
921                    !ast_util::is_local(item.def_id) ||
922                    self.public_items.contains(&id) {
923                     self.paths.insert(item.def_id,
924                                       (self.stack.clone(), shortty(&item)));
925                 }
926             }
927             // link variants to their parent enum because pages aren't emitted
928             // for each variant
929             clean::VariantItem(..) if !self.privmod => {
930                 let mut stack = self.stack.clone();
931                 stack.pop();
932                 self.paths.insert(item.def_id, (stack, ItemType::Enum));
933             }
934
935             clean::PrimitiveItem(..) if item.visibility.is_some() => {
936                 self.paths.insert(item.def_id, (self.stack.clone(),
937                                                 shortty(&item)));
938             }
939
940             _ => {}
941         }
942
943         // Maintain the parent stack
944         let parent_pushed = match item.inner {
945             clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
946                 self.parent_stack.push(item.def_id);
947                 true
948             }
949             clean::ImplItem(ref i) => {
950                 match i.for_ {
951                     clean::ResolvedPath{ did, .. } => {
952                         self.parent_stack.push(did);
953                         true
954                     }
955                     _ => false
956                 }
957             }
958             _ => false
959         };
960
961         // Once we've recursively found all the generics, then hoard off all the
962         // implementations elsewhere
963         let ret = match self.fold_item_recur(item) {
964             Some(item) => {
965                 match item {
966                     clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
967                         use clean::{Primitive, Vector, ResolvedPath, BorrowedRef};
968                         use clean::{FixedVector, Slice, Tuple, PrimitiveTuple};
969
970                         // extract relevant documentation for this impl
971                         let dox = match attrs.into_iter().find(|a| {
972                             match *a {
973                                 clean::NameValue(ref x, _)
974                                         if "doc" == *x => {
975                                     true
976                                 }
977                                 _ => false
978                             }
979                         }) {
980                             Some(clean::NameValue(_, dox)) => Some(dox),
981                             Some(..) | None => None,
982                         };
983
984                         // Figure out the id of this impl. This may map to a
985                         // primitive rather than always to a struct/enum.
986                         let did = match i.for_ {
987                             ResolvedPath { did, .. } => Some(did),
988
989                             // References to primitives are picked up as well to
990                             // recognize implementations for &str, this may not
991                             // be necessary in a DST world.
992                             Primitive(p) |
993                                 BorrowedRef { type_: box Primitive(p), ..} =>
994                             {
995                                 Some(ast_util::local_def(p.to_node_id()))
996                             }
997
998                             // In a DST world, we may only need
999                             // Vector/FixedVector, but for now we also pick up
1000                             // borrowed references
1001                             Vector(..) | FixedVector(..) |
1002                                 BorrowedRef{ type_: box Vector(..), ..  } |
1003                                 BorrowedRef{ type_: box FixedVector(..), .. } =>
1004                             {
1005                                 Some(ast_util::local_def(Slice.to_node_id()))
1006                             }
1007
1008                             Tuple(..) => {
1009                                 let id = PrimitiveTuple.to_node_id();
1010                                 Some(ast_util::local_def(id))
1011                             }
1012
1013                             _ => None,
1014                         };
1015
1016                         if let Some(did) = did {
1017                             let v = match self.impls.entry(did) {
1018                                 Vacant(entry) => entry.set(Vec::with_capacity(1)),
1019                                 Occupied(entry) => entry.into_mut(),
1020                             };
1021                             v.push(Impl {
1022                                 impl_: i,
1023                                 dox: dox,
1024                                 stability: item.stability.clone(),
1025                             });
1026                         }
1027
1028                         None
1029                     }
1030
1031                     i => Some(i),
1032                 }
1033             }
1034             i => i,
1035         };
1036
1037         if pushed { self.stack.pop().unwrap(); }
1038         if parent_pushed { self.parent_stack.pop().unwrap(); }
1039         self.privmod = orig_privmod;
1040         return ret;
1041     }
1042 }
1043
1044 impl<'a> Cache {
1045     fn generics(&mut self, generics: &clean::Generics) {
1046         for typ in generics.type_params.iter() {
1047             self.typarams.insert(typ.did, typ.name.clone());
1048         }
1049     }
1050 }
1051
1052 impl Context {
1053     /// Recurse in the directory structure and change the "root path" to make
1054     /// sure it always points to the top (relatively)
1055     fn recurse<T, F>(&mut self, s: String, f: F) -> T where
1056         F: FnOnce(&mut Context) -> T,
1057     {
1058         if s.len() == 0 {
1059             panic!("Unexpected empty destination: {}", self.current);
1060         }
1061         let prev = self.dst.clone();
1062         self.dst.push(s.as_slice());
1063         self.root_path.push_str("../");
1064         self.current.push(s);
1065
1066         info!("Recursing into {}", self.dst.display());
1067
1068         mkdir(&self.dst).unwrap();
1069         let ret = f(self);
1070
1071         info!("Recursed; leaving {}", self.dst.display());
1072
1073         // Go back to where we were at
1074         self.dst = prev;
1075         let len = self.root_path.len();
1076         self.root_path.truncate(len - 3);
1077         self.current.pop().unwrap();
1078
1079         return ret;
1080     }
1081
1082     /// Main method for rendering a crate.
1083     ///
1084     /// This currently isn't parallelized, but it'd be pretty easy to add
1085     /// parallelization to this function.
1086     fn krate(mut self, mut krate: clean::Crate,
1087              stability: stability_summary::ModuleSummary) -> io::IoResult<()> {
1088         let mut item = match krate.module.take() {
1089             Some(i) => i,
1090             None => return Ok(())
1091         };
1092         item.name = Some(krate.name);
1093
1094         // render stability dashboard
1095         try!(self.recurse(stability.name.clone(), |this| {
1096             let json_dst = &this.dst.join("stability.json");
1097             let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
1098             try!(write!(&mut json_out, "{}", json::as_json(&stability)));
1099
1100             let mut title = stability.name.clone();
1101             title.push_str(" - Stability dashboard");
1102             let desc = format!("API stability overview for the Rust `{}` crate.",
1103                                this.layout.krate);
1104             let page = layout::Page {
1105                 ty: "mod",
1106                 root_path: this.root_path.as_slice(),
1107                 title: title.as_slice(),
1108                 description: desc.as_slice(),
1109                 keywords: get_basic_keywords(),
1110             };
1111             let html_dst = &this.dst.join("stability.html");
1112             let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
1113             layout::render(&mut html_out, &this.layout, &page,
1114                            &Sidebar{ cx: this, item: &item },
1115                            &stability)
1116         }));
1117
1118         // render the crate documentation
1119         let mut work = vec!((self, item));
1120         loop {
1121             match work.pop() {
1122                 Some((mut cx, item)) => try!(cx.item(item, |cx, item| {
1123                     work.push((cx.clone(), item));
1124                 })),
1125                 None => break,
1126             }
1127         }
1128
1129         Ok(())
1130     }
1131
1132     /// Non-parallelized version of rendering an item. This will take the input
1133     /// item, render its contents, and then invoke the specified closure with
1134     /// all sub-items which need to be rendered.
1135     ///
1136     /// The rendering driver uses this closure to queue up more work.
1137     fn item<F>(&mut self, item: clean::Item, mut f: F) -> io::IoResult<()> where
1138         F: FnMut(&mut Context, clean::Item),
1139     {
1140         fn render(w: io::File, cx: &Context, it: &clean::Item,
1141                   pushname: bool) -> io::IoResult<()> {
1142             info!("Rendering an item to {}", w.path().display());
1143             // A little unfortunate that this is done like this, but it sure
1144             // does make formatting *a lot* nicer.
1145             CURRENT_LOCATION_KEY.with(|slot| {
1146                 *slot.borrow_mut() = cx.current.clone();
1147             });
1148
1149             let mut title = cx.current.connect("::");
1150             if pushname {
1151                 if title.len() > 0 {
1152                     title.push_str("::");
1153                 }
1154                 title.push_str(it.name.as_ref().unwrap().as_slice());
1155             }
1156             title.push_str(" - Rust");
1157             let tyname = shortty(it).to_static_str();
1158             let is_crate = match it.inner {
1159                 clean::ModuleItem(clean::Module { items: _, is_crate: true }) => true,
1160                 _ => false
1161             };
1162             let desc = if is_crate {
1163                 format!("API documentation for the Rust `{}` crate.",
1164                         cx.layout.krate)
1165             } else {
1166                 format!("API documentation for the Rust `{}` {} in crate `{}`.",
1167                         it.name.as_ref().unwrap(), tyname, cx.layout.krate)
1168             };
1169             let keywords = make_item_keywords(it);
1170             let page = layout::Page {
1171                 ty: tyname,
1172                 root_path: cx.root_path.as_slice(),
1173                 title: title.as_slice(),
1174                 description: desc.as_slice(),
1175                 keywords: keywords.as_slice(),
1176             };
1177
1178             markdown::reset_headers();
1179
1180             // We have a huge number of calls to write, so try to alleviate some
1181             // of the pain by using a buffered writer instead of invoking the
1182             // write syscall all the time.
1183             let mut writer = BufferedWriter::new(w);
1184             if !cx.render_redirect_pages {
1185                 try!(layout::render(&mut writer, &cx.layout, &page,
1186                                     &Sidebar{ cx: cx, item: it },
1187                                     &Item{ cx: cx, item: it }));
1188             } else {
1189                 let mut url = repeat("../").take(cx.current.len())
1190                                            .collect::<String>();
1191                 match cache().paths.get(&it.def_id) {
1192                     Some(&(ref names, _)) => {
1193                         for name in names[..names.len() - 1].iter() {
1194                             url.push_str(name.as_slice());
1195                             url.push_str("/");
1196                         }
1197                         url.push_str(item_path(it).as_slice());
1198                         try!(layout::redirect(&mut writer, url.as_slice()));
1199                     }
1200                     None => {}
1201                 }
1202             }
1203             writer.flush()
1204         }
1205
1206         // Private modules may survive the strip-private pass if they
1207         // contain impls for public types. These modules can also
1208         // contain items such as publicly reexported structures.
1209         //
1210         // External crates will provide links to these structures, so
1211         // these modules are recursed into, but not rendered normally (a
1212         // flag on the context).
1213         if !self.render_redirect_pages {
1214             self.render_redirect_pages = self.ignore_private_item(&item);
1215         }
1216
1217         match item.inner {
1218             // modules are special because they add a namespace. We also need to
1219             // recurse into the items of the module as well.
1220             clean::ModuleItem(..) => {
1221                 let name = item.name.as_ref().unwrap().to_string();
1222                 let mut item = Some(item);
1223                 self.recurse(name, |this| {
1224                     let item = item.take().unwrap();
1225                     let dst = this.dst.join("index.html");
1226                     let dst = try!(File::create(&dst));
1227                     try!(render(dst, this, &item, false));
1228
1229                     let m = match item.inner {
1230                         clean::ModuleItem(m) => m,
1231                         _ => unreachable!()
1232                     };
1233                     this.sidebar = this.build_sidebar(&m);
1234                     for item in m.items.into_iter() {
1235                         f(this,item);
1236                     }
1237                     Ok(())
1238                 })
1239             }
1240
1241             // Things which don't have names (like impls) don't get special
1242             // pages dedicated to them.
1243             _ if item.name.is_some() => {
1244                 let dst = self.dst.join(item_path(&item));
1245                 let dst = try!(File::create(&dst));
1246                 render(dst, self, &item, true)
1247             }
1248
1249             _ => Ok(())
1250         }
1251     }
1252
1253     fn build_sidebar(&self, m: &clean::Module) -> HashMap<String, Vec<String>> {
1254         let mut map = HashMap::new();
1255         for item in m.items.iter() {
1256             if self.ignore_private_item(item) { continue }
1257
1258             // avoid putting foreign items to the sidebar.
1259             if let &clean::ForeignFunctionItem(..) = &item.inner { continue }
1260             if let &clean::ForeignStaticItem(..) = &item.inner { continue }
1261
1262             let short = shortty(item).to_static_str();
1263             let myname = match item.name {
1264                 None => continue,
1265                 Some(ref s) => s.to_string(),
1266             };
1267             let v = match map.entry(short.to_string()) {
1268                 Vacant(entry) => entry.set(Vec::with_capacity(1)),
1269                 Occupied(entry) => entry.into_mut(),
1270             };
1271             v.push(myname);
1272         }
1273
1274         for (_, items) in map.iter_mut() {
1275             items.sort();
1276         }
1277         return map;
1278     }
1279
1280     fn ignore_private_item(&self, it: &clean::Item) -> bool {
1281         match it.inner {
1282             clean::ModuleItem(ref m) => {
1283                 (m.items.len() == 0 && it.doc_value().is_none()) ||
1284                 (self.passes.contains("strip-private") && it.visibility != Some(ast::Public))
1285             }
1286             clean::PrimitiveItem(..) => it.visibility != Some(ast::Public),
1287             _ => false,
1288         }
1289     }
1290 }
1291
1292 impl<'a> Item<'a> {
1293     fn ismodule(&self) -> bool {
1294         match self.item.inner {
1295             clean::ModuleItem(..) => true, _ => false
1296         }
1297     }
1298
1299     /// Generate a url appropriate for an `href` attribute back to the source of
1300     /// this item.
1301     ///
1302     /// The url generated, when clicked, will redirect the browser back to the
1303     /// original source code.
1304     ///
1305     /// If `None` is returned, then a source link couldn't be generated. This
1306     /// may happen, for example, with externally inlined items where the source
1307     /// of their crate documentation isn't known.
1308     fn href(&self, cx: &Context) -> Option<String> {
1309         // If this item is part of the local crate, then we're guaranteed to
1310         // know the span, so we plow forward and generate a proper url. The url
1311         // has anchors for the line numbers that we're linking to.
1312         if ast_util::is_local(self.item.def_id) {
1313             let mut path = Vec::new();
1314             clean_srcpath(&cx.src_root, self.item.source.filename.as_bytes(),
1315                           |component| {
1316                 path.push(component.to_string());
1317             });
1318             let href = if self.item.source.loline == self.item.source.hiline {
1319                 format!("{}", self.item.source.loline)
1320             } else {
1321                 format!("{}-{}",
1322                         self.item.source.loline,
1323                         self.item.source.hiline)
1324             };
1325             Some(format!("{root}src/{krate}/{path}.html#{href}",
1326                          root = self.cx.root_path,
1327                          krate = self.cx.layout.krate,
1328                          path = path.connect("/"),
1329                          href = href))
1330
1331         // If this item is not part of the local crate, then things get a little
1332         // trickier. We don't actually know the span of the external item, but
1333         // we know that the documentation on the other end knows the span!
1334         //
1335         // In this case, we generate a link to the *documentation* for this type
1336         // in the original crate. There's an extra URL parameter which says that
1337         // we want to go somewhere else, and the JS on the destination page will
1338         // pick it up and instantly redirect the browser to the source code.
1339         //
1340         // If we don't know where the external documentation for this crate is
1341         // located, then we return `None`.
1342         } else {
1343             let cache = cache();
1344             let path = &cache.external_paths[self.item.def_id];
1345             let root = match cache.extern_locations[self.item.def_id.krate] {
1346                 Remote(ref s) => s.to_string(),
1347                 Local => self.cx.root_path.clone(),
1348                 Unknown => return None,
1349             };
1350             Some(format!("{root}{path}/{file}?gotosrc={goto}",
1351                          root = root,
1352                          path = path.slice_to(path.len() - 1).connect("/"),
1353                          file = item_path(self.item),
1354                          goto = self.item.def_id.node))
1355         }
1356     }
1357 }
1358
1359
1360
1361 impl<'a> fmt::Show for Item<'a> {
1362     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1363         // Write the breadcrumb trail header for the top
1364         try!(write!(fmt, "\n<h1 class='fqn'><span class='in-band'>"));
1365         match self.item.inner {
1366             clean::ModuleItem(ref m) => if m.is_crate {
1367                     try!(write!(fmt, "Crate "));
1368                 } else {
1369                     try!(write!(fmt, "Module "));
1370                 },
1371             clean::FunctionItem(..) => try!(write!(fmt, "Function ")),
1372             clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
1373             clean::StructItem(..) => try!(write!(fmt, "Struct ")),
1374             clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
1375             clean::PrimitiveItem(..) => try!(write!(fmt, "Primitive Type ")),
1376             _ => {}
1377         }
1378         let is_primitive = match self.item.inner {
1379             clean::PrimitiveItem(..) => true,
1380             _ => false,
1381         };
1382         if !is_primitive {
1383             let cur = self.cx.current.as_slice();
1384             let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
1385             for (i, component) in cur.iter().enumerate().take(amt) {
1386                 try!(write!(fmt, "<a href='{}index.html'>{}</a>::<wbr>",
1387                             repeat("../").take(cur.len() - i - 1)
1388                                          .collect::<String>(),
1389                             component.as_slice()));
1390             }
1391         }
1392         try!(write!(fmt, "<a class='{}' href=''>{}</a>",
1393                     shortty(self.item), self.item.name.as_ref().unwrap().as_slice()));
1394
1395         // Write stability level
1396         try!(write!(fmt, "<wbr>{}", Stability(&self.item.stability)));
1397
1398         try!(write!(fmt, "</span>")); // in-band
1399         // Links to out-of-band information, i.e. src and stability dashboard
1400         try!(write!(fmt, "<span class='out-of-band'>"));
1401
1402         // Write stability dashboard link
1403         match self.item.inner {
1404             clean::ModuleItem(ref m) if m.is_crate => {
1405                 try!(write!(fmt, "<a href='stability.html'>[stability]</a> "));
1406             }
1407             _ => {}
1408         };
1409
1410         try!(write!(fmt,
1411         r##"<span id='render-detail'>
1412             <a id="collapse-all" href="#">[-]
1413             </a>&nbsp;<a id="expand-all" href="#">[+]</a>
1414         </span>"##));
1415
1416         // Write `src` tag
1417         //
1418         // When this item is part of a `pub use` in a downstream crate, the
1419         // [src] link in the downstream documentation will actually come back to
1420         // this page, and this link will be auto-clicked. The `id` attribute is
1421         // used to find the link to auto-click.
1422         if self.cx.include_sources && !is_primitive {
1423             match self.href(self.cx) {
1424                 Some(l) => {
1425                     try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
1426                                 self.item.def_id.node, l));
1427                 }
1428                 None => {}
1429             }
1430         }
1431
1432         try!(write!(fmt, "</span>")); // out-of-band
1433
1434         try!(write!(fmt, "</h1>\n"));
1435
1436         match self.item.inner {
1437             clean::ModuleItem(ref m) => {
1438                 item_module(fmt, self.cx, self.item, m.items.as_slice())
1439             }
1440             clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
1441                 item_function(fmt, self.item, f),
1442             clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
1443             clean::StructItem(ref s) => item_struct(fmt, self.item, s),
1444             clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
1445             clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
1446             clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
1447             clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p),
1448             clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
1449                 item_static(fmt, self.item, i),
1450             clean::ConstantItem(ref c) => item_constant(fmt, self.item, c),
1451             _ => Ok(())
1452         }
1453     }
1454 }
1455
1456 fn item_path(item: &clean::Item) -> String {
1457     match item.inner {
1458         clean::ModuleItem(..) => {
1459             format!("{}/index.html", item.name.as_ref().unwrap())
1460         }
1461         _ => {
1462             format!("{}.{}.html",
1463                     shortty(item).to_static_str(),
1464                     *item.name.as_ref().unwrap())
1465         }
1466     }
1467 }
1468
1469 fn full_path(cx: &Context, item: &clean::Item) -> String {
1470     let mut s = cx.current.connect("::");
1471     s.push_str("::");
1472     s.push_str(item.name.as_ref().unwrap().as_slice());
1473     return s
1474 }
1475
1476 fn shorter<'a>(s: Option<&'a str>) -> &'a str {
1477     match s {
1478         Some(s) => match s.find_str("\n\n") {
1479             Some(pos) => s.slice_to(pos),
1480             None => s,
1481         },
1482         None => ""
1483     }
1484 }
1485
1486 fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
1487     match item.doc_value() {
1488         Some(s) => {
1489             try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1490         }
1491         None => {}
1492     }
1493     Ok(())
1494 }
1495
1496 fn item_module(w: &mut fmt::Formatter, cx: &Context,
1497                item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
1498     try!(document(w, item));
1499
1500     let mut indices = range(0, items.len()).filter(|i| {
1501         !cx.ignore_private_item(&items[*i])
1502     }).collect::<Vec<uint>>();
1503
1504     // the order of item types in the listing
1505     fn reorder(ty: ItemType) -> u8 {
1506         match ty {
1507             ItemType::ViewItem        => 0,
1508             ItemType::Primitive       => 1,
1509             ItemType::Module          => 2,
1510             ItemType::Macro           => 3,
1511             ItemType::Struct          => 4,
1512             ItemType::Enum            => 5,
1513             ItemType::Constant        => 6,
1514             ItemType::Static          => 7,
1515             ItemType::Trait           => 8,
1516             ItemType::Function        => 9,
1517             ItemType::Typedef         => 10,
1518             _                         => 11 + ty as u8,
1519         }
1520     }
1521
1522     fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
1523         let ty1 = shortty(i1);
1524         let ty2 = shortty(i2);
1525         if ty1 == ty2 {
1526             return i1.name.cmp(&i2.name);
1527         }
1528
1529         let tycmp = reorder(ty1).cmp(&reorder(ty2));
1530         if let Equal = tycmp {
1531             // for reexports, `extern crate` takes precedence.
1532             match (&i1.inner, &i2.inner) {
1533                 (&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => {
1534                     match (&a.inner, &b.inner) {
1535                         (&clean::ExternCrate(..), _) => return Less,
1536                         (_, &clean::ExternCrate(..)) => return Greater,
1537                         _ => {}
1538                     }
1539                 }
1540                 (_, _) => {}
1541             }
1542
1543             idx1.cmp(&idx2)
1544         } else {
1545             tycmp
1546         }
1547     }
1548
1549     indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
1550
1551     debug!("{}", indices);
1552     let mut curty = None;
1553     for &idx in indices.iter() {
1554         let myitem = &items[idx];
1555
1556         let myty = Some(shortty(myitem));
1557         if myty != curty {
1558             if curty.is_some() {
1559                 try!(write!(w, "</table>"));
1560             }
1561             curty = myty;
1562             let (short, name) = match myty.unwrap() {
1563                 ItemType::Module          => ("modules", "Modules"),
1564                 ItemType::Struct          => ("structs", "Structs"),
1565                 ItemType::Enum            => ("enums", "Enums"),
1566                 ItemType::Function        => ("functions", "Functions"),
1567                 ItemType::Typedef         => ("types", "Type Definitions"),
1568                 ItemType::Static          => ("statics", "Statics"),
1569                 ItemType::Constant        => ("constants", "Constants"),
1570                 ItemType::Trait           => ("traits", "Traits"),
1571                 ItemType::Impl            => ("impls", "Implementations"),
1572                 ItemType::ViewItem        => ("reexports", "Reexports"),
1573                 ItemType::TyMethod        => ("tymethods", "Type Methods"),
1574                 ItemType::Method          => ("methods", "Methods"),
1575                 ItemType::StructField     => ("fields", "Struct Fields"),
1576                 ItemType::Variant         => ("variants", "Variants"),
1577                 ItemType::Macro           => ("macros", "Macros"),
1578                 ItemType::Primitive       => ("primitives", "Primitive Types"),
1579                 ItemType::AssociatedType  => ("associated-types", "Associated Types"),
1580             };
1581             try!(write!(w,
1582                         "<h2 id='{id}' class='section-header'>\
1583                         <a href=\"#{id}\">{name}</a></h2>\n<table>",
1584                         id = short, name = name));
1585         }
1586
1587         match myitem.inner {
1588             clean::ViewItemItem(ref item) => {
1589                 match item.inner {
1590                     clean::ExternCrate(ref name, ref src, _) => {
1591                         match *src {
1592                             Some(ref src) =>
1593                                 try!(write!(w, "<tr><td><code>extern crate \"{}\" as {}",
1594                                             src.as_slice(),
1595                                             name.as_slice())),
1596                             None =>
1597                                 try!(write!(w, "<tr><td><code>extern crate {}",
1598                                             name.as_slice())),
1599                         }
1600                         try!(write!(w, ";</code></td></tr>"));
1601                     }
1602
1603                     clean::Import(ref import) => {
1604                         try!(write!(w, "<tr><td><code>{}{}</code></td></tr>",
1605                                       VisSpace(myitem.visibility),
1606                                       *import));
1607                     }
1608                 }
1609
1610             }
1611
1612             _ => {
1613                 if myitem.name.is_none() { continue }
1614                 try!(write!(w, "
1615                     <tr>
1616                         <td>{stab}<a class='{class}' href='{href}'
1617                                title='{title}'>{}</a></td>
1618                         <td class='docblock short'>{}</td>
1619                     </tr>
1620                 ",
1621                 *myitem.name.as_ref().unwrap(),
1622                 Markdown(shorter(myitem.doc_value())),
1623                 class = shortty(myitem),
1624                 href = item_path(myitem),
1625                 title = full_path(cx, myitem),
1626                 stab = ConciseStability(&myitem.stability)));
1627             }
1628         }
1629     }
1630
1631     write!(w, "</table>")
1632 }
1633
1634 struct Initializer<'a>(&'a str);
1635 impl<'a> fmt::Show for Initializer<'a> {
1636     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1637         let Initializer(s) = *self;
1638         if s.len() == 0 { return Ok(()); }
1639         try!(write!(f, "<code> = </code>"));
1640         write!(f, "<code>{}</code>", s.as_slice())
1641     }
1642 }
1643
1644 fn item_constant(w: &mut fmt::Formatter, it: &clean::Item,
1645                  c: &clean::Constant) -> fmt::Result {
1646     try!(write!(w, "<pre class='rust const'>{vis}const \
1647                     {name}: {typ}{init}</pre>",
1648            vis = VisSpace(it.visibility),
1649            name = it.name.as_ref().unwrap().as_slice(),
1650            typ = c.type_,
1651            init = Initializer(c.expr.as_slice())));
1652     document(w, it)
1653 }
1654
1655 fn item_static(w: &mut fmt::Formatter, it: &clean::Item,
1656                s: &clean::Static) -> fmt::Result {
1657     try!(write!(w, "<pre class='rust static'>{vis}static {mutability}\
1658                     {name}: {typ}{init}</pre>",
1659            vis = VisSpace(it.visibility),
1660            mutability = MutableSpace(s.mutability),
1661            name = it.name.as_ref().unwrap().as_slice(),
1662            typ = s.type_,
1663            init = Initializer(s.expr.as_slice())));
1664     document(w, it)
1665 }
1666
1667 fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
1668                  f: &clean::Function) -> fmt::Result {
1669     try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}fn \
1670                     {name}{generics}{decl}{where_clause}</pre>",
1671            vis = VisSpace(it.visibility),
1672            unsafety = UnsafetySpace(f.unsafety),
1673            name = it.name.as_ref().unwrap().as_slice(),
1674            generics = f.generics,
1675            where_clause = WhereClause(&f.generics),
1676            decl = f.decl));
1677     document(w, it)
1678 }
1679
1680 fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1681               t: &clean::Trait) -> fmt::Result {
1682     let mut bounds = String::new();
1683     if t.bounds.len() > 0 {
1684         if bounds.len() > 0 {
1685             bounds.push(' ');
1686         }
1687         bounds.push_str(": ");
1688         for (i, p) in t.bounds.iter().enumerate() {
1689             if i > 0 { bounds.push_str(" + "); }
1690             bounds.push_str(format!("{}", *p).as_slice());
1691         }
1692     }
1693
1694     // Output the trait definition
1695     try!(write!(w, "<pre class='rust trait'>{}{}trait {}{}{}{} ",
1696                   VisSpace(it.visibility),
1697                   UnsafetySpace(t.unsafety),
1698                   it.name.as_ref().unwrap().as_slice(),
1699                   t.generics,
1700                   bounds,
1701                   WhereClause(&t.generics)));
1702
1703     let types = t.items.iter().filter(|m| m.is_type()).collect::<Vec<_>>();
1704     let required = t.items.iter().filter(|m| m.is_req()).collect::<Vec<_>>();
1705     let provided = t.items.iter().filter(|m| m.is_def()).collect::<Vec<_>>();
1706
1707     if t.items.len() == 0 {
1708         try!(write!(w, "{{ }}"));
1709     } else {
1710         try!(write!(w, "{{\n"));
1711         for t in types.iter() {
1712             try!(write!(w, "    "));
1713             try!(render_method(w, t.item()));
1714             try!(write!(w, ";\n"));
1715         }
1716         if types.len() > 0 && required.len() > 0 {
1717             try!(w.write_str("\n"));
1718         }
1719         for m in required.iter() {
1720             try!(write!(w, "    "));
1721             try!(render_method(w, m.item()));
1722             try!(write!(w, ";\n"));
1723         }
1724         if required.len() > 0 && provided.len() > 0 {
1725             try!(w.write_str("\n"));
1726         }
1727         for m in provided.iter() {
1728             try!(write!(w, "    "));
1729             try!(render_method(w, m.item()));
1730             try!(write!(w, " {{ ... }}\n"));
1731         }
1732         try!(write!(w, "}}"));
1733     }
1734     try!(write!(w, "</pre>"));
1735
1736     // Trait documentation
1737     try!(document(w, it));
1738
1739     fn trait_item(w: &mut fmt::Formatter, m: &clean::TraitMethod)
1740                   -> fmt::Result {
1741         try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>",
1742                     shortty(m.item()),
1743                     *m.item().name.as_ref().unwrap(),
1744                     ConciseStability(&m.item().stability)));
1745         try!(render_method(w, m.item()));
1746         try!(write!(w, "</code></h3>"));
1747         try!(document(w, m.item()));
1748         Ok(())
1749     }
1750
1751     if types.len() > 0 {
1752         try!(write!(w, "
1753             <h2 id='associated-types'>Associated Types</h2>
1754             <div class='methods'>
1755         "));
1756         for t in types.iter() {
1757             try!(trait_item(w, *t));
1758         }
1759         try!(write!(w, "</div>"));
1760     }
1761
1762     // Output the documentation for each function individually
1763     if required.len() > 0 {
1764         try!(write!(w, "
1765             <h2 id='required-methods'>Required Methods</h2>
1766             <div class='methods'>
1767         "));
1768         for m in required.iter() {
1769             try!(trait_item(w, *m));
1770         }
1771         try!(write!(w, "</div>"));
1772     }
1773     if provided.len() > 0 {
1774         try!(write!(w, "
1775             <h2 id='provided-methods'>Provided Methods</h2>
1776             <div class='methods'>
1777         "));
1778         for m in provided.iter() {
1779             try!(trait_item(w, *m));
1780         }
1781         try!(write!(w, "</div>"));
1782     }
1783
1784     let cache = cache();
1785     try!(write!(w, "
1786         <h2 id='implementors'>Implementors</h2>
1787         <ul class='item-list' id='implementors-list'>
1788     "));
1789     match cache.implementors.get(&it.def_id) {
1790         Some(implementors) => {
1791             for i in implementors.iter() {
1792                 try!(writeln!(w, "<li>{}<code>impl{} {} for {}{}</code></li>",
1793                               ConciseStability(&i.stability),
1794                               i.generics, i.trait_, i.for_, WhereClause(&i.generics)));
1795             }
1796         }
1797         None => {}
1798     }
1799     try!(write!(w, "</ul>"));
1800     try!(write!(w, r#"<script type="text/javascript" async
1801                               src="{root_path}/implementors/{path}/{ty}.{name}.js">
1802                       </script>"#,
1803                 root_path = repeat("..").take(cx.current.len()).collect::<Vec<_>>().connect("/"),
1804                 path = if ast_util::is_local(it.def_id) {
1805                     cx.current.connect("/")
1806                 } else {
1807                     let path = &cache.external_paths[it.def_id];
1808                     path.slice_to(path.len() - 1).connect("/")
1809                 },
1810                 ty = shortty(it).to_static_str(),
1811                 name = *it.name.as_ref().unwrap()));
1812     Ok(())
1813 }
1814
1815 fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
1816               typ: &clean::TyParam) -> fmt::Result {
1817     try!(write!(w, "type {}", it.name.as_ref().unwrap()));
1818     if typ.bounds.len() > 0 {
1819         try!(write!(w, ": {}", TyParamBounds(&*typ.bounds)))
1820     }
1821     if let Some(ref default) = typ.default {
1822         try!(write!(w, " = {}", default));
1823     }
1824     Ok(())
1825 }
1826
1827 fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
1828     fn method(w: &mut fmt::Formatter, it: &clean::Item, unsafety: ast::Unsafety,
1829            g: &clean::Generics, selfty: &clean::SelfTy,
1830            d: &clean::FnDecl) -> fmt::Result {
1831         write!(w, "{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
1832                    {generics}{decl}{where_clause}",
1833                match unsafety {
1834                    ast::Unsafety::Unsafe => "unsafe ",
1835                    _ => "",
1836                },
1837                ty = shortty(it),
1838                name = it.name.as_ref().unwrap().as_slice(),
1839                generics = *g,
1840                decl = Method(selfty, d),
1841                where_clause = WhereClause(g))
1842     }
1843     match meth.inner {
1844         clean::TyMethodItem(ref m) => {
1845             method(w, meth, m.unsafety, &m.generics, &m.self_, &m.decl)
1846         }
1847         clean::MethodItem(ref m) => {
1848             method(w, meth, m.unsafety, &m.generics, &m.self_, &m.decl)
1849         }
1850         clean::AssociatedTypeItem(ref typ) => {
1851             assoc_type(w, meth, typ)
1852         }
1853         _ => panic!("render_method called on non-method")
1854     }
1855 }
1856
1857 fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
1858                s: &clean::Struct) -> fmt::Result {
1859     try!(write!(w, "<pre class='rust struct'>"));
1860     try!(render_struct(w,
1861                        it,
1862                        Some(&s.generics),
1863                        s.struct_type,
1864                        s.fields.as_slice(),
1865                        "",
1866                        true));
1867     try!(write!(w, "</pre>"));
1868
1869     try!(document(w, it));
1870     let mut fields = s.fields.iter().filter(|f| {
1871         match f.inner {
1872             clean::StructFieldItem(clean::HiddenStructField) => false,
1873             clean::StructFieldItem(clean::TypedStructField(..)) => true,
1874             _ => false,
1875         }
1876     }).peekable();
1877     if let doctree::Plain = s.struct_type {
1878         if fields.peek().is_some() {
1879             try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
1880             for field in fields {
1881                 try!(write!(w, "<tr><td id='structfield.{name}'>\
1882                                   {stab}<code>{name}</code></td><td>",
1883                             stab = ConciseStability(&field.stability),
1884                             name = field.name.as_ref().unwrap().as_slice()));
1885                 try!(document(w, field));
1886                 try!(write!(w, "</td></tr>"));
1887             }
1888             try!(write!(w, "</table>"));
1889         }
1890     }
1891     render_methods(w, it)
1892 }
1893
1894 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
1895              e: &clean::Enum) -> fmt::Result {
1896     try!(write!(w, "<pre class='rust enum'>{}enum {}{}{}",
1897                   VisSpace(it.visibility),
1898                   it.name.as_ref().unwrap().as_slice(),
1899                   e.generics,
1900                   WhereClause(&e.generics)));
1901     if e.variants.len() == 0 && !e.variants_stripped {
1902         try!(write!(w, " {{}}"));
1903     } else {
1904         try!(write!(w, " {{\n"));
1905         for v in e.variants.iter() {
1906             try!(write!(w, "    "));
1907             let name = v.name.as_ref().unwrap().as_slice();
1908             match v.inner {
1909                 clean::VariantItem(ref var) => {
1910                     match var.kind {
1911                         clean::CLikeVariant => try!(write!(w, "{}", name)),
1912                         clean::TupleVariant(ref tys) => {
1913                             try!(write!(w, "{}(", name));
1914                             for (i, ty) in tys.iter().enumerate() {
1915                                 if i > 0 {
1916                                     try!(write!(w, ", "))
1917                                 }
1918                                 try!(write!(w, "{}", *ty));
1919                             }
1920                             try!(write!(w, ")"));
1921                         }
1922                         clean::StructVariant(ref s) => {
1923                             try!(render_struct(w,
1924                                                v,
1925                                                None,
1926                                                s.struct_type,
1927                                                s.fields.as_slice(),
1928                                                "    ",
1929                                                false));
1930                         }
1931                     }
1932                 }
1933                 _ => unreachable!()
1934             }
1935             try!(write!(w, ",\n"));
1936         }
1937
1938         if e.variants_stripped {
1939             try!(write!(w, "    // some variants omitted\n"));
1940         }
1941         try!(write!(w, "}}"));
1942     }
1943     try!(write!(w, "</pre>"));
1944
1945     try!(document(w, it));
1946     if e.variants.len() > 0 {
1947         try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
1948         for variant in e.variants.iter() {
1949             try!(write!(w, "<tr><td id='variant.{name}'>{stab}<code>{name}</code></td><td>",
1950                           stab = ConciseStability(&variant.stability),
1951                           name = variant.name.as_ref().unwrap().as_slice()));
1952             try!(document(w, variant));
1953             match variant.inner {
1954                 clean::VariantItem(ref var) => {
1955                     match var.kind {
1956                         clean::StructVariant(ref s) => {
1957                             let mut fields = s.fields.iter().filter(|f| {
1958                                 match f.inner {
1959                                     clean::StructFieldItem(ref t) => match *t {
1960                                         clean::HiddenStructField => false,
1961                                         clean::TypedStructField(..) => true,
1962                                     },
1963                                     _ => false,
1964                                 }
1965                             });
1966                             try!(write!(w, "<h3 class='fields'>Fields</h3>\n
1967                                               <table>"));
1968                             for field in fields {
1969                                 try!(write!(w, "<tr><td \
1970                                                   id='variant.{v}.field.{f}'>\
1971                                                   <code>{f}</code></td><td>",
1972                                               v = variant.name.as_ref().unwrap().as_slice(),
1973                                               f = field.name.as_ref().unwrap().as_slice()));
1974                                 try!(document(w, field));
1975                                 try!(write!(w, "</td></tr>"));
1976                             }
1977                             try!(write!(w, "</table>"));
1978                         }
1979                         _ => ()
1980                     }
1981                 }
1982                 _ => ()
1983             }
1984             try!(write!(w, "</td></tr>"));
1985         }
1986         try!(write!(w, "</table>"));
1987
1988     }
1989     try!(render_methods(w, it));
1990     Ok(())
1991 }
1992
1993 fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
1994                  g: Option<&clean::Generics>,
1995                  ty: doctree::StructType,
1996                  fields: &[clean::Item],
1997                  tab: &str,
1998                  structhead: bool) -> fmt::Result {
1999     try!(write!(w, "{}{}{}",
2000                   VisSpace(it.visibility),
2001                   if structhead {"struct "} else {""},
2002                   it.name.as_ref().unwrap().as_slice()));
2003     match g {
2004         Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))),
2005         None => {}
2006     }
2007     match ty {
2008         doctree::Plain => {
2009             try!(write!(w, " {{\n{}", tab));
2010             let mut fields_stripped = false;
2011             for field in fields.iter() {
2012                 match field.inner {
2013                     clean::StructFieldItem(clean::HiddenStructField) => {
2014                         fields_stripped = true;
2015                     }
2016                     clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
2017                         try!(write!(w, "    {}{}: {},\n{}",
2018                                       VisSpace(field.visibility),
2019                                       field.name.as_ref().unwrap().as_slice(),
2020                                       *ty,
2021                                       tab));
2022                     }
2023                     _ => unreachable!(),
2024                 };
2025             }
2026
2027             if fields_stripped {
2028                 try!(write!(w, "    // some fields omitted\n{}", tab));
2029             }
2030             try!(write!(w, "}}"));
2031         }
2032         doctree::Tuple | doctree::Newtype => {
2033             try!(write!(w, "("));
2034             for (i, field) in fields.iter().enumerate() {
2035                 if i > 0 {
2036                     try!(write!(w, ", "));
2037                 }
2038                 match field.inner {
2039                     clean::StructFieldItem(clean::HiddenStructField) => {
2040                         try!(write!(w, "_"))
2041                     }
2042                     clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
2043                         try!(write!(w, "{}{}", VisSpace(field.visibility), *ty))
2044                     }
2045                     _ => unreachable!()
2046                 }
2047             }
2048             try!(write!(w, ");"));
2049         }
2050         doctree::Unit => {
2051             try!(write!(w, ";"));
2052         }
2053     }
2054     Ok(())
2055 }
2056
2057 fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
2058     match cache().impls.get(&it.def_id) {
2059         Some(v) => {
2060             let (non_trait, traits): (Vec<_>, _) = v.iter().cloned()
2061                 .partition(|i| i.impl_.trait_.is_none());
2062             if non_trait.len() > 0 {
2063                 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
2064                 for i in non_trait.iter() {
2065                     try!(render_impl(w, i));
2066                 }
2067             }
2068             if traits.len() > 0 {
2069                 try!(write!(w, "<h2 id='implementations'>Trait \
2070                                   Implementations</h2>"));
2071                 let (derived, manual): (Vec<_>, _) = traits.into_iter()
2072                     .partition(|i| i.impl_.derived);
2073                 for i in manual.iter() {
2074                     try!(render_impl(w, i));
2075                 }
2076                 if derived.len() > 0 {
2077                     try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
2078                                 </h3>"));
2079                     for i in derived.iter() {
2080                         try!(render_impl(w, i));
2081                     }
2082                 }
2083             }
2084         }
2085         None => {}
2086     }
2087     Ok(())
2088 }
2089
2090 fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
2091     try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
2092                 ConciseStability(&i.stability),
2093                 i.impl_.generics));
2094     match i.impl_.trait_ {
2095         Some(ref ty) => try!(write!(w, "{} for ", *ty)),
2096         None => {}
2097     }
2098     try!(write!(w, "{}{}</code></h3>", i.impl_.for_, WhereClause(&i.impl_.generics)));
2099     match i.dox {
2100         Some(ref dox) => {
2101             try!(write!(w, "<div class='docblock'>{}</div>",
2102                           Markdown(dox.as_slice())));
2103         }
2104         None => {}
2105     }
2106
2107     fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool)
2108                     -> fmt::Result {
2109         match item.inner {
2110             clean::MethodItem(..) | clean::TyMethodItem(..) => {
2111                 try!(write!(w, "<h4 id='method.{}' class='{}'>{}<code>",
2112                             *item.name.as_ref().unwrap(),
2113                             shortty(item),
2114                             ConciseStability(&item.stability)));
2115                 try!(render_method(w, item));
2116                 try!(write!(w, "</code></h4>\n"));
2117             }
2118             clean::TypedefItem(ref tydef) => {
2119                 let name = item.name.as_ref().unwrap();
2120                 try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>",
2121                             *name,
2122                             shortty(item),
2123                             ConciseStability(&item.stability)));
2124                 try!(write!(w, "type {} = {}", name, tydef.type_));
2125                 try!(write!(w, "</code></h4>\n"));
2126             }
2127             clean::AssociatedTypeItem(ref typaram) => {
2128                 let name = item.name.as_ref().unwrap();
2129                 try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>",
2130                             *name,
2131                             shortty(item),
2132                             ConciseStability(&item.stability)));
2133                 try!(assoc_type(w, item, typaram));
2134                 try!(write!(w, "</code></h4>\n"));
2135             }
2136             _ => panic!("can't make docs for trait item with name {}", item.name)
2137         }
2138         match item.doc_value() {
2139             Some(s) if dox => {
2140                 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
2141                 Ok(())
2142             }
2143             Some(..) | None => Ok(())
2144         }
2145     }
2146
2147     try!(write!(w, "<div class='impl-items'>"));
2148     for trait_item in i.impl_.items.iter() {
2149         try!(doctraititem(w, trait_item, true));
2150     }
2151
2152     fn render_default_methods(w: &mut fmt::Formatter,
2153                               t: &clean::Trait,
2154                               i: &clean::Impl) -> fmt::Result {
2155         for trait_item in t.items.iter() {
2156             let n = trait_item.item().name.clone();
2157             match i.items.iter().find(|m| { m.name == n }) {
2158                 Some(..) => continue,
2159                 None => {}
2160             }
2161
2162             try!(doctraititem(w, trait_item.item(), false));
2163         }
2164         Ok(())
2165     }
2166
2167     // If we've implemented a trait, then also emit documentation for all
2168     // default methods which weren't overridden in the implementation block.
2169     // FIXME: this also needs to be done for associated types, whenever defaults
2170     // for them work.
2171     match i.impl_.trait_ {
2172         Some(clean::ResolvedPath { did, .. }) => {
2173             try!({
2174                 match cache().traits.get(&did) {
2175                     Some(t) => try!(render_default_methods(w, t, &i.impl_)),
2176                     None => {}
2177                 }
2178                 Ok(())
2179             })
2180         }
2181         Some(..) | None => {}
2182     }
2183     try!(write!(w, "</div>"));
2184     Ok(())
2185 }
2186
2187 fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
2188                 t: &clean::Typedef) -> fmt::Result {
2189     try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
2190                   it.name.as_ref().unwrap().as_slice(),
2191                   t.generics,
2192                   t.type_));
2193
2194     document(w, it)
2195 }
2196
2197 impl<'a> fmt::Show for Sidebar<'a> {
2198     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2199         let cx = self.cx;
2200         let it = self.item;
2201         try!(write!(fmt, "<p class='location'>"));
2202         let len = cx.current.len() - if it.is_mod() {1} else {0};
2203         for (i, name) in cx.current.iter().take(len).enumerate() {
2204             if i > 0 {
2205                 try!(write!(fmt, "::<wbr>"));
2206             }
2207             try!(write!(fmt, "<a href='{}index.html'>{}</a>",
2208                           cx.root_path
2209                             .as_slice()
2210                             .slice_to((cx.current.len() - i - 1) * 3),
2211                           *name));
2212         }
2213         try!(write!(fmt, "</p>"));
2214
2215         fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
2216                  cur: &clean::Item, cx: &Context) -> fmt::Result {
2217             let items = match cx.sidebar.get(short) {
2218                 Some(items) => items.as_slice(),
2219                 None => return Ok(())
2220             };
2221             try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
2222             for item in items.iter() {
2223                 let curty = shortty(cur).to_static_str();
2224                 let class = if cur.name.as_ref().unwrap() == item &&
2225                                short == curty { "current" } else { "" };
2226                 try!(write!(w, "<a class='{ty} {class}' href='{href}{path}'>\
2227                                 {name}</a>",
2228                        ty = short,
2229                        class = class,
2230                        href = if curty == "mod" {"../"} else {""},
2231                        path = if short == "mod" {
2232                            format!("{}/index.html", item.as_slice())
2233                        } else {
2234                            format!("{}.{}.html", short, item.as_slice())
2235                        },
2236                        name = item.as_slice()));
2237             }
2238             try!(write!(w, "</div>"));
2239             Ok(())
2240         }
2241
2242         try!(block(fmt, "mod", "Modules", it, cx));
2243         try!(block(fmt, "struct", "Structs", it, cx));
2244         try!(block(fmt, "enum", "Enums", it, cx));
2245         try!(block(fmt, "trait", "Traits", it, cx));
2246         try!(block(fmt, "fn", "Functions", it, cx));
2247         try!(block(fmt, "macro", "Macros", it, cx));
2248         Ok(())
2249     }
2250 }
2251
2252 impl<'a> fmt::Show for Source<'a> {
2253     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2254         let Source(s) = *self;
2255         let lines = s.lines().count();
2256         let mut cols = 0;
2257         let mut tmp = lines;
2258         while tmp > 0 {
2259             cols += 1;
2260             tmp /= 10;
2261         }
2262         try!(write!(fmt, "<pre class='line-numbers'>"));
2263         for i in range(1, lines + 1) {
2264             try!(write!(fmt, "<span id='{0}'>{0:1$}</span>\n", i, cols));
2265         }
2266         try!(write!(fmt, "</pre>"));
2267         try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None)));
2268         Ok(())
2269     }
2270 }
2271
2272 fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
2273               t: &clean::Macro) -> fmt::Result {
2274     try!(w.write_str(highlight::highlight(t.source.as_slice(),
2275                                           Some("macro"),
2276                                           None)[]));
2277     document(w, it)
2278 }
2279
2280 fn item_primitive(w: &mut fmt::Formatter,
2281                   it: &clean::Item,
2282                   _p: &clean::PrimitiveType) -> fmt::Result {
2283     try!(document(w, it));
2284     render_methods(w, it)
2285 }
2286
2287 fn get_basic_keywords() -> &'static str {
2288     "rust, rustlang, rust-lang"
2289 }
2290
2291 fn make_item_keywords(it: &clean::Item) -> String {
2292     format!("{}, {}", get_basic_keywords(), it.name.as_ref().unwrap())
2293 }
2294
2295 pub fn cache() -> Arc<Cache> {
2296     CACHE_KEY.with(|c| c.borrow().clone())
2297 }