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