From 5caf9c0a1f10a26d3b37dc6c3dbcc9f253b7a472 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 17 Oct 2024 15:27:31 -0500 Subject: [PATCH] rustdoc: allow searches to match against both type and name repurposes existing syntax that previously had a nonsese meaning. now `fn:add, u8 -> u8` searches for fn items with "add" in the name, that take a `u8` argument and return a `u8`. the kind is included in anticipation that type based searches will soon work on items other than functions and methods. fixes #131130 --- src/librustdoc/html/static/js/externs.js | 2 +- src/librustdoc/html/static/js/search.js | 55 ++++++++++++++++++++++-- tests/rustdoc-js-std/type-and-name.js | 7 +++ 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc-js-std/type-and-name.js diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index c4faca1c0c3bc..5e1a042e6cdbd 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -36,8 +36,8 @@ let ParserState; * userQuery: string, * typeFilter: number, * elems: Array, - * args: Array, * returned: Array, + * extraNameElem: QueryElement | null, * foundElems: number, * totalElems: number, * literalSearch: boolean, diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 4e1bbbbf59d89..e548f229a7b3d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -63,6 +63,12 @@ const TY_PRIMITIVE = itemTypes.indexOf("primitive"); const TY_GENERIC = itemTypes.indexOf("generic"); const TY_IMPORT = itemTypes.indexOf("import"); const TY_TRAIT = itemTypes.indexOf("trait"); +// used for isType +const TY_STRUCT = itemTypes.indexOf("struct"); +const TY_ENUM = itemTypes.indexOf("enum"); +const TY_UNION = itemTypes.indexOf("union"); +const TY_PRIMATIVE = itemTypes.indexOf("primative"); +const TY_FOREIGN_TYPE = itemTypes.indexOf("foreigntype"); const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../"; // Hard limit on how deep to recurse into generics when doing type-driven search. @@ -250,6 +256,18 @@ function prevIs(parserState, lookingFor) { return false; } +function isType(ty) { + return ty === TY_STRUCT || ty === TY_ENUM || ty === TY_UNION || + ty === TY_PRIMATIVE || ty === TY_FOREIGN_TYPE || ty === -1; +} + +/** + * This function removes any queryElem that cannot be a function argument. + */ +function filterOnlyTypes(elems) { + return elems.filter(elem => isType(elem.typeFilter)); +} + /** * Returns `true` if the last element in the `elems` argument has generics. * @@ -1870,6 +1888,8 @@ class DocSearch { correction: null, proposeCorrectionFrom: null, proposeCorrectionTo: null, + // used for type-and-name searches + extraNameElem: null, // bloom filter build from type ids typeFingerprint: new Uint32Array(4), }; @@ -2002,6 +2022,17 @@ class DocSearch { query.literalSearch = parserState.totalElems > 1; } query.foundElems = query.elems.length + query.returned.length; + if (query.returned.length > 0 || query.elems.length > 1) { + for (const elem of query.elems) { + if (!isType(elem.typeFilter)) { + query.extraNameElem = elem; + query.elems = filterOnlyTypes(query.elems); + query.hasReturnArrow = true; + console.log(query.elems); + break; + } + } + } query.totalElems = parserState.totalElems; return query; } @@ -3687,7 +3718,7 @@ class DocSearch { * @param {integer} pos - Position in the `searchIndex`. * @param {Object} results */ - function handleArgs(row, pos, results) { + function handleArgs(row, pos, results, maxEditDistance) { if (!row || (filterCrates !== null && row.crate !== filterCrates) || !row.type) { return; } @@ -3724,8 +3755,26 @@ class DocSearch { return; } + let name_dist = 0; + let path_dist = tfpDist; + const name_elem = parsedQuery.extraNameElem; + if (name_elem !== null) { + if (!typePassesFilter(name_elem.typeFilter, row.ty)) { + return; + } + name_dist = editDistance( + row.normalizedName, name_elem.normalizedPathLast, maxEditDistance); + if (row.normalizedName.includes(name_elem.normalizedPathLast)) { + name_dist = name_dist / 3; + } + if (name_dist > maxEditDistance) { + return; + } + const real_path_dist = checkPath(name_elem.fullPath, row); + path_dist = (path_dist + real_path_dist) / 2; + } results.max_dist = Math.max(results.max_dist || 0, tfpDist); - addIntoResults(results, row.id, pos, 0, tfpDist, 0, Number.MAX_VALUE); + addIntoResults(results, row.id, pos, name_dist, path_dist, 0, Number.MAX_VALUE); } /** @@ -3928,7 +3977,7 @@ class DocSearch { parsedQuery.elems.sort(sortQ); parsedQuery.returned.sort(sortQ); for (let i = 0, nSearchIndex = this.searchIndex.length; i < nSearchIndex; ++i) { - handleArgs(this.searchIndex[i], i, results_others); + handleArgs(this.searchIndex[i], i, results_others, maxEditDistance); } } }; diff --git a/tests/rustdoc-js-std/type-and-name.js b/tests/rustdoc-js-std/type-and-name.js new file mode 100644 index 0000000000000..1ecc446788926 --- /dev/null +++ b/tests/rustdoc-js-std/type-and-name.js @@ -0,0 +1,7 @@ +const EXPECTED = { + 'query': 'method:ascii, char -> bool', + 'others': [ + { 'path': 'char', 'name': 'is_ascii_digit' }, + { 'path': 'char', 'name': 'eq_ignore_ascii_case' }, + ], +}