From 21e18619c7fd166fbf91e3eaa41b028c7f0af513 Mon Sep 17 00:00:00 2001 From: Brandon Wamboldt Date: Fri, 24 Apr 2015 18:50:04 -0700 Subject: [PATCH 1/2] Fix scoring to favor exact substring matches --- spec/filter-spec.coffee | 9 ++++++--- src/filter.coffee | 1 + src/fuzzaldrin.coffee | 1 + src/scorer.coffee | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spec/filter-spec.coffee b/spec/filter-spec.coffee index f6cf935..74e11cd 100644 --- a/spec/filter-spec.coffee +++ b/spec/filter-spec.coffee @@ -15,13 +15,13 @@ rootPath = (segments...) -> describe "filtering", -> it "returns an array of the most accurate results", -> - candidates = ['Gruntfile','filter', 'bile', null, '', undefined] - expect(filter(candidates, 'file')).toEqual ['filter', 'Gruntfile'] + candidates = ['Gruntfile', 'filter', 'bile', null, '', undefined] + expect(filter(candidates, 'file')).toEqual ['Gruntfile', 'filter'] describe "when the maxResults option is set", -> it "limits the results to the result size", -> candidates = ['Gruntfile', 'filter', 'bile'] - expect(bestMatch(candidates, 'file')).toBe 'filter' + expect(bestMatch(candidates, 'file')).toBe 'Gruntfile' describe "when the entries contains slashes", -> it "weighs basename matches higher", -> @@ -112,6 +112,9 @@ describe "filtering", -> expect(bestMatch(['z_a_b', 'a_b'], 'ab')).toBe 'a_b' expect(bestMatch(['a_b_c', 'c_a_b'], 'ab')).toBe 'a_b_c' + it "weights matches that are substring matches higher", -> + expect(bestMatch(['/a/b/c/install.txt', 'inst-all.txt'])).toBe '/a/b/c/install.txt' + describe "when the entries are of differing directory depths", -> it "places exact matches first, even if they're deeper", -> candidates = [ diff --git a/src/filter.coffee b/src/filter.coffee index 49cbb65..8a73f4f 100644 --- a/src/filter.coffee +++ b/src/filter.coffee @@ -13,6 +13,7 @@ module.exports = (candidates, query, queryHasSlashes, {key, maxResults}={}) -> score = scorer.score(string, query, queryHasSlashes) unless queryHasSlashes score = scorer.basenameScore(string, query, score) + score = scorer.substringScore(string, query, score) scoredCandidates.push({candidate, score}) if score > 0 # Sort scores in descending order diff --git a/src/fuzzaldrin.coffee b/src/fuzzaldrin.coffee index e8a7f83..fc8b71d 100644 --- a/src/fuzzaldrin.coffee +++ b/src/fuzzaldrin.coffee @@ -21,6 +21,7 @@ module.exports = query = query.replace(SpaceRegex, '') score = scorer.score(string, query) score = scorer.basenameScore(string, query, score) unless queryHasSlashes + score = scorer.substringScore(string, query, score) score match: (string, query) -> diff --git a/src/scorer.coffee b/src/scorer.coffee index c8ea04e..2d8358d 100644 --- a/src/scorer.coffee +++ b/src/scorer.coffee @@ -42,6 +42,22 @@ exports.basenameScore = (string, query, score) -> score *= depth * 0.01 score +exports.substringScore = (string, query, score) -> + # Return a near perfect score if the query is a substring match + substrIndex = string.indexOf(query) + substrIndexi = string.toLowerCase().indexOf(query.toLowerCase()) + + if substrIndex >= 0 + return score + 1.155 if substrIndex == 0 + return score + 1.145 if string[substrIndex - 1] == PathSeparator + return score + 1.135 + else if substrIndexi >= 0 + return score + 1.15 if substrIndexi == 0 + return score + 1.14 if string[substrIndexi - 1] == PathSeparator + return score + 1.13 + + return score + exports.score = (string, query) -> return 1 if string is query From eca4bb4269145b33cafc9350627126deef534ecd Mon Sep 17 00:00:00 2001 From: Brandon Wamboldt Date: Fri, 24 Apr 2015 19:10:24 -0700 Subject: [PATCH 2/2] Fix comment --- spec/filter-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/filter-spec.coffee b/spec/filter-spec.coffee index 74e11cd..0f09782 100644 --- a/spec/filter-spec.coffee +++ b/spec/filter-spec.coffee @@ -112,7 +112,7 @@ describe "filtering", -> expect(bestMatch(['z_a_b', 'a_b'], 'ab')).toBe 'a_b' expect(bestMatch(['a_b_c', 'c_a_b'], 'ab')).toBe 'a_b_c' - it "weights matches that are substring matches higher", -> + it "weighs matches that are substring matches higher", -> expect(bestMatch(['/a/b/c/install.txt', 'inst-all.txt'])).toBe '/a/b/c/install.txt' describe "when the entries are of differing directory depths", ->