@@ -89,6 +89,10 @@ const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
8989// of permutations we need to check.
9090const UNBOXING_LIMIT = 5 ;
9191
92+ // used for search query verification
93+ const REGEX_IDENT = / \p{ ID_Start} \p{ ID_Continue} * | _ \p{ ID_Continue} + / uy;
94+ const REGEX_INVALID_TYPE_FILTER = / [ ^ a - z ] / ui;
95+
9296// In the search display, allows to switch between tabs.
9397function printTab ( nb ) {
9498 let iter = 0 ;
@@ -410,18 +414,21 @@ function initSearch(rawSearchIndex) {
410414 }
411415
412416 /**
413- * Returns `true` if the given `c` character is valid for an ident.
417+ * If the current parser position is at the beginning of an identifier,
418+ * move the position to the end of it and return `true`. Otherwise, return `false`.
414419 *
415- * @param {string } c
420+ * @param {ParserState } parserState
416421 *
417422 * @return {boolean }
418423 */
419- function isIdentCharacter ( c ) {
420- return (
421- c === "_" ||
422- ( c >= "0" && c <= "9" ) ||
423- ( c >= "a" && c <= "z" ) ||
424- ( c >= "A" && c <= "Z" ) ) ;
424+ function consumeIdent ( parserState ) {
425+ REGEX_IDENT . lastIndex = parserState . pos ;
426+ const match = parserState . userQuery . match ( REGEX_IDENT ) ;
427+ if ( match ) {
428+ parserState . pos += match [ 0 ] . length ;
429+ return true ;
430+ }
431+ return false ;
425432 }
426433
427434 /**
@@ -618,70 +625,62 @@ function initSearch(rawSearchIndex) {
618625 * @return {integer }
619626 */
620627 function getIdentEndPosition ( parserState ) {
621- const start = parserState . pos ;
628+ let afterIdent = consumeIdent ( parserState ) ;
622629 let end = parserState . pos ;
623- let foundExclamation = - 1 ;
630+ let macroExclamation = - 1 ;
624631 while ( parserState . pos < parserState . length ) {
625632 const c = parserState . userQuery [ parserState . pos ] ;
626- if ( ! isIdentCharacter ( c ) ) {
627- if ( c === "!" ) {
628- if ( foundExclamation !== - 1 ) {
629- throw [ "Cannot have more than one " , "!" , " in an ident" ] ;
630- } else if ( parserState . pos + 1 < parserState . length &&
631- isIdentCharacter ( parserState . userQuery [ parserState . pos + 1 ] )
632- ) {
633+ if ( c === "!" ) {
634+ if ( macroExclamation !== - 1 ) {
635+ throw [ "Cannot have more than one " , "!" , " in an ident" ] ;
636+ } else if ( parserState . pos + 1 < parserState . length ) {
637+ const pos = parserState . pos ;
638+ parserState . pos ++ ;
639+ const beforeIdent = consumeIdent ( parserState ) ;
640+ parserState . pos = pos ;
641+ if ( beforeIdent ) {
633642 throw [ "Unexpected " , "!" , ": it can only be at the end of an ident" ] ;
634643 }
635- foundExclamation = parserState . pos ;
636- } else if ( isPathSeparator ( c ) ) {
637- if ( c === ":" ) {
638- if ( ! isPathStart ( parserState ) ) {
644+ }
645+ if ( afterIdent ) macroExclamation = parserState . pos ;
646+ } else if ( isPathSeparator ( c ) ) {
647+ if ( c === ":" ) {
648+ if ( ! isPathStart ( parserState ) ) {
649+ break ;
650+ }
651+ // Skip current ":".
652+ parserState . pos += 1 ;
653+ } else {
654+ while ( parserState . pos + 1 < parserState . length ) {
655+ const next_c = parserState . userQuery [ parserState . pos + 1 ] ;
656+ if ( next_c !== " " ) {
639657 break ;
640658 }
641- // Skip current ":".
642659 parserState . pos += 1 ;
643- } else {
644- while ( parserState . pos + 1 < parserState . length ) {
645- const next_c = parserState . userQuery [ parserState . pos + 1 ] ;
646- if ( next_c !== " " ) {
647- break ;
648- }
649- parserState . pos += 1 ;
650- }
651660 }
652- if ( foundExclamation !== - 1 ) {
653- if ( foundExclamation !== start &&
654- isIdentCharacter ( parserState . userQuery [ foundExclamation - 1 ] )
655- ) {
656- throw [ "Cannot have associated items in macros" ] ;
657- } else {
658- // while the never type has no associated macros, we still
659- // can parse a path like that
660- foundExclamation = - 1 ;
661- }
662- }
663- } else if (
664- c === "[" ||
665- c === "(" ||
666- isEndCharacter ( c ) ||
667- isSpecialStartCharacter ( c ) ||
668- isSeparatorCharacter ( c )
669- ) {
670- break ;
671- } else if ( parserState . pos > 0 ) {
672- throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
673- } else {
674- throw [ "Unexpected " , c ] ;
675661 }
662+ if ( macroExclamation !== - 1 ) {
663+ throw [ "Cannot have associated items in macros" ] ;
664+ }
665+ } else if (
666+ c === "[" ||
667+ c === "(" ||
668+ isEndCharacter ( c ) ||
669+ isSpecialStartCharacter ( c ) ||
670+ isSeparatorCharacter ( c )
671+ ) {
672+ break ;
673+ } else if ( parserState . pos > 0 ) {
674+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ,
675+ " (not a valid identifier)" ] ;
676+ } else {
677+ throw [ "Unexpected " , c , " (not a valid identifier)" ] ;
676678 }
677679 parserState . pos += 1 ;
680+ afterIdent = consumeIdent ( parserState ) ;
678681 end = parserState . pos ;
679682 }
680- // if start == end - 1, we got the never type
681- if ( foundExclamation !== - 1 &&
682- foundExclamation !== start &&
683- isIdentCharacter ( parserState . userQuery [ foundExclamation - 1 ] )
684- ) {
683+ if ( macroExclamation !== - 1 ) {
685684 if ( parserState . typeFilter === null ) {
686685 parserState . typeFilter = "macro" ;
687686 } else if ( parserState . typeFilter !== "macro" ) {
@@ -693,7 +692,7 @@ function initSearch(rawSearchIndex) {
693692 " both specified" ,
694693 ] ;
695694 }
696- end = foundExclamation ;
695+ end = macroExclamation ;
697696 }
698697 return end ;
699698 }
@@ -1071,16 +1070,15 @@ function initSearch(rawSearchIndex) {
10711070 function checkExtraTypeFilterCharacters ( start , parserState ) {
10721071 const query = parserState . userQuery . slice ( start , parserState . pos ) . trim ( ) ;
10731072
1074- for ( const c in query ) {
1075- if ( ! isIdentCharacter ( query [ c ] ) ) {
1076- throw [
1077- "Unexpected " ,
1078- query [ c ] ,
1079- " in type filter (before " ,
1080- ":" ,
1081- ")" ,
1082- ] ;
1083- }
1073+ const match = query . match ( REGEX_INVALID_TYPE_FILTER ) ;
1074+ if ( match ) {
1075+ throw [
1076+ "Unexpected " ,
1077+ match [ 0 ] ,
1078+ " in type filter (before " ,
1079+ ":" ,
1080+ ")" ,
1081+ ] ;
10841082 }
10851083 }
10861084
@@ -2127,7 +2125,7 @@ function initSearch(rawSearchIndex) {
21272125 } ;
21282126 }
21292127
2130- function handleAliases ( ret , query , filterCrates , currentCrate ) {
2128+ async function handleAliases ( ret , query , filterCrates , currentCrate ) {
21312129 const lowerQuery = query . toLowerCase ( ) ;
21322130 // We separate aliases and crate aliases because we want to have current crate
21332131 // aliases to be before the others in the displayed results.
@@ -2163,6 +2161,15 @@ function initSearch(rawSearchIndex) {
21632161 crateAliases . sort ( sortFunc ) ;
21642162 aliases . sort ( sortFunc ) ;
21652163
2164+ const fetchDesc = alias => {
2165+ return searchIndexEmptyDesc . get ( alias . crate ) . contains ( alias . bitIndex ) ?
2166+ "" : searchState . loadDesc ( alias ) ;
2167+ } ;
2168+ const [ crateDescs , descs ] = await Promise . all ( [
2169+ Promise . all ( crateAliases . map ( fetchDesc ) ) ,
2170+ Promise . all ( aliases . map ( fetchDesc ) ) ,
2171+ ] ) ;
2172+
21662173 const pushFunc = alias => {
21672174 alias . alias = query ;
21682175 const res = buildHrefAndPath ( alias ) ;
@@ -2176,7 +2183,13 @@ function initSearch(rawSearchIndex) {
21762183 }
21772184 } ;
21782185
2186+ aliases . forEach ( ( alias , i ) => {
2187+ alias . desc = descs [ i ] ;
2188+ } ) ;
21792189 aliases . forEach ( pushFunc ) ;
2190+ crateAliases . forEach ( ( alias , i ) => {
2191+ alias . desc = crateDescs [ i ] ;
2192+ } ) ;
21802193 crateAliases . forEach ( pushFunc ) ;
21812194 }
21822195
@@ -2538,7 +2551,8 @@ function initSearch(rawSearchIndex) {
25382551 sorted_returned ,
25392552 sorted_others ,
25402553 parsedQuery ) ;
2541- handleAliases ( ret , parsedQuery . original . replace ( / " / g, "" ) , filterCrates , currentCrate ) ;
2554+ await handleAliases ( ret , parsedQuery . original . replace ( / " / g, "" ) ,
2555+ filterCrates , currentCrate ) ;
25422556 await Promise . all ( [ ret . others , ret . returned , ret . in_args ] . map ( async list => {
25432557 const descs = await Promise . all ( list . map ( result => {
25442558 return searchIndexEmptyDesc . get ( result . crate ) . contains ( result . bitIndex ) ?
0 commit comments