Skip to content

Commit 4c5f6e6

Browse files
committed
Auto merge of #92570 - jsha:rustdoc-search-refactor, r=GuillaumeGomez
Simplify rustdoc search test Previously, rustdoc search attempted to parse search.js and extract out only certain methods and variables. This change makes search.js and search-index.js loadable as [CommonJS modules](https://nodejs.org/api/modules.html#modules-commonjs-modules), so they can be loaded directly. As part of that change, I had to separate execSearch from interacting with the DOM. This wound up being a nice cleanup that made more explicit what inputs it was taking. I removed search.js' dependency on storage.js by moving hasOwnPropertyRustdoc directly into search.js, and replacing onEach with forEach in a path that is called by the tester. r? `@GuillaumeGomez` Demo: https://rustdoc.crud.net/jsha/rustdoc-search-refactor/std/?search=foo
2 parents 00755e4 + 4539794 commit 4c5f6e6

File tree

4 files changed

+117
-313
lines changed

4 files changed

+117
-313
lines changed

src/librustdoc/html/render/write_shared.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,13 @@ pub(super) fn write_shared(
438438
write_crate("search-index.js", &|| {
439439
let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
440440
v.push_str(&all_indexes.join(",\\\n"));
441-
v.push_str("\\\n}');\nif (window.initSearch) {window.initSearch(searchIndex)};");
441+
v.push_str(
442+
r#"\
443+
}');
444+
if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)};
445+
if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
446+
"#,
447+
);
442448
Ok(v.into_bytes())
443449
})?;
444450

src/librustdoc/html/static/js/search.js

+66-46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
2-
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */
1+
/* global addClass, getNakedUrl, getSettingValue */
2+
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
33

44
"use strict";
55

@@ -38,6 +38,11 @@ const itemTypes = [
3838
// used for special search precedence
3939
const TY_PRIMITIVE = itemTypes.indexOf("primitive");
4040
const TY_KEYWORD = itemTypes.indexOf("keyword");
41+
const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
42+
43+
function hasOwnPropertyRustdoc(obj, property) {
44+
return Object.prototype.hasOwnProperty.call(obj, property);
45+
}
4146

4247
// In the search display, allows to switch between tabs.
4348
function printTab(nb) {
@@ -106,7 +111,7 @@ function levenshtein(s1, s2) {
106111
return s1_len + s2_len;
107112
}
108113

109-
window.initSearch = rawSearchIndex => {
114+
function initSearch(rawSearchIndex) {
110115
const MAX_LEV_DISTANCE = 3;
111116
const MAX_RESULTS = 200;
112117
const GENERICS_DATA = 2;
@@ -120,15 +125,6 @@ window.initSearch = rawSearchIndex => {
120125
let searchIndex;
121126
let currentResults;
122127
const ALIASES = Object.create(null);
123-
const params = searchState.getQueryStringParams();
124-
125-
// Populate search bar with query string search term when provided,
126-
// but only if the input bar is empty. This avoid the obnoxious issue
127-
// where you start trying to do a search, and the index loads, and
128-
// suddenly your search is gone!
129-
if (searchState.input.value === "") {
130-
searchState.input.value = params.search || "";
131-
}
132128

133129
function isWhitespace(c) {
134130
return " \t\n\r".indexOf(c) !== -1;
@@ -726,10 +722,11 @@ window.initSearch = rawSearchIndex => {
726722
* @param {ParsedQuery} parsedQuery - The parsed user query
727723
* @param {Object} searchWords - The list of search words to query against
728724
* @param {Object} [filterCrates] - Crate to search in if defined
725+
* @param {Object} [currentCrate] - Current crate, to rank results from this crate higher
729726
*
730727
* @return {ResultsTable}
731728
*/
732-
function execQuery(parsedQuery, searchWords, filterCrates) {
729+
function execQuery(parsedQuery, searchWords, filterCrates, currentCrate) {
733730
const results_others = {}, results_in_args = {}, results_returned = {};
734731

735732
function transformResults(results) {
@@ -761,7 +758,7 @@ window.initSearch = rawSearchIndex => {
761758
return out;
762759
}
763760

764-
function sortResults(results, isType) {
761+
function sortResults(results, isType, preferredCrate) {
765762
const userQuery = parsedQuery.userQuery;
766763
const ar = [];
767764
for (const entry in results) {
@@ -796,9 +793,9 @@ window.initSearch = rawSearchIndex => {
796793
return a - b;
797794
}
798795

799-
// sort by crate (non-current crate goes later)
800-
a = (aaa.item.crate !== window.currentCrate);
801-
b = (bbb.item.crate !== window.currentCrate);
796+
// sort by crate (current crate comes first)
797+
a = (aaa.item.crate !== preferredCrate);
798+
b = (bbb.item.crate !== preferredCrate);
802799
if (a !== b) {
803800
return a - b;
804801
}
@@ -1178,7 +1175,7 @@ window.initSearch = rawSearchIndex => {
11781175
};
11791176
}
11801177

1181-
function handleAliases(ret, query, filterCrates) {
1178+
function handleAliases(ret, query, filterCrates, currentCrate) {
11821179
const lowerQuery = query.toLowerCase();
11831180
// We separate aliases and crate aliases because we want to have current crate
11841181
// aliases to be before the others in the displayed results.
@@ -1194,7 +1191,7 @@ window.initSearch = rawSearchIndex => {
11941191
} else {
11951192
Object.keys(ALIASES).forEach(crate => {
11961193
if (ALIASES[crate][lowerQuery]) {
1197-
const pushTo = crate === window.currentCrate ? crateAliases : aliases;
1194+
const pushTo = crate === currentCrate ? crateAliases : aliases;
11981195
const query_aliases = ALIASES[crate][lowerQuery];
11991196
for (const alias of query_aliases) {
12001197
pushTo.push(createAliasFromItem(searchIndex[alias]));
@@ -1226,8 +1223,9 @@ window.initSearch = rawSearchIndex => {
12261223
ret.others.pop();
12271224
}
12281225
};
1229-
onEach(aliases, pushFunc);
1230-
onEach(crateAliases, pushFunc);
1226+
1227+
aliases.forEach(pushFunc);
1228+
crateAliases.forEach(pushFunc);
12311229
}
12321230

12331231
/**
@@ -1444,11 +1442,11 @@ window.initSearch = rawSearchIndex => {
14441442
}
14451443

14461444
const ret = createQueryResults(
1447-
sortResults(results_in_args, true),
1448-
sortResults(results_returned, true),
1449-
sortResults(results_others, false),
1445+
sortResults(results_in_args, true, currentCrate),
1446+
sortResults(results_returned, true, currentCrate),
1447+
sortResults(results_others, false, currentCrate),
14501448
parsedQuery);
1451-
handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
1449+
handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate);
14521450
if (parsedQuery.error !== null && ret.others.length !== 0) {
14531451
// It means some doc aliases were found so let's "remove" the error!
14541452
ret.query.error = null;
@@ -1521,18 +1519,18 @@ window.initSearch = rawSearchIndex => {
15211519

15221520
if (type === "mod") {
15231521
displayPath = path + "::";
1524-
href = window.rootPath + path.replace(/::/g, "/") + "/" +
1525-
name + "/index.html";
1522+
href = ROOT_PATH + path.replace(/::/g, "/") + "/" +
1523+
name + "/index.html";
15261524
} else if (type === "import") {
15271525
displayPath = item.path + "::";
1528-
href = window.rootPath + item.path.replace(/::/g, "/") + "/index.html#reexport." + name;
1526+
href = ROOT_PATH + item.path.replace(/::/g, "/") + "/index.html#reexport." + name;
15291527
} else if (type === "primitive" || type === "keyword") {
15301528
displayPath = "";
1531-
href = window.rootPath + path.replace(/::/g, "/") +
1532-
"/" + type + "." + name + ".html";
1529+
href = ROOT_PATH + path.replace(/::/g, "/") +
1530+
"/" + type + "." + name + ".html";
15331531
} else if (type === "externcrate") {
15341532
displayPath = "";
1535-
href = window.rootPath + name + "/index.html";
1533+
href = ROOT_PATH + name + "/index.html";
15361534
} else if (item.parent !== undefined) {
15371535
const myparent = item.parent;
15381536
let anchor = "#" + type + "." + name;
@@ -1555,14 +1553,14 @@ window.initSearch = rawSearchIndex => {
15551553
} else {
15561554
displayPath = path + "::" + myparent.name + "::";
15571555
}
1558-
href = window.rootPath + path.replace(/::/g, "/") +
1559-
"/" + pageType +
1560-
"." + pageName +
1561-
".html" + anchor;
1556+
href = ROOT_PATH + path.replace(/::/g, "/") +
1557+
"/" + pageType +
1558+
"." + pageName +
1559+
".html" + anchor;
15621560
} else {
15631561
displayPath = item.path + "::";
1564-
href = window.rootPath + item.path.replace(/::/g, "/") +
1565-
"/" + type + "." + name + ".html";
1562+
href = ROOT_PATH + item.path.replace(/::/g, "/") +
1563+
"/" + type + "." + name + ".html";
15661564
}
15671565
return [displayPath, href];
15681566
}
@@ -1835,7 +1833,7 @@ window.initSearch = rawSearchIndex => {
18351833
}
18361834

18371835
showResults(
1838-
execQuery(query, searchWords, filterCrates),
1836+
execQuery(query, searchWords, filterCrates, window.currentCrate),
18391837
params.go_to_first,
18401838
filterCrates);
18411839
}
@@ -2015,6 +2013,16 @@ window.initSearch = rawSearchIndex => {
20152013
}
20162014

20172015
function registerSearchEvents() {
2016+
const params = searchState.getQueryStringParams();
2017+
2018+
// Populate search bar with query string search term when provided,
2019+
// but only if the input bar is empty. This avoid the obnoxious issue
2020+
// where you start trying to do a search, and the index loads, and
2021+
// suddenly your search is gone!
2022+
if (searchState.input.value === "") {
2023+
searchState.input.value = params.search || "";
2024+
}
2025+
20182026
const searchAfter500ms = () => {
20192027
searchState.clearInputTimeout();
20202028
if (searchState.input.value.length === 0) {
@@ -2167,20 +2175,32 @@ window.initSearch = rawSearchIndex => {
21672175
* @type {Array<string>}
21682176
*/
21692177
const searchWords = buildIndex(rawSearchIndex);
2170-
registerSearchEvents();
2171-
2172-
function runSearchIfNeeded() {
2178+
if (typeof window !== "undefined") {
2179+
registerSearchEvents();
21732180
// If there's a search term in the URL, execute the search now.
2174-
if (searchState.getQueryStringParams().search) {
2181+
if (window.searchState.getQueryStringParams().search) {
21752182
search();
21762183
}
21772184
}
21782185

2179-
runSearchIfNeeded();
2180-
};
2186+
if (typeof exports !== "undefined") {
2187+
exports.initSearch = initSearch;
2188+
exports.execQuery = execQuery;
2189+
exports.parseQuery = parseQuery;
2190+
}
2191+
return searchWords;
2192+
}
21812193

2182-
if (window.searchIndex !== undefined) {
2183-
initSearch(window.searchIndex);
2194+
if (typeof window !== "undefined") {
2195+
window.initSearch = initSearch;
2196+
if (window.searchIndex !== undefined) {
2197+
initSearch(window.searchIndex);
2198+
}
2199+
} else {
2200+
// Running in Node, not a browser. Run initSearch just to produce the
2201+
// exports.
2202+
initSearch({});
21842203
}
21852204

2205+
21862206
})();

src/librustdoc/html/static/js/storage.js

-5
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,6 @@ function onEachLazy(lazyArray, func, reversed) {
100100
reversed);
101101
}
102102

103-
// eslint-disable-next-line no-unused-vars
104-
function hasOwnPropertyRustdoc(obj, property) {
105-
return Object.prototype.hasOwnProperty.call(obj, property);
106-
}
107-
108103
function updateLocalStorage(name, value) {
109104
try {
110105
window.localStorage.setItem("rustdoc-" + name, value);

0 commit comments

Comments
 (0)