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