(index<- )        ./librustdoc/html/render.rs

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


librustdoc/html/render.rs:194:61-194:61 -struct- definition:
/// by hand to a large JS file at the end of cache-creation.
struct IndexItem {
    ty: ItemType,
references:- 3
274:                 Some(&(ref fqp, _)) => {
275:                     index.push(IndexItem {
276:                         ty: shortty(item),
--
664:                     (parent, Some(path)) if !self.privmod => {
665:                         self.search_index.push(IndexItem {
666:                             ty: shortty(&item),


librustdoc/html/render.rs:121:21-121:21 -struct- definition:
/// rendering tasks.
pub struct Cache {
    /// Mapping of typaram ids to the name of the type parameter. This is used
references:- 8
246:     let public_items = public_items.unwrap_or(NodeSet::new());
247:     let mut cache = Cache {
248:         impls: HashMap::new(),
--
825:     /// parallelization to this function.
826:     fn krate(self, mut krate: clean::Crate, cache: Cache) -> io::IoResult<()> {
827:         let mut item = match krate.module.take() {
librustdoc/html/format.rs:
185:         root: |&render::Cache, &[~str]| -> Option<~str>,
186:         info: |&render::Cache| -> Option<(Vec<~str> , ItemType)>)
187:     -> fmt::Result
librustdoc/html/render.rs:
266:     {
267:         let Cache { search_index: ref mut index,
268:                     orphan_methods: ref meths, paths: ref mut paths, ..} = cache;


librustdoc/html/render.rs:1015:1-1015:1 -fn- definition:
fn item_path(item: &clean::Item) -> ~str {
    match item.inner {
        clean::ModuleItem(..) => *item.name.get_ref() + "/index.html",
references:- 2
914:             _ if item.name.is_some() => {
915:                 let dst = self.dst.join(item_path(&item));
916:                 let dst = try!(File::create(&dst));
--
1203:                 class = shortty(myitem),
1204:                 href = item_path(myitem),
1205:                 title = full_path(cx, myitem)));


librustdoc/html/render.rs:1268:4-1268:4 -fn- definition:
    fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
        try!(write!(w, "<h3 id='{}.{}' class='method'><code>",
                      shortty(m.item()),
references:- 2
1284:         for m in required.iter() {
1285:             try!(meth(w, *m));
1286:         }
--
1294:         for m in provided.iter() {
1295:             try!(meth(w, *m));
1296:         }


librustdoc/html/render.rs:1323:1-1323:1 -fn- definition:
fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
    fn fun(w: &mut Writer, it: &clean::Item, fn_style: ast::FnStyle,
           g: &clean::Generics, selfty: &clean::SelfTy,
references:- 4
1257:             try!(write!(w, "    "));
1258:             try!(render_method(w, m.item()));
1259:             try!(write!(w, " \\{ ... \\}\n"));
--
1617:                       *item.name.get_ref()));
1618:         try!(render_method(w, item));
1619:         try!(write!(w, "</code></h4>\n"));


librustdoc/html/render.rs:1482:1-1482:1 -fn- definition:
fn render_struct(w: &mut Writer, it: &clean::Item,
                 g: Option<&clean::Generics>,
                 ty: doctree::StructType,
references:- 2
1352:     try!(write!(w, "<pre class='rust struct'>"));
1353:     try!(render_struct(w,
1354:                        it,
--
1413:                         clean::StructVariant(ref s) => {
1414:                             try!(render_struct(w,
1415:                                                v,


librustdoc/html/render.rs:1591:1-1591:1 -fn- definition:
fn render_impl(w: &mut Writer, i: &clean::Impl,
               dox: &Option<~str>) -> fmt::Result {
    try!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics));
references:- 3
1580:                         if i.derived {
1581:                             try!(render_impl(w, i, dox));
1582:                         }


librustdoc/html/render.rs:68:19-68:19 -struct- definition:
pub struct Context {
    /// Current hierarchy of components leading down to what's currently being
    /// rendered
references:- 15
67: /// rustdoc tree).
69: pub struct Context {
--
209: pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
210:     let mut cx = Context {
211:         dst: dst,
--
796:     /// sure it always points to the top (relatively)
797:     fn recurse<T>(&mut self, s: ~str, f: |&mut Context| -> T) -> T {
798:         if s.len() == 0 {
--
853:     fn item(&mut self, item: clean::Item,
854:             f: |&mut Context, clean::Item|) -> io::IoResult<()> {
855:         fn render(w: io::File, cx: &mut Context, it: &clean::Item,
856:                   pushname: bool) -> io::IoResult<()> {
--
1690:         fn block(w: &mut Writer, short: &str, longty: &str,
1691:                  cur: &clean::Item, cx: &Context) -> fmt::Result {
1692:             let items = match cx.sidebar.find_equiv(&short) {


librustdoc/html/render.rs:1546:1-1546:1 -fn- definition:
fn render_methods(w: &mut Writer, it: &clean::Item) -> fmt::Result {
    match cache_key.get().unwrap().impls.find(&it.id) {
        Some(v) => {
references:- 2
1478:     }
1479:     try!(render_methods(w, it));
1480:     Ok(())


librustdoc/html/render.rs:1036:1-1036:1 -fn- definition:
fn shorter<'a>(s: Option<&'a str>) -> &'a str {
    match s {
        Some(s) => match s.find_str("\n\n") {
references:- 3
278:                         path: fqp.slice_to(fqp.len() - 1).connect("::"),
279:                         desc: shorter(item.doc_value()).to_owned(),
280:                         parent: Some(*pid),
--
1201:                 *myitem.name.get_ref(),
1202:                 Markdown(shorter(myitem.doc_value())),
1203:                 class = shortty(myitem),


librustdoc/html/render.rs:190:60-190:60 -struct- definition:
struct Item<'a> { cx: &'a Context, item: &'a clean::Item, }
struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
/// Struct representing one entry in the JS search index. These are all emitted
references:- 2
882:             try!(layout::render(&mut writer as &mut Writer, &cx.layout, &page,
883:                                   &Sidebar{ cx: cx, item: it },
884:                                   &Item{ cx: cx, item: it }));
--
1672: impl<'a> fmt::Show for Sidebar<'a> {
1673:     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {


librustdoc/html/render.rs:173:58-173:58 -struct- definition:
/// Helper struct to render all source code to HTML pages
struct SourceCollector<'a> {
    cx: &'a mut Context,
references:- 3
406:         try!(mkdir(&dst));
407:         let mut folder = SourceCollector {
408:             dst: dst,
--
490: impl<'a> DocFolder for SourceCollector<'a> {
491:     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
--
518: impl<'a> SourceCollector<'a> {
519:     /// Renders the given filename into its corresponding HTML source file.


librustdoc/html/render.rs:189:1-189:1 -struct- definition:
struct Item<'a> { cx: &'a Context, item: &'a clean::Item, }
struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
/// Struct representing one entry in the JS search index. These are all emitted
references:- 5
883:                                   &Sidebar{ cx: cx, item: it },
884:                                   &Item{ cx: cx, item: it }));
885:             writer.flush()
--
1165:                 s.type_,
1166:                 Initializer(s.expr, Item { cx: cx, item: myitem }),
1167:                 Markdown(blank(myitem.doc_value()))));


librustdoc/html/render.rs:1690:8-1690:8 -fn- definition:
        fn block(w: &mut Writer, short: &str, longty: &str,
                 cur: &clean::Item, cx: &Context) -> fmt::Result {
            let items = match cx.sidebar.find_equiv(&short) {
references:- 5
1718:         try!(block(fmt.buf, "mod", "Modules", it, cx));
1719:         try!(block(fmt.buf, "struct", "Structs", it, cx));
1720:         try!(block(fmt.buf, "enum", "Enums", it, cx));
1721:         try!(block(fmt.buf, "trait", "Traits", it, cx));
1722:         try!(block(fmt.buf, "fn", "Functions", it, cx));
1723:         Ok(())


librustdoc/html/render.rs:430:46-430:46 -fn- definition:
/// skipping if the directory already exists.
fn mkdir(path: &Path) -> io::IoResult<()> {
    if !path.exists() {
references:- 6
808:         mkdir(&self.dst).unwrap();
809:         let ret = f(self);


librustdoc/html/render.rs:1614:4-1614:4 -fn- definition:
    fn docmeth(w: &mut Writer, item: &clean::Item,
               dox: bool) -> io::IoResult<()> {
        try!(write!(w, "<h4 id='method.{}' class='method'><code>",
references:- 2
1649:                             try!(docmeth(w, method.item(), false));
1650:                         }


librustdoc/html/render.rs:1325:4-1325:4 -fn- definition:
    fn fun(w: &mut Writer, it: &clean::Item, fn_style: ast::FnStyle,
           g: &clean::Generics, selfty: &clean::SelfTy,
           d: &clean::FnDecl) -> fmt::Result {
references:- 2
1340:         clean::TyMethodItem(ref m) => {
1341:             fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
1342:         }
1343:         clean::MethodItem(ref m) => {
1344:             fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
1345:         }


librustdoc/html/render.rs:424:22-424:22 -fn- definition:
/// catch any errors.
fn write(dst: Path, contents: &[u8]) -> io::IoResult<()> {
    File::create(&dst).write(contents)
references:- 9
363:         try!(write(cx.dst.join("main.js"), include_bin!("static/main.js")));
364:         try!(write(cx.dst.join("main.css"), include_bin!("static/main.css")));
365:         try!(write(cx.dst.join("normalize.css"),
--
374:                    include_bin!("static/Heuristica-Italic.woff")));
375:         try!(write(cx.dst.join("Heuristica-Bold.woff"),
376:                    include_bin!("static/Heuristica-Bold.woff")));


librustdoc/html/render.rs:855:8-855:8 -fn- definition:
        fn render(w: io::File, cx: &mut Context, it: &clean::Item,
                  pushname: bool) -> io::IoResult<()> {
            info!("Rendering an item to {}", w.path().display());
references:- 2
897:                     let dst = try!(File::create(&dst));
898:                     try!(render(dst, this, &item, false));
--
916:                 let dst = try!(File::create(&dst));
917:                 render(dst, self, &item, true)
918:             }


librustdoc/html/render.rs:94:52-94:52 -enum- definition:
/// Indicates where an external crate can be found.
pub enum ExternalLocation {
    /// Remote URL root of the external crate
references:- 2
457: /// rendering in to the specified source destination.
458: fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
459:     // See if there's documentation generated into the local directory


librustdoc/html/render.rs:1046:1-1046:1 -fn- definition:
fn document(w: &mut Writer, item: &clean::Item) -> fmt::Result {
    match item.doc_value() {
        Some(s) => {
references:- 11
1273:         try!(write!(w, "</code></h3>"));
1274:         try!(document(w, m.item()));
1275:         Ok(())
--
1362:     try!(document(w, it));
1363:     let mut fields = s.fields.iter().filter(|f| {
--
1436:     try!(document(w, it));
1437:     if e.variants.len() > 0 {
--
1441:                           name = variant.name.get_ref().as_slice()));
1442:             try!(document(w, variant));
1443:             match variant.inner {
--
1669:     document(w, it)
1670: }
--
1767:     try!(w.write_str(highlight::highlight(t.source, Some("macro"))));
1768:     document(w, it)
1769: }


librustdoc/html/render.rs:442:69-442:69 -fn- definition:
// FIXME (#9639): The closure should deal with &[u8] instead of &str
fn clean_srcpath(src: &[u8], f: |&str|) {
    let p = Path::new(src);
references:- 2
933:         let mut path = Vec::new();
934:         clean_srcpath(self.item.source.filename.as_bytes(), |component| {
935:             path.push(component.to_owned());