aboutsummaryrefslogtreecommitdiffstats
path: root/background_scripts
diff options
context:
space:
mode:
authorStephen Blott2015-06-06 12:01:23 +0100
committerStephen Blott2015-06-06 12:01:25 +0100
commit4eda19de339212f86a9b008a4f3142a61d62829e (patch)
treedc9c314b327baf8cdebb05062087413431090cab /background_scripts
parent2d5a01c9791a81aa87eaa935a1183f10950bdc84 (diff)
downloadvimium-4eda19de339212f86a9b008a4f3142a61d62829e.tar.bz2
Re-work completions: extend engine wrapper to handle prefixes.
This commit contains the bulk og the material changes for which the previous commits established the basis. 1) Add a general framework for detecting query prefixes in search URLs, adding them to query sent to the completion engine, and stripping them from the resulting suggestions. This allows the user to have a search engine... j: http://www.google.com/search?q=javascript+%s Javascript and have the prefix "javascript" included (automatically) in queries sent to completion engines, which results in substantially better suggestions. 2) Re-work completion for Google Maps in a simpler form.
Diffstat (limited to 'background_scripts')
-rw-r--r--background_scripts/completion.coffee13
-rw-r--r--background_scripts/completion_engines.coffee55
-rw-r--r--background_scripts/completion_search.coffee66
3 files changed, 81 insertions, 53 deletions
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index c83066a6..6b58f4ea 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -450,7 +450,7 @@ class SearchEngineCompleter
{ keyword, searchUrl, description } = engine
extend request, searchUrl, customSearchMode: true
- factor = 0.5
+ @previousSuggestions[searchUrl] ?= []
haveCompletionEngine = CompletionSearch.haveCompletionEngine searchUrl
# This filter is applied to all of the suggestions from all of the completers, after they have been
@@ -466,13 +466,14 @@ class SearchEngineCompleter
)
# If a previous suggestion still matches the query, then we keep it (even if the completion engine may not
- # return it for the current query). This allows the user to pick suggestions by typing fragments of their
- # text, without regard to whether the completion engine can complete the actual text of the query.
+ # return it for the current query). This allows the user to pick suggestions they've previously seen by
+ # typing fragments of their text, without regard to whether the completion engine can continue to complete
+ # the actual text of the query.
previousSuggestions =
if queryTerms.length == 0
[]
else
- for url, suggestion of @previousSuggestions
+ for url, suggestion of @previousSuggestions[searchUrl]
continue unless RankingUtils.matches queryTerms, suggestion.title
# Reset various fields, they may not be correct wrt. the current query.
extend suggestion, relevancy: null, html: null, queryTerms: queryTerms
@@ -484,6 +485,7 @@ class SearchEngineCompleter
type: description
url: Utils.createSearchUrl queryTerms, searchUrl
title: queryTerms.join " "
+ searchUrl: searchUrl
relevancy: 2.0
autoSelect: true
highlightTerms: false
@@ -496,11 +498,12 @@ class SearchEngineCompleter
count = 0
(suggestion) =>
url = Utils.createSearchUrl suggestion, searchUrl
- @previousSuggestions[url] = new Suggestion
+ @previousSuggestions[searchUrl][url] = new Suggestion
queryTerms: queryTerms
type: description
url: url
title: suggestion
+ searchUrl: searchUrl
insertText: suggestion
highlightTerms: false
highlightTermsExcludeUrl: true
diff --git a/background_scripts/completion_engines.coffee b/background_scripts/completion_engines.coffee
index afbb2040..b572375d 100644
--- a/background_scripts/completion_engines.coffee
+++ b/background_scripts/completion_engines.coffee
@@ -15,9 +15,9 @@
# successfully), and returns a list of suggestions (a list of strings). This method is always executed
# within the context of a try/catch block, so errors do not propagate.
#
-# 4. For documentation only, each completion engine *must* and example custom search engine. The example
-# must include an example "keyword" and and example "searchUrl", and may include and example
-# "description".
+# 4. Each completion engine *must* include an example custom search engine. The example must include an
+# example "keyword" and an example "searchUrl", and may include an example "description" and an
+# "explanation".
#
# Each new completion engine must be added to the list "CompletionEngines" at the bottom of this file.
#
@@ -45,37 +45,34 @@ class GoogleXMLBaseEngine extends BaseEngine
suggestion
class Google extends GoogleXMLBaseEngine
- constructor: (regexps = null) ->
+ constructor: () ->
super
engineUrl: "http://suggestqueries.google.com/complete/search?ss_protocol=legace&client=toolbar&q=%s"
- regexps: regexps ? "^https?://[a-z]+\\.google\\.(com|ie|co\\.uk|ca|com\\.au)/"
+ regexps: "^https?://[a-z]+\\.google\\.(com|ie|co\\.uk|ca|com\\.au)/"
example:
searchUrl: "http://www.google.com/search?q=%s"
keyword: "g"
-## # A wrapper class for Google completions. This adds prefix terms to the query, and strips those terms from
-## # the resulting suggestions. For example, for Google Maps, we add "map of" as a prefix, then strip "map of"
-## # from the resulting suggestions.
-## class GoogleWithPrefix extends Google
-## constructor: (prefix, args...) ->
-## super args...
-## prefix = prefix.trim()
-## @prefix = "#{prefix} "
-## @queryTerms = prefix.split /\s+/
-## getUrl: (queryTerms) -> super [ @queryTerms..., queryTerms... ]
-## parse: (xhr) ->
-## super(xhr)
-## .filter (suggestion) => suggestion.startsWith @prefix
-## .map (suggestion) => suggestion[@prefix.length..].ltrim()
-##
-## # For Google Maps, we add the prefix "map of" to the query, and send it to Google's general search engine,
-## # then strip "map of" from the resulting suggestions.
-## class GoogleMaps extends GoogleWithPrefix
-## constructor: ->
-## super "map of", "^https?://[a-z]+\\.google\\.(com|ie|co\\.uk|ca|com\\.au)/maps"
-## @exampleSearchUrl = "https://www.google.com/maps?q=%s"
-## @exampleKeyword = "m"
-## @exampleDescription = "Google maps"
+class GoogleMaps extends GoogleXMLBaseEngine
+ prefix: "map of "
+ constructor: () ->
+ super
+ engineUrl: "http://suggestqueries.google.com/complete/search?ss_protocol=legace&client=toolbar&q=#{@prefix.split(' ').join '+'}%s"
+ regexps: "^https?://[a-z]+\\.google\\.(com|ie|co\\.uk|ca|com\\.au)/maps"
+ example:
+ searchUrl: "https://www.google.com/maps?q=%s"
+ keyword: "m"
+ explanation:
+ """
+ This uses regular Google completion, but prepends the text "<tt>map of</tt>" to the query. It works
+ well for places, countries, states, geographical regions and the like, but will not perform address
+ search.
+ """
+
+ parse: (xhr) ->
+ for suggestion in super xhr
+ continue unless suggestion.startsWith @prefix
+ suggestion[@prefix.length..]
class Youtube extends GoogleXMLBaseEngine
constructor: ->
@@ -154,7 +151,7 @@ class DummyCompletionEngine extends BaseEngine
# Note: Order matters here.
CompletionEngines = [
Youtube
- # GoogleMaps
+ GoogleMaps
Google
DuckDuckGo
Wikipedia
diff --git a/background_scripts/completion_search.coffee b/background_scripts/completion_search.coffee
index b3ae88d4..09261ff6 100644
--- a/background_scripts/completion_search.coffee
+++ b/background_scripts/completion_search.coffee
@@ -1,12 +1,38 @@
-class EngineWrapper
+# This is a wrapper class for completion engines. It handles the case where a custom search engine includes a
+# prefix query term (or terms). For example:
+#
+# http://www.google.com/search?q=javascript+%s
+#
+# In this case, we get better suggestions if we include the term "javascript" in queries sent to the
+# completion engine. This wrapper handles adding such prefixes to completion-engine queries and removing them
+# from the resulting suggestions.
+class EnginePrefixWrapper
constructor: (@searchUrl, @engine) ->
getUrl: (queryTerms) ->
+ # This tests whether @searchUrl contains something of the form "...=abc+def+%s...", from which we extract
+ # a prefix of the form "abc def ".
+ if /\=.+\+%s/.test @searchUrl
+ terms = @searchUrl.replace /\+%s.*/, ""
+ terms = terms.replace /.*=/, ""
+ terms = terms.replace /\+/g, " "
+
+ queryTerms = [ terms.split(" ")..., queryTerms... ]
+ prefix = "#{terms} "
+
+ @postprocessSuggestions =
+ (suggestions) ->
+ for suggestion in suggestions
+ continue unless suggestion.startsWith prefix
+ suggestion[prefix.length..]
+
@engine.getUrl queryTerms
parse: (xhr) ->
- @engine.parse xhr
+ @postprocessSuggestions @engine.parse xhr
+
+ postprocessSuggestions: (suggestions) -> suggestions
CompletionSearch =
debug: false
@@ -74,22 +100,23 @@ CompletionSearch =
# If the user appears to be typing a continuation of the characters of the most recent query, then we can
# sometimes re-use the previous suggestions.
- if @mostRecentQuery? and @mostRecentSuggestions?
- reusePreviousSuggestions = do =>
- # Verify that the previous query is a prefix of the current query.
- return false unless 0 == query.indexOf @mostRecentQuery.toLowerCase()
- # Verify that every previous suggestion contains the text of the new query.
- # Note: @mostRecentSuggestions may also be empty, in which case we drop though. The effect is that
- # previous queries with no suggestions suppress subsequent no-hope HTTP requests as the user continues
- # to type.
- for suggestion in @mostRecentSuggestions
- return false unless 0 <= suggestion.indexOf query
- # Ok. Re-use the suggestion.
- true
-
- if reusePreviousSuggestions
- console.log "reuse previous query:", @mostRecentQuery, @mostRecentSuggestions.length if @debug
- return callback @completionCache.set completionCacheKey, @mostRecentSuggestions
+ if @mostRecentQuery? and @mostRecentSuggestions? and @mostRecentSearchUrl?
+ if searchUrl == @mostRecentSearchUrl
+ reusePreviousSuggestions = do =>
+ # Verify that the previous query is a prefix of the current query.
+ return false unless 0 == query.indexOf @mostRecentQuery.toLowerCase()
+ # Verify that every previous suggestion contains the text of the new query.
+ # Note: @mostRecentSuggestions may also be empty, in which case we drop though. The effect is that
+ # previous queries with no suggestions suppress subsequent no-hope HTTP requests as the user continues
+ # to type.
+ for suggestion in @mostRecentSuggestions
+ return false unless 0 <= suggestion.indexOf query
+ # Ok. Re-use the suggestion.
+ true
+
+ if reusePreviousSuggestions
+ console.log "reuse previous query:", @mostRecentQuery, @mostRecentSuggestions.length if @debug
+ return callback @completionCache.set completionCacheKey, @mostRecentSuggestions
# That's all of the caches we can try. Bail if the caller is only requesting synchronous results. We
# signal that we haven't found a match by returning null.
@@ -102,7 +129,7 @@ CompletionSearch =
# Elide duplicate requests. First fetch the suggestions...
@inTransit[completionCacheKey] ?= new AsyncDataFetcher (callback) =>
- engine = new EngineWrapper searchUrl, @lookupEngine searchUrl
+ engine = new EnginePrefixWrapper searchUrl, @lookupEngine searchUrl
url = engine.getUrl queryTerms
@get searchUrl, url, (xhr = null) =>
@@ -128,6 +155,7 @@ CompletionSearch =
# ... then use the suggestions.
@inTransit[completionCacheKey].use (suggestions) =>
+ @mostRecentSearchUrl = searchUrl
@mostRecentQuery = query
@mostRecentSuggestions = suggestions
callback @completionCache.set completionCacheKey, suggestions