From 810a51402917672a6dd8a3f063ea118c79016481 Mon Sep 17 00:00:00 2001 From: mitaa Date: Tue, 16 Feb 2016 20:00:57 +0100 Subject: [PATCH 1/2] Add crates to search-index --- src/librustdoc/html/render.rs | 22 ++++++++++++++-------- src/librustdoc/html/static/main.js | 13 +++++++++++++ src/librustdoc/html/static/styles/main.css | 2 +- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2053fc73e8f..2a97ac81ea9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -52,7 +52,7 @@ use std::sync::Arc; use externalfiles::ExternalHtml; -use serialize::json::{self, ToJson}; +use serialize::json::as_json; use syntax::{abi, ast}; use syntax::feature_gate::UnstableFeatures; use rustc::middle::cstore::LOCAL_CRATE; @@ -534,8 +534,8 @@ pub fn run(mut krate: clean::Crate, cx.krate(krate) } +/// Build the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { - // Build the search index from the collected metadata let mut nodeid_to_pathid = HashMap::new(); let mut pathid_to_nodeid = Vec::new(); { @@ -582,7 +582,13 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { // Collect the index into a string let mut w = io::Cursor::new(Vec::new()); - write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name).unwrap(); + let krate_doc = krate.module.as_ref().map(|module| { + Escape(&shorter(module.doc_value())).to_string() + }).unwrap_or("".to_owned()); + + write!(&mut w, r#"searchIndex[{}] = {{doc: {}, "items":["#, + as_json(&krate.name), + as_json(&krate_doc)).unwrap(); let mut lastpath = "".to_string(); for (i, item) in cache.search_index.iter().enumerate() { @@ -598,9 +604,9 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { 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(); + write!(&mut w, "[{},{},{},{}", + item.ty as usize, + as_json(&item.name), as_json(&path), as_json(&item.desc)).unwrap(); match item.parent { Some(nodeid) => { let pathid = *nodeid_to_pathid.get(&nodeid).unwrap(); @@ -693,7 +699,7 @@ fn write_shared(cx: &Context, if !line.starts_with(key) { continue } - if line.starts_with(&format!("{}['{}']", key, krate)) { + if line.starts_with(&format!(r#"{}["{}"]"#, key, krate)) { continue } ret.push(line.to_string()); @@ -1387,7 +1393,7 @@ impl Context { 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({});", - json::as_json(&items)), &js_dst); + as_json(&items)), &js_dst); } for item in m.items { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 8844ed82bb5..95fa2cac210 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -580,6 +580,9 @@ displayPath = ""; href = rootPath + item.path.replace(/::/g, '/') + '/' + type + '.' + name + '.html'; + } else if (type === "externcrate") { + displayPath = ""; + href = rootPath + name + '/index.html'; } else if (item.parent !== undefined) { var myparent = item.parent; var anchor = '#' + type + '.' + name; @@ -678,6 +681,16 @@ for (var crate in rawSearchIndex) { if (!rawSearchIndex.hasOwnProperty(crate)) { continue; } + searchWords.push(crate); + searchIndex.push({ + crate: crate, + ty: 1, // == ExternCrate + name: crate, + path: "", + desc: rawSearchIndex[crate].doc, + type: null, + }); + // an array of [(Number) item type, // (String) name, // (String) full path or empty string for previous path, diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index 02bb5221886..5c073860f08 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -82,7 +82,7 @@ pre { } .content a.primitive { color: #39a7bf; } -.content span.mod, .content a.mod, block a.current.mod { color: #4d76ae; } +.content span.externcrate, span.mod, .content a.mod, block a.current.mod { color: #4d76ae; } .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, From 81f673d3bc6828acefd548df3f4733f330259c4c Mon Sep 17 00:00:00 2001 From: mitaa Date: Tue, 16 Feb 2016 19:48:28 +0100 Subject: [PATCH 2/2] Simplify search-index serialization --- src/librustdoc/html/render.rs | 218 ++++++++++++++++------------------ 1 file changed, 100 insertions(+), 118 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2a97ac81ea9..692d230446c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -52,7 +52,7 @@ use std::sync::Arc; use externalfiles::ExternalHtml; -use serialize::json::as_json; +use serialize::json::{ToJson, Json, as_json}; use syntax::{abi, ast}; use syntax::feature_gate::UnstableFeatures; use rustc::middle::cstore::LOCAL_CRATE; @@ -290,22 +290,40 @@ struct IndexItem { path: String, desc: String, parent: Option, + parent_idx: Option, search_type: Option, } +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) + } +} + /// A type used for the search index. struct Type { name: Option, } -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. +impl ToJson for Type { + fn to_json(&self) -> Json { match self.name { - Some(ref n) => write!(f, "{{\"name\":\"{}\"}}", n), - None => write!(f, "null") + Some(ref name) => { + let mut data = BTreeMap::new(); + data.insert("name".to_owned(), name.to_json()); + Json::Object(data) + }, + None => Json::Null } } } @@ -316,26 +334,17 @@ struct IndexItemFunctionType { output: Option } -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 { +impl ToJson for IndexItemFunctionType { + fn to_json(&self) -> Json { // If we couldn't figure out a type, just write `null`. - 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") + 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) } - - let inputs: Vec = 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, "}}"))) } } @@ -537,104 +546,76 @@ pub fn run(mut krate: clean::Crate, /// Build the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let mut nodeid_to_pathid = HashMap::new(); - let mut pathid_to_nodeid = Vec::new(); - { - let Cache { ref mut search_index, - ref orphan_methods, - ref mut paths, .. } = *cache; + let mut crate_items = Vec::with_capacity(cache.search_index.len()); + let mut crate_paths = Vec::::new(); - // 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 => {} - } - } + let Cache { ref mut search_index, + ref orphan_methods, + ref mut paths, .. } = *cache; - // 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 => {} - } + // 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 => {} } - assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len()); } + // 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; + + 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; + + let &(ref fqp, short) = paths.get(&nodeid).unwrap(); + crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json()); + pathid + } + }); + + // 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(); + } + crate_items.push(item.to_json()); + } + + let crate_doc = krate.module.as_ref().map(|module| { + Escape(&shorter(module.doc_value())).to_string() + }).unwrap_or(String::new()); + + 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 - let mut w = io::Cursor::new(Vec::new()); - let krate_doc = krate.module.as_ref().map(|module| { - Escape(&shorter(module.doc_value())).to_string() - }).unwrap_or("".to_owned()); - - write!(&mut w, r#"searchIndex[{}] = {{doc: {}, "items":["#, - as_json(&krate.name), - as_json(&krate_doc)).unwrap(); - - 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; - }; - - if i > 0 { - write!(&mut w, ",").unwrap(); - } - write!(&mut w, "[{},{},{},{}", - item.ty as usize, - as_json(&item.name), as_json(&path), as_json(&item.desc)).unwrap(); - match item.parent { - Some(nodeid) => { - let pathid = *nodeid_to_pathid.get(&nodeid).unwrap(); - write!(&mut w, ",{}", pathid).unwrap(); - } - 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(); - - 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(); - } - write!(&mut w, r#"[{},"{}"]"#, - short as usize, *fqp.last().unwrap()).unwrap(); - } - - write!(&mut w, "]}};").unwrap(); - - String::from_utf8(w.into_inner()).unwrap() + format!("searchIndex[{}] = {};", + as_json(&krate.name), + Json::Object(crate_data)) } fn write_shared(cx: &Context, @@ -1073,6 +1054,7 @@ impl DocFolder for Cache { path: path.join("::").to_string(), desc: Escape(&shorter(item.doc_value())).to_string(), parent: parent, + parent_idx: None, search_type: get_index_search_type(&item, parent_basename), }); }