Improve the documentation search code.

Instead of just one array for exact results and one for all the rest,
use one array for each possible comparison result, and concatenate them
all for the final list.
This commit is contained in:
Eli Barzilay 2012-06-14 11:08:09 -04:00
parent 41745e4f38
commit ecc43ff104

View File

@ -246,26 +246,26 @@ function AdjustResultsNum() {
} }
} }
// Terms are compared using Compare(), which returns one of several constants: // Terms are compared using Compare(pat,str), which returns one of several
// - C_fail: there was no match // constants, in increasing order of success:
// - C_match: there was a match somewhere in the string // - C_fail: no match
// - C_prefix: there was a prefix match (starts at 0) // - C_words: all of the "subwords" in pat matched, where a word is an
// - C_rexact: there was a ("real") exact match // alphanumeric or a punctuation substring (for example, "foo-bar!!" has
// There is also C_exact which can be returned by some of the X: operators. // these words: "foo", "-", "bar", "!!"), and a match means a prefix of a
// It's purpose is to be able to return a result that doesn't affect the // subword in str matched one of pat's subwords
// exactness of the search (for example L:foo searches for a source module that // - C_match: pat matched somewhere in str
// is exactly `foo', but it will return C_exact which means that it doesn't // - C_prefix: pat is a prefix of str
// change whether the match is considered exact or not). Note that these // - C_exact: pat is equal to str
// constants are ordered, so: // - C_rexact: there was a ("real") exact match, see below
// - < exact => this match is inexact // Note that the value is searched from the last one and going back, so, for
// - = exact => does not affect the exactness of this match // example, if pat is a prefix of str the result is C_prefix, and no subword
// - > exact => this is an exact match as far as this predicate goes // matching is attempted. A result of C_exact can be returned by some of the
// Finally, there is also a C_wordmatch that is used when there is no proper // `X:' operators: its purpose is to be able to return a result that doesn't
// match, but all the words in the term match (where a word is an alphanumeric // affect the exactness of the search (for example L:foo searches for a source
// sequence or a punctuation, for example, "foo-bar!!" has these words: "foo", // module that is exactly `foo', but it will return C_exact which means that it
// "-", "bar", "!!") // doesn't change whether the match is considered exact or not).
var C_fail = 0, C_min = 0, var C_fail = 0, C_min = 0,
C_wordmatch = 1, C_words = 1,
C_match = 2, C_match = 2,
C_prefix = 3, C_prefix = 3,
C_exact = 4, C_exact = 4,
@ -287,18 +287,18 @@ function CompareRx(pat, str) {
return C_match; return C_match;
} }
function MaxCompares(pat, strs) { function MaxCompares(pat, strs) {
var r = C_min; var r = C_min, c;
for (var i=0; i<strs.length; i++) { for (var i=0; i<strs.length; i++) {
r = Math.max(r, Compare(pat,strs[i])); c = Compare(pat,strs[i]);
if (r >= C_max) return r; if (c > r) { if (c >= C_max) return c; else r = c; }
} }
return r; return r;
} }
function MinComparesRx(pats, str) { function MinComparesRx(pats, str) {
var r = C_max; var r = C_max, c;
for (var i=0; i<pats.length; i++) { for (var i=0; i<pats.length; i++) {
r = Math.min(r, CompareRx(pats[i],str)); c = CompareRx(pats[i],str);
if (r <= C_min) return r; if (c < r) { if (c <= C_min) return c; else r = c; }
} }
return r; return r;
} }
@ -329,9 +329,10 @@ function UrlToManual(url) {
// Tests for matches and highlights: // Tests for matches and highlights:
// "append" // "append"
// "L:scheme append" // "L:racket append"
// "L:scheme" (no exact matches except for the `scheme' module) // "L:racket" (no exact matches except for the `racket' module)
// "L:schem" (only module names that match `schem') // "L:racke" (only module names that match `racke')
// "edi" and "edit" (the top few should be the same)
// Additional "hidden" operators: // Additional "hidden" operators:
// "A:{ foo bar }" -- an `and' query // "A:{ foo bar }" -- an `and' query
@ -374,24 +375,24 @@ function CompileTerm(term) {
for (var i=0; i<words.length; i++) for (var i=0; i<words.length; i++)
if (words[i].search(/^\w/) >= 0) words[i] = new RegExp("\\b"+words[i]); if (words[i].search(/^\w/) >= 0) words[i] = new RegExp("\\b"+words[i]);
// (note: seems like removing duplicates is not important since search // (note: seems like removing duplicates is not important since search
// strings will not have them, except, maybe, for an occasional x-y-z) // strings will not have them, except for dashes in things like x-y-z)
return function(x) { return function(x) {
var r = Compare(term,x[0]); var r = Compare(term,x[0]);
// only bindings can be used for exact matches // only bindings can be used for rexact matches
if (r >= C_exact) return (x[3] ? C_rexact : C_match); if (r >= C_rexact) return (x[3] ? r : C_exact);
if (r >= C_match) return r; if (r > C_words) return r;
if (MinComparesRx(words,x[0]) > C_fail) return C_wordmatch; if (MinComparesRx(words,x[0]) <= C_fail) return r;
return r; return C_words;
} }
} }
} }
function CompileAndTerms(preds) { function CompileAndTerms(preds) {
return function(x) { return function(x) {
var r = C_max; var r = C_max, c;
for (var i=0; i<preds.length; i++) { for (var i=0; i<preds.length; i++) {
r = Math.min(r, preds[i](x)); c = preds[i](x);
if (r <= C_min) return r; if (c < r) { if (c <= C_min) return c; else r = c; }
} }
return r; return r;
}; };
@ -399,10 +400,10 @@ function CompileAndTerms(preds) {
function CompileOrTerms(preds) { function CompileOrTerms(preds) {
return function(x) { return function(x) {
var r = C_min; var r = C_min, c;
for (var i=0; i<preds.length; i++) { for (var i=0; i<preds.length; i++) {
r = Math.max(r, preds[i](x)); c = preds[i](x);
if (r >= C_max) return r; if (c > r) { if (c >= C_max) return c; else r = c; }
} }
return r; return r;
}; };
@ -471,27 +472,32 @@ function Search(data, term, is_pre, K) {
if (K) { K(ret); return killer; } if (K) { K(ret); return killer; }
else return ret; else return ret;
} }
var matches = new Array(), exacts = new Array(), wordmatches = new Array();
var i = 0; var i = 0;
var matches = new Array(C_max-C_min);
for (i=0; i<matches.length; i++) matches[i] = new Array();
var chunk_fuel = K ? Math.round(data.length/10) : data.length; var chunk_fuel = K ? Math.round(data.length/10) : data.length;
var progress = K ? MakeShowProgress() : Id; var progress = K ? MakeShowProgress() : Id;
i = 0;
var DoChunk = function() { var DoChunk = function() {
var fuel = Math.min(chunk_fuel, data.length-i); var fuel = Math.min(chunk_fuel, data.length-i);
progress(i+fuel); progress(i+fuel);
while (fuel > 0) { while (fuel > 0) {
var r, min = C_max, max = C_min; var r, min = C_max, max = C_min;
for (var j=0; j<preds.length; j++) { for (var j=0; j<preds.length; j++) {
r = preds[j](data[i]); min = Math.min(r, min); max = Math.max(r, max); r = preds[j](data[i]);
if (min <= C_min) break; // get out if it's hopeless if (r < min) {
min = r;
if (r <= C_min) break; // get out if it's hopeless
}
if (r > max) max = r;
} }
if (max >= C_rexact && min >= C_exact) exacts.push(data[i]); if (max >= C_rexact && min >= C_exact) min = C_rexact;
else if (min > C_wordmatch) matches.push(data[i]); if (min > C_min) matches[C_max - min].push(data[i]);
else if (min > C_fail) wordmatches.push(data[i]);
fuel--; i++; fuel--; i++;
} }
if (i<data.length) t = setTimeout(DoChunk,5); if (i<data.length) t = setTimeout(DoChunk,5);
else { else {
r = [exacts.length, exacts.concat(matches).concat(wordmatches)]; r = [matches[0].length, [].concat.apply([],matches)];
if (K) K(r); else return r; if (K) K(r); else return r;
} }
}; };