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