aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Blott2015-05-10 05:57:47 +0100
committerStephen Blott2015-05-10 06:12:39 +0100
commit5fdbb8e579c068a54e9a397097d87063a3d8a146 (patch)
tree7167ff7a914724b7b6532162db84e24b03aabea2
parent313a1f96d666f23c2bc75ef340f0f828319e127c (diff)
downloadvimium-5fdbb8e579c068a54e9a397097d87063a3d8a146.tar.bz2
Search completion; rework SimpleCache.
-rw-r--r--background_scripts/completion.coffee16
-rw-r--r--lib/utils.coffee49
-rw-r--r--pages/vomnibar.coffee2
3 files changed, 35 insertions, 32 deletions
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index 94109b84..024ea54c 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -355,11 +355,14 @@ class TabCompleter
tabRecency.recencyScore(suggestion.tabId)
class SearchEngineCompleter
- searchEngineConfig: null
+ searchEngines: null
+
+ cancel: ->
+ CompletionEngines.cancel()
refresh: (port) ->
# Load and parse the search-engine configuration.
- @searchEngineConfig = new AsyncDataFetcher (callback) ->
+ @searchEngines = new AsyncDataFetcher (callback) ->
engines = {}
for line in Settings.get("searchEngines").split "\n"
line = line.trim()
@@ -373,18 +376,18 @@ class SearchEngineCompleter
searchUrl: tokens[1]
description: description
- # Deliver the resulting engines lookup table.
+ # Deliver the resulting engines AsyncDataFetcher lookup table.
callback engines
# Let the vomnibar know the custom search engine keywords.
port.postMessage
- handler: "customSearchEngineKeywords"
+ handler: "keywords"
keywords: key for own key of engines
filter: ({ queryTerms, query }, onComplete) ->
return onComplete [] if queryTerms.length == 0
- @searchEngineConfig.use (engines) =>
+ @searchEngines.use (engines) =>
keyword = queryTerms[0]
{ custom, searchUrl, description, queryTerms } =
@@ -482,9 +485,6 @@ class SearchEngineCompleter
count = Math.min 6, Math.max 3, MultiCompleter.maxResults - existingSuggestions.length
onComplete suggestions[...count]
- cancel: ->
- CompletionEngines.cancel()
-
# A completer which calls filter() on many completers, aggregates the results, ranks them, and returns the top
# 10. Queries from the vomnibar frontend script come through a multi completer.
class MultiCompleter
diff --git a/lib/utils.coffee b/lib/utils.coffee
index 51b16351..b0abfd8f 100644
--- a/lib/utils.coffee
+++ b/lib/utils.coffee
@@ -212,24 +212,45 @@ globalRoot.extend = (hash1, hash2) ->
# A simple cache. Entries used within two expiry periods are retained, otherwise they are discarded.
# At most 2 * @entries entries are retained.
+#
+# Note. We need to be careful with @timer. If all references to a cache are lost, then eventually its
+# contents must be garbage collected, which will not happen if there are active timers.
class SimpleCache
# expiry: expiry time in milliseconds (default, one hour)
# entries: maximum number of entries in @cache (there may be this many entries in @previous, too)
constructor: (@expiry = 60 * 60 * 1000, @entries = 1000) ->
@cache = {}
- @rotate() # Force start the rotation timer.
+ @previous = {}
+ @timer = null
rotate: ->
@previous = @cache
@cache = {}
# We reset the timer every time the cache is rotated (which could be because a previous timer expired, or
- # because the number of @entries was exceeded.
+ # because the number of @entries was exceeded). We only restart the timer if the cache is not empty.
clearTimeout @timer if @timer?
- @timer = Utils.setTimeout @expiry, => @rotate()
+ @timer = null
+ @checkTimer() if 0 < Object.keys(@previous).length
+
+ checkTimer: ->
+ unless @timer?
+ @timer = Utils.setTimeout @expiry, => @rotate()
has: (key) ->
(key of @cache) or key of @previous
+ # Set value, and return that value. If value is null, then delete key.
+ set: (key, value = null) ->
+ @checkTimer()
+ if value?
+ @cache[key] = value
+ delete @previous[key]
+ @rotate() if @entries < Object.keys(@cache).length
+ else
+ delete @cache[key]
+ delete @previous[key]
+ value
+
get: (key) ->
if key of @cache
@cache[key]
@@ -242,27 +263,9 @@ class SimpleCache
@rotate()
@rotate()
- # Because of the timer, we can't just let these caches go out of scope and have the garbage collector
- # harvest them. Whenever they may fall out of use, we need to remove the timer. @rotate() can be used to
- # restart the cache.
- suspend: ->
- clearTimeout @timer if @timer?
- @timer = null
-
- # Set value, and return that value. If value is null, then delete key.
- set: (key, value = null) ->
- if value?
- @cache[key] = value
- delete @previous[key]
- @rotate() if @entries < Object.keys(@cache).length
- else
- delete @cache[key]
- delete @previous[key]
- value
-
# This is a simple class for the common case where we want to use some data value which may be immediately
-# available, or we may have to wait. It implements the use-immediately-or-wait queue, and calls the function
-# to fetch the data asynchronously.
+# available, or for which we may have to wait. It implements the use-immediately-or-wait queue, and calls the
+# function to fetch the data asynchronously.
class AsyncDataFetcher
constructor: (fetch) ->
@data = null
diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee
index b53028ca..b8ada233 100644
--- a/pages/vomnibar.coffee
+++ b/pages/vomnibar.coffee
@@ -352,7 +352,7 @@ class BackgroundCompleter
@port.onMessage.addListener (msg) =>
switch msg.handler
- when "customSearchEngineKeywords"
+ when "keywords"
@keywords = msg.keywords
@lastUI.setKeywords @keywords
when "completions"