Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5983db9
rustdoc-search: parse and search with ML-style HOF
notriddle Jan 6, 2024
8eac04f
rustdoc: clean up search.js by removing empty sort case
notriddle Jan 6, 2024
df043c4
rustdoc: use `const` for the special type name ids
notriddle Jan 6, 2024
84d7a2c
rustdoc-search: add search query syntax `Fn(T) -> U`
notriddle Jan 6, 2024
3ab6936
mir-opt unnamed-fields filecheck annotations
Kirandevraj Mar 1, 2024
6f1156a
fixing mir pass name to text comment
Kirandevraj Mar 9, 2024
3af28f0
Fix 32-bit overflows in LLVM composite constants
erer1243 Mar 4, 2024
b66d7f5
Update books
rustbot Mar 11, 2024
779ac69
Update Windows platform support
ChrisDenton Mar 10, 2024
aeec0d1
Update /NODEFAUTLIB comment for msvc
ChrisDenton Mar 11, 2024
2a1d4dd
Don't ICE when non-self part of trait goal is constrained in new solver
compiler-errors Mar 11, 2024
0b6b330
Move project -> normalize, move normalize tests
compiler-errors Mar 11, 2024
f614eae
Remove some unnecessary allow(incomplete_features)
compiler-errors Mar 11, 2024
ba70528
updating variable names in CHECK
Kirandevraj Mar 11, 2024
7ec3516
Rollup merge of #115141 - ChrisDenton:windows-support, r=wesleywiser
matthiaskrgr Mar 11, 2024
c87410e
Rollup merge of #119676 - notriddle:notriddle/rustdoc-search-hof, r=G…
matthiaskrgr Mar 11, 2024
8fb5cda
Rollup merge of #121865 - Kirandevraj:unnamed-fields-filecheck, r=oli…
matthiaskrgr Mar 11, 2024
7a27bd3
Rollup merge of #122000 - erer1243:issue-121868, r=nikic
matthiaskrgr Mar 11, 2024
92e9023
Rollup merge of #122319 - compiler-errors:next-solver-normalizing-sel…
matthiaskrgr Mar 11, 2024
60d7ef8
Rollup merge of #122339 - rustbot:docs-update, r=ehuss
matthiaskrgr Mar 11, 2024
2b344e3
Rollup merge of #122342 - ChrisDenton:defautlib, r=petrochenkov
matthiaskrgr Mar 11, 2024
2336a89
Rollup merge of #122343 - compiler-errors:rando, r=fmease
matthiaskrgr Mar 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rustdoc-search: add search query syntax Fn(T) -> U
This is implemented, in addition to the ML-style one,
because Rust does it. If we don't, we'll never hear the end of it.

This commit also refactors some duplicate parts of the parser
into a dedicated function.
  • Loading branch information
notriddle committed Jan 7, 2024
commit 84d7a2c9da08fbae6bae815f1e306a887a1cb3b2
46 changes: 30 additions & 16 deletions src/doc/rustdoc/src/read-documentation/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,26 @@ will match these queries:

But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.

To search for a function that accepts a function as a parameter,
like `Iterator::all`, wrap the nested signature in parenthesis,
as in [`Iterator<T>, (T -> bool) -> bool`][iterator-all].
You can also search for a specific closure trait,
such as `Iterator<T>, (FnMut(T) -> bool) -> bool`,
but you need to know which one you want.

[iterator-all]: ../../std/vec/struct.Vec.html?search=Iterator<T>%2C+(T+->+bool)+->+bool&filter-crate=std

### Primitives with Special Syntax

| Shorthand | Explicit names |
| --------- | ------------------------------------------------ |
| `[]` | `primitive:slice` and/or `primitive:array` |
| `[T]` | `primitive:slice<T>` and/or `primitive:array<T>` |
| `()` | `primitive:unit` and/or `primitive:tuple` |
| `(T)` | `T` |
| `(T,)` | `primitive:tuple<T>` |
| `!` | `primitive:never` |
| Shorthand | Explicit names |
| ---------------- | ------------------------------------------------- |
| `[]` | `primitive:slice` and/or `primitive:array` |
| `[T]` | `primitive:slice<T>` and/or `primitive:array<T>` |
| `()` | `primitive:unit` and/or `primitive:tuple` |
| `(T)` | `T` |
| `(T,)` | `primitive:tuple<T>` |
| `!` | `primitive:never` |
| `(T, U -> V, W)` | `fn(T, U) -> (V, W)`, `Fn`, `FnMut`, and `FnOnce` |

When searching for `[]`, Rustdoc will return search results with either slices
or arrays. If you know which one you want, you can force it to return results
Expand All @@ -182,6 +192,10 @@ results for types that match tuples, even though it also matches the type on
its own. That is, `(u32)` matches `(u32,)` for the exact same reason that it
also matches `Result<u32, Error>`.

The `->` operator has lower precedence than comma. If it's not wrapped
in brackets, it delimits the return value for the function being searched for.
To search for functions that take functions as parameters, use parenthesis.

### Limitations and quirks of type-based search

Type-based search is still a buggy, experimental, work-in-progress feature.
Expand Down Expand Up @@ -220,9 +234,6 @@ Most of these limitations should be addressed in future version of Rustdoc.

* Searching for lifetimes is not supported.

* It's impossible to search for closures based on their parameters or
return values.

* It's impossible to search based on the length of an array.

## Item filtering
Expand All @@ -239,19 +250,21 @@ Item filters can be used in both name-based and type signature-based searches.

```text
ident = *(ALPHA / DIGIT / "_")
path = ident *(DOUBLE-COLON ident) [!]
path = ident *(DOUBLE-COLON ident) [BANG]
slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / [!])
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like)
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) [ return-args ]
generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
generics = OPEN-ANGLE-BRACKET [ generic-arg-list ] *(type-sep)
normal-generics = OPEN-ANGLE-BRACKET [ generic-arg-list ] *(type-sep)
CLOSE-ANGLE-BRACKET
fn-like-generics = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN [ RETURN-ARROW arg ]
generics = normal-generics / fn-like-generics
return-args = RETURN-ARROW *(type-sep) nonempty-arg-list

exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
type-search = [ nonempty-arg-list ] [ return-args ]
type-search = [ nonempty-arg-list ]

query = *WS (exact-search / type-search) *WS

Expand Down Expand Up @@ -296,6 +309,7 @@ QUOTE = %x22
COMMA = ","
RETURN-ARROW = "->"
EQUAL = "="
BANG = "!"

ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
DIGIT = %x30-39
Expand Down
112 changes: 64 additions & 48 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,10 @@ function initSearch(rawSearchIndex) {
// Syntactically, bindings are parsed as generics,
// but the query engine treats them differently.
if (gen.bindingName !== null) {
bindings.set(gen.bindingName.name, [gen, ...gen.bindingName.generics]);
if (gen.name !== null) {
gen.bindingName.generics.unshift(gen);
}
bindings.set(gen.bindingName.name, gen.bindingName.generics);
return false;
}
return true;
Expand Down Expand Up @@ -678,6 +681,38 @@ function initSearch(rawSearchIndex) {
return end;
}

function getFilteredNextElem(query, parserState, elems, isInGenerics) {
const start = parserState.pos;
if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
throw ["Expected type filter before ", ":"];
}
getNextElem(query, parserState, elems, isInGenerics);
if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
if (parserState.typeFilter !== null) {
throw [
"Unexpected ",
":",
" (expected path after type filter ",
parserState.typeFilter + ":",
")",
];
}
if (elems.length === 0) {
throw ["Expected type filter before ", ":"];
} else if (query.literalSearch) {
throw ["Cannot use quotes on type filter"];
}
// The type filter doesn't count as an element since it's a modifier.
const typeFilterElem = elems.pop();
checkExtraTypeFilterCharacters(start, parserState);
parserState.typeFilter = typeFilterElem.name;
parserState.pos += 1;
parserState.totalElems -= 1;
query.literalSearch = false;
getNextElem(query, parserState, elems, isInGenerics);
}
}

/**
* @param {ParsedQuery} query
* @param {ParserState} parserState
Expand Down Expand Up @@ -752,6 +787,32 @@ function initSearch(rawSearchIndex) {
}
parserState.pos += 1;
getItemsBefore(query, parserState, generics, ">");
} else if (parserState.pos < parserState.length &&
parserState.userQuery[parserState.pos] === "("
) {
if (start >= end) {
throw ["Found generics without a path"];
}
if (parserState.isInBinding) {
throw ["Unexpected ", "(", " after ", "="];
}
parserState.pos += 1;
const typeFilter = parserState.typeFilter;
parserState.typeFilter = null;
getItemsBefore(query, parserState, generics, ")");
skipWhitespace(parserState);
if (isReturnArrow(parserState)) {
parserState.pos += 2;
skipWhitespace(parserState);
getFilteredNextElem(query, parserState, generics, isInGenerics);
generics[generics.length - 1].bindingName = makePrimitiveElement("output");
} else {
generics.push(makePrimitiveElement(null, {
bindingName: makePrimitiveElement("output"),
typeFilter: null,
}));
}
parserState.typeFilter = typeFilter;
}
if (isStringElem) {
skipWhitespace(parserState);
Expand Down Expand Up @@ -811,7 +872,6 @@ function initSearch(rawSearchIndex) {
function getItemsBefore(query, parserState, elems, endChar) {
let foundStopChar = true;
let foundSeparator = false;
let start = parserState.pos;

// If this is a generic, keep the outer item's type filter around.
const oldTypeFilter = parserState.typeFilter;
Expand Down Expand Up @@ -874,24 +934,6 @@ function initSearch(rawSearchIndex) {
continue;
} else if (c === ":" && isPathStart(parserState)) {
throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
} else if (c === ":") {
if (parserState.typeFilter !== null) {
throw ["Unexpected ", ":"];
}
if (elems.length === 0) {
throw ["Expected type filter before ", ":"];
} else if (query.literalSearch) {
throw ["Cannot use quotes on type filter"];
}
// The type filter doesn't count as an element since it's a modifier.
const typeFilterElem = elems.pop();
checkExtraTypeFilterCharacters(start, parserState);
parserState.typeFilter = typeFilterElem.name;
parserState.pos += 1;
parserState.totalElems -= 1;
query.literalSearch = false;
foundStopChar = true;
continue;
} else if (isEndCharacter(c)) {
throw ["Unexpected ", c, " after ", extra];
}
Expand Down Expand Up @@ -926,8 +968,7 @@ function initSearch(rawSearchIndex) {
];
}
const posBefore = parserState.pos;
start = parserState.pos;
getNextElem(query, parserState, elems, endChar !== "");
getFilteredNextElem(query, parserState, elems, endChar !== "");
if (endChar !== "" && parserState.pos >= parserState.length) {
throw ["Unclosed ", extra];
}
Expand Down Expand Up @@ -1004,7 +1045,6 @@ function initSearch(rawSearchIndex) {
*/
function parseInput(query, parserState) {
let foundStopChar = true;
let start = parserState.pos;

while (parserState.pos < parserState.length) {
const c = parserState.userQuery[parserState.pos];
Expand All @@ -1022,29 +1062,6 @@ function initSearch(rawSearchIndex) {
throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]];
}
throw ["Unexpected ", c];
} else if (c === ":" && !isPathStart(parserState)) {
if (parserState.typeFilter !== null) {
throw [
"Unexpected ",
":",
" (expected path after type filter ",
parserState.typeFilter + ":",
")",
];
} else if (query.elems.length === 0) {
throw ["Expected type filter before ", ":"];
} else if (query.literalSearch) {
throw ["Cannot use quotes on type filter"];
}
// The type filter doesn't count as an element since it's a modifier.
const typeFilterElem = query.elems.pop();
checkExtraTypeFilterCharacters(start, parserState);
parserState.typeFilter = typeFilterElem.name;
parserState.pos += 1;
parserState.totalElems -= 1;
query.literalSearch = false;
foundStopChar = true;
continue;
} else if (c === " ") {
skipWhitespace(parserState);
continue;
Expand Down Expand Up @@ -1080,8 +1097,7 @@ function initSearch(rawSearchIndex) {
];
}
const before = query.elems.length;
start = parserState.pos;
getNextElem(query, parserState, query.elems, false);
getFilteredNextElem(query, parserState, query.elems, false);
if (query.elems.length === before) {
// Nothing was added, weird... Let's increase the position to not remain stuck.
parserState.pos += 1;
Expand Down
15 changes: 12 additions & 3 deletions tests/rustdoc-js-std/parser-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ const PARSED = [
original: "a (b:",
returned: [],
userQuery: "a (b:",
error: "Expected `,`, `:` or `->`, found `(`",
error: "Unclosed `(`",
},
{
query: "_:",
Expand Down Expand Up @@ -357,7 +357,16 @@ const PARSED = [
original: "a,:",
returned: [],
userQuery: "a,:",
error: 'Unexpected `,` in type filter (before `:`)',
error: 'Expected type filter before `:`',
},
{
query: "a!:",
elems: [],
foundElems: 0,
original: "a!:",
returned: [],
userQuery: "a!:",
error: 'Unexpected `!` in type filter (before `:`)',
},
{
query: " a<> :",
Expand All @@ -366,7 +375,7 @@ const PARSED = [
original: "a<> :",
returned: [],
userQuery: "a<> :",
error: 'Unexpected `<` in type filter (before `:`)',
error: 'Expected `,`, `:` or `->` after `>`, found `:`',
},
{
query: "mod : :",
Expand Down
Loading