aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--background_scripts/completion.coffee15
-rw-r--r--background_scripts/completion_engines.coffee8
-rw-r--r--background_scripts/main.coffee18
-rw-r--r--pages/vomnibar.coffee78
4 files changed, 79 insertions, 40 deletions
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 746e662d..f17ca28c 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -491,22 +491,27 @@ class MultiCompleter
# (ie. a SearchEngineCompleter). This prevents hiding the vomnibar briefly before showing it
# again, which looks ugly.
unless shouldRunContinuation and suggestions.length == 0
- onComplete @prepareSuggestions queryTerms, suggestions
+ onComplete
+ results: @prepareSuggestions queryTerms, suggestions
+ callerMayCacheResults: not shouldRunContinuation
# Allow subsequent queries to begin.
@filterInProgress = false
if shouldRunContinuation
continuation suggestions, (newSuggestions) =>
if 0 < newSuggestions.length
- onComplete @prepareSuggestions queryTerms, suggestions.concat newSuggestions
+ suggestions.push newSuggestions...
+ onComplete
+ results: @prepareSuggestions queryTerms, suggestions
+ callerMayCacheResults: true
else
@filter @mostRecentQuery.queryTerms, @mostRecentQuery.onComplete if @mostRecentQuery
prepareSuggestions: (queryTerms, suggestions) ->
suggestion.computeRelevancy queryTerms for suggestion in suggestions
suggestions.sort (a, b) -> b.relevancy - a.relevancy
- suggestions = suggestions[0...@maxResults]
- suggestion.generateHtml() for suggestion in suggestions
- suggestions
+ for suggestion in suggestions[0...@maxResults]
+ suggestion.generateHtml()
+ suggestion
# Utilities which help us compute a relevancy score for a given item.
RankingUtils =
diff --git a/background_scripts/completion_engines.coffee b/background_scripts/completion_engines.coffee
index 19a18ecd..52db90d0 100644
--- a/background_scripts/completion_engines.coffee
+++ b/background_scripts/completion_engines.coffee
@@ -209,9 +209,13 @@ CompletionEngines =
# We pause in case the user is still typing.
Utils.setTimeout @delay, handler = @mostRecentHandler = =>
- if handler != @mostRecentHandler # Bail if another completion has begun, or the user is typing.
+ if handler != @mostRecentHandler
+ # Bail! Another completion has begun, or the user is typing.
+ # NOTE: We do *not* call the callback (because we are not providing results, and we don't want allow
+ # any higher-level component to cache the results -- specifically, the vomnibar itself, via
+ # callerMayCacheResults).
console.log "bail", completionCacheKey if @debug
- return callback []
+ return
@mostRecentHandler = null
# Don't allow duplicate identical active requests. This can happen, for example, when the user enters or
# removes a space, or when they enter a character and immediately delete it.
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index a3ddb48c..1a3281bf 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -43,26 +43,26 @@ chrome.storage.local.set
vimiumSecret: Math.floor Math.random() * 2000000000
completionSources =
- bookmarks: new BookmarkCompleter()
- history: new HistoryCompleter()
- domains: new DomainCompleter()
- tabs: new TabCompleter()
- searchEngines: new SearchEngineCompleter()
+ bookmarks: new BookmarkCompleter
+ history: new HistoryCompleter
+ domains: new DomainCompleter
+ tabs: new TabCompleter
+ searchEngines: new SearchEngineCompleter
completers =
omni: new MultiCompleter [
completionSources.bookmarks
completionSources.history
completionSources.domains
- # This comes last, because it delivers additional, asynchronous results.
completionSources.searchEngines
]
- bookmarks: new MultiCompleter([completionSources.bookmarks])
- tabs: new MultiCompleter([completionSources.tabs])
+ bookmarks: new MultiCompleter [completionSources.bookmarks]
+ tabs: new MultiCompleter [completionSources.tabs]
completionHandlers =
filter: (completer, args, port) ->
- completer.filter args.queryTerms, (results) -> port.postMessage id: args.id, results: results
+ completer.filter args.queryTerms, (response) ->
+ port.postMessage extend args, response
refresh: (completer) -> completer.refresh()
cancel: (completer) -> completer.cancel()
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index 29dc4a82..cac191de 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -218,53 +218,83 @@ class VomnibarUI
# Sends requests to a Vomnibox completer on the background page.
#
class BackgroundCompleter
+ debug: true
+
# name is background-page completer to connect to: "omni", "tabs", or "bookmarks".
constructor: (@name) ->
@messageId = null
@port = chrome.runtime.connect name: "completions"
- @port.onMessage.addListener handler = @messageHandler
+ @port.onMessage.addListener (msg) => @messageHandler msg
+ @reset()
+
+ reset: ->
+ # We only cache results for the duration of a single vomnibar activation.
+ @cache = new SimpleCache 1000 * 60 * 5
+
+ messageHandler: (msg) ->
+ # The result objects coming from the background page will be of the form:
+ # { html: "", type: "", url: "" }
+ # Type will be one of [tab, bookmark, history, domain, search], or a custom search engine description.
+ for result in msg.results
+ result.performAction =
+ if result.type == "tab"
+ @completionActions.switchToTab.curry result.tabId
+ else
+ @completionActions.navigateToUrl.curry result.url
+
+ # Cache the results (but only if the background completer tells us that it's ok to do so).
+ if msg.callerMayCacheResults
+ console.log "cache set:", msg.query if @debug
+ @cache.set msg.query, msg.results
+ else
+ console.log "not setting cache:", msg.query if @debug
- messageHandler: (msg) =>
# We ignore messages which arrive too late.
if msg.id == @messageId
- # The result objects coming from the background page will be of the form:
- # { html: "", type: "", url: "" }
- # Type will be one of [tab, bookmark, history, domain, search], or a custom search engine description.
- for result in msg.results
- result.performAction =
- if result.type == "tab"
- @completionActions.switchToTab.curry result.tabId
- else
- @completionActions.navigateToUrl.curry result.url
@mostRecentCallback msg.results
filter: (query, @mostRecentCallback) ->
- # Ignore identical consecutive queries. This can happen, for example, if the user adds whitespace to the
- # query. We normalize the query first to ensure that differences only in whitespace are ignored.
queryTerms = query.trim().split(/\s+/).filter (term) -> 0 < term.length
query = queryTerms.join " "
- unless @mostRecentQuery? and query == @mostRecentQuery
- @mostRecentQuery = query
- @messageId = Utils.createUniqueId()
- @port.postMessage name: @name, handler: "filter", id: @messageId, queryTerms: queryTerms
+ if @cache.has query
+ console.log "cache hit:", query if @debug
+ @mostRecentCallback @cache.get query
+ else
+ # Silently drop identical consecutive queries. This can happen, for example, if the user adds
+ # whitespace to the query.
+ unless @mostRecentQuery? and query == @mostRecentQuery
+ @mostRecentQuery = query
+ @messageId = Utils.createUniqueId()
+ @port.postMessage
+ name: @name
+ handler: "filter"
+ id: @messageId
+ query: query
+ queryTerms: queryTerms
refresh: ->
+ @reset()
+ # Inform the background completer that we have a new vomnibar activation.
@port.postMessage name: @name, handler: "refresh"
cancel: ->
+ # Inform the background completer that it may (should it choose to do so) abandon any pending query
+ # (because the user is typing, and there'll be another query along soon).
@port.postMessage name: @name, handler: "cancel"
- # These are the actions we can perform when the user selects a result in the Vomnibox.
+ # These are the actions we can perform when the user selects a result.
completionActions:
navigateToUrl: (url, openInNewTab) ->
- # If the URL is a bookmarklet prefixed with javascript:, we shouldn't open that in a new tab.
- openInNewTab = false if url.startsWith("javascript:")
- chrome.runtime.sendMessage(
+ # If the URL is a bookmarklet (so, prefixed with "javascript:"), then we always open it in the current
+ # tab.
+ openInNewTab &&= not Utils.hasJavascriptPrefix url
+ chrome.runtime.sendMessage
handler: if openInNewTab then "openUrlInNewTab" else "openUrlInCurrentTab"
- url: url,
- selected: openInNewTab)
+ url: url
+ selected: openInNewTab
- switchToTab: (tabId) -> chrome.runtime.sendMessage({ handler: "selectSpecificTab", id: tabId })
+ switchToTab: (tabId) ->
+ chrome.runtime.sendMessage handler: "selectSpecificTab", id: tabId
UIComponentServer.registerHandler (event) ->
switch event.data