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