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