Skip to content

Commit dda5058

Browse files
authored
Rollup merge of #143988 - GuillaumeGomez:alias-inexact, r=lolbinarycat
[rustdoc] Make aliases search support partial matching Fixes #140782. To make this work, I moved aliases into the `searchIndex` like any other item. It links to the "original" item with a new `original` field. No so great part is that we need to have some fields like `bitIndex` to be set on the alias to make the description load to work but I consider it minor enough to be ok. This PR voluntarily doesn't handle de-prioritization of aliases as ```@lolbinarycat``` wished to work on this so I'll leave them this part. 😉 cc ```@lolbinarycat```
2 parents a8c2e54 + 2f14d0a commit dda5058

File tree

6 files changed

+151
-107
lines changed

6 files changed

+151
-107
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/rustdoc.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ declare namespace rustdoc {
219219
crate: string,
220220
descShard: SearchDescShard,
221221
id: number,
222+
// This is the name of the item. For doc aliases, if you want the name of the aliased
223+
// item, take a look at `Row.original.name`.
222224
name: string,
223225
normalizedName: string,
224226
word: string,
@@ -227,6 +229,11 @@ declare namespace rustdoc {
227229
path: string,
228230
ty: number,
229231
type: FunctionSearchType | null,
232+
descIndex: number,
233+
bitIndex: number,
234+
implDisambiguator: String | null,
235+
is_alias?: boolean,
236+
original?: Row,
230237
}
231238

232239
/**

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

Lines changed: 77 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<[string, { [key: string]: Array<number> }, number]>} */
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,58 @@ 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+
is_alias: true,
2305+
ty: original.ty,
2306+
type: original.type,
2307+
paramNames: [],
2308+
word,
2309+
id,
2310+
parent: undefined,
2311+
original,
2312+
path: "",
2313+
implDisambiguator: original.implDisambiguator,
2314+
// Needed to load the description of the original item.
2315+
// @ts-ignore
2316+
descShard: original.descShard,
2317+
descIndex: original.descIndex,
2318+
bitIndex: original.bitIndex,
2319+
};
2320+
aliases_map.push(row);
2321+
this.nameTrie.insert(normalizedName, id, this.tailTable);
2322+
id += 1;
2323+
searchIndex.push(row);
2324+
}
2325+
}
2326+
}
22952327
// Drop the (rather large) hash table used for reusing function items
22962328
this.TYPES_POOL = new Map();
22972329
return searchIndex;
@@ -2536,6 +2568,8 @@ class DocSearch {
25362568
parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
25372569
parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
25382570
const maxEditDistance = Math.floor(queryLen / 3);
2571+
// We reinitialize the `FOUND_ALIASES` map.
2572+
this.FOUND_ALIASES.clear();
25392573

25402574
/**
25412575
* @type {Map<string, number>}
@@ -2695,6 +2729,10 @@ class DocSearch {
26952729
const buildHrefAndPath = item => {
26962730
let displayPath;
26972731
let href;
2732+
if (item.is_alias) {
2733+
this.FOUND_ALIASES.add(item.word);
2734+
item = item.original;
2735+
}
26982736
const type = itemTypes[item.ty];
26992737
const name = item.name;
27002738
let path = item.path;
@@ -3198,8 +3236,7 @@ class DocSearch {
31983236
result.item = this.searchIndex[result.id];
31993237
result.word = this.searchIndex[result.id].word;
32003238
if (isReturnTypeQuery) {
3201-
// we are doing a return-type based search,
3202-
// deprioritize "clone-like" results,
3239+
// We are doing a return-type based search, deprioritize "clone-like" results,
32033240
// ie. functions that also take the queried type as an argument.
32043241
const resultItemType = result.item && result.item.type;
32053242
if (!resultItemType) {
@@ -4259,28 +4296,13 @@ class DocSearch {
42594296
return false;
42604297
}
42614298

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-
42814299
// @ts-expect-error
42824300
const handleAliases = async(ret, query, filterCrates, currentCrate) => {
42834301
const lowerQuery = query.toLowerCase();
4302+
if (this.FOUND_ALIASES.has(lowerQuery)) {
4303+
return;
4304+
}
4305+
this.FOUND_ALIASES.add(lowerQuery);
42844306
// We separate aliases and crate aliases because we want to have current crate
42854307
// aliases to be before the others in the displayed results.
42864308
// @ts-expect-error
@@ -4292,7 +4314,7 @@ class DocSearch {
42924314
&& this.ALIASES.get(filterCrates).has(lowerQuery)) {
42934315
const query_aliases = this.ALIASES.get(filterCrates).get(lowerQuery);
42944316
for (const alias of query_aliases) {
4295-
aliases.push(createAliasFromItem(this.searchIndex[alias]));
4317+
aliases.push(alias);
42964318
}
42974319
}
42984320
} else {
@@ -4302,17 +4324,17 @@ class DocSearch {
43024324
const pushTo = crate === currentCrate ? crateAliases : aliases;
43034325
const query_aliases = crateAliasesIndex.get(lowerQuery);
43044326
for (const alias of query_aliases) {
4305-
pushTo.push(createAliasFromItem(this.searchIndex[alias]));
4327+
pushTo.push(alias);
43064328
}
43074329
}
43084330
}
43094331
}
43104332

43114333
// @ts-expect-error
43124334
const sortFunc = (aaa, bbb) => {
4313-
if (aaa.path < bbb.path) {
4335+
if (aaa.original.path < bbb.original.path) {
43144336
return 1;
4315-
} else if (aaa.path === bbb.path) {
4337+
} else if (aaa.original.path === bbb.original.path) {
43164338
return 0;
43174339
}
43184340
return -1;
@@ -4321,21 +4343,10 @@ class DocSearch {
43214343
crateAliases.sort(sortFunc);
43224344
aliases.sort(sortFunc);
43234345

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-
43364346
// @ts-expect-error
43374347
const pushFunc = alias => {
4338-
alias.alias = query;
4348+
// Cloning `alias` to prevent its fields to be updated.
4349+
alias = {...alias};
43394350
const res = buildHrefAndPath(alias);
43404351
alias.displayPath = pathSplitter(res[0]);
43414352
alias.fullPath = alias.displayPath + alias.name;
@@ -4347,16 +4358,8 @@ class DocSearch {
43474358
}
43484359
};
43494360

4350-
aliases.forEach((alias, i) => {
4351-
// @ts-expect-error
4352-
alias.desc = descs[i];
4353-
});
43544361
aliases.forEach(pushFunc);
43554362
// @ts-expect-error
4356-
crateAliases.forEach((alias, i) => {
4357-
alias.desc = crateDescs[i];
4358-
});
4359-
// @ts-expect-error
43604363
crateAliases.forEach(pushFunc);
43614364
};
43624365

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

48044807
const lis = Promise.all(array.map(async item => {
4805-
const name = item.name;
4808+
const name = item.is_alias ? item.original.name : item.name;
48064809
const type = itemTypes[item.ty];
48074810
const longType = longItemTypes[item.ty];
48084811
const typeName = longType.length !== 0 ? `${longType}` : "?";
@@ -4822,7 +4825,7 @@ async function addTab(array, query, display) {
48224825
let alias = " ";
48234826
if (item.is_alias) {
48244827
alias = ` <div class="alias">\
4825-
<b>${item.alias}</b><i class="grey">&nbsp;- see&nbsp;</i>\
4828+
<b>${item.name}</b><i class="grey">&nbsp;- see&nbsp;</i>\
48264829
</div>`;
48274830
}
48284831
resultName.insertAdjacentHTML(
@@ -5201,6 +5204,7 @@ function registerSearchEvents() {
52015204
if (searchState.input.value.length === 0) {
52025205
searchState.hideResults();
52035206
} else {
5207+
// @ts-ignore
52045208
searchState.timeout = setTimeout(search, 500);
52055209
}
52065210
};
@@ -5842,8 +5846,8 @@ Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new In
58425846
// be called ONLY when the whole file has been parsed and loaded.
58435847

58445848
// @ts-expect-error
5845-
function initSearch(searchIndx) {
5846-
rawSearchIndex = searchIndx;
5849+
function initSearch(searchIndex) {
5850+
rawSearchIndex = searchIndex;
58475851
if (typeof window !== "undefined") {
58485852
// @ts-expect-error
58495853
docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);

0 commit comments

Comments
 (0)