@@ -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 /**
@@ -619,69 +626,61 @@ function initSearch(rawSearchIndex) {
619626 */
620627 function getIdentEndPosition ( parserState ) {
621628 const start = parserState . pos ;
629+ let afterIdent = consumeIdent ( parserState ) ;
622630 let end = parserState . pos ;
623- let foundExclamation = - 1 ;
631+ let macroExclamation = - 1 ;
624632 while ( parserState . pos < parserState . length ) {
625633 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- ) {
634+ if ( c === "!" ) {
635+ if ( macroExclamation !== - 1 ) {
636+ throw [ "Cannot have more than one " , "!" , " in an ident" ] ;
637+ } else if ( parserState . pos + 1 < parserState . length ) {
638+ const pos = parserState . pos ;
639+ parserState . pos ++ ;
640+ const beforeIdent = consumeIdent ( parserState ) ;
641+ parserState . pos = pos ;
642+ if ( beforeIdent ) {
633643 throw [ "Unexpected " , "!" , ": it can only be at the end of an ident" ] ;
634644 }
635- foundExclamation = parserState . pos ;
636- } else if ( isPathSeparator ( c ) ) {
637- if ( c === ":" ) {
638- if ( ! isPathStart ( parserState ) ) {
645+ }
646+ if ( afterIdent ) macroExclamation = parserState . pos ;
647+ } else if ( isPathSeparator ( c ) ) {
648+ if ( c === ":" ) {
649+ if ( ! isPathStart ( parserState ) ) {
650+ break ;
651+ }
652+ // Skip current ":".
653+ parserState . pos += 1 ;
654+ } else {
655+ while ( parserState . pos + 1 < parserState . length ) {
656+ const next_c = parserState . userQuery [ parserState . pos + 1 ] ;
657+ if ( next_c !== " " ) {
639658 break ;
640659 }
641- // Skip current ":".
642660 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- }
651661 }
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 ] ;
675662 }
663+ if ( macroExclamation !== - 1 ) {
664+ throw [ "Cannot have associated items in macros" ] ;
665+ }
666+ } else if (
667+ c === "[" ||
668+ c === "(" ||
669+ isEndCharacter ( c ) ||
670+ isSpecialStartCharacter ( c ) ||
671+ isSeparatorCharacter ( c )
672+ ) {
673+ break ;
674+ } else if ( parserState . pos > 0 ) {
675+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
676+ } else {
677+ throw [ "Unexpected " , c ] ;
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,14 @@ 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 ) ? "" : searchState . loadDesc ( alias ) ;
2166+ } ;
2167+ const [ crateDescs , descs ] = await Promise . all ( [
2168+ Promise . all ( crateAliases . map ( fetchDesc ) ) ,
2169+ Promise . all ( aliases . map ( fetchDesc ) )
2170+ ] ) ;
2171+
21662172 const pushFunc = alias => {
21672173 alias . alias = query ;
21682174 const res = buildHrefAndPath ( alias ) ;
@@ -2176,7 +2182,9 @@ function initSearch(rawSearchIndex) {
21762182 }
21772183 } ;
21782184
2185+ aliases . forEach ( ( alias , i ) => alias . desc = descs [ i ] ) ;
21792186 aliases . forEach ( pushFunc ) ;
2187+ crateAliases . forEach ( ( alias , i ) => alias . desc = crateDescs [ i ] ) ;
21802188 crateAliases . forEach ( pushFunc ) ;
21812189 }
21822190
@@ -2538,7 +2546,7 @@ function initSearch(rawSearchIndex) {
25382546 sorted_returned ,
25392547 sorted_others ,
25402548 parsedQuery ) ;
2541- handleAliases ( ret , parsedQuery . original . replace ( / " / g, "" ) , filterCrates , currentCrate ) ;
2549+ await handleAliases ( ret , parsedQuery . original . replace ( / " / g, "" ) , filterCrates , currentCrate ) ;
25422550 await Promise . all ( [ ret . others , ret . returned , ret . in_args ] . map ( async list => {
25432551 const descs = await Promise . all ( list . map ( result => {
25442552 return searchIndexEmptyDesc . get ( result . crate ) . contains ( result . bitIndex ) ?
0 commit comments