From e97990e479989bd05f9d6377cfb327fccdcc1ed9 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 4 Nov 2012 07:56:56 +0000 Subject: Generalise RegexpCache, refactor, add tests. This is a no-op, currently. It's just setting up the RegexpCache interface for subsequent development. --- background_scripts/completion.coffee | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'background_scripts') diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 9e12d497..9314d9be 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -307,12 +307,16 @@ RegexpCache = clear: -> @cache = {} - get: (string) -> + # Get rexexp for string from cache, creating the regexp if necessary. + # Regexp meta-characters in string are escaped. + # Regexp is wrapped in prefix/suffix, which may contain meta-characters. + get: (string, prefix="", suffix="") -> @init() unless @initialized - @cache[string] ||= @escapeRegexp(string) - - # Creates a Regexp from the given string, with all special Regexp characters escaped. - escapeRegexp: (string) -> new RegExp(string.replace(@escapeRegExp, "\\$&"), "i") + regexpString = string.replace(@escapeRegExp, "\\$&") + # Avoid cost of constructing new strings if prefix/suffix are empty (which is expected to be a common case). + regexpString = prefix + regexpString if prefix + regexpString = regexpString + suffix if suffix + @cache[regexpString] ||= new RegExp(regexpString, "i") # Provides cached access to Chrome's history. As the user browses to new pages, we add those pages to this # history cache. @@ -382,3 +386,4 @@ root.DomainCompleter = DomainCompleter root.TabCompleter = TabCompleter root.HistoryCache = HistoryCache root.RankingUtils = RankingUtils +root.RegexpCache = RegexpCache -- cgit v1.2.3 From e5aa0993b7353b16308f7dbfd0a1e217264c2cae Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 4 Nov 2012 08:26:06 +0000 Subject: Highlight all matches, not just the first. --- background_scripts/completion.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'background_scripts') diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 9314d9be..c8a06b27 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -50,8 +50,15 @@ class Suggestion highlightTerms: (string) -> ranges = [] for term in @queryTerms - i = string.search(RegexpCache.get(term)) - ranges.push([i, i + term.length]) if i >= 0 + textPosition = 0 + splits = string.split(RegexpCache.get(term, "(", ")")).reverse() + while 0 < splits.length + unmatchedText = splits.pop() + textPosition += unmatchedText.length + matchedText = if 0 < splits.length then splits.pop() else null + if matchedText + ranges.push([textPosition, textPosition + matchedText.length]) + textPosition += matchedText.length return string if ranges.length == 0 -- cgit v1.2.3 From d0157d93d24c8c7f1a86289efe29e203d98bb072 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Mon, 5 Nov 2012 09:01:39 +0000 Subject: Factor pushMatchingRanges, improve comments/tests 1. Factor out `pushMatchingRanges`: This then allows us to ... 2. Add unit tests for `pushMatchingRanges` In effect, these tests verify where matches are highlighted in suggestions. 3. Added Utils.zip. This helps simplify `pushMatchingRanges` unit tests. 4. Improve comments. --- background_scripts/completion.coffee | 42 +++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) (limited to 'background_scripts') diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index c8a06b27..ab24377a 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -46,19 +46,32 @@ class Suggestion url = url.substring(url, url.length - 1) if url[url.length - 1] == "/" url + # Push the ranges within `string` which match `term` onto `ranges`. + pushMatchingRanges: (string,term,ranges) -> + textPosition = 0 + # Split `string` into a (flat) list of pairs: + # - splits[i%2] is unmatched text + # - splits[(i%2)+1] is the following matched text (matching `term`) + # (except for the final element, for which there is no following matched text). + # Example: + # - string = "Abacab" + # - term = "a" + # - splits = [ "", "A", "b", "a", "c", "a", b" ] + # UM M UM M UM M UM (M=Matched, UM=Unmatched) + splits = string.split(RegexpCache.get(term, "(", ")")) + for index in [0..splits.length-2] by 2 + unmatchedText = splits[index] + matchedText = splits[index+1] + # Add the indices spanning `matchedText` to `ranges`. + textPosition += unmatchedText.length + ranges.push([textPosition, textPosition + matchedText.length]) + textPosition += matchedText.length + # Wraps each occurence of the query terms in the given string in a . highlightTerms: (string) -> ranges = [] for term in @queryTerms - textPosition = 0 - splits = string.split(RegexpCache.get(term, "(", ")")).reverse() - while 0 < splits.length - unmatchedText = splits.pop() - textPosition += unmatchedText.length - matchedText = if 0 < splits.length then splits.pop() else null - if matchedText - ranges.push([textPosition, textPosition + matchedText.length]) - textPosition += matchedText.length + @pushMatchingRanges string, term, ranges return string if ranges.length == 0 @@ -314,9 +327,14 @@ RegexpCache = clear: -> @cache = {} - # Get rexexp for string from cache, creating the regexp if necessary. - # Regexp meta-characters in string are escaped. - # Regexp is wrapped in prefix/suffix, which may contain meta-characters. + # Get rexexp for `string` from cache, creating it if necessary. + # Regexp meta-characters in `string` are escaped. + # Regexp is wrapped in `prefix`/`suffix`, which may contain meta-characters (these are not escaped). + # With their default values, `prefix` and `suffix` have no effect. + # Example: + # - string="go", prefix="\b", suffix="" + # - this returns regexp matching "google", but not "agog" (the "go" must occur at the start of a word) + # TODO: `prefix` and `suffix` might be useful in richer word-relevancy scoring. get: (string, prefix="", suffix="") -> @init() unless @initialized regexpString = string.replace(@escapeRegExp, "\\$&") -- cgit v1.2.3 From 7497b56d3acba5c8750cca5b000a428d099e66b3 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Wed, 7 Nov 2012 20:30:21 +0000 Subject: Fix incorrect/misleading comment. --- background_scripts/completion.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'background_scripts') diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index ab24377a..6df4f80b 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -50,9 +50,10 @@ class Suggestion pushMatchingRanges: (string,term,ranges) -> textPosition = 0 # Split `string` into a (flat) list of pairs: - # - splits[i%2] is unmatched text - # - splits[(i%2)+1] is the following matched text (matching `term`) - # (except for the final element, for which there is no following matched text). + # - for i=0,2,4,6,... + # - splits[i] is unmatched text + # - splits[i+1] is the following matched text (matching `term`) + # (except for the final element, for which there is no following matched text). # Example: # - string = "Abacab" # - term = "a" -- cgit v1.2.3