]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render.rs
auto merge of #15727 : fhahn/rust/remove-some-unwraps, r=alexcrichton
[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                 match parent {
849                     (parent, Some(path)) if !self.privmod => {
850                         self.search_index.push(IndexItem {
851                             ty: shortty(&item),
852                             name: s.to_string(),
853                             path: path.connect("::").to_string(),
854                             desc: shorter(item.doc_value()).to_string(),
855                             parent: parent,
856                         });
857                     }
858                     (Some(parent), None) if !self.privmod => {
859                         if ast_util::is_local(parent) {
860                             // We have a parent, but we don't know where they're
861                             // defined yet. Wait for later to index this item.
862                             self.orphan_methods.push((parent.node, item.clone()))
863                         }
864                     }
865                     _ => {}
866                 }
867             }
868             None => {}
869         }
870
871         // Keep track of the fully qualified path for this item.
872         let pushed = if item.name.is_some() {
873             let n = item.name.get_ref();
874             if n.len() > 0 {
875                 self.stack.push(n.to_string());
876                 true
877             } else { false }
878         } else { false };
879         match item.inner {
880             clean::StructItem(..) | clean::EnumItem(..) |
881             clean::TypedefItem(..) | clean::TraitItem(..) |
882             clean::FunctionItem(..) | clean::ModuleItem(..) |
883             clean::ForeignFunctionItem(..) if !self.privmod => {
884                 // Reexported items mean that the same id can show up twice
885                 // in the rustdoc ast that we're looking at. We know,
886                 // however, that a reexported item doesn't show up in the
887                 // `public_items` map, so we can skip inserting into the
888                 // paths map if there was already an entry present and we're
889                 // not a public item.
890                 let id = item.def_id.node;
891                 if !self.paths.contains_key(&item.def_id) ||
892                    !ast_util::is_local(item.def_id) ||
893                    self.public_items.contains(&id) {
894                     self.paths.insert(item.def_id,
895                                       (self.stack.clone(), shortty(&item)));
896                 }
897             }
898             // link variants to their parent enum because pages aren't emitted
899             // for each variant
900             clean::VariantItem(..) if !self.privmod => {
901                 let mut stack = self.stack.clone();
902                 stack.pop();
903                 self.paths.insert(item.def_id, (stack, item_type::Enum));
904             }
905
906             clean::PrimitiveItem(..) if item.visibility.is_some() => {
907                 self.paths.insert(item.def_id, (self.stack.clone(),
908                                                 shortty(&item)));
909             }
910
911             _ => {}
912         }
913
914         // Maintain the parent stack
915         let parent_pushed = match item.inner {
916             clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
917                 self.parent_stack.push(item.def_id);
918                 true
919             }
920             clean::ImplItem(ref i) => {
921                 match i.for_ {
922                     clean::ResolvedPath{ did, .. } => {
923                         self.parent_stack.push(did);
924                         true
925                     }
926                     _ => false
927                 }
928             }
929             _ => false
930         };
931
932         // Once we've recursively found all the generics, then hoard off all the
933         // implementations elsewhere
934         let ret = match self.fold_item_recur(item) {
935             Some(item) => {
936                 match item {
937                     clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
938                         use clean::{Primitive, Vector, ResolvedPath, BorrowedRef};
939                         use clean::{FixedVector, Slice, Tuple, PrimitiveTuple};
940
941                         // extract relevant documentation for this impl
942                         let dox = match attrs.move_iter().find(|a| {
943                             match *a {
944                                 clean::NameValue(ref x, _)
945                                         if "doc" == x.as_slice() => {
946                                     true
947                                 }
948                                 _ => false
949                             }
950                         }) {
951                             Some(clean::NameValue(_, dox)) => Some(dox),
952                             Some(..) | None => None,
953                         };
954
955                         // Figure out the id of this impl. This may map to a
956                         // primitive rather than always to a struct/enum.
957                         let did = match i.for_ {
958                             ResolvedPath { did, .. } => Some(did),
959
960                             // References to primitives are picked up as well to
961                             // recognize implementations for &str, this may not
962                             // be necessary in a DST world.
963                             Primitive(p) |
964                                 BorrowedRef { type_: box Primitive(p), ..} =>
965                             {
966                                 Some(ast_util::local_def(p.to_node_id()))
967                             }
968
969                             // In a DST world, we may only need
970                             // Vector/FixedVector, but for now we also pick up
971                             // borrowed references
972                             Vector(..) | FixedVector(..) |
973                                 BorrowedRef{ type_: box Vector(..), ..  } |
974                                 BorrowedRef{ type_: box FixedVector(..), .. } =>
975                             {
976                                 Some(ast_util::local_def(Slice.to_node_id()))
977                             }
978
979                             Tuple(..) => {
980                                 let id = PrimitiveTuple.to_node_id();
981                                 Some(ast_util::local_def(id))
982                             }
983
984                             _ => None,
985                         };
986
987                         match did {
988                             Some(did) => {
989                                 let v = self.impls.find_or_insert_with(did, |_| {
990                                     Vec::new()
991                                 });
992                                 v.push(Impl {
993                                     impl_: i,
994                                     dox: dox,
995                                     stability: item.stability.clone(),
996                                 });
997                             }
998                             None => {}
999                         }
1000                         None
1001                     }
1002
1003                     i => Some(i),
1004                 }
1005             }
1006             i => i,
1007         };
1008
1009         if pushed { self.stack.pop().unwrap(); }
1010         if parent_pushed { self.parent_stack.pop().unwrap(); }
1011         self.privmod = orig_privmod;
1012         return ret;
1013     }
1014 }
1015
1016 impl<'a> Cache {
1017     fn generics(&mut self, generics: &clean::Generics) {
1018         for typ in generics.type_params.iter() {
1019             self.typarams.insert(typ.did, typ.name.clone());
1020         }
1021     }
1022 }
1023
1024 impl Context {
1025     /// Recurse in the directory structure and change the "root path" to make
1026     /// sure it always points to the top (relatively)
1027     fn recurse<T>(&mut self, s: String, f: |&mut Context| -> T) -> T {
1028         if s.len() == 0 {
1029             fail!("what {:?}", self);
1030         }
1031         let prev = self.dst.clone();
1032         self.dst.push(s.as_slice());
1033         self.root_path.push_str("../");
1034         self.current.push(s);
1035
1036         info!("Recursing into {}", self.dst.display());
1037
1038         mkdir(&self.dst).unwrap();
1039         let ret = f(self);
1040
1041         info!("Recursed; leaving {}", self.dst.display());
1042
1043         // Go back to where we were at
1044         self.dst = prev;
1045         let len = self.root_path.len();
1046         self.root_path.truncate(len - 3);
1047         self.current.pop().unwrap();
1048
1049         return ret;
1050     }
1051
1052     /// Main method for rendering a crate.
1053     ///
1054     /// This currently isn't parallelized, but it'd be pretty easy to add
1055     /// parallelization to this function.
1056     fn krate(mut self, mut krate: clean::Crate,
1057              stability: stability_summary::ModuleSummary) -> io::IoResult<()> {
1058         let mut item = match krate.module.take() {
1059             Some(i) => i,
1060             None => return Ok(())
1061         };
1062         item.name = Some(krate.name);
1063
1064         // render stability dashboard
1065         try!(self.recurse(stability.name.clone(), |this| {
1066             let json_dst = &this.dst.join("stability.json");
1067             let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
1068             try!(stability.encode(&mut json::Encoder::new(&mut json_out)));
1069
1070             let title = stability.name.clone().append(" - Stability dashboard");
1071             let page = layout::Page {
1072                 ty: "mod",
1073                 root_path: this.root_path.as_slice(),
1074                 title: title.as_slice(),
1075             };
1076             let html_dst = &this.dst.join("stability.html");
1077             let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
1078             layout::render(&mut html_out, &this.layout, &page,
1079                            &Sidebar{ cx: this, item: &item },
1080                            &stability)
1081         }));
1082
1083         // render the crate documentation
1084         let mut work = vec!((self, item));
1085         loop {
1086             match work.pop() {
1087                 Some((mut cx, item)) => try!(cx.item(item, |cx, item| {
1088                     work.push((cx.clone(), item));
1089                 })),
1090                 None => break,
1091             }
1092         }
1093
1094         Ok(())
1095     }
1096
1097     /// Non-parellelized version of rendering an item. This will take the input
1098     /// item, render its contents, and then invoke the specified closure with
1099     /// all sub-items which need to be rendered.
1100     ///
1101     /// The rendering driver uses this closure to queue up more work.
1102     fn item(&mut self, item: clean::Item,
1103             f: |&mut Context, clean::Item|) -> io::IoResult<()> {
1104         fn render(w: io::File, cx: &Context, it: &clean::Item,
1105                   pushname: bool) -> io::IoResult<()> {
1106             info!("Rendering an item to {}", w.path().display());
1107             // A little unfortunate that this is done like this, but it sure
1108             // does make formatting *a lot* nicer.
1109             current_location_key.replace(Some(cx.current.clone()));
1110
1111             let mut title = cx.current.connect("::");
1112             if pushname {
1113                 if title.len() > 0 {
1114                     title.push_str("::");
1115                 }
1116                 title.push_str(it.name.get_ref().as_slice());
1117             }
1118             title.push_str(" - Rust");
1119             let page = layout::Page {
1120                 ty: shortty(it).to_static_str(),
1121                 root_path: cx.root_path.as_slice(),
1122                 title: title.as_slice(),
1123             };
1124
1125             markdown::reset_headers();
1126
1127             // We have a huge number of calls to write, so try to alleviate some
1128             // of the pain by using a buffered writer instead of invoking the
1129             // write sycall all the time.
1130             let mut writer = BufferedWriter::new(w);
1131             if !cx.render_redirect_pages {
1132                 try!(layout::render(&mut writer, &cx.layout, &page,
1133                                     &Sidebar{ cx: cx, item: it },
1134                                     &Item{ cx: cx, item: it }));
1135             } else {
1136                 let mut url = "../".repeat(cx.current.len());
1137                 match cache_key.get().unwrap().paths.find(&it.def_id) {
1138                     Some(&(ref names, _)) => {
1139                         for name in names.slice_to(names.len() - 1).iter() {
1140                             url.push_str(name.as_slice());
1141                             url.push_str("/");
1142                         }
1143                         url.push_str(item_path(it).as_slice());
1144                         try!(layout::redirect(&mut writer, url.as_slice()));
1145                     }
1146                     None => {}
1147                 }
1148             }
1149             writer.flush()
1150         }
1151
1152         // Private modules may survive the strip-private pass if they
1153         // contain impls for public types. These modules can also
1154         // contain items such as publicly reexported structures.
1155         //
1156         // External crates will provide links to these structures, so
1157         // these modules are recursed into, but not rendered normally (a
1158         // flag on the context).
1159         if !self.render_redirect_pages {
1160             self.render_redirect_pages = ignore_private_item(&item);
1161         }
1162
1163         match item.inner {
1164             // modules are special because they add a namespace. We also need to
1165             // recurse into the items of the module as well.
1166             clean::ModuleItem(..) => {
1167                 let name = item.name.get_ref().to_string();
1168                 let mut item = Some(item);
1169                 self.recurse(name, |this| {
1170                     let item = item.take_unwrap();
1171                     let dst = this.dst.join("index.html");
1172                     let dst = try!(File::create(&dst));
1173                     try!(render(dst, this, &item, false));
1174
1175                     let m = match item.inner {
1176                         clean::ModuleItem(m) => m,
1177                         _ => unreachable!()
1178                     };
1179                     this.sidebar = build_sidebar(&m);
1180                     for item in m.items.move_iter() {
1181                         f(this,item);
1182                     }
1183                     Ok(())
1184                 })
1185             }
1186
1187             // Things which don't have names (like impls) don't get special
1188             // pages dedicated to them.
1189             _ if item.name.is_some() => {
1190                 let dst = self.dst.join(item_path(&item));
1191                 let dst = try!(File::create(&dst));
1192                 render(dst, self, &item, true)
1193             }
1194
1195             _ => Ok(())
1196         }
1197     }
1198 }
1199
1200 impl<'a> Item<'a> {
1201     fn ismodule(&self) -> bool {
1202         match self.item.inner {
1203             clean::ModuleItem(..) => true, _ => false
1204         }
1205     }
1206
1207     /// Generate a url appropriate for an `href` attribute back to the source of
1208     /// this item.
1209     ///
1210     /// The url generated, when clicked, will redirect the browser back to the
1211     /// original source code.
1212     ///
1213     /// If `None` is returned, then a source link couldn't be generated. This
1214     /// may happen, for example, with externally inlined items where the source
1215     /// of their crate documentation isn't known.
1216     fn href(&self) -> Option<String> {
1217         // If this item is part of the local crate, then we're guaranteed to
1218         // know the span, so we plow forward and generate a proper url. The url
1219         // has anchors for the line numbers that we're linking to.
1220         if ast_util::is_local(self.item.def_id) {
1221             let mut path = Vec::new();
1222             clean_srcpath(self.item.source.filename.as_bytes(), |component| {
1223                 path.push(component.to_string());
1224             });
1225             let href = if self.item.source.loline == self.item.source.hiline {
1226                 format!("{}", self.item.source.loline)
1227             } else {
1228                 format!("{}-{}",
1229                         self.item.source.loline,
1230                         self.item.source.hiline)
1231             };
1232             Some(format!("{root}src/{krate}/{path}.html#{href}",
1233                          root = self.cx.root_path,
1234                          krate = self.cx.layout.krate,
1235                          path = path.connect("/"),
1236                          href = href))
1237
1238         // If this item is not part of the local crate, then things get a little
1239         // trickier. We don't actually know the span of the external item, but
1240         // we know that the documentation on the other end knows the span!
1241         //
1242         // In this case, we generate a link to the *documentation* for this type
1243         // in the original crate. There's an extra URL parameter which says that
1244         // we want to go somewhere else, and the JS on the destination page will
1245         // pick it up and instantly redirect the browser to the source code.
1246         //
1247         // If we don't know where the external documentation for this crate is
1248         // located, then we return `None`.
1249         } else {
1250             let cache = cache_key.get().unwrap();
1251             let path = cache.external_paths.get(&self.item.def_id);
1252             let root = match *cache.extern_locations.get(&self.item.def_id.krate) {
1253                 Remote(ref s) => s.to_string(),
1254                 Local => self.cx.root_path.clone(),
1255                 Unknown => return None,
1256             };
1257             Some(format!("{root}{path}/{file}?gotosrc={goto}",
1258                          root = root,
1259                          path = path.slice_to(path.len() - 1).connect("/"),
1260                          file = item_path(self.item),
1261                          goto = self.item.def_id.node))
1262         }
1263     }
1264 }
1265
1266
1267
1268 impl<'a> fmt::Show for Item<'a> {
1269     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1270         // Write the breadcrumb trail header for the top
1271         try!(write!(fmt, "\n<h1 class='fqn'>"));
1272         match self.item.inner {
1273             clean::ModuleItem(ref m) => if m.is_crate {
1274                     try!(write!(fmt, "Crate "));
1275                 } else {
1276                     try!(write!(fmt, "Module "));
1277                 },
1278             clean::FunctionItem(..) => try!(write!(fmt, "Function ")),
1279             clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
1280             clean::StructItem(..) => try!(write!(fmt, "Struct ")),
1281             clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
1282             clean::PrimitiveItem(..) => try!(write!(fmt, "Primitive Type ")),
1283             _ => {}
1284         }
1285         let is_primitive = match self.item.inner {
1286             clean::PrimitiveItem(..) => true,
1287             _ => false,
1288         };
1289         if !is_primitive {
1290             let cur = self.cx.current.as_slice();
1291             let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
1292             for (i, component) in cur.iter().enumerate().take(amt) {
1293                 try!(write!(fmt, "<a href='{}index.html'>{}</a>::",
1294                             "../".repeat(cur.len() - i - 1),
1295                             component.as_slice()));
1296             }
1297         }
1298         try!(write!(fmt, "<a class='{}' href=''>{}</a>",
1299                     shortty(self.item), self.item.name.get_ref().as_slice()));
1300
1301         // Write stability level
1302         try!(write!(fmt, "{}", Stability(&self.item.stability)));
1303
1304         // Links to out-of-band information, i.e. src and stability dashboard
1305         try!(write!(fmt, "<span class='out-of-band'>"));
1306
1307         // Write stability dashboard link
1308         match self.item.inner {
1309             clean::ModuleItem(ref m) if m.is_crate => {
1310                 try!(write!(fmt, "<a href='stability.html'>[stability dashboard]</a> "));
1311             }
1312             _ => {}
1313         };
1314
1315         // Write `src` tag
1316         //
1317         // When this item is part of a `pub use` in a downstream crate, the
1318         // [src] link in the downstream documentation will actually come back to
1319         // this page, and this link will be auto-clicked. The `id` attribute is
1320         // used to find the link to auto-click.
1321         if self.cx.include_sources && !is_primitive {
1322             match self.href() {
1323                 Some(l) => {
1324                     try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
1325                                 self.item.def_id.node, l));
1326                 }
1327                 None => {}
1328             }
1329         }
1330
1331         try!(write!(fmt, "</span>"));
1332
1333         try!(write!(fmt, "</h1>\n"));
1334
1335         match self.item.inner {
1336             clean::ModuleItem(ref m) => {
1337                 item_module(fmt, self.cx, self.item, m.items.as_slice())
1338             }
1339             clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
1340                 item_function(fmt, self.item, f),
1341             clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
1342             clean::StructItem(ref s) => item_struct(fmt, self.item, s),
1343             clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
1344             clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
1345             clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
1346             clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p),
1347             _ => Ok(())
1348         }
1349     }
1350 }
1351
1352 fn item_path(item: &clean::Item) -> String {
1353     match item.inner {
1354         clean::ModuleItem(..) => {
1355             format!("{}/index.html", item.name.get_ref())
1356         }
1357         _ => {
1358             format!("{}.{}.html",
1359                     shortty(item).to_static_str(),
1360                     *item.name.get_ref())
1361         }
1362     }
1363 }
1364
1365 fn full_path(cx: &Context, item: &clean::Item) -> String {
1366     let mut s = cx.current.connect("::");
1367     s.push_str("::");
1368     s.push_str(item.name.get_ref().as_slice());
1369     return s
1370 }
1371
1372 fn blank<'a>(s: Option<&'a str>) -> &'a str {
1373     match s {
1374         Some(s) => s,
1375         None => ""
1376     }
1377 }
1378
1379 fn shorter<'a>(s: Option<&'a str>) -> &'a str {
1380     match s {
1381         Some(s) => match s.find_str("\n\n") {
1382             Some(pos) => s.slice_to(pos),
1383             None => s,
1384         },
1385         None => ""
1386     }
1387 }
1388
1389 fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
1390     match item.doc_value() {
1391         Some(s) => {
1392             try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1393         }
1394         None => {}
1395     }
1396     Ok(())
1397 }
1398
1399 fn item_module(w: &mut fmt::Formatter, cx: &Context,
1400                item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
1401     try!(document(w, item));
1402
1403     let mut indices = range(0, items.len()).filter(|i| {
1404         !ignore_private_item(&items[*i])
1405     }).collect::<Vec<uint>>();
1406
1407     fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
1408         if shortty(i1) == shortty(i2) {
1409             return i1.name.cmp(&i2.name);
1410         }
1411         match (&i1.inner, &i2.inner) {
1412             (&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => {
1413                 match (&a.inner, &b.inner) {
1414                     (&clean::ExternCrate(..), _) => Less,
1415                     (_, &clean::ExternCrate(..)) => Greater,
1416                     _ => idx1.cmp(&idx2),
1417                 }
1418             }
1419             (&clean::ViewItemItem(..), _) => Less,
1420             (_, &clean::ViewItemItem(..)) => Greater,
1421             (&clean::PrimitiveItem(..), _) => Less,
1422             (_, &clean::PrimitiveItem(..)) => Greater,
1423             (&clean::ModuleItem(..), _) => Less,
1424             (_, &clean::ModuleItem(..)) => Greater,
1425             (&clean::MacroItem(..), _) => Less,
1426             (_, &clean::MacroItem(..)) => Greater,
1427             (&clean::StructItem(..), _) => Less,
1428             (_, &clean::StructItem(..)) => Greater,
1429             (&clean::EnumItem(..), _) => Less,
1430             (_, &clean::EnumItem(..)) => Greater,
1431             (&clean::StaticItem(..), _) => Less,
1432             (_, &clean::StaticItem(..)) => Greater,
1433             (&clean::ForeignFunctionItem(..), _) => Less,
1434             (_, &clean::ForeignFunctionItem(..)) => Greater,
1435             (&clean::ForeignStaticItem(..), _) => Less,
1436             (_, &clean::ForeignStaticItem(..)) => Greater,
1437             (&clean::TraitItem(..), _) => Less,
1438             (_, &clean::TraitItem(..)) => Greater,
1439             (&clean::FunctionItem(..), _) => Less,
1440             (_, &clean::FunctionItem(..)) => Greater,
1441             (&clean::TypedefItem(..), _) => Less,
1442             (_, &clean::TypedefItem(..)) => Greater,
1443             _ => idx1.cmp(&idx2),
1444         }
1445     }
1446
1447     indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
1448
1449     debug!("{:?}", indices);
1450     let mut curty = None;
1451     for &idx in indices.iter() {
1452         let myitem = &items[idx];
1453
1454         let myty = Some(shortty(myitem));
1455         if myty != curty {
1456             if curty.is_some() {
1457                 try!(write!(w, "</table>"));
1458             }
1459             curty = myty;
1460             let (short, name) = match myitem.inner {
1461                 clean::ModuleItem(..)          => ("modules", "Modules"),
1462                 clean::StructItem(..)          => ("structs", "Structs"),
1463                 clean::EnumItem(..)            => ("enums", "Enums"),
1464                 clean::FunctionItem(..)        => ("functions", "Functions"),
1465                 clean::TypedefItem(..)         => ("types", "Type Definitions"),
1466                 clean::StaticItem(..)          => ("statics", "Statics"),
1467                 clean::TraitItem(..)           => ("traits", "Traits"),
1468                 clean::ImplItem(..)            => ("impls", "Implementations"),
1469                 clean::ViewItemItem(..)        => ("reexports", "Reexports"),
1470                 clean::TyMethodItem(..)        => ("tymethods", "Type Methods"),
1471                 clean::MethodItem(..)          => ("methods", "Methods"),
1472                 clean::StructFieldItem(..)     => ("fields", "Struct Fields"),
1473                 clean::VariantItem(..)         => ("variants", "Variants"),
1474                 clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"),
1475                 clean::ForeignStaticItem(..)   => ("ffi-statics", "Foreign Statics"),
1476                 clean::MacroItem(..)           => ("macros", "Macros"),
1477                 clean::PrimitiveItem(..)       => ("primitives", "Primitive Types"),
1478             };
1479             try!(write!(w,
1480                         "<h2 id='{id}' class='section-header'>\
1481                         <a href=\"#{id}\">{name}</a></h2>\n<table>",
1482                         id = short, name = name));
1483         }
1484
1485         match myitem.inner {
1486             clean::StaticItem(ref s) | clean::ForeignStaticItem(ref s) => {
1487                 struct Initializer<'a>(&'a str, Item<'a>);
1488                 impl<'a> fmt::Show for Initializer<'a> {
1489                     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1490                         let Initializer(s, item) = *self;
1491                         if s.len() == 0 { return Ok(()); }
1492                         try!(write!(f, "<code> = </code>"));
1493                         if s.contains("\n") {
1494                             match item.href() {
1495                                 Some(url) => {
1496                                     write!(f, "<a href='{}'>[definition]</a>",
1497                                            url)
1498                                 }
1499                                 None => Ok(()),
1500                             }
1501                         } else {
1502                             write!(f, "<code>{}</code>", s.as_slice())
1503                         }
1504                     }
1505                 }
1506
1507                 try!(write!(w, "
1508                     <tr>
1509                         <td>{}<code>{}static {}{}: {}</code>{}</td>
1510                         <td class='docblock'>{}&nbsp;</td>
1511                     </tr>
1512                 ",
1513                 ConciseStability(&myitem.stability),
1514                 VisSpace(myitem.visibility),
1515                 MutableSpace(s.mutability),
1516                 *myitem.name.get_ref(),
1517                 s.type_,
1518                 Initializer(s.expr.as_slice(), Item { cx: cx, item: myitem }),
1519                 Markdown(blank(myitem.doc_value()))));
1520             }
1521
1522             clean::ViewItemItem(ref item) => {
1523                 match item.inner {
1524                     clean::ExternCrate(ref name, ref src, _) => {
1525                         try!(write!(w, "<tr><td><code>extern crate {}",
1526                                       name.as_slice()));
1527                         match *src {
1528                             Some(ref src) => try!(write!(w, " = \"{}\"",
1529                                                            src.as_slice())),
1530                             None => {}
1531                         }
1532                         try!(write!(w, ";</code></td></tr>"));
1533                     }
1534
1535                     clean::Import(ref import) => {
1536                         try!(write!(w, "<tr><td><code>{}{}</code></td></tr>",
1537                                       VisSpace(myitem.visibility),
1538                                       *import));
1539                     }
1540                 }
1541
1542             }
1543
1544             _ => {
1545                 if myitem.name.is_none() { continue }
1546                 try!(write!(w, "
1547                     <tr>
1548                         <td>{stab}<a class='{class}' href='{href}'
1549                                title='{title}'>{}</a></td>
1550                         <td class='docblock short'>{}</td>
1551                     </tr>
1552                 ",
1553                 *myitem.name.get_ref(),
1554                 Markdown(shorter(myitem.doc_value())),
1555                 class = shortty(myitem),
1556                 href = item_path(myitem),
1557                 title = full_path(cx, myitem),
1558                 stab = ConciseStability(&myitem.stability)));
1559             }
1560         }
1561     }
1562
1563     write!(w, "</table>")
1564 }
1565
1566 fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
1567                  f: &clean::Function) -> fmt::Result {
1568     try!(write!(w, "<pre class='rust fn'>{vis}{fn_style}fn \
1569                     {name}{generics}{decl}</pre>",
1570            vis = VisSpace(it.visibility),
1571            fn_style = FnStyleSpace(f.fn_style),
1572            name = it.name.get_ref().as_slice(),
1573            generics = f.generics,
1574            decl = f.decl));
1575     document(w, it)
1576 }
1577
1578 fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1579               t: &clean::Trait) -> fmt::Result {
1580     let mut parents = String::new();
1581     if t.parents.len() > 0 {
1582         parents.push_str(": ");
1583         for (i, p) in t.parents.iter().enumerate() {
1584             if i > 0 { parents.push_str(" + "); }
1585             parents.push_str(format!("{}", *p).as_slice());
1586         }
1587     }
1588
1589     // Output the trait definition
1590     try!(write!(w, "<pre class='rust trait'>{}trait {}{}{} ",
1591                   VisSpace(it.visibility),
1592                   it.name.get_ref().as_slice(),
1593                   t.generics,
1594                   parents));
1595     let required = t.methods.iter().filter(|m| m.is_req()).collect::<Vec<&clean::TraitMethod>>();
1596     let provided = t.methods.iter().filter(|m| !m.is_req()).collect::<Vec<&clean::TraitMethod>>();
1597
1598     if t.methods.len() == 0 {
1599         try!(write!(w, "{{ }}"));
1600     } else {
1601         try!(write!(w, "{{\n"));
1602         for m in required.iter() {
1603             try!(write!(w, "    "));
1604             try!(render_method(w, m.item()));
1605             try!(write!(w, ";\n"));
1606         }
1607         if required.len() > 0 && provided.len() > 0 {
1608             try!(w.write("\n".as_bytes()));
1609         }
1610         for m in provided.iter() {
1611             try!(write!(w, "    "));
1612             try!(render_method(w, m.item()));
1613             try!(write!(w, " {{ ... }}\n"));
1614         }
1615         try!(write!(w, "}}"));
1616     }
1617     try!(write!(w, "</pre>"));
1618
1619     // Trait documentation
1620     try!(document(w, it));
1621
1622     fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
1623         try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>",
1624                     shortty(m.item()),
1625                     *m.item().name.get_ref(),
1626                     ConciseStability(&m.item().stability)));
1627         try!(render_method(w, m.item()));
1628         try!(write!(w, "</code></h3>"));
1629         try!(document(w, m.item()));
1630         Ok(())
1631     }
1632
1633     // Output the documentation for each function individually
1634     if required.len() > 0 {
1635         try!(write!(w, "
1636             <h2 id='required-methods'>Required Methods</h2>
1637             <div class='methods'>
1638         "));
1639         for m in required.iter() {
1640             try!(meth(w, *m));
1641         }
1642         try!(write!(w, "</div>"));
1643     }
1644     if provided.len() > 0 {
1645         try!(write!(w, "
1646             <h2 id='provided-methods'>Provided Methods</h2>
1647             <div class='methods'>
1648         "));
1649         for m in provided.iter() {
1650             try!(meth(w, *m));
1651         }
1652         try!(write!(w, "</div>"));
1653     }
1654
1655     let cache = cache_key.get().unwrap();
1656     try!(write!(w, "
1657         <h2 id='implementors'>Implementors</h2>
1658         <ul class='item-list' id='implementors-list'>
1659     "));
1660     match cache.implementors.find(&it.def_id) {
1661         Some(implementors) => {
1662             for i in implementors.iter() {
1663                 try!(writeln!(w, "<li>{}<code>impl{} {} for {}</code></li>",
1664                               ConciseStability(&i.stability),
1665                               i.generics, i.trait_, i.for_));
1666             }
1667         }
1668         None => {}
1669     }
1670     try!(write!(w, "</ul>"));
1671     try!(write!(w, r#"<script type="text/javascript" async
1672                               src="{root_path}/implementors/{path}/{ty}.{name}.js">
1673                       </script>"#,
1674                 root_path = Vec::from_elem(cx.current.len(), "..").connect("/"),
1675                 path = if ast_util::is_local(it.def_id) {
1676                     cx.current.connect("/")
1677                 } else {
1678                     let path = cache.external_paths.get(&it.def_id);
1679                     path.slice_to(path.len() - 1).connect("/")
1680                 },
1681                 ty = shortty(it).to_static_str(),
1682                 name = *it.name.get_ref()));
1683     Ok(())
1684 }
1685
1686 fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
1687     fn fun(w: &mut fmt::Formatter, it: &clean::Item, fn_style: ast::FnStyle,
1688            g: &clean::Generics, selfty: &clean::SelfTy,
1689            d: &clean::FnDecl) -> fmt::Result {
1690         write!(w, "{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
1691                    {generics}{decl}",
1692                match fn_style {
1693                    ast::UnsafeFn => "unsafe ",
1694                    _ => "",
1695                },
1696                ty = shortty(it),
1697                name = it.name.get_ref().as_slice(),
1698                generics = *g,
1699                decl = Method(selfty, d))
1700     }
1701     match meth.inner {
1702         clean::TyMethodItem(ref m) => {
1703             fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
1704         }
1705         clean::MethodItem(ref m) => {
1706             fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
1707         }
1708         _ => unreachable!()
1709     }
1710 }
1711
1712 fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
1713                s: &clean::Struct) -> fmt::Result {
1714     try!(write!(w, "<pre class='rust struct'>"));
1715     try!(render_struct(w,
1716                        it,
1717                        Some(&s.generics),
1718                        s.struct_type,
1719                        s.fields.as_slice(),
1720                        "",
1721                        true));
1722     try!(write!(w, "</pre>"));
1723
1724     try!(document(w, it));
1725     let mut fields = s.fields.iter().filter(|f| {
1726         match f.inner {
1727             clean::StructFieldItem(clean::HiddenStructField) => false,
1728             clean::StructFieldItem(clean::TypedStructField(..)) => true,
1729             _ => false,
1730         }
1731     }).peekable();
1732     match s.struct_type {
1733         doctree::Plain if fields.peek().is_some() => {
1734             try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
1735             for field in fields {
1736                 try!(write!(w, "<tr><td id='structfield.{name}'>\
1737                                   {stab}<code>{name}</code></td><td>",
1738                               stab = ConciseStability(&field.stability),
1739                               name = field.name.get_ref().as_slice()));
1740                 try!(document(w, field));
1741                 try!(write!(w, "</td></tr>"));
1742             }
1743             try!(write!(w, "</table>"));
1744         }
1745         _ => {}
1746     }
1747     render_methods(w, it)
1748 }
1749
1750 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
1751              e: &clean::Enum) -> fmt::Result {
1752     try!(write!(w, "<pre class='rust enum'>{}enum {}{}",
1753                   VisSpace(it.visibility),
1754                   it.name.get_ref().as_slice(),
1755                   e.generics));
1756     if e.variants.len() == 0 && !e.variants_stripped {
1757         try!(write!(w, " {{}}"));
1758     } else {
1759         try!(write!(w, " {{\n"));
1760         for v in e.variants.iter() {
1761             try!(write!(w, "    "));
1762             let name = v.name.get_ref().as_slice();
1763             match v.inner {
1764                 clean::VariantItem(ref var) => {
1765                     match var.kind {
1766                         clean::CLikeVariant => try!(write!(w, "{}", name)),
1767                         clean::TupleVariant(ref tys) => {
1768                             try!(write!(w, "{}(", name));
1769                             for (i, ty) in tys.iter().enumerate() {
1770                                 if i > 0 {
1771                                     try!(write!(w, ", "))
1772                                 }
1773                                 try!(write!(w, "{}", *ty));
1774                             }
1775                             try!(write!(w, ")"));
1776                         }
1777                         clean::StructVariant(ref s) => {
1778                             try!(render_struct(w,
1779                                                v,
1780                                                None,
1781                                                s.struct_type,
1782                                                s.fields.as_slice(),
1783                                                "    ",
1784                                                false));
1785                         }
1786                     }
1787                 }
1788                 _ => unreachable!()
1789             }
1790             try!(write!(w, ",\n"));
1791         }
1792
1793         if e.variants_stripped {
1794             try!(write!(w, "    // some variants omitted\n"));
1795         }
1796         try!(write!(w, "}}"));
1797     }
1798     try!(write!(w, "</pre>"));
1799
1800     try!(document(w, it));
1801     if e.variants.len() > 0 {
1802         try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
1803         for variant in e.variants.iter() {
1804             try!(write!(w, "<tr><td id='variant.{name}'>{stab}<code>{name}</code></td><td>",
1805                           stab = ConciseStability(&variant.stability),
1806                           name = variant.name.get_ref().as_slice()));
1807             try!(document(w, variant));
1808             match variant.inner {
1809                 clean::VariantItem(ref var) => {
1810                     match var.kind {
1811                         clean::StructVariant(ref s) => {
1812                             let mut fields = s.fields.iter().filter(|f| {
1813                                 match f.inner {
1814                                     clean::StructFieldItem(ref t) => match *t {
1815                                         clean::HiddenStructField => false,
1816                                         clean::TypedStructField(..) => true,
1817                                     },
1818                                     _ => false,
1819                                 }
1820                             });
1821                             try!(write!(w, "<h3 class='fields'>Fields</h3>\n
1822                                               <table>"));
1823                             for field in fields {
1824                                 try!(write!(w, "<tr><td \
1825                                                   id='variant.{v}.field.{f}'>\
1826                                                   <code>{f}</code></td><td>",
1827                                               v = variant.name.get_ref().as_slice(),
1828                                               f = field.name.get_ref().as_slice()));
1829                                 try!(document(w, field));
1830                                 try!(write!(w, "</td></tr>"));
1831                             }
1832                             try!(write!(w, "</table>"));
1833                         }
1834                         _ => ()
1835                     }
1836                 }
1837                 _ => ()
1838             }
1839             try!(write!(w, "</td></tr>"));
1840         }
1841         try!(write!(w, "</table>"));
1842
1843     }
1844     try!(render_methods(w, it));
1845     Ok(())
1846 }
1847
1848 fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
1849                  g: Option<&clean::Generics>,
1850                  ty: doctree::StructType,
1851                  fields: &[clean::Item],
1852                  tab: &str,
1853                  structhead: bool) -> fmt::Result {
1854     try!(write!(w, "{}{}{}",
1855                   VisSpace(it.visibility),
1856                   if structhead {"struct "} else {""},
1857                   it.name.get_ref().as_slice()));
1858     match g {
1859         Some(g) => try!(write!(w, "{}", *g)),
1860         None => {}
1861     }
1862     match ty {
1863         doctree::Plain => {
1864             try!(write!(w, " {{\n{}", tab));
1865             let mut fields_stripped = false;
1866             for field in fields.iter() {
1867                 match field.inner {
1868                     clean::StructFieldItem(clean::HiddenStructField) => {
1869                         fields_stripped = true;
1870                     }
1871                     clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
1872                         try!(write!(w, "    {}{}: {},\n{}",
1873                                       VisSpace(field.visibility),
1874                                       field.name.get_ref().as_slice(),
1875                                       *ty,
1876                                       tab));
1877                     }
1878                     _ => unreachable!(),
1879                 };
1880             }
1881
1882             if fields_stripped {
1883                 try!(write!(w, "    // some fields omitted\n{}", tab));
1884             }
1885             try!(write!(w, "}}"));
1886         }
1887         doctree::Tuple | doctree::Newtype => {
1888             try!(write!(w, "("));
1889             for (i, field) in fields.iter().enumerate() {
1890                 if i > 0 {
1891                     try!(write!(w, ", "));
1892                 }
1893                 match field.inner {
1894                     clean::StructFieldItem(clean::HiddenStructField) => {
1895                         try!(write!(w, "_"))
1896                     }
1897                     clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
1898                         try!(write!(w, "{}{}", VisSpace(field.visibility), *ty))
1899                     }
1900                     _ => unreachable!()
1901                 }
1902             }
1903             try!(write!(w, ");"));
1904         }
1905         doctree::Unit => {
1906             try!(write!(w, ";"));
1907         }
1908     }
1909     Ok(())
1910 }
1911
1912 fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
1913     match cache_key.get().unwrap().impls.find(&it.def_id) {
1914         Some(v) => {
1915             let (non_trait, traits) = v.partitioned(|i| i.impl_.trait_.is_none());
1916             if non_trait.len() > 0 {
1917                 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
1918                 for i in non_trait.iter() {
1919                     try!(render_impl(w, i));
1920                 }
1921             }
1922             if traits.len() > 0 {
1923                 try!(write!(w, "<h2 id='implementations'>Trait \
1924                                   Implementations</h2>"));
1925                 let (derived, manual) = traits.partition(|i| i.impl_.derived);
1926                 for i in manual.iter() {
1927                     try!(render_impl(w, i));
1928                 }
1929                 if derived.len() > 0 {
1930                     try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
1931                                 </h3>"));
1932                     for i in derived.iter() {
1933                         try!(render_impl(w, i));
1934                     }
1935                 }
1936             }
1937         }
1938         None => {}
1939     }
1940     Ok(())
1941 }
1942
1943 fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
1944     try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
1945                 ConciseStability(&i.stability),
1946                 i.impl_.generics));
1947     match i.impl_.trait_ {
1948         Some(ref ty) => try!(write!(w, "{} for ", *ty)),
1949         None => {}
1950     }
1951     try!(write!(w, "{}</code></h3>", i.impl_.for_));
1952     match i.dox {
1953         Some(ref dox) => {
1954             try!(write!(w, "<div class='docblock'>{}</div>",
1955                           Markdown(dox.as_slice())));
1956         }
1957         None => {}
1958     }
1959
1960     fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
1961                dox: bool) -> fmt::Result {
1962         try!(write!(w, "<h4 id='method.{}' class='method'>{}<code>",
1963                     *item.name.get_ref(),
1964                     ConciseStability(&item.stability)));
1965         try!(render_method(w, item));
1966         try!(write!(w, "</code></h4>\n"));
1967         match item.doc_value() {
1968             Some(s) if dox => {
1969                 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1970                 Ok(())
1971             }
1972             Some(..) | None => Ok(())
1973         }
1974     }
1975
1976     try!(write!(w, "<div class='impl-methods'>"));
1977     for meth in i.impl_.methods.iter() {
1978         try!(docmeth(w, meth, true));
1979     }
1980
1981     fn render_default_methods(w: &mut fmt::Formatter,
1982                               t: &clean::Trait,
1983                               i: &clean::Impl) -> fmt::Result {
1984         for method in t.methods.iter() {
1985             let n = method.item().name.clone();
1986             match i.methods.iter().find(|m| { m.name == n }) {
1987                 Some(..) => continue,
1988                 None => {}
1989             }
1990
1991             try!(docmeth(w, method.item(), false));
1992         }
1993         Ok(())
1994     }
1995
1996     // If we've implemented a trait, then also emit documentation for all
1997     // default methods which weren't overridden in the implementation block.
1998     match i.impl_.trait_ {
1999         Some(clean::ResolvedPath { did, .. }) => {
2000             try!({
2001                 match cache_key.get().unwrap().traits.find(&did) {
2002                     Some(t) => try!(render_default_methods(w, t, &i.impl_)),
2003                     None => {}
2004                 }
2005                 Ok(())
2006             })
2007         }
2008         Some(..) | None => {}
2009     }
2010     try!(write!(w, "</div>"));
2011     Ok(())
2012 }
2013
2014 fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
2015                 t: &clean::Typedef) -> fmt::Result {
2016     try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
2017                   it.name.get_ref().as_slice(),
2018                   t.generics,
2019                   t.type_));
2020
2021     document(w, it)
2022 }
2023
2024 impl<'a> fmt::Show for Sidebar<'a> {
2025     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2026         let cx = self.cx;
2027         let it = self.item;
2028         try!(write!(fmt, "<p class='location'>"));
2029         let len = cx.current.len() - if it.is_mod() {1} else {0};
2030         for (i, name) in cx.current.iter().take(len).enumerate() {
2031             if i > 0 {
2032                 try!(write!(fmt, "&#8203;::"));
2033             }
2034             try!(write!(fmt, "<a href='{}index.html'>{}</a>",
2035                           cx.root_path
2036                             .as_slice()
2037                             .slice_to((cx.current.len() - i - 1) * 3),
2038                           *name));
2039         }
2040         try!(write!(fmt, "</p>"));
2041
2042         fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
2043                  cur: &clean::Item, cx: &Context) -> fmt::Result {
2044             let items = match cx.sidebar.find_equiv(&short) {
2045                 Some(items) => items.as_slice(),
2046                 None => return Ok(())
2047             };
2048             try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
2049             for item in items.iter() {
2050                 let curty = shortty(cur).to_static_str();
2051                 let class = if cur.name.get_ref() == item &&
2052                                short == curty { "current" } else { "" };
2053                 try!(write!(w, "<a class='{ty} {class}' href='{href}{path}'>\
2054                                 {name}</a>",
2055                        ty = short,
2056                        class = class,
2057                        href = if curty == "mod" {"../"} else {""},
2058                        path = if short == "mod" {
2059                            format!("{}/index.html", item.as_slice())
2060                        } else {
2061                            format!("{}.{}.html", short, item.as_slice())
2062                        },
2063                        name = item.as_slice()));
2064             }
2065             try!(write!(w, "</div>"));
2066             Ok(())
2067         }
2068
2069         try!(block(fmt, "mod", "Modules", it, cx));
2070         try!(block(fmt, "struct", "Structs", it, cx));
2071         try!(block(fmt, "enum", "Enums", it, cx));
2072         try!(block(fmt, "trait", "Traits", it, cx));
2073         try!(block(fmt, "fn", "Functions", it, cx));
2074         try!(block(fmt, "macro", "Macros", it, cx));
2075         Ok(())
2076     }
2077 }
2078
2079 fn build_sidebar(m: &clean::Module) -> HashMap<String, Vec<String>> {
2080     let mut map = HashMap::new();
2081     for item in m.items.iter() {
2082         if ignore_private_item(item) { continue }
2083
2084         let short = shortty(item).to_static_str();
2085         let myname = match item.name {
2086             None => continue,
2087             Some(ref s) => s.to_string(),
2088         };
2089         let v = map.find_or_insert_with(short.to_string(), |_| Vec::new());
2090         v.push(myname);
2091     }
2092
2093     for (_, items) in map.mut_iter() {
2094         items.as_mut_slice().sort();
2095     }
2096     return map;
2097 }
2098
2099 impl<'a> fmt::Show for Source<'a> {
2100     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2101         let Source(s) = *self;
2102         let lines = s.lines().count();
2103         let mut cols = 0;
2104         let mut tmp = lines;
2105         while tmp > 0 {
2106             cols += 1;
2107             tmp /= 10;
2108         }
2109         try!(write!(fmt, "<pre class='line-numbers'>"));
2110         for i in range(1, lines + 1) {
2111             try!(write!(fmt, "<span id='{0:u}'>{0:1$u}</span>\n", i, cols));
2112         }
2113         try!(write!(fmt, "</pre>"));
2114         try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None)));
2115         Ok(())
2116     }
2117 }
2118
2119 fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
2120               t: &clean::Macro) -> fmt::Result {
2121     try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro"),
2122                                       None).as_bytes()));
2123     document(w, it)
2124 }
2125
2126 fn item_primitive(w: &mut fmt::Formatter,
2127                   it: &clean::Item,
2128                   _p: &clean::Primitive) -> fmt::Result {
2129     try!(document(w, it));
2130     render_methods(w, it)
2131 }
2132
2133 fn ignore_private_item(it: &clean::Item) -> bool {
2134     match it.inner {
2135         clean::ModuleItem(ref m) => {
2136             (m.items.len() == 0 && it.doc_value().is_none()) ||
2137                it.visibility != Some(ast::Public)
2138         }
2139         clean::PrimitiveItem(..) => it.visibility != Some(ast::Public),
2140         _ => false,
2141     }
2142 }