rustdoc-search: add support for nested generics

This commit is contained in:
Michael Howell 2023-03-30 21:53:11 -07:00
parent 276fa29480
commit afee2411e3
4 changed files with 184 additions and 13 deletions

View File

@ -461,9 +461,7 @@ function initSearch(rawSearchIndex) {
if (parserState.pos < parserState.length && if (parserState.pos < parserState.length &&
parserState.userQuery[parserState.pos] === "<" parserState.userQuery[parserState.pos] === "<"
) { ) {
if (isInGenerics) { if (start >= end) {
throw ["Unexpected ", "<", " after ", "<"];
} else if (start >= end) {
throw ["Found generics without a path"]; throw ["Found generics without a path"];
} }
parserState.pos += 1; parserState.pos += 1;
@ -765,13 +763,10 @@ function initSearch(rawSearchIndex) {
* ident = *(ALPHA / DIGIT / "_") * ident = *(ALPHA / DIGIT / "_")
* path = ident *(DOUBLE-COLON ident) [!] * path = ident *(DOUBLE-COLON ident) [!]
* arg = [type-filter *WS COLON *WS] path [generics] * arg = [type-filter *WS COLON *WS] path [generics]
* arg-without-generic = [type-filter *WS COLON *WS] path
* type-sep = COMMA/WS *(COMMA/WS) * type-sep = COMMA/WS *(COMMA/WS)
* nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
* nonempty-arg-list-without-generics = *(type-sep) arg-without-generic * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list ] *(type-sep)
* *(type-sep arg-without-generic) *(type-sep) * CLOSE-ANGLE-BRACKET
* generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
* CLOSE-ANGLE-BRACKET/EOF
* return-args = RETURN-ARROW *(type-sep) nonempty-arg-list * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
* *
* exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ] * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
@ -1127,7 +1122,7 @@ function initSearch(rawSearchIndex) {
currentEntryElems = []; currentEntryElems = [];
elems.set(entry.name, currentEntryElems); elems.set(entry.name, currentEntryElems);
} }
currentEntryElems.push(entry.ty); currentEntryElems.push(entry);
} }
// We need to find the type that matches the most to remove it in order // We need to find the type that matches the most to remove it in order
// to move forward. // to move forward.
@ -1136,8 +1131,12 @@ function initSearch(rawSearchIndex) {
return false; return false;
} }
const matchElems = elems.get(generic.name); const matchElems = elems.get(generic.name);
const matchIdx = matchElems.findIndex(tmp_elem => const matchIdx = matchElems.findIndex(tmp_elem => {
typePassesFilter(generic.typeFilter, tmp_elem)); if (checkGenerics(tmp_elem, generic, 0, maxEditDistance) !== 0) {
return false;
}
return typePassesFilter(generic.typeFilter, tmp_elem.ty);
});
if (matchIdx === -1) { if (matchIdx === -1) {
return false; return false;
} }

View File

@ -1,4 +1,11 @@
const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>']; const QUERY = [
'A<B<C<D>, E>',
'p<> u8',
'"p"<a>',
'p<u<x>>',
'p<u<x>, r>',
'p<u<x, r>>',
];
const PARSED = [ const PARSED = [
{ {
@ -7,7 +14,7 @@ const PARSED = [
original: 'A<B<C<D>, E>', original: 'A<B<C<D>, E>',
returned: [], returned: [],
userQuery: 'a<b<c<d>, e>', userQuery: 'a<b<c<d>, e>',
error: 'Unexpected `<` after `<`', error: 'Unclosed `<`',
}, },
{ {
elems: [ elems: [
@ -59,4 +66,117 @@ const PARSED = [
userQuery: '"p"<a>', userQuery: '"p"<a>',
error: null, error: null,
}, },
{
elems: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [
{
name: "u",
fullPath: ["u"],
pathWithoutLast: [],
pathLast: "u",
generics: [
{
name: "x",
fullPath: ["x"],
pathWithoutLast: [],
pathLast: "x",
generics: [],
},
],
},
],
typeFilter: -1,
},
],
foundElems: 1,
original: 'p<u<x>>',
returned: [],
userQuery: 'p<u<x>>',
error: null,
},
{
elems: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [
{
name: "u",
fullPath: ["u"],
pathWithoutLast: [],
pathLast: "u",
generics: [
{
name: "x",
fullPath: ["x"],
pathWithoutLast: [],
pathLast: "x",
generics: [],
},
],
},
{
name: "r",
fullPath: ["r"],
pathWithoutLast: [],
pathLast: "r",
generics: [],
},
],
typeFilter: -1,
},
],
foundElems: 1,
original: 'p<u<x>, r>',
returned: [],
userQuery: 'p<u<x>, r>',
error: null,
},
{
elems: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [
{
name: "u",
fullPath: ["u"],
pathWithoutLast: [],
pathLast: "u",
generics: [
{
name: "x",
fullPath: ["x"],
pathWithoutLast: [],
pathLast: "x",
generics: [],
},
{
name: "r",
fullPath: ["r"],
pathWithoutLast: [],
pathLast: "r",
generics: [],
},
],
},
],
typeFilter: -1,
},
],
foundElems: 1,
original: 'p<u<x, r>>',
returned: [],
userQuery: 'p<u<x, r>>',
error: null,
},
]; ];

View File

@ -0,0 +1,33 @@
// exact-check
const QUERY = [
'-> Out<First<Second>>',
'-> Out<Second<First>>',
'-> Out<First, Second>',
'-> Out<Second, First>',
];
const EXPECTED = [
{
// -> Out<First<Second>>
'others': [
{ 'path': 'generics_nested', 'name': 'alef' },
],
},
{
// -> Out<Second<First>>
'others': [],
},
{
// -> Out<First, Second>
'others': [
{ 'path': 'generics_nested', 'name': 'bet' },
],
},
{
// -> Out<Second, First>
'others': [
{ 'path': 'generics_nested', 'name': 'bet' },
],
},
];

View File

@ -0,0 +1,19 @@
pub struct Out<A, B = ()> {
a: A,
b: B,
}
pub struct First<In = ()> {
in_: In,
}
pub struct Second;
// Out<First<Second>>
pub fn alef() -> Out<First<Second>> {
loop {}
}
pub fn bet() -> Out<First, Second> {
loop {}
}