Skip to content

Commit 325d00e

Browse files
Make aliases search support partial matching
1 parent aa51a9b commit 325d00e

File tree

2 files changed

+81
-74
lines changed

2 files changed

+81
-74
lines changed

src/librustdoc/html/render/search_index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub(crate) fn build_index(
116116
// Set up alias indexes.
117117
for (i, item) in cache.search_index.iter().enumerate() {
118118
for alias in &item.aliases[..] {
119-
aliases.entry(alias.as_str().to_lowercase()).or_default().push(i);
119+
aliases.entry(alias.to_string()).or_default().push(i);
120120
}
121121
}
122122

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

Lines changed: 80 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
830830
*/
831831
function makePrimitiveElement(name, extra) {
832832
return Object.assign({
833-
name: name,
833+
name,
834834
id: null,
835835
fullPath: [name],
836836
pathWithoutLast: [],
@@ -1483,6 +1483,7 @@ class DocSearch {
14831483
*/
14841484
this.assocTypeIdNameMap = new Map();
14851485
this.ALIASES = new Map();
1486+
this.FOUND_ALIASES = new Set();
14861487
this.rootPath = rootPath;
14871488
this.searchState = searchState;
14881489

@@ -2030,6 +2031,8 @@ class DocSearch {
20302031
// normalized names, type signature objects and fingerprints, and aliases.
20312032
id = 0;
20322033

2034+
/** @type {Array<Array<any>>} */
2035+
const allAliases = [];
20332036
for (const [crate, crateCorpus] of rawSearchIndex) {
20342037
// a string representing the lengths of each description shard
20352038
// a string representing the list of function types
@@ -2178,10 +2181,10 @@ class DocSearch {
21782181
paths[i] = { ty, name, path, exactPath, unboxFlag };
21792182
}
21802183

2181-
// convert `item*` into an object form, and construct word indices.
2184+
// Convert `item*` into an object form, and construct word indices.
21822185
//
2183-
// before any analysis is performed lets gather the search terms to
2184-
// search against apart from the rest of the data. This is a quick
2186+
// Before any analysis is performed, let's gather the search terms to
2187+
// search against apart from the rest of the data. This is a quick
21852188
// operation that is cached for the life of the page state so that
21862189
// all other search operations have access to this cached data for
21872190
// faster analysis operations
@@ -2269,29 +2272,61 @@ class DocSearch {
22692272
}
22702273

22712274
if (aliases) {
2272-
const currentCrateAliases = new Map();
2273-
this.ALIASES.set(crate, currentCrateAliases);
2274-
for (const alias_name in aliases) {
2275-
if (!Object.prototype.hasOwnProperty.call(aliases, alias_name)) {
2276-
continue;
2277-
}
2278-
2279-
/** @type{number[]} */
2280-
let currentNameAliases;
2281-
if (currentCrateAliases.has(alias_name)) {
2282-
currentNameAliases = currentCrateAliases.get(alias_name);
2283-
} else {
2284-
currentNameAliases = [];
2285-
currentCrateAliases.set(alias_name, currentNameAliases);
2286-
}
2287-
for (const local_alias of aliases[alias_name]) {
2288-
currentNameAliases.push(local_alias + currentIndex);
2289-
}
2290-
}
2275+
// We need to add the aliases in `searchIndex` after we finished filling it
2276+
// to not mess up indexes.
2277+
allAliases.push([crate, aliases, currentIndex]);
22912278
}
22922279
currentIndex += itemTypes.length;
22932280
this.searchState.descShards.set(crate, descShardList);
22942281
}
2282+
2283+
for (const [crate, aliases, index] of allAliases) {
2284+
for (const [alias_name, alias_refs] of Object.entries(aliases)) {
2285+
if (!this.ALIASES.has(crate)) {
2286+
this.ALIASES.set(crate, new Map());
2287+
}
2288+
const word = alias_name.toLowerCase();
2289+
const crate_alias_map = this.ALIASES.get(crate);
2290+
if (!crate_alias_map.has(word)) {
2291+
crate_alias_map.set(word, []);
2292+
}
2293+
const aliases_map = crate_alias_map.get(word);
2294+
2295+
const normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
2296+
for (const alias of alias_refs) {
2297+
const originalIndex = alias + index;
2298+
const original = searchIndex[originalIndex];
2299+
/** @type {rustdoc.Row} */
2300+
const row = {
2301+
crate,
2302+
name: alias_name,
2303+
normalizedName,
2304+
// @ts-ignore
2305+
is_alias: true,
2306+
ty: original.ty,
2307+
paramNames: [],
2308+
word,
2309+
id,
2310+
parent: undefined,
2311+
original,
2312+
path: "",
2313+
// @ts-ignore
2314+
implDisambiguator: original.implDisambiguator,
2315+
// Needed to load the description of the original item.
2316+
// @ts-ignore
2317+
descShard: original.descShard,
2318+
// @ts-ignore
2319+
descIndex: original.descIndex,
2320+
// @ts-ignore
2321+
bitIndex: original.bitIndex,
2322+
};
2323+
aliases_map.push(row);
2324+
this.nameTrie.insert(normalizedName, id, this.tailTable);
2325+
id += 1;
2326+
searchIndex.push(row);
2327+
}
2328+
}
2329+
}
22952330
// Drop the (rather large) hash table used for reusing function items
22962331
this.TYPES_POOL = new Map();
22972332
return searchIndex;
@@ -2536,6 +2571,8 @@ class DocSearch {
25362571
parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
25372572
parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
25382573
const maxEditDistance = Math.floor(queryLen / 3);
2574+
// We reinitialize the `FOUND_ALIASES` map.
2575+
this.FOUND_ALIASES.clear();
25392576

25402577
/**
25412578
* @type {Map<string, number>}
@@ -2695,6 +2732,10 @@ class DocSearch {
26952732
const buildHrefAndPath = item => {
26962733
let displayPath;
26972734
let href;
2735+
if (item.is_alias) {
2736+
this.FOUND_ALIASES.add(item.word);
2737+
item = item.original;
2738+
}
26982739
const type = itemTypes[item.ty];
26992740
const name = item.name;
27002741
let path = item.path;
@@ -3198,8 +3239,7 @@ class DocSearch {
31983239
result.item = this.searchIndex[result.id];
31993240
result.word = this.searchIndex[result.id].word;
32003241
if (isReturnTypeQuery) {
3201-
// we are doing a return-type based search,
3202-
// deprioritize "clone-like" results,
3242+
// We are doing a return-type based search, deprioritize "clone-like" results,
32033243
// ie. functions that also take the queried type as an argument.
32043244
const resultItemType = result.item && result.item.type;
32053245
if (!resultItemType) {
@@ -4259,28 +4299,13 @@ class DocSearch {
42594299
return false;
42604300
}
42614301

4262-
// this does not yet have a type in `rustdoc.d.ts`.
4263-
// @ts-expect-error
4264-
function createAliasFromItem(item) {
4265-
return {
4266-
crate: item.crate,
4267-
name: item.name,
4268-
path: item.path,
4269-
descShard: item.descShard,
4270-
descIndex: item.descIndex,
4271-
exactPath: item.exactPath,
4272-
ty: item.ty,
4273-
parent: item.parent,
4274-
type: item.type,
4275-
is_alias: true,
4276-
bitIndex: item.bitIndex,
4277-
implDisambiguator: item.implDisambiguator,
4278-
};
4279-
}
4280-
42814302
// @ts-expect-error
42824303
const handleAliases = async(ret, query, filterCrates, currentCrate) => {
42834304
const lowerQuery = query.toLowerCase();
4305+
if (this.FOUND_ALIASES.has(lowerQuery)) {
4306+
return;
4307+
}
4308+
this.FOUND_ALIASES.add(lowerQuery);
42844309
// We separate aliases and crate aliases because we want to have current crate
42854310
// aliases to be before the others in the displayed results.
42864311
// @ts-expect-error
@@ -4292,7 +4317,7 @@ class DocSearch {
42924317
&& this.ALIASES.get(filterCrates).has(lowerQuery)) {
42934318
const query_aliases = this.ALIASES.get(filterCrates).get(lowerQuery);
42944319
for (const alias of query_aliases) {
4295-
aliases.push(createAliasFromItem(this.searchIndex[alias]));
4320+
aliases.push(alias);
42964321
}
42974322
}
42984323
} else {
@@ -4302,17 +4327,17 @@ class DocSearch {
43024327
const pushTo = crate === currentCrate ? crateAliases : aliases;
43034328
const query_aliases = crateAliasesIndex.get(lowerQuery);
43044329
for (const alias of query_aliases) {
4305-
pushTo.push(createAliasFromItem(this.searchIndex[alias]));
4330+
pushTo.push(alias);
43064331
}
43074332
}
43084333
}
43094334
}
43104335

43114336
// @ts-expect-error
43124337
const sortFunc = (aaa, bbb) => {
4313-
if (aaa.path < bbb.path) {
4338+
if (aaa.original.path < bbb.original.path) {
43144339
return 1;
4315-
} else if (aaa.path === bbb.path) {
4340+
} else if (aaa.original.path === bbb.original.path) {
43164341
return 0;
43174342
}
43184343
return -1;
@@ -4321,21 +4346,10 @@ class DocSearch {
43214346
crateAliases.sort(sortFunc);
43224347
aliases.sort(sortFunc);
43234348

4324-
// @ts-expect-error
4325-
const fetchDesc = alias => {
4326-
// @ts-expect-error
4327-
return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ?
4328-
"" : this.searchState.loadDesc(alias);
4329-
};
4330-
const [crateDescs, descs] = await Promise.all([
4331-
// @ts-expect-error
4332-
Promise.all(crateAliases.map(fetchDesc)),
4333-
Promise.all(aliases.map(fetchDesc)),
4334-
]);
4335-
43364349
// @ts-expect-error
43374350
const pushFunc = alias => {
4338-
alias.alias = query;
4351+
// Cloning `alias` to prevent its fields to be updated.
4352+
alias = {...alias};
43394353
const res = buildHrefAndPath(alias);
43404354
alias.displayPath = pathSplitter(res[0]);
43414355
alias.fullPath = alias.displayPath + alias.name;
@@ -4347,16 +4361,8 @@ class DocSearch {
43474361
}
43484362
};
43494363

4350-
aliases.forEach((alias, i) => {
4351-
// @ts-expect-error
4352-
alias.desc = descs[i];
4353-
});
43544364
aliases.forEach(pushFunc);
43554365
// @ts-expect-error
4356-
crateAliases.forEach((alias, i) => {
4357-
alias.desc = crateDescs[i];
4358-
});
4359-
// @ts-expect-error
43604366
crateAliases.forEach(pushFunc);
43614367
};
43624368

@@ -4802,7 +4808,7 @@ async function addTab(array, query, display) {
48024808
output.className = "search-results " + extraClass;
48034809

48044810
const lis = Promise.all(array.map(async item => {
4805-
const name = item.name;
4811+
const name = item.is_alias ? item.original.name : item.name;
48064812
const type = itemTypes[item.ty];
48074813
const longType = longItemTypes[item.ty];
48084814
const typeName = longType.length !== 0 ? `${longType}` : "?";
@@ -4822,7 +4828,7 @@ async function addTab(array, query, display) {
48224828
let alias = " ";
48234829
if (item.is_alias) {
48244830
alias = ` <div class="alias">\
4825-
<b>${item.alias}</b><i class="grey">&nbsp;- see&nbsp;</i>\
4831+
<b>${item.name}</b><i class="grey">&nbsp;- see&nbsp;</i>\
48264832
</div>`;
48274833
}
48284834
resultName.insertAdjacentHTML(
@@ -5201,6 +5207,7 @@ function registerSearchEvents() {
52015207
if (searchState.input.value.length === 0) {
52025208
searchState.hideResults();
52035209
} else {
5210+
// @ts-ignore
52045211
searchState.timeout = setTimeout(search, 500);
52055212
}
52065213
};
@@ -5842,8 +5849,8 @@ Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new In
58425849
// be called ONLY when the whole file has been parsed and loaded.
58435850

58445851
// @ts-expect-error
5845-
function initSearch(searchIndx) {
5846-
rawSearchIndex = searchIndx;
5852+
function initSearch(searchIndex) {
5853+
rawSearchIndex = searchIndex;
58475854
if (typeof window !== "undefined") {
58485855
// @ts-expect-error
58495856
docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);

0 commit comments

Comments
 (0)