Change:
E.g. doesn't show the crate.
ccing myself, will have a look at this in the next week or so.
cc me
Triage: searching for libc doesn't show libc.
Hmm, I deliberately removed the search-index entry in because it was .

Discussion:
use externalfiles::ExternalHtml; <del> use serialize::json::{self, ToJson}; </del> <ins> use serialize::json::{ToJson, Json, as_json}; </ins> use syntax::{abi, ast}; use syntax::feature_gate::UnstableFeatures; use rustc::middle::cstore::LOCAL_CRATE;

path: String, desc: String, parent: Option<DefId>, <ins> parent_idx: Option<usize>, </ins> search_type: Option<IndexItemFunctionType>, } <ins> impl ToJson for IndexItem { fn to_json(&self) -> Json { assert_eq!(self.parent.is_some(), self.parent_idx.is_some()); let mut data = Vec::with_capacity(6); data.push((self.ty as usize).to_json()); data.push(self.name.to_json()); data.push(self.path.to_json()); data.push(self.desc.to_json()); data.push(self.parent_idx.to_json()); data.push(self.search_type.to_json()); Json::Array(data) } } </ins> /// A type used for the search index. struct Type { name: Option<String>, } <del> impl fmt::Display for Type { /// Formats type as {name: $name}. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Wrapping struct fmt should never call us when self.name is None, // but just to be safe we write `null` in that case. </del> <ins> impl ToJson for Type { fn to_json(&self) -> Json { </ins> match self.name { <del> Some(ref n) => write!(f, "{{"name":"{}"}}", n), None => write!(f, "null") </del> <ins> Some(ref name) => { let mut data = BTreeMap::new(); data.insert("name".to_owned(), name.to_json()); Json::Object(data) }, None => Json::Null </ins> } } }

output: Option<Type> } <del> impl fmt::Display for IndexItemFunctionType { /// Formats a full fn type as a JSON {inputs: [Type], outputs: Type/null}. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { </del> <ins> impl ToJson for IndexItemFunctionType { fn to_json(&self) -> Json { </ins> // If we couldn't figure out a type, just write `null`. <del> if self.inputs.iter().any(|ref i| i.name.is_none()) || (self.output.is_some() && self.output.as_ref().unwrap().name.is_none()) { return write!(f, "null") </del> <ins> if self.inputs.iter().chain(self.output.iter()).any(|ref i| i.name.is_none()) { Json::Null } else { let mut data = BTreeMap::new(); data.insert("inputs".to_owned(), self.inputs.to_json()); data.insert("output".to_owned(), self.output.to_json()); Json::Object(data) </ins> } <del> let inputs: Vec<String> = self.inputs.iter().map(|ref t| { format!("{}", t) }).collect(); try!(write!(f, "{{"inputs":[{}],"output":", inputs.join(","))); match self.output { Some(ref t) => try!(write!(f, "{}", t)), None => try!(write!(f, "null")) }; Ok(try!(write!(f, "}}"))) </del> } }

cx.krate(krate) } <ins> /// Build the search index from the collected metadata </ins> fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { <del> // Build the search index from the collected metadata </del> let mut nodeid_to_pathid = HashMap::new(); <del> let mut pathid_to_nodeid = Vec::new(); { let Cache { ref mut search_index, ref orphan_methods, ref mut paths, .. } = *cache; // Attach all orphan methods to the type's definition if the type // has since been learned. for &(did, ref item) in orphan_methods { match paths.get(&did) { Some(&(ref fqp, _)) => { // Needed to determine `self` type. let parent_basename = Some(fqp[fqp.len() - 1].clone()); search_index.push(IndexItem { ty: shortty(item), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), desc: Escape(&shorter(item.doc_value())).to_string(), parent: Some(did), search_type: get_index_search_type(&item, parent_basename), }); }, None => {} } } // Reduce `NodeId` in paths into smaller sequential numbers, // and prune the paths that do not appear in the index. for item in search_index.iter() { match item.parent { Some(nodeid) => { if !nodeid_to_pathid.contains_key(&nodeid) { let pathid = pathid_to_nodeid.len(); nodeid_to_pathid.insert(nodeid, pathid); pathid_to_nodeid.push(nodeid); } } None => {} } </del> <ins> let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = Vec::<Json>::new(); let Cache { ref mut search_index, ref orphan_methods, ref mut paths, .. } = *cache; // Attach all orphan methods to the type's definition if the type // has since been learned. for &(did, ref item) in orphan_methods { match paths.get(&did) { Some(&(ref fqp, _)) => { // Needed to determine `self` type. let parent_basename = Some(fqp[fqp.len() - 1].clone()); search_index.push(IndexItem { ty: shortty(item), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), desc: Escape(&shorter(item.doc_value())).to_string(), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item, parent_basename), }); }, None => {} </ins> } <del> assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len()); </del> } <del> // Collect the index into a string let mut w = io::Cursor::new(Vec::new()); write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name).unwrap(); </del> <ins> // Reduce `NodeId` in paths into smaller sequential numbers, // and prune the paths that do not appear in the index. let mut lastpath = String::new(); let mut lastpathid = 0usize; </ins> <del> let mut lastpath = "".to_string(); for (i, item) in cache.search_index.iter().enumerate() { // Omit the path if it is same to that of the prior item. let path; if lastpath == item.path { path = ""; } else { lastpath = item.path.to_string(); path = &item.path; }; </del> <ins> for item in search_index { item.parent_idx = item.parent.map(|nodeid| { if nodeid_to_pathid.contains_key(&nodeid) { *nodeid_to_pathid.get(&nodeid).unwrap() } else { let pathid = lastpathid; nodeid_to_pathid.insert(nodeid, pathid); lastpathid += 1; </ins> <del> if i > 0 { write!(&mut w, ",").unwrap(); } write!(&mut w, r#"[{},"{}","{}",{}"#, item.ty as usize, item.name, path, item.desc.to_json().to_string()).unwrap(); match item.parent { Some(nodeid) => { let pathid = *nodeid_to_pathid.get(&nodeid).unwrap(); write!(&mut w, ",{}", pathid).unwrap(); </del> <ins> let &(ref fqp, short) = paths.get(&nodeid).unwrap(); crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json()); pathid </ins> } <del> None => write!(&mut w, ",null").unwrap() } match item.search_type { Some(ref t) => write!(&mut w, ",{}", t).unwrap(), None => write!(&mut w, ",null").unwrap() } write!(&mut w, "]").unwrap(); } write!(&mut w, r#"],"paths":["#).unwrap(); </del> <ins> }); </ins> <del> for (i, &did) in pathid_to_nodeid.iter().enumerate() { let &(ref fqp, short) = cache.paths.get(&did).unwrap(); if i > 0 { write!(&mut w, ",").unwrap(); </del> <ins> // Omit the parent path if it is same to that of the prior item. if lastpath == item.path { item.path.clear(); } else { lastpath = item.path.clone(); </ins> } <del> write!(&mut w, r#"[{},"{}"]"#, short as usize, *fqp.last().unwrap()).unwrap(); </del> <ins> crate_items.push(item.to_json()); </ins> } <del> write!(&mut w, "]}};").unwrap(); </del> <ins> let crate_doc = krate.module.as_ref().map(|module| { Escape(&shorter(module.doc_value())).to_string() }).unwrap_or(String::new()); </ins> <del> String::from_utf8(w.into_inner()).unwrap() </del> <ins> let mut crate_data = BTreeMap::new(); crate_data.insert("doc".to_owned(), Json::String(crate_doc)); crate_data.insert("items".to_owned(), Json::Array(crate_items)); crate_data.insert("paths".to_owned(), Json::Array(crate_paths)); // Collect the index into a string format!("searchIndex[{}] = {};", as_json(&krate.name), Json::Object(crate_data)) </ins> } fn write_shared(cx: &Context,

if !line.starts_with(key) { continue } <del> if line.starts_with(&format!("{}['{}']", key, krate)) { </del> <ins> if line.starts_with(&format!(r#"{}["{}"]"#, key, krate)) { </ins> continue } ret.push(line.to_string());

path: path.join("::").to_string(), desc: Escape(&shorter(item.doc_value())).to_string(), parent: parent, <ins> parent_idx: None, </ins> search_type: get_index_search_type(&item, parent_basename), }); }

let js_dst = this.dst.join("sidebar-items.js"); let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst)); try_err!(write!(&mut js_out, "initSidebarItems({});", <del> json::as_json(&items)), &js_dst); </del> <ins> as_json(&items)), &js_dst); </ins> } for item in m.items {

displayPath = ""; href = rootPath + item.path.replace(/::/g, '/') + '/' + type + '.' + name + '.html'; <ins> } else if (type === "externcrate") { displayPath = ""; href = rootPath + name + '/index.html'; </ins> } else if (item.parent !== undefined) { var myparent = item.parent; var anchor = '#' + type + '.' + name;

for (var crate in rawSearchIndex) { if (!rawSearchIndex.hasOwnProperty(crate)) { continue; } <ins> searchWords.push(crate); searchIndex.push({ crate: crate, ty: 1, // == ExternCrate name: crate, path: "", desc: rawSearchIndex[crate].doc, type: null, }); </ins> // an array of [(Number) item type, //              (String) name, //              (String) full path or empty string for previous path,

} .content a.primitive { color: #39a7bf; } <del> .content span.mod, .content a.mod, block a.current.mod { color: #4d76ae; } </del> <ins> .content span.externcrate, span.mod, .content a.mod, block a.current.mod { color: #4d76ae; } </ins> .content span.fn, .content a.fn, .block a.current.fn, .content span.method, .content a.method, .block a.current.method, .content span.tymethod, .content a.tymethod, .block a.current.tymethod,