aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--background_scripts/completion.coffee29
-rw-r--r--tests/unit_tests/completion_test.coffee42
-rw-r--r--tests/unit_tests/test_chrome_stubs.coffee4
3 files changed, 73 insertions, 2 deletions
diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee
index b75ebb87..b6a52a15 100644
--- a/background_scripts/completion.coffee
+++ b/background_scripts/completion.coffee
@@ -261,6 +261,29 @@ class DomainCompleter
# Suggestions from the Domain completer have the maximum relevancy. They should be shown first in the list.
computeRelevancy: -> 1
+# TabRecency associates a logical timestamp with each tab id.
+class TabRecency
+ constructor: ->
+ @timestamp = 1
+ @cache = {}
+
+ chrome.tabs.onActivated.addListener (activeInfo) => @add activeInfo.tabId
+ chrome.tabs.onRemoved.addListener (tabId) => @remove tabId
+
+ chrome.tabs.onReplaced.addListener (addedTabId, removedTabId) =>
+ @remove removedTabId
+ @add addedTabId
+
+ add: (tabId) -> @cache[tabId] = ++@timestamp
+ remove: (tabId) -> delete @cache[tabId]
+
+ # Recently-visited tabs get a higher score (except the current tab, which gets a low score).
+ recencyScore: (tabId) ->
+ @cache[tabId] ||= 1
+ if @cache[tabId] == @timestamp then 0.0 else @cache[tabId] / @timestamp
+
+tabRecency = new TabRecency()
+
# Searches through all open tabs, matching on title and URL.
class TabCompleter
filter: (queryTerms, onComplete) ->
@@ -276,7 +299,10 @@ class TabCompleter
onComplete(suggestions)
computeRelevancy: (suggestion) ->
- RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
+ if suggestion.queryTerms.length
+ RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)
+ else
+ tabRecency.recencyScore(suggestion.tabId)
# A completer which will return your search engines
class SearchEngineCompleter
@@ -549,3 +575,4 @@ root.SearchEngineCompleter = SearchEngineCompleter
root.HistoryCache = HistoryCache
root.RankingUtils = RankingUtils
root.RegexpCache = RegexpCache
+root.TabRecency = TabRecency
diff --git a/tests/unit_tests/completion_test.coffee b/tests/unit_tests/completion_test.coffee
index 44989267..88f59b7e 100644
--- a/tests/unit_tests/completion_test.coffee
+++ b/tests/unit_tests/completion_test.coffee
@@ -1,8 +1,8 @@
require "./test_helper.js"
extend(global, require "../../lib/utils.js")
extend(global, require "../../background_scripts/completion.js")
+extend global, require "./test_chrome_stubs.js"
-global.chrome = {}
global.document =
createElement: -> {}
@@ -399,6 +399,46 @@ context "RegexpCache",
should "search for a string with a prefix/suffix (negative case)", ->
assert.isTrue "hound dog".search(RegexpCache.get("do", "\\b", "\\b")) == -1
+context "TabRecency",
+ setup ->
+ @tabRecency = new TabRecency()
+ @tabRecency.add 3
+ @tabRecency.add 2
+ @tabRecency.add 9
+ @tabRecency.add 1
+ @tabRecency.remove 9
+ @tabRecency.add 4
+
+ should "have entries for active tabs", ->
+ assert.isTrue @tabRecency.cache[1]
+ assert.isTrue @tabRecency.cache[2]
+ assert.isTrue @tabRecency.cache[3]
+ assert.isTrue @tabRecency.cache[4]
+
+ should "not have entries for removed tabs", ->
+ assert.isFalse @tabRecency.cache[9]
+
+ should "give a high score to the most recent tab", ->
+ assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 1
+ assert.isTrue @tabRecency.recencyScore(3) < @tabRecency.recencyScore 1
+ assert.isTrue @tabRecency.recencyScore(2) < @tabRecency.recencyScore 1
+
+ should "give a low score to the current tab", ->
+ assert.isTrue @tabRecency.recencyScore(1) > @tabRecency.recencyScore 4
+ assert.isTrue @tabRecency.recencyScore(2) > @tabRecency.recencyScore 4
+ assert.isTrue @tabRecency.recencyScore(3) > @tabRecency.recencyScore 4
+
+ should "rank tabs by recency", ->
+ assert.isTrue @tabRecency.recencyScore(3) < @tabRecency.recencyScore 2
+ assert.isTrue @tabRecency.recencyScore(2) < @tabRecency.recencyScore 1
+ @tabRecency.add 3
+ @tabRecency.add 4 # Making 3 the most recent tab which isn't the current tab.
+ assert.isTrue @tabRecency.recencyScore(1) < @tabRecency.recencyScore 3
+ assert.isTrue @tabRecency.recencyScore(2) < @tabRecency.recencyScore 3
+ assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 3
+ assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 1
+ assert.isTrue @tabRecency.recencyScore(4) < @tabRecency.recencyScore 2
+
# A convenience wrapper around completer.filter() so it can be called synchronously in tests.
filterCompleter = (completer, queryTerms) ->
results = []
diff --git a/tests/unit_tests/test_chrome_stubs.coffee b/tests/unit_tests/test_chrome_stubs.coffee
index 2abd26c9..80750337 100644
--- a/tests/unit_tests/test_chrome_stubs.coffee
+++ b/tests/unit_tests/test_chrome_stubs.coffee
@@ -30,6 +30,10 @@ exports.chrome =
addListener: () -> true
onActiveChanged:
addListener: () -> true
+ onActivated:
+ addListener: () -> true
+ onReplaced:
+ addListener: () -> true
query: () -> true
windows: