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