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