]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render.rs
ce7f230ea53f0022484ed9797d03811e8ec163a7
[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
36 use collections::{HashMap, HashSet};
37 use std::fmt;
38 use std::io::{fs, File, BufferedWriter, MemWriter, BufferedReader};
39 use std::io;
40 use std::str;
41 use std::string::String;
42
43 use sync::Arc;
44 use serialize::json::ToJson;
45 use syntax::ast;
46 use syntax::ast_util;
47 use syntax::attr;
48 use syntax::parse::token::InternedString;
49 use rustc::util::nodemap::NodeSet;
50
51 use clean;
52 use doctree;
53 use fold::DocFolder;
54 use html::format::{VisSpace, Method, FnStyleSpace};
55 use html::highlight;
56 use html::item_type::{ItemType, shortty};
57 use html::item_type;
58 use html::layout;
59 use html::markdown::Markdown;
60 use html::markdown;
61
62 /// Major driving force in all rustdoc rendering. This contains information
63 /// about where in the tree-like hierarchy rendering is occurring and controls
64 /// how the current page is being rendered.
65 ///
66 /// It is intended that this context is a lightweight object which can be fairly
67 /// easily cloned because it is cloned per work-job (about once per item in the
68 /// rustdoc tree).
69 #[deriving(Clone)]
70 pub struct Context {
71     /// Current hierarchy of components leading down to what's currently being
72     /// rendered
73     pub current: Vec<String> ,
74     /// String representation of how to get back to the root path of the 'doc/'
75     /// folder in terms of a relative URL.
76     pub root_path: String,
77     /// The current destination folder of where HTML artifacts should be placed.
78     /// This changes as the context descends into the module hierarchy.
79     pub dst: Path,
80     /// This describes the layout of each page, and is not modified after
81     /// creation of the context (contains info like the favicon)
82     pub layout: layout::Layout,
83     /// This map is a list of what should be displayed on the sidebar of the
84     /// current page. The key is the section header (traits, modules,
85     /// functions), and the value is the list of containers belonging to this
86     /// header. This map will change depending on the surrounding context of the
87     /// page.
88     pub sidebar: HashMap<String, Vec<String>>,
89     /// This flag indicates whether [src] links should be generated or not. If
90     /// the source files are present in the html rendering, then this will be
91     /// `true`.
92     pub include_sources: bool,
93 }
94
95 /// Indicates where an external crate can be found.
96 pub enum ExternalLocation {
97     /// Remote URL root of the external crate
98     Remote(String),
99     /// This external crate can be found in the local doc/ folder
100     Local,
101     /// The external crate could not be found.
102     Unknown,
103 }
104
105 /// Different ways an implementor of a trait can be rendered.
106 pub enum Implementor {
107     /// Paths are displayed specially by omitting the `impl XX for` cruft
108     PathType(clean::Type),
109     /// This is the generic representation of a trait implementor, used for
110     /// primitive types and otherwise non-path types.
111     OtherType(clean::Generics, /* trait */ clean::Type, /* for */ clean::Type),
112 }
113
114 /// This cache is used to store information about the `clean::Crate` being
115 /// rendered in order to provide more useful documentation. This contains
116 /// information like all implementors of a trait, all traits a type implements,
117 /// documentation for all known traits, etc.
118 ///
119 /// This structure purposefully does not implement `Clone` because it's intended
120 /// to be a fairly large and expensive structure to clone. Instead this adheres
121 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
122 /// rendering tasks.
123 pub struct Cache {
124     /// Mapping of typaram ids to the name of the type parameter. This is used
125     /// when pretty-printing a type (so pretty printing doesn't have to
126     /// painfully maintain a context like this)
127     pub typarams: HashMap<ast::DefId, String>,
128
129     /// Maps a type id to all known implementations for that type. This is only
130     /// recognized for intra-crate `ResolvedPath` types, and is used to print
131     /// out extra documentation on the page of an enum/struct.
132     ///
133     /// The values of the map are a list of implementations and documentation
134     /// found on that implementation.
135     pub impls: HashMap<ast::DefId, Vec<(clean::Impl, Option<String>)>>,
136
137     /// Maintains a mapping of local crate node ids to the fully qualified name
138     /// and "short type description" of that node. This is used when generating
139     /// URLs when a type is being linked to. External paths are not located in
140     /// this map because the `External` type itself has all the information
141     /// necessary.
142     pub paths: HashMap<ast::DefId, (Vec<String>, ItemType)>,
143
144     /// Similar to `paths`, but only holds external paths. This is only used for
145     /// generating explicit hyperlinks to other crates.
146     pub external_paths: HashMap<ast::DefId, Vec<StrBuf>>,
147
148     /// This map contains information about all known traits of this crate.
149     /// Implementations of a crate should inherit the documentation of the
150     /// parent trait if no extra documentation is specified, and default methods
151     /// should show up in documentation about trait implementations.
152     pub traits: HashMap<ast::DefId, clean::Trait>,
153
154     /// When rendering traits, it's often useful to be able to list all
155     /// implementors of the trait, and this mapping is exactly, that: a mapping
156     /// of trait ids to the list of known implementors of the trait
157     pub implementors: HashMap<ast::DefId, Vec<Implementor>>,
158
159     /// Cache of where external crate documentation can be found.
160     pub extern_locations: HashMap<ast::CrateNum, ExternalLocation>,
161
162     // Private fields only used when initially crawling a crate to build a cache
163
164     stack: Vec<String>,
165     parent_stack: Vec<ast::DefId>,
166     search_index: Vec<IndexItem>,
167     privmod: bool,
168     public_items: NodeSet,
169
170     // In rare case where a structure is defined in one module but implemented
171     // in another, if the implementing module is parsed before defining module,
172     // then the fully qualified name of the structure isn't presented in `paths`
173     // yet when its implementation methods are being indexed. Caches such methods
174     // and their parent id here and indexes them at the end of crate parsing.
175     orphan_methods: Vec<(ast::NodeId, clean::Item)>,
176 }
177
178 /// Helper struct to render all source code to HTML pages
179 struct SourceCollector<'a> {
180     cx: &'a mut Context,
181
182     /// Processed source-file paths
183     seen: HashSet<String>,
184     /// Root destination to place all HTML output into
185     dst: Path,
186 }
187
188 /// Wrapper struct to render the source code of a file. This will do things like
189 /// adding line numbers to the left-hand side.
190 struct Source<'a>(&'a str);
191
192 // Helper structs for rendering items/sidebars and carrying along contextual
193 // information
194
195 struct Item<'a> { cx: &'a Context, item: &'a clean::Item, }
196 struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
197
198 /// Struct representing one entry in the JS search index. These are all emitted
199 /// by hand to a large JS file at the end of cache-creation.
200 struct IndexItem {
201     ty: ItemType,
202     name: String,
203     path: String,
204     desc: String,
205     parent: Option<ast::DefId>,
206 }
207
208 // TLS keys used to carry information around during rendering.
209
210 local_data_key!(pub cache_key: Arc<Cache>)
211 local_data_key!(pub current_location_key: Vec<String> )
212
213 /// Generates the documentation for `crate` into the directory `dst`
214 pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
215     let mut cx = Context {
216         dst: dst,
217         current: Vec::new(),
218         root_path: String::new(),
219         sidebar: HashMap::new(),
220         layout: layout::Layout {
221             logo: "".to_strbuf(),
222             favicon: "".to_strbuf(),
223             krate: krate.name.clone(),
224         },
225         include_sources: true,
226     };
227     try!(mkdir(&cx.dst));
228
229     match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
230         Some(attrs) => {
231             for attr in attrs.iter() {
232                 match *attr {
233                     clean::NameValue(ref x, ref s)
234                             if "html_favicon_url" == x.as_slice() => {
235                         cx.layout.favicon = s.to_strbuf();
236                     }
237                     clean::NameValue(ref x, ref s)
238                             if "html_logo_url" == x.as_slice() => {
239                         cx.layout.logo = s.to_strbuf();
240                     }
241                     clean::Word(ref x)
242                             if "html_no_source" == x.as_slice() => {
243                         cx.include_sources = false;
244                     }
245                     _ => {}
246                 }
247             }
248         }
249         None => {}
250     }
251
252     // Crawl the crate to build various caches used for the output
253     let analysis = ::analysiskey.get();
254     let public_items = analysis.as_ref().map(|a| a.public_items.clone());
255     let public_items = public_items.unwrap_or(NodeSet::new());
256     let paths: HashMap<ast::DefId, (Vec<StrBuf>, ItemType)> =
257       analysis.as_ref().map(|a| {
258         let paths = a.external_paths.borrow_mut().take_unwrap();
259         paths.move_iter().map(|(k, (v, t))| {
260             (k, (v, match t {
261                 clean::TypeStruct => item_type::Struct,
262                 clean::TypeEnum => item_type::Enum,
263                 clean::TypeFunction => item_type::Function,
264                 clean::TypeTrait => item_type::Trait,
265                 clean::TypeModule => item_type::Module,
266                 clean::TypeStatic => item_type::Static,
267                 clean::TypeVariant => item_type::Variant,
268             }))
269         }).collect()
270     }).unwrap_or(HashMap::new());
271     let mut cache = Cache {
272         impls: HashMap::new(),
273         external_paths: paths.iter().map(|(&k, &(ref v, _))| (k, v.clone()))
274                              .collect(),
275         paths: paths,
276         implementors: HashMap::new(),
277         stack: Vec::new(),
278         parent_stack: Vec::new(),
279         search_index: Vec::new(),
280         extern_locations: HashMap::new(),
281         privmod: false,
282         public_items: public_items,
283         orphan_methods: Vec::new(),
284         traits: analysis.as_ref().map(|a| {
285             a.external_traits.borrow_mut().take_unwrap()
286         }).unwrap_or(HashMap::new()),
287         typarams: analysis.as_ref().map(|a| {
288             a.external_typarams.borrow_mut().take_unwrap()
289         }).unwrap_or(HashMap::new()),
290     };
291     cache.stack.push(krate.name.clone());
292     krate = cache.fold_crate(krate);
293
294     let mut nodeid_to_pathid = HashMap::new();
295     let mut pathid_to_nodeid = Vec::new();
296     {
297         let Cache { search_index: ref mut index,
298                     orphan_methods: ref meths, paths: ref mut paths, ..} = cache;
299
300         // Attach all orphan methods to the type's definition if the type
301         // has since been learned.
302         for &(pid, ref item) in meths.iter() {
303             let did = ast_util::local_def(pid);
304             match paths.find(&did) {
305                 Some(&(ref fqp, _)) => {
306                     index.push(IndexItem {
307                         ty: shortty(item),
308                         name: item.name.clone().unwrap(),
309                         path: fqp.slice_to(fqp.len() - 1).connect("::")
310                                                          .to_strbuf(),
311                         desc: shorter(item.doc_value()).to_strbuf(),
312                         parent: Some(did),
313                     });
314                 },
315                 None => {}
316             }
317         };
318
319         // Reduce `NodeId` in paths into smaller sequential numbers,
320         // and prune the paths that do not appear in the index.
321         for item in index.iter() {
322             match item.parent {
323                 Some(nodeid) => {
324                     if !nodeid_to_pathid.contains_key(&nodeid) {
325                         let pathid = pathid_to_nodeid.len();
326                         nodeid_to_pathid.insert(nodeid, pathid);
327                         pathid_to_nodeid.push(nodeid);
328                     }
329                 }
330                 None => {}
331             }
332         }
333         assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len());
334     }
335
336     // Publish the search index
337     let index = {
338         let mut w = MemWriter::new();
339         try!(write!(&mut w, r#"searchIndex['{}'] = \{"items":["#, krate.name));
340
341         let mut lastpath = "".to_strbuf();
342         for (i, item) in cache.search_index.iter().enumerate() {
343             // Omit the path if it is same to that of the prior item.
344             let path;
345             if lastpath.as_slice() == item.path.as_slice() {
346                 path = "";
347             } else {
348                 lastpath = item.path.to_strbuf();
349                 path = item.path.as_slice();
350             };
351
352             if i > 0 {
353                 try!(write!(&mut w, ","));
354             }
355             try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#,
356                         item.ty, item.name, path,
357                         item.desc.to_json().to_str()));
358             match item.parent {
359                 Some(nodeid) => {
360                     let pathid = *nodeid_to_pathid.find(&nodeid).unwrap();
361                     try!(write!(&mut w, ",{}", pathid));
362                 }
363                 None => {}
364             }
365             try!(write!(&mut w, "]"));
366         }
367
368         try!(write!(&mut w, r#"],"paths":["#));
369
370         for (i, &did) in pathid_to_nodeid.iter().enumerate() {
371             let &(ref fqp, short) = cache.paths.find(&did).unwrap();
372             if i > 0 {
373                 try!(write!(&mut w, ","));
374             }
375             try!(write!(&mut w, r#"[{:u},"{}"]"#,
376                         short, *fqp.last().unwrap()));
377         }
378
379         try!(write!(&mut w, r"]\};"));
380
381         str::from_utf8(w.unwrap().as_slice()).unwrap().to_owned()
382     };
383
384     // Write out the shared files. Note that these are shared among all rustdoc
385     // docs placed in the output directory, so this needs to be a synchronized
386     // operation with respect to all other rustdocs running around.
387     {
388         try!(mkdir(&cx.dst));
389         let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
390
391         // Add all the static files. These may already exist, but we just
392         // overwrite them anyway to make sure that they're fresh and up-to-date.
393         try!(write(cx.dst.join("jquery.js"),
394                    include_bin!("static/jquery-2.1.0.min.js")));
395         try!(write(cx.dst.join("main.js"), include_bin!("static/main.js")));
396         try!(write(cx.dst.join("main.css"), include_bin!("static/main.css")));
397         try!(write(cx.dst.join("normalize.css"),
398                    include_bin!("static/normalize.css")));
399         try!(write(cx.dst.join("FiraSans-Regular.woff"),
400                    include_bin!("static/FiraSans-Regular.woff")));
401         try!(write(cx.dst.join("FiraSans-Medium.woff"),
402                    include_bin!("static/FiraSans-Medium.woff")));
403         try!(write(cx.dst.join("Heuristica-Regular.woff"),
404                    include_bin!("static/Heuristica-Regular.woff")));
405         try!(write(cx.dst.join("Heuristica-Italic.woff"),
406                    include_bin!("static/Heuristica-Italic.woff")));
407         try!(write(cx.dst.join("Heuristica-Bold.woff"),
408                    include_bin!("static/Heuristica-Bold.woff")));
409
410         fn collect(path: &Path, krate: &str,
411                    key: &str) -> io::IoResult<Vec<String>> {
412             let mut ret = Vec::new();
413             if path.exists() {
414                 for line in BufferedReader::new(File::open(path)).lines() {
415                     let line = try!(line);
416                     if !line.as_slice().starts_with(key) {
417                         continue
418                     }
419                     if line.as_slice().starts_with(
420                             format!("{}['{}']", key, krate).as_slice()) {
421                         continue
422                     }
423                     ret.push(line.to_strbuf());
424                 }
425             }
426             return Ok(ret);
427         }
428
429         // Update the search index
430         let dst = cx.dst.join("search-index.js");
431         let all_indexes = try!(collect(&dst, krate.name.as_slice(),
432                                        "searchIndex"));
433         let mut w = try!(File::create(&dst));
434         try!(writeln!(&mut w, r"var searchIndex = \{\};"));
435         try!(writeln!(&mut w, "{}", index));
436         for index in all_indexes.iter() {
437             try!(writeln!(&mut w, "{}", *index));
438         }
439         try!(writeln!(&mut w, "initSearch(searchIndex);"));
440
441         // Update the list of all implementors for traits
442         let dst = cx.dst.join("implementors");
443         try!(mkdir(&dst));
444         for (&did, imps) in cache.implementors.iter() {
445             if ast_util::is_local(did) { continue }
446             let &(ref remote_path, remote_item_type) = cache.paths.get(&did);
447
448             let mut mydst = dst.clone();
449             for part in remote_path.slice_to(remote_path.len() - 1).iter() {
450                 mydst.push(part.as_slice());
451                 try!(mkdir(&mydst));
452             }
453             mydst.push(format!("{}.{}.js",
454                                remote_item_type.to_static_str(),
455                                *remote_path.get(remote_path.len() - 1)));
456             let all_implementors = try!(collect(&mydst, krate.name.as_slice(),
457                                                 "implementors"));
458
459             try!(mkdir(&mydst.dir_path()));
460             let mut f = BufferedWriter::new(try!(File::create(&mydst)));
461             try!(writeln!(&mut f, r"(function() \{var implementors = \{\};"));
462
463             for implementor in all_implementors.iter() {
464                 try!(writeln!(&mut f, "{}", *implementor));
465             }
466
467             try!(write!(&mut f, r"implementors['{}'] = \{", krate.name));
468             for imp in imps.iter() {
469                 let &(ref path, item_type) = match *imp {
470                     PathType(clean::ResolvedPath { did, .. }) => {
471                         cache.paths.get(&did)
472                     }
473                     PathType(..) | OtherType(..) => continue,
474                 };
475                 try!(write!(&mut f, r#"{}:"#, *path.get(path.len() - 1)));
476                 try!(write!(&mut f, r#""{}"#,
477                             path.slice_to(path.len() - 1).connect("/")));
478                 try!(write!(&mut f, r#"/{}.{}.html","#,
479                             item_type.to_static_str(),
480                             *path.get(path.len() - 1)));
481             }
482             try!(writeln!(&mut f, r"\};"));
483             try!(writeln!(&mut f, "{}", r"
484                 if (window.register_implementors) {
485                     window.register_implementors(implementors);
486                 } else {
487                     window.pending_implementors = implementors;
488                 }
489             "));
490             try!(writeln!(&mut f, r"\})()"));
491         }
492     }
493
494     // Render all source files (this may turn into a giant no-op)
495     {
496         info!("emitting source files");
497         let dst = cx.dst.join("src");
498         try!(mkdir(&dst));
499         let dst = dst.join(krate.name.as_slice());
500         try!(mkdir(&dst));
501         let mut folder = SourceCollector {
502             dst: dst,
503             seen: HashSet::new(),
504             cx: &mut cx,
505         };
506         // skip all invalid spans
507         folder.seen.insert("".to_strbuf());
508         krate = folder.fold_crate(krate);
509     }
510
511     for &(n, ref e) in krate.externs.iter() {
512         cache.extern_locations.insert(n, extern_location(e, &cx.dst));
513         let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID };
514         cache.paths.insert(did, (vec![e.name.to_strbuf()], item_type::Module));
515     }
516
517     // And finally render the whole crate's documentation
518     cx.krate(krate, cache)
519 }
520
521 /// Writes the entire contents of a string to a destination, not attempting to
522 /// catch any errors.
523 fn write(dst: Path, contents: &[u8]) -> io::IoResult<()> {
524     File::create(&dst).write(contents)
525 }
526
527 /// Makes a directory on the filesystem, failing the task if an error occurs and
528 /// skipping if the directory already exists.
529 fn mkdir(path: &Path) -> io::IoResult<()> {
530     if !path.exists() {
531         fs::mkdir(path, io::UserRWX)
532     } else {
533         Ok(())
534     }
535 }
536
537 /// Takes a path to a source file and cleans the path to it. This canonicalizes
538 /// things like ".." to components which preserve the "top down" hierarchy of a
539 /// static HTML tree.
540 // FIXME (#9639): The closure should deal with &[u8] instead of &str
541 fn clean_srcpath(src: &[u8], f: |&str|) {
542     let p = Path::new(src);
543     if p.as_vec() != bytes!(".") {
544         for c in p.str_components().map(|x|x.unwrap()) {
545             if ".." == c {
546                 f("up");
547             } else {
548                 f(c.as_slice())
549             }
550         }
551     }
552 }
553
554 /// Attempts to find where an external crate is located, given that we're
555 /// rendering in to the specified source destination.
556 fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
557     // See if there's documentation generated into the local directory
558     let local_location = dst.join(e.name.as_slice());
559     if local_location.is_dir() {
560         return Local;
561     }
562
563     // Failing that, see if there's an attribute specifying where to find this
564     // external crate
565     for attr in e.attrs.iter() {
566         match *attr {
567             clean::List(ref x, ref list) if "doc" == x.as_slice() => {
568                 for attr in list.iter() {
569                     match *attr {
570                         clean::NameValue(ref x, ref s)
571                                 if "html_root_url" == x.as_slice() => {
572                             if s.as_slice().ends_with("/") {
573                                 return Remote(s.to_strbuf());
574                             }
575                             return Remote(format_strbuf!("{}/", s));
576                         }
577                         _ => {}
578                     }
579                 }
580             }
581             _ => {}
582         }
583     }
584
585     // Well, at least we tried.
586     return Unknown;
587 }
588
589 impl<'a> DocFolder for SourceCollector<'a> {
590     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
591         // If we're including source files, and we haven't seen this file yet,
592         // then we need to render it out to the filesystem
593         if self.cx.include_sources && !self.seen.contains(&item.source.filename) {
594
595             // If it turns out that we couldn't read this file, then we probably
596             // can't read any of the files (generating html output from json or
597             // something like that), so just don't include sources for the
598             // entire crate. The other option is maintaining this mapping on a
599             // per-file basis, but that's probably not worth it...
600             self.cx
601                 .include_sources = match self.emit_source(item.source
602                                                               .filename
603                                                               .as_slice()) {
604                 Ok(()) => true,
605                 Err(e) => {
606                     println!("warning: source code was requested to be rendered, \
607                               but processing `{}` had an error: {}",
608                              item.source.filename, e);
609                     println!("         skipping rendering of source code");
610                     false
611                 }
612             };
613             self.seen.insert(item.source.filename.clone());
614         }
615
616         self.fold_item_recur(item)
617     }
618 }
619
620 impl<'a> SourceCollector<'a> {
621     /// Renders the given filename into its corresponding HTML source file.
622     fn emit_source(&mut self, filename: &str) -> io::IoResult<()> {
623         let p = Path::new(filename);
624
625         // If we couldn't open this file, then just returns because it
626         // probably means that it's some standard library macro thing and we
627         // can't have the source to it anyway.
628         let contents = match File::open(&p).read_to_end() {
629             Ok(r) => r,
630             // macros from other libraries get special filenames which we can
631             // safely ignore
632             Err(..) if filename.starts_with("<") &&
633                        filename.ends_with("macros>") => return Ok(()),
634             Err(e) => return Err(e)
635         };
636         let contents = str::from_utf8(contents.as_slice()).unwrap();
637
638         // Remove the utf-8 BOM if any
639         let contents = if contents.starts_with("\ufeff") {
640             contents.as_slice().slice_from(3)
641         } else {
642             contents.as_slice()
643         };
644
645         // Create the intermediate directories
646         let mut cur = self.dst.clone();
647         let mut root_path = String::from_str("../../");
648         clean_srcpath(p.dirname(), |component| {
649             cur.push(component);
650             mkdir(&cur).unwrap();
651             root_path.push_str("../");
652         });
653
654         cur.push(Vec::from_slice(p.filename().expect("source has no filename"))
655                  .append(bytes!(".html")));
656         let mut w = BufferedWriter::new(try!(File::create(&cur)));
657
658         let title = format!("{} -- source", cur.filename_display());
659         let page = layout::Page {
660             title: title.as_slice(),
661             ty: "source",
662             root_path: root_path.as_slice(),
663         };
664         try!(layout::render(&mut w as &mut Writer, &self.cx.layout,
665                             &page, &(""), &Source(contents)));
666         try!(w.flush());
667         return Ok(());
668     }
669 }
670
671 impl DocFolder for Cache {
672     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
673         // If this is a private module, we don't want it in the search index.
674         let orig_privmod = match item.inner {
675             clean::ModuleItem(..) => {
676                 let prev = self.privmod;
677                 self.privmod = prev || item.visibility != Some(ast::Public);
678                 prev
679             }
680             _ => self.privmod,
681         };
682
683         // Register any generics to their corresponding string. This is used
684         // when pretty-printing types
685         match item.inner {
686             clean::StructItem(ref s)          => self.generics(&s.generics),
687             clean::EnumItem(ref e)            => self.generics(&e.generics),
688             clean::FunctionItem(ref f)        => self.generics(&f.generics),
689             clean::TypedefItem(ref t)         => self.generics(&t.generics),
690             clean::TraitItem(ref t)           => self.generics(&t.generics),
691             clean::ImplItem(ref i)            => self.generics(&i.generics),
692             clean::TyMethodItem(ref i)        => self.generics(&i.generics),
693             clean::MethodItem(ref i)          => self.generics(&i.generics),
694             clean::ForeignFunctionItem(ref f) => self.generics(&f.generics),
695             _ => {}
696         }
697
698         // Propagate a trait methods' documentation to all implementors of the
699         // trait
700         match item.inner {
701             clean::TraitItem(ref t) => {
702                 self.traits.insert(item.def_id, t.clone());
703             }
704             _ => {}
705         }
706
707         // Collect all the implementors of traits.
708         match item.inner {
709             clean::ImplItem(ref i) => {
710                 match i.trait_ {
711                     Some(clean::ResolvedPath{ did, .. }) => {
712                         let v = self.implementors.find_or_insert_with(did, |_| {
713                             Vec::new()
714                         });
715                         match i.for_ {
716                             clean::ResolvedPath{..} => {
717                                 v.unshift(PathType(i.for_.clone()));
718                             }
719                             _ => {
720                                 v.push(OtherType(i.generics.clone(),
721                                                  i.trait_.get_ref().clone(),
722                                                  i.for_.clone()));
723                             }
724                         }
725                     }
726                     Some(..) | None => {}
727                 }
728             }
729             _ => {}
730         }
731
732         // Index this method for searching later on
733         match item.name {
734             Some(ref s) => {
735                 let parent = match item.inner {
736                     clean::TyMethodItem(..) |
737                     clean::StructFieldItem(..) |
738                     clean::VariantItem(..) => {
739                         (Some(*self.parent_stack.last().unwrap()),
740                          Some(self.stack.slice_to(self.stack.len() - 1)))
741                     }
742                     clean::MethodItem(..) => {
743                         if self.parent_stack.len() == 0 {
744                             (None, None)
745                         } else {
746                             let last = self.parent_stack.last().unwrap();
747                             let did = *last;
748                             let path = match self.paths.find(&did) {
749                                 Some(&(_, item_type::Trait)) =>
750                                     Some(self.stack.slice_to(self.stack.len() - 1)),
751                                 // The current stack not necessarily has correlation for
752                                 // where the type was defined. On the other hand,
753                                 // `paths` always has the right information if present.
754                                 Some(&(ref fqp, item_type::Struct)) |
755                                 Some(&(ref fqp, item_type::Enum)) =>
756                                     Some(fqp.slice_to(fqp.len() - 1)),
757                                 Some(..) => Some(self.stack.as_slice()),
758                                 None => None
759                             };
760                             (Some(*last), path)
761                         }
762                     }
763                     _ => (None, Some(self.stack.as_slice()))
764                 };
765                 match parent {
766                     (parent, Some(path)) if !self.privmod => {
767                         self.search_index.push(IndexItem {
768                             ty: shortty(&item),
769                             name: s.to_strbuf(),
770                             path: path.connect("::").to_strbuf(),
771                             desc: shorter(item.doc_value()).to_strbuf(),
772                             parent: parent,
773                         });
774                     }
775                     (Some(parent), None) if !self.privmod => {
776                         if ast_util::is_local(parent) {
777                             // We have a parent, but we don't know where they're
778                             // defined yet. Wait for later to index this item.
779                             self.orphan_methods.push((parent.node, item.clone()))
780                         }
781                     }
782                     _ => {}
783                 }
784             }
785             None => {}
786         }
787
788         // Keep track of the fully qualified path for this item.
789         let pushed = if item.name.is_some() {
790             let n = item.name.get_ref();
791             if n.len() > 0 {
792                 self.stack.push(n.to_strbuf());
793                 true
794             } else { false }
795         } else { false };
796         match item.inner {
797             clean::StructItem(..) | clean::EnumItem(..) |
798             clean::TypedefItem(..) | clean::TraitItem(..) |
799             clean::FunctionItem(..) | clean::ModuleItem(..) |
800             clean::ForeignFunctionItem(..) => {
801                 // Reexported items mean that the same id can show up twice
802                 // in the rustdoc ast that we're looking at. We know,
803                 // however, that a reexported item doesn't show up in the
804                 // `public_items` map, so we can skip inserting into the
805                 // paths map if there was already an entry present and we're
806                 // not a public item.
807                 let id = item.def_id.node;
808                 if !self.paths.contains_key(&item.def_id) ||
809                    !ast_util::is_local(item.def_id) ||
810                    self.public_items.contains(&id) {
811                     self.paths.insert(item.def_id,
812                                       (self.stack.clone(), shortty(&item)));
813                 }
814             }
815             // link variants to their parent enum because pages aren't emitted
816             // for each variant
817             clean::VariantItem(..) => {
818                 let mut stack = self.stack.clone();
819                 stack.pop();
820                 self.paths.insert(item.def_id, (stack, item_type::Enum));
821             }
822             _ => {}
823         }
824
825         // Maintain the parent stack
826         let parent_pushed = match item.inner {
827             clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
828                 self.parent_stack.push(item.def_id);
829                 true
830             }
831             clean::ImplItem(ref i) => {
832                 match i.for_ {
833                     clean::ResolvedPath{ did, .. } => {
834                         self.parent_stack.push(did);
835                         true
836                     }
837                     _ => false
838                 }
839             }
840             _ => false
841         };
842
843         // Once we've recursively found all the generics, then hoard off all the
844         // implementations elsewhere
845         let ret = match self.fold_item_recur(item) {
846             Some(item) => {
847                 match item {
848                     clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
849                         match i.for_ {
850                             clean::ResolvedPath { did, .. } => {
851                                 let v = self.impls.find_or_insert_with(did, |_| {
852                                     Vec::new()
853                                 });
854                                 // extract relevant documentation for this impl
855                                 match attrs.move_iter().find(|a| {
856                                     match *a {
857                                         clean::NameValue(ref x, _)
858                                                 if "doc" == x.as_slice() => {
859                                             true
860                                         }
861                                         _ => false
862                                     }
863                                 }) {
864                                     Some(clean::NameValue(_, dox)) => {
865                                         v.push((i, Some(dox)));
866                                     }
867                                     Some(..) | None => {
868                                         v.push((i, None));
869                                     }
870                                 }
871                             }
872                             _ => {}
873                         }
874                         None
875                     }
876                     // Private modules may survive the strip-private pass if
877                     // they contain impls for public types, but those will get
878                     // stripped here
879                     clean::Item { inner: clean::ModuleItem(ref m),
880                                   visibility, .. }
881                             if (m.items.len() == 0 &&
882                                 item.doc_value().is_none()) ||
883                                visibility != Some(ast::Public) => None,
884
885                     i => Some(i),
886                 }
887             }
888             i => i,
889         };
890
891         if pushed { self.stack.pop().unwrap(); }
892         if parent_pushed { self.parent_stack.pop().unwrap(); }
893         self.privmod = orig_privmod;
894         return ret;
895     }
896 }
897
898 impl<'a> Cache {
899     fn generics(&mut self, generics: &clean::Generics) {
900         for typ in generics.type_params.iter() {
901             self.typarams.insert(typ.did, typ.name.clone());
902         }
903     }
904 }
905
906 impl Context {
907     /// Recurse in the directory structure and change the "root path" to make
908     /// sure it always points to the top (relatively)
909     fn recurse<T>(&mut self, s: String, f: |&mut Context| -> T) -> T {
910         if s.len() == 0 {
911             fail!("what {:?}", self);
912         }
913         let prev = self.dst.clone();
914         self.dst.push(s.as_slice());
915         self.root_path.push_str("../");
916         self.current.push(s);
917
918         info!("Recursing into {}", self.dst.display());
919
920         mkdir(&self.dst).unwrap();
921         let ret = f(self);
922
923         info!("Recursed; leaving {}", self.dst.display());
924
925         // Go back to where we were at
926         self.dst = prev;
927         let len = self.root_path.len();
928         self.root_path.truncate(len - 3);
929         self.current.pop().unwrap();
930
931         return ret;
932     }
933
934     /// Main method for rendering a crate.
935     ///
936     /// This currently isn't parallelized, but it'd be pretty easy to add
937     /// parallelization to this function.
938     fn krate(self, mut krate: clean::Crate, cache: Cache) -> io::IoResult<()> {
939         let mut item = match krate.module.take() {
940             Some(i) => i,
941             None => return Ok(())
942         };
943         item.name = Some(krate.name);
944
945         // using a rwarc makes this parallelizable in the future
946         cache_key.replace(Some(Arc::new(cache)));
947
948         let mut work = vec!((self, item));
949         loop {
950             match work.pop() {
951                 Some((mut cx, item)) => try!(cx.item(item, |cx, item| {
952                     work.push((cx.clone(), item));
953                 })),
954                 None => break,
955             }
956         }
957         Ok(())
958     }
959
960     /// Non-parellelized version of rendering an item. This will take the input
961     /// item, render its contents, and then invoke the specified closure with
962     /// all sub-items which need to be rendered.
963     ///
964     /// The rendering driver uses this closure to queue up more work.
965     fn item(&mut self, item: clean::Item,
966             f: |&mut Context, clean::Item|) -> io::IoResult<()> {
967         fn render(w: io::File, cx: &mut Context, it: &clean::Item,
968                   pushname: bool) -> io::IoResult<()> {
969             info!("Rendering an item to {}", w.path().display());
970             // A little unfortunate that this is done like this, but it sure
971             // does make formatting *a lot* nicer.
972             current_location_key.replace(Some(cx.current.clone()));
973
974             let mut title = cx.current.connect("::");
975             if pushname {
976                 if title.len() > 0 {
977                     title.push_str("::");
978                 }
979                 title.push_str(it.name.get_ref().as_slice());
980             }
981             title.push_str(" - Rust");
982             let page = layout::Page {
983                 ty: shortty(it).to_static_str(),
984                 root_path: cx.root_path.as_slice(),
985                 title: title.as_slice(),
986             };
987
988             markdown::reset_headers();
989
990             // We have a huge number of calls to write, so try to alleviate some
991             // of the pain by using a buffered writer instead of invoking the
992             // write sycall all the time.
993             let mut writer = BufferedWriter::new(w);
994             try!(layout::render(&mut writer as &mut Writer, &cx.layout, &page,
995                                 &Sidebar{ cx: cx, item: it },
996                                 &Item{ cx: cx, item: it }));
997             writer.flush()
998         }
999
1000         match item.inner {
1001             // modules are special because they add a namespace. We also need to
1002             // recurse into the items of the module as well.
1003             clean::ModuleItem(..) => {
1004                 let name = item.name.get_ref().to_strbuf();
1005                 let mut item = Some(item);
1006                 self.recurse(name, |this| {
1007                     let item = item.take_unwrap();
1008                     let dst = this.dst.join("index.html");
1009                     let dst = try!(File::create(&dst));
1010                     try!(render(dst, this, &item, false));
1011
1012                     let m = match item.inner {
1013                         clean::ModuleItem(m) => m,
1014                         _ => unreachable!()
1015                     };
1016                     this.sidebar = build_sidebar(&m);
1017                     for item in m.items.move_iter() {
1018                         f(this,item);
1019                     }
1020                     Ok(())
1021                 })
1022             }
1023
1024             // Things which don't have names (like impls) don't get special
1025             // pages dedicated to them.
1026             _ if item.name.is_some() => {
1027                 let dst = self.dst.join(item_path(&item));
1028                 let dst = try!(File::create(&dst));
1029                 render(dst, self, &item, true)
1030             }
1031
1032             _ => Ok(())
1033         }
1034     }
1035 }
1036
1037 impl<'a> Item<'a> {
1038     fn ismodule(&self) -> bool {
1039         match self.item.inner {
1040             clean::ModuleItem(..) => true, _ => false
1041         }
1042     }
1043
1044     fn link(&self) -> Option<String> {
1045         if ast_util::is_local(self.item.def_id) {
1046             let mut path = Vec::new();
1047             clean_srcpath(self.item.source.filename.as_bytes(), |component| {
1048                 path.push(component.to_owned());
1049             });
1050             let href = if self.item.source.loline == self.item.source.hiline {
1051                 format!("{}", self.item.source.loline)
1052             } else {
1053                 format!("{}-{}",
1054                         self.item.source.loline,
1055                         self.item.source.hiline)
1056             };
1057             Some(format!("{root}src/{krate}/{path}.html\\#{href}",
1058                          root = self.cx.root_path,
1059                          krate = self.cx.layout.krate,
1060                          path = path.connect("/"),
1061                          href = href))
1062         } else {
1063             let cache = cache_key.get().unwrap();
1064             let path = cache.external_paths.get(&self.item.def_id);
1065             let root = match *cache.extern_locations.get(&self.item.def_id.krate) {
1066                 Remote(ref s) => s.to_strbuf(),
1067                 Local => format!("{}/..", self.cx.root_path),
1068                 Unknown => return None,
1069             };
1070             Some(format!("{root}/{path}/{file}?gotosrc={goto}",
1071                          root = root,
1072                          path = path.slice_to(path.len() - 1).connect("/"),
1073                          file = item_path(self.item),
1074                          goto = self.item.def_id.node))
1075         }
1076     }
1077 }
1078
1079 impl<'a> fmt::Show for Item<'a> {
1080     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1081         // Write the breadcrumb trail header for the top
1082         try!(write!(fmt, "\n<h1 class='fqn'>"));
1083         match self.item.inner {
1084             clean::ModuleItem(ref m) => if m.is_crate {
1085                     try!(write!(fmt, "Crate "));
1086                 } else {
1087                     try!(write!(fmt, "Module "));
1088                 },
1089             clean::FunctionItem(..) => try!(write!(fmt, "Function ")),
1090             clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
1091             clean::StructItem(..) => try!(write!(fmt, "Struct ")),
1092             clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
1093             _ => {}
1094         }
1095         let cur = self.cx.current.as_slice();
1096         let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
1097         for (i, component) in cur.iter().enumerate().take(amt) {
1098             let mut trail = String::new();
1099             for _ in range(0, cur.len() - i - 1) {
1100                 trail.push_str("../");
1101             }
1102             try!(write!(fmt, "<a href='{}index.html'>{}</a>::",
1103                         trail, component.as_slice()));
1104         }
1105         try!(write!(fmt, "<a class='{}' href=''>{}</a>",
1106                     shortty(self.item), self.item.name.get_ref().as_slice()));
1107
1108         // Write stability attributes
1109         match attr::find_stability_generic(self.item.attrs.iter()) {
1110             Some((ref stability, _)) => {
1111                 try!(write!(fmt,
1112                        "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
1113                        lvl = stability.level.to_str(),
1114                        reason = match stability.text {
1115                            Some(ref s) => (*s).clone(),
1116                            None => InternedString::new(""),
1117                        }));
1118             }
1119             None => {}
1120         }
1121
1122         // Write `src` tag
1123         if self.cx.include_sources {
1124             match self.link() {
1125                 Some(l) => {
1126                     try!(write!(fmt,
1127                                 "<a class='source' id='src-{}' \
1128                                     href='{}'>[src]</a>",
1129                                 self.item.def_id.node, l));
1130                 }
1131                 None => {}
1132             }
1133         }
1134         try!(write!(fmt, "</h1>\n"));
1135
1136         match self.item.inner {
1137             clean::ModuleItem(ref m) => {
1138                 item_module(fmt, self.cx, self.item, m.items.as_slice())
1139             }
1140             clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
1141                 item_function(fmt, self.item, f),
1142             clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
1143             clean::StructItem(ref s) => item_struct(fmt, self.item, s),
1144             clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
1145             clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
1146             clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
1147             _ => Ok(())
1148         }
1149     }
1150 }
1151
1152 fn item_path(item: &clean::Item) -> String {
1153     match item.inner {
1154         clean::ModuleItem(..) => {
1155             format_strbuf!("{}/index.html", item.name.get_ref())
1156         }
1157         _ => {
1158             format_strbuf!("{}.{}.html",
1159                            shortty(item).to_static_str(),
1160                            *item.name.get_ref())
1161         }
1162     }
1163 }
1164
1165 fn full_path(cx: &Context, item: &clean::Item) -> String {
1166     let mut s = cx.current.connect("::");
1167     s.push_str("::");
1168     s.push_str(item.name.get_ref().as_slice());
1169     return s
1170 }
1171
1172 fn blank<'a>(s: Option<&'a str>) -> &'a str {
1173     match s {
1174         Some(s) => s,
1175         None => ""
1176     }
1177 }
1178
1179 fn shorter<'a>(s: Option<&'a str>) -> &'a str {
1180     match s {
1181         Some(s) => match s.find_str("\n\n") {
1182             Some(pos) => s.slice_to(pos),
1183             None => s,
1184         },
1185         None => ""
1186     }
1187 }
1188
1189 fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
1190     match item.doc_value() {
1191         Some(s) => {
1192             try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1193         }
1194         None => {}
1195     }
1196     Ok(())
1197 }
1198
1199 fn item_module(w: &mut fmt::Formatter, cx: &Context,
1200                item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
1201     try!(document(w, item));
1202     debug!("{:?}", items);
1203     let mut indices = Vec::from_fn(items.len(), |i| i);
1204
1205     fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
1206         if shortty(i1) == shortty(i2) {
1207             return i1.name.cmp(&i2.name);
1208         }
1209         match (&i1.inner, &i2.inner) {
1210             (&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => {
1211                 match (&a.inner, &b.inner) {
1212                     (&clean::ExternCrate(..), _) => Less,
1213                     (_, &clean::ExternCrate(..)) => Greater,
1214                     _ => idx1.cmp(&idx2),
1215                 }
1216             }
1217             (&clean::ViewItemItem(..), _) => Less,
1218             (_, &clean::ViewItemItem(..)) => Greater,
1219             (&clean::ModuleItem(..), _) => Less,
1220             (_, &clean::ModuleItem(..)) => Greater,
1221             (&clean::MacroItem(..), _) => Less,
1222             (_, &clean::MacroItem(..)) => Greater,
1223             (&clean::StructItem(..), _) => Less,
1224             (_, &clean::StructItem(..)) => Greater,
1225             (&clean::EnumItem(..), _) => Less,
1226             (_, &clean::EnumItem(..)) => Greater,
1227             (&clean::StaticItem(..), _) => Less,
1228             (_, &clean::StaticItem(..)) => Greater,
1229             (&clean::ForeignFunctionItem(..), _) => Less,
1230             (_, &clean::ForeignFunctionItem(..)) => Greater,
1231             (&clean::ForeignStaticItem(..), _) => Less,
1232             (_, &clean::ForeignStaticItem(..)) => Greater,
1233             (&clean::TraitItem(..), _) => Less,
1234             (_, &clean::TraitItem(..)) => Greater,
1235             (&clean::FunctionItem(..), _) => Less,
1236             (_, &clean::FunctionItem(..)) => Greater,
1237             (&clean::TypedefItem(..), _) => Less,
1238             (_, &clean::TypedefItem(..)) => Greater,
1239             _ => idx1.cmp(&idx2),
1240         }
1241     }
1242
1243     debug!("{:?}", indices);
1244     indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
1245
1246     debug!("{:?}", indices);
1247     let mut curty = None;
1248     for &idx in indices.iter() {
1249         let myitem = &items[idx];
1250
1251         let myty = Some(shortty(myitem));
1252         if myty != curty {
1253             if curty.is_some() {
1254                 try!(write!(w, "</table>"));
1255             }
1256             curty = myty;
1257             let (short, name) = match myitem.inner {
1258                 clean::ModuleItem(..)          => ("modules", "Modules"),
1259                 clean::StructItem(..)          => ("structs", "Structs"),
1260                 clean::EnumItem(..)            => ("enums", "Enums"),
1261                 clean::FunctionItem(..)        => ("functions", "Functions"),
1262                 clean::TypedefItem(..)         => ("types", "Type Definitions"),
1263                 clean::StaticItem(..)          => ("statics", "Statics"),
1264                 clean::TraitItem(..)           => ("traits", "Traits"),
1265                 clean::ImplItem(..)            => ("impls", "Implementations"),
1266                 clean::ViewItemItem(..)        => ("reexports", "Reexports"),
1267                 clean::TyMethodItem(..)        => ("tymethods", "Type Methods"),
1268                 clean::MethodItem(..)          => ("methods", "Methods"),
1269                 clean::StructFieldItem(..)     => ("fields", "Struct Fields"),
1270                 clean::VariantItem(..)         => ("variants", "Variants"),
1271                 clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"),
1272                 clean::ForeignStaticItem(..)   => ("ffi-statics", "Foreign Statics"),
1273                 clean::MacroItem(..)           => ("macros", "Macros"),
1274             };
1275             try!(write!(w,
1276                         "<h2 id='{id}' class='section-header'>\
1277                         <a href=\"\\#{id}\">{name}</a></h2>\n<table>",
1278                         id = short, name = name));
1279         }
1280
1281         match myitem.inner {
1282             clean::StaticItem(ref s) | clean::ForeignStaticItem(ref s) => {
1283                 struct Initializer<'a>(&'a str, Item<'a>);
1284                 impl<'a> fmt::Show for Initializer<'a> {
1285                     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1286                         let Initializer(s, item) = *self;
1287                         if s.len() == 0 { return Ok(()); }
1288                         try!(write!(f, "<code> = </code>"));
1289                         if s.contains("\n") {
1290                             write!(f, "<a href='{}'>[definition]</a>",
1291                                    item.link())
1292                         } else {
1293                             write!(f, "<code>{}</code>", s.as_slice())
1294                         }
1295                     }
1296                 }
1297
1298                 try!(write!(w, "
1299                     <tr>
1300                         <td><code>{}static {}: {}</code>{}</td>
1301                         <td class='docblock'>{}&nbsp;</td>
1302                     </tr>
1303                 ",
1304                 VisSpace(myitem.visibility),
1305                 *myitem.name.get_ref(),
1306                 s.type_,
1307                 Initializer(s.expr.as_slice(), Item { cx: cx, item: myitem }),
1308                 Markdown(blank(myitem.doc_value()))));
1309             }
1310
1311             clean::ViewItemItem(ref item) => {
1312                 match item.inner {
1313                     clean::ExternCrate(ref name, ref src, _) => {
1314                         try!(write!(w, "<tr><td><code>extern crate {}",
1315                                       name.as_slice()));
1316                         match *src {
1317                             Some(ref src) => try!(write!(w, " = \"{}\"",
1318                                                            src.as_slice())),
1319                             None => {}
1320                         }
1321                         try!(write!(w, ";</code></td></tr>"));
1322                     }
1323
1324                     clean::Import(ref import) => {
1325                         try!(write!(w, "<tr><td><code>{}{}</code></td></tr>",
1326                                       VisSpace(myitem.visibility),
1327                                       *import));
1328                     }
1329                 }
1330
1331             }
1332
1333             _ => {
1334                 if myitem.name.is_none() { continue }
1335                 try!(write!(w, "
1336                     <tr>
1337                         <td><a class='{class}' href='{href}'
1338                                title='{title}'>{}</a></td>
1339                         <td class='docblock short'>{}</td>
1340                     </tr>
1341                 ",
1342                 *myitem.name.get_ref(),
1343                 Markdown(shorter(myitem.doc_value())),
1344                 class = shortty(myitem),
1345                 href = item_path(myitem),
1346                 title = full_path(cx, myitem)));
1347             }
1348         }
1349     }
1350     write!(w, "</table>")
1351 }
1352
1353 fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
1354                  f: &clean::Function) -> fmt::Result {
1355     try!(write!(w, "<pre class='rust fn'>{vis}{fn_style}fn \
1356                     {name}{generics}{decl}</pre>",
1357            vis = VisSpace(it.visibility),
1358            fn_style = FnStyleSpace(f.fn_style),
1359            name = it.name.get_ref().as_slice(),
1360            generics = f.generics,
1361            decl = f.decl));
1362     document(w, it)
1363 }
1364
1365 fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1366               t: &clean::Trait) -> fmt::Result {
1367     let mut parents = String::new();
1368     if t.parents.len() > 0 {
1369         parents.push_str(": ");
1370         for (i, p) in t.parents.iter().enumerate() {
1371             if i > 0 { parents.push_str(" + "); }
1372             parents.push_str(format!("{}", *p).as_slice());
1373         }
1374     }
1375
1376     // Output the trait definition
1377     try!(write!(w, "<pre class='rust trait'>{}trait {}{}{} ",
1378                   VisSpace(it.visibility),
1379                   it.name.get_ref().as_slice(),
1380                   t.generics,
1381                   parents));
1382     let required = t.methods.iter().filter(|m| m.is_req()).collect::<Vec<&clean::TraitMethod>>();
1383     let provided = t.methods.iter().filter(|m| !m.is_req()).collect::<Vec<&clean::TraitMethod>>();
1384
1385     if t.methods.len() == 0 {
1386         try!(write!(w, "\\{ \\}"));
1387     } else {
1388         try!(write!(w, "\\{\n"));
1389         for m in required.iter() {
1390             try!(write!(w, "    "));
1391             try!(render_method(w, m.item()));
1392             try!(write!(w, ";\n"));
1393         }
1394         if required.len() > 0 && provided.len() > 0 {
1395             try!(w.write("\n".as_bytes()));
1396         }
1397         for m in provided.iter() {
1398             try!(write!(w, "    "));
1399             try!(render_method(w, m.item()));
1400             try!(write!(w, " \\{ ... \\}\n"));
1401         }
1402         try!(write!(w, "\\}"));
1403     }
1404     try!(write!(w, "</pre>"));
1405
1406     // Trait documentation
1407     try!(document(w, it));
1408
1409     fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
1410         try!(write!(w, "<h3 id='{}.{}' class='method'><code>",
1411                       shortty(m.item()),
1412                       *m.item().name.get_ref()));
1413         try!(render_method(w, m.item()));
1414         try!(write!(w, "</code></h3>"));
1415         try!(document(w, m.item()));
1416         Ok(())
1417     }
1418
1419     // Output the documentation for each function individually
1420     if required.len() > 0 {
1421         try!(write!(w, "
1422             <h2 id='required-methods'>Required Methods</h2>
1423             <div class='methods'>
1424         "));
1425         for m in required.iter() {
1426             try!(meth(w, *m));
1427         }
1428         try!(write!(w, "</div>"));
1429     }
1430     if provided.len() > 0 {
1431         try!(write!(w, "
1432             <h2 id='provided-methods'>Provided Methods</h2>
1433             <div class='methods'>
1434         "));
1435         for m in provided.iter() {
1436             try!(meth(w, *m));
1437         }
1438         try!(write!(w, "</div>"));
1439     }
1440
1441     match cache_key.get().unwrap().implementors.find(&it.def_id) {
1442         Some(implementors) => {
1443             try!(write!(w, "
1444                 <h2 id='implementors'>Implementors</h2>
1445                 <ul class='item-list' id='implementors-list'>
1446             "));
1447             for i in implementors.iter() {
1448                 match *i {
1449                     PathType(ref ty) => {
1450                         try!(write!(w, "<li><code>{}</code></li>", *ty));
1451                     }
1452                     OtherType(ref generics, ref trait_, ref for_) => {
1453                         try!(write!(w, "<li><code>impl{} {} for {}</code></li>",
1454                                       *generics, *trait_, *for_));
1455                     }
1456                 }
1457             }
1458             try!(write!(w, "</ul>"));
1459             try!(write!(w, r#"<script type="text/javascript" async
1460                                       src="{}/implementors/{}/{}.{}.js"></script>"#,
1461                         cx.current.iter().map(|_| "..")
1462                                   .collect::<Vec<&str>>().connect("/"),
1463                         cx.current.connect("/"),
1464                         shortty(it).to_static_str(),
1465                         *it.name.get_ref()));
1466         }
1467         None => {}
1468     }
1469     Ok(())
1470 }
1471
1472 fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
1473     fn fun(w: &mut fmt::Formatter, it: &clean::Item, fn_style: ast::FnStyle,
1474            g: &clean::Generics, selfty: &clean::SelfTy,
1475            d: &clean::FnDecl) -> fmt::Result {
1476         write!(w, "{}fn <a href='\\#{ty}.{name}' class='fnname'>{name}</a>\
1477                    {generics}{decl}",
1478                match fn_style {
1479                    ast::UnsafeFn => "unsafe ",
1480                    _ => "",
1481                },
1482                ty = shortty(it),
1483                name = it.name.get_ref().as_slice(),
1484                generics = *g,
1485                decl = Method(selfty, d))
1486     }
1487     match meth.inner {
1488         clean::TyMethodItem(ref m) => {
1489             fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
1490         }
1491         clean::MethodItem(ref m) => {
1492             fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
1493         }
1494         _ => unreachable!()
1495     }
1496 }
1497
1498 fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
1499                s: &clean::Struct) -> fmt::Result {
1500     try!(write!(w, "<pre class='rust struct'>"));
1501     try!(render_struct(w,
1502                        it,
1503                        Some(&s.generics),
1504                        s.struct_type,
1505                        s.fields.as_slice(),
1506                        "",
1507                        true));
1508     try!(write!(w, "</pre>"));
1509
1510     try!(document(w, it));
1511     let mut fields = s.fields.iter().filter(|f| {
1512         match f.inner {
1513             clean::StructFieldItem(clean::HiddenStructField) => false,
1514             clean::StructFieldItem(clean::TypedStructField(..)) => true,
1515             _ => false,
1516         }
1517     }).peekable();
1518     match s.struct_type {
1519         doctree::Plain if fields.peek().is_some() => {
1520             try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
1521             for field in fields {
1522                 try!(write!(w, "<tr><td id='structfield.{name}'>\
1523                                   <code>{name}</code></td><td>",
1524                               name = field.name.get_ref().as_slice()));
1525                 try!(document(w, field));
1526                 try!(write!(w, "</td></tr>"));
1527             }
1528             try!(write!(w, "</table>"));
1529         }
1530         _ => {}
1531     }
1532     render_methods(w, it)
1533 }
1534
1535 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
1536              e: &clean::Enum) -> fmt::Result {
1537     try!(write!(w, "<pre class='rust enum'>{}enum {}{}",
1538                   VisSpace(it.visibility),
1539                   it.name.get_ref().as_slice(),
1540                   e.generics));
1541     if e.variants.len() == 0 && !e.variants_stripped {
1542         try!(write!(w, " \\{\\}"));
1543     } else {
1544         try!(write!(w, " \\{\n"));
1545         for v in e.variants.iter() {
1546             try!(write!(w, "    "));
1547             let name = v.name.get_ref().as_slice();
1548             match v.inner {
1549                 clean::VariantItem(ref var) => {
1550                     match var.kind {
1551                         clean::CLikeVariant => try!(write!(w, "{}", name)),
1552                         clean::TupleVariant(ref tys) => {
1553                             try!(write!(w, "{}(", name));
1554                             for (i, ty) in tys.iter().enumerate() {
1555                                 if i > 0 {
1556                                     try!(write!(w, ", "))
1557                                 }
1558                                 try!(write!(w, "{}", *ty));
1559                             }
1560                             try!(write!(w, ")"));
1561                         }
1562                         clean::StructVariant(ref s) => {
1563                             try!(render_struct(w,
1564                                                v,
1565                                                None,
1566                                                s.struct_type,
1567                                                s.fields.as_slice(),
1568                                                "    ",
1569                                                false));
1570                         }
1571                     }
1572                 }
1573                 _ => unreachable!()
1574             }
1575             try!(write!(w, ",\n"));
1576         }
1577
1578         if e.variants_stripped {
1579             try!(write!(w, "    // some variants omitted\n"));
1580         }
1581         try!(write!(w, "\\}"));
1582     }
1583     try!(write!(w, "</pre>"));
1584
1585     try!(document(w, it));
1586     if e.variants.len() > 0 {
1587         try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
1588         for variant in e.variants.iter() {
1589             try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
1590                           name = variant.name.get_ref().as_slice()));
1591             try!(document(w, variant));
1592             match variant.inner {
1593                 clean::VariantItem(ref var) => {
1594                     match var.kind {
1595                         clean::StructVariant(ref s) => {
1596                             let mut fields = s.fields.iter().filter(|f| {
1597                                 match f.inner {
1598                                     clean::StructFieldItem(ref t) => match *t {
1599                                         clean::HiddenStructField => false,
1600                                         clean::TypedStructField(..) => true,
1601                                     },
1602                                     _ => false,
1603                                 }
1604                             });
1605                             try!(write!(w, "<h3 class='fields'>Fields</h3>\n
1606                                               <table>"));
1607                             for field in fields {
1608                                 try!(write!(w, "<tr><td \
1609                                                   id='variant.{v}.field.{f}'>\
1610                                                   <code>{f}</code></td><td>",
1611                                               v = variant.name.get_ref().as_slice(),
1612                                               f = field.name.get_ref().as_slice()));
1613                                 try!(document(w, field));
1614                                 try!(write!(w, "</td></tr>"));
1615                             }
1616                             try!(write!(w, "</table>"));
1617                         }
1618                         _ => ()
1619                     }
1620                 }
1621                 _ => ()
1622             }
1623             try!(write!(w, "</td></tr>"));
1624         }
1625         try!(write!(w, "</table>"));
1626
1627     }
1628     try!(render_methods(w, it));
1629     Ok(())
1630 }
1631
1632 fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
1633                  g: Option<&clean::Generics>,
1634                  ty: doctree::StructType,
1635                  fields: &[clean::Item],
1636                  tab: &str,
1637                  structhead: bool) -> fmt::Result {
1638     try!(write!(w, "{}{}{}",
1639                   VisSpace(it.visibility),
1640                   if structhead {"struct "} else {""},
1641                   it.name.get_ref().as_slice()));
1642     match g {
1643         Some(g) => try!(write!(w, "{}", *g)),
1644         None => {}
1645     }
1646     match ty {
1647         doctree::Plain => {
1648             try!(write!(w, " \\{\n{}", tab));
1649             let mut fields_stripped = false;
1650             for field in fields.iter() {
1651                 match field.inner {
1652                     clean::StructFieldItem(clean::HiddenStructField) => {
1653                         fields_stripped = true;
1654                     }
1655                     clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
1656                         try!(write!(w, "    {}{}: {},\n{}",
1657                                       VisSpace(field.visibility),
1658                                       field.name.get_ref().as_slice(),
1659                                       *ty,
1660                                       tab));
1661                     }
1662                     _ => unreachable!(),
1663                 };
1664             }
1665
1666             if fields_stripped {
1667                 try!(write!(w, "    // some fields omitted\n{}", tab));
1668             }
1669             try!(write!(w, "\\}"));
1670         }
1671         doctree::Tuple | doctree::Newtype => {
1672             try!(write!(w, "("));
1673             for (i, field) in fields.iter().enumerate() {
1674                 if i > 0 {
1675                     try!(write!(w, ", "));
1676                 }
1677                 match field.inner {
1678                     clean::StructFieldItem(clean::HiddenStructField) => {
1679                         try!(write!(w, "_"))
1680                     }
1681                     clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
1682                         try!(write!(w, "{}{}", VisSpace(field.visibility), *ty))
1683                     }
1684                     _ => unreachable!()
1685                 }
1686             }
1687             try!(write!(w, ");"));
1688         }
1689         doctree::Unit => {
1690             try!(write!(w, ";"));
1691         }
1692     }
1693     Ok(())
1694 }
1695
1696 fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
1697     match cache_key.get().unwrap().impls.find(&it.def_id) {
1698         Some(v) => {
1699             let mut non_trait = v.iter().filter(|p| {
1700                 p.ref0().trait_.is_none()
1701             });
1702             let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<String>)>>();
1703             let mut traits = v.iter().filter(|p| {
1704                 p.ref0().trait_.is_some()
1705             });
1706             let traits = traits.collect::<Vec<&(clean::Impl, Option<String>)>>();
1707
1708             if non_trait.len() > 0 {
1709                 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
1710                 for &(ref i, ref dox) in non_trait.move_iter() {
1711                     try!(render_impl(w, i, dox));
1712                 }
1713             }
1714             if traits.len() > 0 {
1715                 try!(write!(w, "<h2 id='implementations'>Trait \
1716                                   Implementations</h2>"));
1717                 let mut any_derived = false;
1718                 for & &(ref i, ref dox) in traits.iter() {
1719                     if !i.derived {
1720                         try!(render_impl(w, i, dox));
1721                     } else {
1722                         any_derived = true;
1723                     }
1724                 }
1725                 if any_derived {
1726                     try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
1727                                 </h3>"));
1728                     for &(ref i, ref dox) in traits.move_iter() {
1729                         if i.derived {
1730                             try!(render_impl(w, i, dox));
1731                         }
1732                     }
1733                 }
1734             }
1735         }
1736         None => {}
1737     }
1738     Ok(())
1739 }
1740
1741 fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
1742                dox: &Option<String>) -> fmt::Result {
1743     try!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics));
1744     match i.trait_ {
1745         Some(ref ty) => try!(write!(w, "{} for ", *ty)),
1746         None => {}
1747     }
1748     try!(write!(w, "{}</code></h3>", i.for_));
1749     match *dox {
1750         Some(ref dox) => {
1751             try!(write!(w, "<div class='docblock'>{}</div>",
1752                           Markdown(dox.as_slice())));
1753         }
1754         None => {}
1755     }
1756
1757     fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
1758                dox: bool) -> fmt::Result {
1759         try!(write!(w, "<h4 id='method.{}' class='method'><code>",
1760                       *item.name.get_ref()));
1761         try!(render_method(w, item));
1762         try!(write!(w, "</code></h4>\n"));
1763         match item.doc_value() {
1764             Some(s) if dox => {
1765                 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1766                 Ok(())
1767             }
1768             Some(..) | None => Ok(())
1769         }
1770     }
1771
1772     try!(write!(w, "<div class='methods'>"));
1773     for meth in i.methods.iter() {
1774         try!(docmeth(w, meth, true));
1775     }
1776
1777     fn render_default_methods(w: &mut fmt::Formatter,
1778                               t: &clean::Trait,
1779                               i: &clean::Impl) -> fmt::Result {
1780         for method in t.methods.iter() {
1781             let n = method.item().name.clone();
1782             match i.methods.iter().find(|m| { m.name == n }) {
1783                 Some(..) => continue,
1784                 None => {}
1785             }
1786
1787             try!(docmeth(w, method.item(), false));
1788         }
1789         Ok(())
1790     }
1791
1792     // If we've implemented a trait, then also emit documentation for all
1793     // default methods which weren't overridden in the implementation block.
1794     match i.trait_ {
1795         Some(clean::ResolvedPath { did, .. }) => {
1796             try!({
1797                 match cache_key.get().unwrap().traits.find(&did) {
1798                     Some(t) => try!(render_default_methods(w, t, i)),
1799                     None => {}
1800                 }
1801                 Ok(())
1802             })
1803         }
1804         Some(..) | None => {}
1805     }
1806     try!(write!(w, "</div>"));
1807     Ok(())
1808 }
1809
1810 fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
1811                 t: &clean::Typedef) -> fmt::Result {
1812     try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
1813                   it.name.get_ref().as_slice(),
1814                   t.generics,
1815                   t.type_));
1816
1817     document(w, it)
1818 }
1819
1820 impl<'a> fmt::Show for Sidebar<'a> {
1821     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1822         let cx = self.cx;
1823         let it = self.item;
1824         try!(write!(fmt, "<p class='location'>"));
1825         let len = cx.current.len() - if it.is_mod() {1} else {0};
1826         for (i, name) in cx.current.iter().take(len).enumerate() {
1827             if i > 0 {
1828                 try!(write!(fmt, "&\\#8203;::"));
1829             }
1830             try!(write!(fmt, "<a href='{}index.html'>{}</a>",
1831                           cx.root_path
1832                             .as_slice()
1833                             .slice_to((cx.current.len() - i - 1) * 3),
1834                           *name));
1835         }
1836         try!(write!(fmt, "</p>"));
1837
1838         fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
1839                  cur: &clean::Item, cx: &Context) -> fmt::Result {
1840             let items = match cx.sidebar.find_equiv(&short) {
1841                 Some(items) => items.as_slice(),
1842                 None => return Ok(())
1843             };
1844             try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
1845             for item in items.iter() {
1846                 let curty = shortty(cur).to_static_str();
1847                 let class = if cur.name.get_ref() == item &&
1848                                short == curty { "current" } else { "" };
1849                 try!(write!(w, "<a class='{ty} {class}' href='{curty, select,
1850                                 mod{../}
1851                                 other{}
1852                            }{tysel, select,
1853                                 mod{{name}/index.html}
1854                                 other{#.{name}.html}
1855                            }'>{name}</a><br/>",
1856                        ty = short,
1857                        tysel = short,
1858                        class = class,
1859                        curty = curty,
1860                        name = item.as_slice()));
1861             }
1862             try!(write!(w, "</div>"));
1863             Ok(())
1864         }
1865
1866         try!(block(fmt, "mod", "Modules", it, cx));
1867         try!(block(fmt, "struct", "Structs", it, cx));
1868         try!(block(fmt, "enum", "Enums", it, cx));
1869         try!(block(fmt, "trait", "Traits", it, cx));
1870         try!(block(fmt, "fn", "Functions", it, cx));
1871         try!(block(fmt, "macro", "Macros", it, cx));
1872         Ok(())
1873     }
1874 }
1875
1876 fn build_sidebar(m: &clean::Module) -> HashMap<String, Vec<String>> {
1877     let mut map = HashMap::new();
1878     for item in m.items.iter() {
1879         let short = shortty(item).to_static_str();
1880         let myname = match item.name {
1881             None => continue,
1882             Some(ref s) => s.to_strbuf(),
1883         };
1884         let v = map.find_or_insert_with(short.to_strbuf(), |_| Vec::new());
1885         v.push(myname);
1886     }
1887
1888     for (_, items) in map.mut_iter() {
1889         items.as_mut_slice().sort();
1890     }
1891     return map;
1892 }
1893
1894 impl<'a> fmt::Show for Source<'a> {
1895     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1896         let Source(s) = *self;
1897         let lines = s.lines().len();
1898         let mut cols = 0;
1899         let mut tmp = lines;
1900         while tmp > 0 {
1901             cols += 1;
1902             tmp /= 10;
1903         }
1904         try!(write!(fmt, "<pre class='line-numbers'>"));
1905         for i in range(1, lines + 1) {
1906             try!(write!(fmt, "<span id='{0:u}'>{0:1$u}</span>\n", i, cols));
1907         }
1908         try!(write!(fmt, "</pre>"));
1909         try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None)));
1910         Ok(())
1911     }
1912 }
1913
1914 fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
1915               t: &clean::Macro) -> fmt::Result {
1916     try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro")).as_bytes()));
1917     document(w, it)
1918 }