diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 7c55d10836c45..d419e384a594a 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -176,16 +176,13 @@ window.initSearch = function(rawSearchIndex) { var ar = []; for (var entry in results) { if (hasOwnPropertyRustdoc(results, entry)) { - ar.push(results[entry]); + var result = results[entry]; + result.word = searchWords[result.id]; + result.item = searchIndex[result.id] || {}; + ar.push(result); } } results = ar; - var i, len, result; - for (i = 0, len = results.length; i < len; ++i) { - result = results[i]; - result.word = searchWords[result.id]; - result.item = searchIndex[result.id] || {}; - } // if there are no results then return to default and fail if (results.length === 0) { return []; @@ -258,7 +255,7 @@ window.initSearch = function(rawSearchIndex) { return 0; }); - for (i = 0, len = results.length; i < len; ++i) { + for (var i = 0, len = results.length; i < len; ++i) { result = results[i]; // this validation does not make sense when searching by types @@ -344,7 +341,17 @@ window.initSearch = function(rawSearchIndex) { return MAX_LEV_DISTANCE + 1; } - // Check for type name and type generics (if any). + /** + * This function checks if the object (`obj`) matches the given type (`val`) and its + * generics (if any). + * + * @param {Object} obj + * @param {string} val + * @param {boolean} literalSearch + * + * @return {integer} - Returns a Levenshtein distance to the best match. If there is + * no match, returns `MAX_LEV_DISTANCE + 1`. + */ function checkType(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; var tmp_lev = MAX_LEV_DISTANCE + 1; @@ -363,24 +370,23 @@ window.initSearch = function(rawSearchIndex) { elems[obj[GENERICS_DATA][x][NAME]] += 1; } - var allFound = true; len = val.generics.length; for (x = 0; x < len; ++x) { firstGeneric = val.generics[x]; if (elems[firstGeneric]) { elems[firstGeneric] -= 1; } else { - allFound = false; - break; + // Something wasn't found and this is a literal search so + // abort and return a "failing" distance. + return MAX_LEV_DISTANCE + 1; } } - if (allFound) { - return true; - } + // Everything was found, success! + return 0; } - return false; + return MAX_LEV_DISTANCE + 1; } - return true; + return 0; } else { // If the type has generics but don't match, then it won't return at this point. // Otherwise, `checkGenerics` will return 0 and it'll return. @@ -392,14 +398,15 @@ window.initSearch = function(rawSearchIndex) { } } } else if (literalSearch) { + var found = false; if ((!val.generics || val.generics.length === 0) && obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) { - return obj[GENERICS_DATA].some( + found = obj[GENERICS_DATA].some( function(gen) { return gen[NAME] === val.name; }); } - return false; + return found ? 0 : MAX_LEV_DISTANCE + 1; } lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance); if (lev_distance <= MAX_LEV_DISTANCE) { @@ -430,6 +437,17 @@ window.initSearch = function(rawSearchIndex) { return Math.min(lev_distance, tmp_lev) + 1; } + /** + * This function checks if the object (`obj`) has an argument with the given type (`val`). + * + * @param {Object} obj + * @param {string} val + * @param {boolean} literalSearch + * @param {integer} typeFilter + * + * @return {integer} - Returns a Levenshtein distance to the best match. If there is no + * match, returns `MAX_LEV_DISTANCE + 1`. + */ function findArg(obj, val, literalSearch, typeFilter) { var lev_distance = MAX_LEV_DISTANCE + 1; @@ -441,19 +459,15 @@ window.initSearch = function(rawSearchIndex) { continue; } tmp = checkType(tmp, val, literalSearch); - if (literalSearch) { - if (tmp) { - return true; - } + if (tmp === 0) { + return 0; + } else if (literalSearch) { continue; } lev_distance = Math.min(tmp, lev_distance); - if (lev_distance === 0) { - return 0; - } } } - return literalSearch ? false : lev_distance; + return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance; } function checkReturned(obj, val, literalSearch, typeFilter) { @@ -470,19 +484,15 @@ window.initSearch = function(rawSearchIndex) { continue; } tmp = checkType(tmp, val, literalSearch); - if (literalSearch) { - if (tmp) { - return true; - } + if (tmp === 0) { + return 0; + } else if (literalSearch) { continue; } lev_distance = Math.min(tmp, lev_distance); - if (lev_distance === 0) { - return 0; - } } } - return literalSearch ? false : lev_distance; + return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance; } function checkPath(contains, lastElem, ty) { @@ -612,6 +622,44 @@ window.initSearch = function(rawSearchIndex) { onEach(crateAliases, pushFunc); } + /** + * This function adds the given result into the provided `res` map if it matches the + * following condition: + * + * * If it is a "literal search" (`isExact`), then `lev` must be 0. + * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`. + * + * The `res` map contains information which will be used to sort the search results: + * + * * `fullId` is a `string`` used as the key of the object we use for the `res` map. + * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element. + * * `index` is an `integer`` used to sort by the position of the word in the item's name. + * * `lev` is the main metric used to sort the search results. + * + * @param {boolean} isExact + * @param {Object} res + * @param {string} fullId + * @param {integer} id + * @param {integer} index + * @param {integer} lev + */ + function addIntoResults(isExact, res, fullId, id, index, lev) { + if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) { + if (res[fullId] !== undefined) { + var result = res[fullId]; + if (result.dontValidate || result.lev <= lev) { + return; + } + } + res[fullId] = { + id: id, + index: index, + dontValidate: isExact, + lev: lev, + }; + } + } + // quoted values mean literal search var nSearchWords = searchWords.length; var i, it; @@ -634,28 +682,11 @@ window.initSearch = function(rawSearchIndex) { fullId = ty.id; if (searchWords[i] === val.name - && typePassesFilter(typeFilter, searchIndex[i].ty) - && results[fullId] === undefined) { - results[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; - } - if (in_args && results_in_args[fullId] === undefined) { - results_in_args[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; - } - if (returned && results_returned[fullId] === undefined) { - results_returned[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; + && typePassesFilter(typeFilter, searchIndex[i].ty)) { + addIntoResults(true, results, fullId, i, -1, 0); } + addIntoResults(true, results_in_args, fullId, i, -1, in_args); + addIntoResults(true, results_returned, fullId, i, -1, returned); } query.inputs = [val]; query.output = val; @@ -684,39 +715,27 @@ window.initSearch = function(rawSearchIndex) { fullId = ty.id; returned = checkReturned(ty, output, true, NO_TYPE_FILTER); - if (output.name === "*" || returned) { + if (output.name === "*" || returned === 0) { in_args = false; var is_module = false; if (input === "*") { is_module = true; } else { - var allFound = true; - for (it = 0, len = inputs.length; allFound && it < len; it++) { - allFound = checkType(type, inputs[it], true); + var firstNonZeroDistance = 0; + for (it = 0, len = inputs.length; it < len; it++) { + var distance = checkType(type, inputs[it], true); + if (distance > 0) { + firstNonZeroDistance = distance; + break; + } } - in_args = allFound; - } - if (in_args) { - results_in_args[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; - } - if (returned) { - results_returned[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; + in_args = firstNonZeroDistance; } + addIntoResults(true, results_in_args, fullId, i, -1, in_args); + addIntoResults(true, results_returned, fullId, i, -1, returned); if (is_module) { - results[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; + addIntoResults(true, results, fullId, i, -1, 0); } } } @@ -788,41 +807,14 @@ window.initSearch = function(rawSearchIndex) { lev = 0; } } - if (in_args <= MAX_LEV_DISTANCE) { - if (results_in_args[fullId] === undefined) { - results_in_args[fullId] = { - id: j, - index: index, - lev: in_args, - }; - } - results_in_args[fullId].lev = - Math.min(results_in_args[fullId].lev, in_args); - } - if (returned <= MAX_LEV_DISTANCE) { - if (results_returned[fullId] === undefined) { - results_returned[fullId] = { - id: j, - index: index, - lev: returned, - }; - } - results_returned[fullId].lev = - Math.min(results_returned[fullId].lev, returned); - } + addIntoResults(false, results_in_args, fullId, j, index, in_args); + addIntoResults(false, results_returned, fullId, j, index, returned); if (typePassesFilter(typeFilter, ty.ty) && (index !== -1 || lev <= MAX_LEV_DISTANCE)) { if (index !== -1 && paths.length < 2) { lev = 0; } - if (results[fullId] === undefined) { - results[fullId] = { - id: j, - index: index, - lev: lev, - }; - } - results[fullId].lev = Math.min(results[fullId].lev, lev); + addIntoResults(false, results, fullId, j, index, lev); } } }