diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index da020b85ed4..b91aab44f10 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -789,6 +789,37 @@ themePicker.onblur = handleThemeButtonsBlur; Ok((ret, krates)) } + fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec, Vec)> { + let mut ret = Vec::new(); + let mut krates = Vec::new(); + + if path.exists() { + for line in BufReader::new(File::open(path)?).lines() { + let line = line?; + if !line.starts_with("\"") { + continue; + } + if line.starts_with(&format!("\"{}\"", krate)) { + continue; + } + if line.ends_with(",\\") { + ret.push(line[..line.len() - 2].to_string()); + } else { + // Ends with "\\" (it's the case for the last added crate line) + ret.push(line[..line.len() - 1].to_string()); + } + krates.push( + line.split('"') + .filter(|s| !s.is_empty()) + .next() + .map(|s| s.to_owned()) + .unwrap_or_else(String::new), + ); + } + } + Ok((ret, krates)) + } + fn show_item(item: &IndexItem, krate: &str) -> String { format!( "{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}", @@ -909,18 +940,18 @@ themePicker.onblur = handleThemeButtonsBlur; // Update the search index let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix)); - let (mut all_indexes, mut krates) = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst); + let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name), &dst); all_indexes.push(search_index); // Sort the indexes by crate so the file will be generated identically even // with rustdoc running in parallel. all_indexes.sort(); { - let mut v = String::from("var searchIndex={};\n"); - v.push_str(&all_indexes.join("\n")); + let mut v = String::from("var searchIndex = JSON.parse('{\\\n"); + v.push_str(&all_indexes.join(",\\\n")); // "addSearchOptions" has to be called first so the crate filtering can be set before the // search might start (if it's set into the URL for example). - v.push_str("\naddSearchOptions(searchIndex);initSearch(searchIndex);"); + v.push_str("\\\n}');\naddSearchOptions(searchIndex);initSearch(searchIndex);"); cx.shared.fs.write(&dst, &v)?; } if options.enable_index_page { diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index a8efb16a1d3..03aa5d519c6 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -631,7 +631,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { // Collect the index into a string format!( - r#"searchIndex["{}"] = {};"#, + r#""{}":{}"#, krate.name, serde_json::to_string(&CrateData { doc: crate_doc, @@ -639,6 +639,11 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { paths: crate_paths, }) .expect("failed serde conversion") + // All these `replace` calls are because we have to go through JS string for JSON content. + .replace(r"\", r"\\") + .replace("'", r"\'") + // We need to escape double quotes for the JSON. + .replace("\\\"", "\\\\\"") ) }