diff --git a/src/search/QuickOpen.js b/src/search/QuickOpen.js index b6e3ee57ef4..ae15ceace6f 100644 --- a/src/search/QuickOpen.js +++ b/src/search/QuickOpen.js @@ -680,7 +680,7 @@ define(function (require, exports, module) { displayName += '(' + item.matchGoodness + ') '; + sd.notStartingOnSpecial + ', upper: ' + sd.upper + '">(' + item.matchGoodness + ') '; } // Put the path pieces together, highlighting the matched parts diff --git a/src/utils/StringMatch.js b/src/utils/StringMatch.js index fa95cdc241f..7f43e1f3631 100644 --- a/src/utils/StringMatch.js +++ b/src/utils/StringMatch.js @@ -117,34 +117,30 @@ define(function (require, exports, module) { // Constants for scoring - var SPECIAL_CASE_POINTS = 50; // Both a Special and a Case match var SPECIAL_POINTS = 40; var MATCH_POINTS = 10; - var MATCH_CASE_POINTS = 7; // Consecutive non-case matches have higher priority + var UPPER_CASE_MATCH = 100; var CONSECUTIVE_MATCHES_POINTS = 8; var BEGINNING_OF_NAME_POINTS = 13; var LAST_SEGMENT_BOOST = 1; var DEDUCTION_FOR_LENGTH = 0.2; var NOT_STARTING_ON_SPECIAL_PENALTY = 25; - function SpecialCaseMatch(index) { - this.index = index; - } - // Used in match lists to designate matches of "special" characters (see // findSpecialCharacters above - function SpecialMatch(index) { + function SpecialMatch(index, upper) { this.index = index; + if (upper) { + this.upper = upper; + } } // Used in match lists to designate any matched characters that are not special - function NormalMatch(index) { - this.index = index; - } - - // Used in match lists to designate any matched characters that are case-sensitive matches - function CaseMatch(index) { + function NormalMatch(index, upper) { this.index = index; + if (upper) { + this.upper = upper; + } } /* @@ -272,11 +268,13 @@ define(function (require, exports, module) { } else if (query[queryCounter] === str[specials[i]]) { // we have a match! do the required tracking strCounter = specials[i]; - if (originalQuery[queryCounter] === originalStr[strCounter]) { - result.push(new SpecialCaseMatch(strCounter)); - } else { - result.push(new SpecialMatch(strCounter)); - } + + // Upper case match check: + // If the query and original string matched, but the original string + // and the lower case version did not, that means that the original + // was upper case. + var upper = originalQuery[queryCounter] === originalStr[strCounter] && originalStr[strCounter] !== str[strCounter]; + result.push(new SpecialMatch(strCounter, upper)); specialsCounter = i; queryCounter++; strCounter++; @@ -310,7 +308,7 @@ define(function (require, exports, module) { // searching from. queryCounter--; - if (item instanceof SpecialMatch || item instanceof SpecialCaseMatch) { + if (item instanceof SpecialMatch) { // pulled off a special, which means we need to make that special available // for matching again specialsCounter--; @@ -357,11 +355,11 @@ define(function (require, exports, module) { // we look character by character for matches if (query[queryCounter] === str[strCounter]) { // got a match! record it, and switch back to searching specials - if (originalQuery[queryCounter] === originalStr[strCounter]) { - result.push(new CaseMatch(strCounter++)); - } else { - result.push(new NormalMatch(strCounter++)); - } + + // See the specials section above for a comment on the expression + // for `upper` below. + var upper = originalQuery[queryCounter] === originalStr[strCounter] && originalStr[strCounter] !== str[strCounter]; + result.push(new NormalMatch(strCounter++, upper)); queryCounter++; state = SPECIALS_MATCH; @@ -517,7 +515,7 @@ define(function (require, exports, module) { scoreDebug = { special: 0, match: 0, - case: 0, + upper: 0, lastSegment: 0, beginning: 0, lengthDeduction: 0, @@ -581,11 +579,11 @@ define(function (require, exports, module) { } newPoints += MATCH_POINTS; - if (match instanceof CaseMatch || match instanceof SpecialCaseMatch) { + if (match.upper) { if (DEBUG_SCORES) { - scoreDebug.case += MATCH_CASE_POINTS; + scoreDebug.upper += UPPER_CASE_MATCH; } - newPoints += MATCH_CASE_POINTS; + newPoints += UPPER_CASE_MATCH; } // A bonus is given for characters that match at the beginning @@ -635,11 +633,6 @@ define(function (require, exports, module) { scoreDebug.special += SPECIAL_POINTS; } newPoints += SPECIAL_POINTS; - } else if (match instanceof SpecialCaseMatch) { - if (DEBUG_SCORES) { - scoreDebug.special += SPECIAL_CASE_POINTS; - } - newPoints += SPECIAL_CASE_POINTS; } score += newPoints; @@ -666,7 +659,7 @@ define(function (require, exports, module) { // Check to see if this new matched range is starting on a special // character. We penalize those ranges that don't, because most // people will search on the logical boundaries of the name - currentRangeStartedOnSpecial = match instanceof SpecialMatch || match instanceof SpecialCaseMatch; + currentRangeStartedOnSpecial = match instanceof SpecialMatch; } else { currentRange.text += str[c]; } @@ -990,9 +983,7 @@ define(function (require, exports, module) { exports._setDebugScores = _setDebugScores; exports._generateMatchList = _generateMatchList; exports._SpecialMatch = SpecialMatch; - exports._SpecialCaseMatch = SpecialCaseMatch; exports._NormalMatch = NormalMatch; - exports._CaseMatch = CaseMatch; exports._computeRangesAndScore = _computeRangesAndScore; // public exports diff --git a/test/spec/StringMatch-test.js b/test/spec/StringMatch-test.js index c9f3a45242e..7f918eac12d 100644 --- a/test/spec/StringMatch-test.js +++ b/test/spec/StringMatch-test.js @@ -63,22 +63,16 @@ define(function (require, exports, module) { var generateMatchList = StringMatch._generateMatchList; var SpecialMatch = StringMatch._SpecialMatch; - var SpecialCaseMatch = StringMatch._SpecialCaseMatch; var NormalMatch = StringMatch._NormalMatch; - var CaseMatch = StringMatch._CaseMatch; beforeEach(function () { SpecialMatch.prototype.type = "special"; NormalMatch.prototype.type = "normal"; - CaseMatch.prototype.type = "case"; - SpecialCaseMatch.prototype.type = "specialCase"; }); afterEach(function () { delete SpecialMatch.prototype.type; delete NormalMatch.prototype.type; - delete SpecialCaseMatch.prototype.type; - delete CaseMatch.prototype.type; }); var path = "src/document/DocumentCommandHandler.js"; @@ -100,18 +94,18 @@ define(function (require, exports, module) { it("should try contiguous matches as well, but prefer specials", function () { var result = generateMatchList("do", pathLower, "do", path, specialsInfo.specials, specialsInfo.lastSegmentSpecialsIndex); - expect(result).toEqual([new SpecialMatch(13), new CaseMatch(14)]); + expect(result).toEqual([new SpecialMatch(13), new NormalMatch(14)]); result = generateMatchList("doc", pathLower, "doc", path, specialsInfo.specials, specialsInfo.lastSegmentSpecialsIndex); - expect(result).toEqual([new SpecialMatch(13), new CaseMatch(14), new SpecialMatch(21)]); + expect(result).toEqual([new SpecialMatch(13), new NormalMatch(14), new SpecialMatch(21)]); result = generateMatchList("doch", pathLower, "doch", path, specialsInfo.specials, specialsInfo.lastSegmentSpecialsIndex); - expect(result).toEqual([new SpecialMatch(13), new CaseMatch(14), new SpecialMatch(21), new SpecialMatch(28)]); + expect(result).toEqual([new SpecialMatch(13), new NormalMatch(14), new SpecialMatch(21), new SpecialMatch(28)]); }); it("should handle contiguous matches that stand alone", function () { var result = generateMatchList("o", pathLower, "o", path, specialsInfo.specials, specialsInfo.lastSegmentSpecialsIndex); - expect(result).toEqual([new CaseMatch(14)]); + expect(result).toEqual([new NormalMatch(14)]); }); it("should recognize non-matches", function () { @@ -121,7 +115,7 @@ define(function (require, exports, module) { it("should backtrack as needed", function () { var result = generateMatchList("cu", pathLower, "cu", path, specialsInfo.specials, specialsInfo.lastSegmentSpecialsIndex); - expect(result).toEqual([new CaseMatch(15), new CaseMatch(16)]); + expect(result).toEqual([new NormalMatch(15), new NormalMatch(16)]); result = generateMatchList("dcho", pathLower, "dcho", path, specialsInfo.specials, specialsInfo.lastSegmentSpecialsIndex); expect(result).toEqual(null); @@ -134,10 +128,10 @@ define(function (require, exports, module) { expect(result).toEqual([new SpecialMatch(0)]); result = generateMatchList("mu", btpathLower, "mu", btpath, btspecials.specials, 0); - expect(result).toEqual([new SpecialMatch(0), new CaseMatch(11)]); + expect(result).toEqual([new SpecialMatch(0), new NormalMatch(11)]); result = generateMatchList("mamo", btpathLower, "mamo", btpath, btspecials.specials, 0); - expect(result).toEqual([new SpecialMatch(0), new CaseMatch(1), new SpecialMatch(4), new CaseMatch(9)]); + expect(result).toEqual([new SpecialMatch(0), new NormalMatch(1), new SpecialMatch(4), new NormalMatch(9)]); btpath = "AbcdefzBcdefCdefDefEfF"; btspecials = fSC(btpath); @@ -147,24 +141,24 @@ define(function (require, exports, module) { expect(result).toEqual([new SpecialMatch(21)]); result = generateMatchList("abcdefz", btpathLower, "abcdefz", btpath, btspecials.specials, 0); - expect(result).toEqual([new SpecialMatch(0), new CaseMatch(1), new CaseMatch(2), new CaseMatch(3), new CaseMatch(4), new CaseMatch(5), new CaseMatch(6)]); + expect(result).toEqual([new SpecialMatch(0), new NormalMatch(1), new NormalMatch(2), new NormalMatch(3), new NormalMatch(4), new NormalMatch(5), new NormalMatch(6)]); result = generateMatchList("abcdefz", btpathLower, "ABCDEFZ", btpath, btspecials.specials, 0); - expect(result).toEqual([new SpecialCaseMatch(0), new NormalMatch(1), new NormalMatch(2), new NormalMatch(3), new NormalMatch(4), new NormalMatch(5), new NormalMatch(6)]); + expect(result).toEqual([new SpecialMatch(0, true), new NormalMatch(1), new NormalMatch(2), new NormalMatch(3), new NormalMatch(4), new NormalMatch(5), new NormalMatch(6)]); result = generateMatchList("abcdefe", btpathLower, "abcdefe", btpath, btspecials.specials, 0); - expect(result).toEqual([new SpecialMatch(0), new SpecialMatch(7), new SpecialMatch(12), new SpecialMatch(16), new CaseMatch(17), new CaseMatch(18), new SpecialMatch(19)]); + expect(result).toEqual([new SpecialMatch(0), new SpecialMatch(7), new SpecialMatch(12), new SpecialMatch(16), new NormalMatch(17), new NormalMatch(18), new SpecialMatch(19)]); var str = "_computeRangesAndScore"; var strSpecials = fSC(str); var strLower = str.toLowerCase(); result = generateMatchList("_computerangesa", strLower, "_computerangesa", str, strSpecials.specials, 0); expect(result).toEqual([ - new SpecialCaseMatch(0), new SpecialCaseMatch(1), new CaseMatch(2), - new CaseMatch(3), new CaseMatch(4), new CaseMatch(5), - new CaseMatch(6), new CaseMatch(7), new SpecialMatch(8), - new CaseMatch(9), new CaseMatch(10), new CaseMatch(11), - new CaseMatch(12), new CaseMatch(13), new SpecialMatch(14) + new SpecialMatch(0), new SpecialMatch(1), new NormalMatch(2), + new NormalMatch(3), new NormalMatch(4), new NormalMatch(5), + new NormalMatch(6), new NormalMatch(7), new SpecialMatch(8), + new NormalMatch(9), new NormalMatch(10), new NormalMatch(11), + new NormalMatch(12), new NormalMatch(13), new SpecialMatch(14) ]); }); @@ -202,21 +196,15 @@ define(function (require, exports, module) { describe("_lastSegmentSearch", function () { var SpecialMatch = StringMatch._SpecialMatch; var NormalMatch = StringMatch._NormalMatch; - var CaseMatch = StringMatch._CaseMatch; - var SpecialCaseMatch = StringMatch._SpecialCaseMatch; beforeEach(function () { SpecialMatch.prototype.type = "special"; NormalMatch.prototype.type = "normal"; - CaseMatch.prototype.type = "case"; - SpecialCaseMatch.prototype.type = "specialCase"; }); afterEach(function () { delete SpecialMatch.prototype.type; delete NormalMatch.prototype.type; - delete CaseMatch.prototype.type; - delete SpecialCaseMatch.prototype.type; }); it("should compare results in the final segment properly", function () { @@ -237,7 +225,7 @@ define(function (require, exports, module) { originalRemainder: "", matchList: [ new SpecialMatch(13), - new CaseMatch(14) + new NormalMatch(14) ] }); @@ -246,7 +234,7 @@ define(function (require, exports, module) { originalRemainder: "", matchList: [ new SpecialMatch(13), - new CaseMatch(14), + new NormalMatch(14), new SpecialMatch(21) ] }); @@ -256,8 +244,8 @@ define(function (require, exports, module) { originalRemainder: "", matchList: [ new SpecialMatch(13), - new CaseMatch(14), - new CaseMatch(15), + new NormalMatch(14), + new NormalMatch(15), new SpecialMatch(21) ] }); @@ -267,8 +255,8 @@ define(function (require, exports, module) { originalRemainder: "", matchList: [ new SpecialMatch(13), - new CaseMatch(14), - new CaseMatch(15), + new NormalMatch(14), + new NormalMatch(15), new SpecialMatch(21), new SpecialMatch(28) ] @@ -279,13 +267,13 @@ define(function (require, exports, module) { originalRemainder: "", matchList: [ new SpecialMatch(13), - new CaseMatch(14), - new CaseMatch(15), + new NormalMatch(14), + new NormalMatch(15), new SpecialMatch(21), new SpecialMatch(28), - new SpecialCaseMatch(35), - new SpecialCaseMatch(36), - new CaseMatch(37) + new SpecialMatch(35), + new SpecialMatch(36), + new NormalMatch(37) ] }); @@ -293,9 +281,9 @@ define(function (require, exports, module) { remainder: "", originalRemainder: "", matchList: [ - new CaseMatch(14), - new CaseMatch(15), - new CaseMatch(16) + new NormalMatch(14), + new NormalMatch(15), + new NormalMatch(16) ] }); @@ -303,11 +291,11 @@ define(function (require, exports, module) { remainder: "", originalRemainder: "", matchList: [ - new CaseMatch(14), - new CaseMatch(15), - new CaseMatch(16), + new NormalMatch(14), + new NormalMatch(15), + new NormalMatch(16), new SpecialMatch(28), - new CaseMatch(29) + new NormalMatch(29) ] }); @@ -319,7 +307,7 @@ define(function (require, exports, module) { originalRemainder: "s", matchList: [ new SpecialMatch(13), - new CaseMatch(14), + new NormalMatch(14), new SpecialMatch(21) ] }); @@ -345,26 +333,26 @@ define(function (require, exports, module) { var comparePath = path.toLowerCase(); expect(wholeStringSearch("sdoc", comparePath, "sdoc", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual([ - new SpecialCaseMatch(0), + new SpecialMatch(0), new SpecialMatch(13), - new CaseMatch(14), + new NormalMatch(14), new SpecialMatch(21) ]); expect(wholeStringSearch("doc", comparePath, "doc", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual([ new SpecialMatch(13), - new CaseMatch(14), + new NormalMatch(14), new SpecialMatch(21) ]); expect(wholeStringSearch("z", comparePath, "z", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual(null); expect(wholeStringSearch("docdoc", comparePath, "docdoc", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual([ - new SpecialCaseMatch(4), - new CaseMatch(5), - new CaseMatch(6), + new SpecialMatch(4), + new NormalMatch(5), + new NormalMatch(6), new SpecialMatch(13), - new CaseMatch(14), + new NormalMatch(14), new SpecialMatch(21) ]); @@ -382,37 +370,37 @@ define(function (require, exports, module) { expect(wholeStringSearch("quick", comparePath, "quick", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual([ new SpecialMatch(23), - new CaseMatch(24), - new CaseMatch(25), - new CaseMatch(26), - new CaseMatch(27) + new NormalMatch(24), + new NormalMatch(25), + new NormalMatch(26), + new NormalMatch(27) ]); expect(wholeStringSearch("quickopen", comparePath, "quickopen", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual([ new SpecialMatch(23), - new CaseMatch(24), - new CaseMatch(25), - new CaseMatch(26), - new CaseMatch(27), + new NormalMatch(24), + new NormalMatch(25), + new NormalMatch(26), + new NormalMatch(27), new SpecialMatch(28), - new CaseMatch(29), - new CaseMatch(30), - new CaseMatch(39) + new NormalMatch(29), + new NormalMatch(30), + new NormalMatch(39) ]); expect(wholeStringSearch("quickopenain", comparePath, "quickopenain", path, sc.specials, sc.lastSegmentSpecialsIndex)).toEqual([ new SpecialMatch(23), - new CaseMatch(24), - new CaseMatch(25), - new CaseMatch(26), - new CaseMatch(27), + new NormalMatch(24), + new NormalMatch(25), + new NormalMatch(26), + new NormalMatch(27), new SpecialMatch(28), - new CaseMatch(29), - new CaseMatch(30), - new CaseMatch(31), - new CaseMatch(37), - new CaseMatch(38), - new CaseMatch(39) + new NormalMatch(29), + new NormalMatch(30), + new NormalMatch(31), + new NormalMatch(37), + new NormalMatch(38), + new NormalMatch(39) ]); }); }); @@ -589,9 +577,9 @@ define(function (require, exports, module) { it("should place QuickOpen well relative to other quicks", function () { expect(goodRelativeOrdering("quick", [ - "samples/root/Getting Started/screenshots/quick-edit.png", "src/search/QuickOpen.js", "test/spec/QuickOpen-test.js", + "samples/root/Getting Started/screenshots/quick-edit.png", "src/extensions/default/QuickOpenCSS/main.js" ])).toBe(true); }); @@ -682,12 +670,12 @@ define(function (require, exports, module) { ])).toBe(true); expect(goodRelativeOrdering("st", [ "str", + "String", "stringMatch", + "StringMatcher", "screenTop", "scrollTo", "setTimeout", - "String", - "StringMatcher", "switch" ])).toBe(true); }); @@ -707,7 +695,7 @@ define(function (require, exports, module) { ])).toBe(true); expect(goodRelativeOrdering("Pack", [ "src/extensibility/Package.js", - "src/node/package.json" + "package.json" ])).toBe(true); }); });