diff options
| author | Stephen Blott | 2015-05-09 08:30:29 +0100 | 
|---|---|---|
| committer | Stephen Blott | 2015-05-09 08:31:35 +0100 | 
| commit | 6fd0e15b96325222abf1a19886bd5e0fb48fcdbb (patch) | |
| tree | 61578992f46de2c97e6f7102cb331925c1581c02 | |
| parent | 8c308d47cc615b9fa0eed47e4ecddd1fd9d125eb (diff) | |
| download | vimium-6fd0e15b96325222abf1a19886bd5e0fb48fcdbb.tar.bz2 | |
Search completion; refactor SearchCompleter activation.
| -rw-r--r-- | background_scripts/completion.coffee | 39 | ||||
| -rw-r--r-- | background_scripts/main.coffee | 2 | ||||
| -rw-r--r-- | lib/utils.coffee | 3 | ||||
| -rw-r--r-- | pages/vomnibar.coffee | 42 | ||||
| -rw-r--r-- | tests/unit_tests/completion_test.coffee | 2 | 
5 files changed, 35 insertions, 53 deletions
| diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 011ff72b..c1f76b81 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -136,8 +136,7 @@ class BookmarkCompleter    # These bookmarks are loaded asynchronously when refresh() is called.    bookmarks: null -  filter: (queryTerms, @onComplete) -> -    @queryTerms = queryTerms.filter (t) -> 0 < t.length +  filter: ({ @queryTerms }, @onComplete) ->      @currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }      @performSearch() if @bookmarks @@ -198,8 +197,7 @@ class BookmarkCompleter      RankingUtils.wordRelevancy(suggestion.queryTerms, suggestion.url, suggestion.title)  class HistoryCompleter -  filter: (queryTerms, onComplete) -> -    queryTerms = queryTerms.filter (t) -> 0 < t.length +  filter: ({ queryTerms }, onComplete) ->      @currentSearch = { queryTerms: @queryTerms, onComplete: @onComplete }      results = []      HistoryCache.use (history) => @@ -233,8 +231,7 @@ class DomainCompleter    #     If `referenceCount` goes to zero, the domain entry can and should be deleted.    domains: null -  filter: (queryTerms, onComplete) -> -    queryTerms = queryTerms.filter (t) -> 0 < t.length +  filter: ({ queryTerms }, onComplete) ->      return onComplete([]) unless queryTerms.length == 1      if @domains        @performSearch(queryTerms, onComplete) @@ -336,8 +333,7 @@ tabRecency = new TabRecency()  # Searches through all open tabs, matching on title and URL.  class TabCompleter -  filter: (queryTerms, onComplete) -> -    queryTerms = queryTerms.filter (t) -> 0 < t.length +  filter: ({ queryTerms }, onComplete) ->      # NOTE(philc): We search all tabs, not just those in the current window. I'm not sure if this is the      # correct UX.      chrome.tabs.query {}, (tabs) => @@ -371,10 +367,11 @@ class SearchEngineCompleter        handler: "customSearchEngineKeywords"        keywords: key for own key of @searchEngines -  filter: (queryTerms, onComplete) -> +  filter: ({ queryTerms, query }, onComplete) -> +    return onComplete [] if queryTerms.length == 0      suggestions = [] -    { keyword, searchUrl, description } = @getSearchEngineMatches queryTerms +    { keyword, searchUrl, description } = @getSearchEngineMatches queryTerms, query      custom = searchUrl? and keyword?      searchUrl ?= Settings.get "searchUrl"      haveDescription = description? and 0 < description.length @@ -382,7 +379,6 @@ class SearchEngineCompleter      queryTerms = queryTerms[1..] if custom      query = queryTerms.join " " -    return onComplete [] if queryTerms.length == 0      # For custom search engines, we add an auto-selected suggestion.      if custom @@ -399,9 +395,6 @@ class SearchEngineCompleter          # Suppress the "w" from "w query terms" in the vomnibar input.          suppressLeadingKeyword: true -    # We filter out the empty strings late so that we can distinguish between, for example, "w" and "w ". -    queryTerms = queryTerms.filter (t) -> 0 < t.length -      # Exclude results from other completers if this is a custom search engine and we have a completer.      filter =        if custom and CompletionEngines.haveCompletionEngine searchUrl @@ -431,7 +424,6 @@ class SearchEngineCompleter          characterCount = query.length - queryTerms.length + 1          relavancy = 0.6 * (Math.min(characterCount, 10.0)/10.0) -        queryTerms = queryTerms.filter (t) -> 0 < t.length          if 0 < existingSuggestions.length            existingSuggestionsMinScore = existingSuggestions[existingSuggestions.length-1].relevancy            if relavancy < existingSuggestionsMinScore and MultiCompleter.maxResults <= existingSuggestions.length @@ -457,8 +449,14 @@ class SearchEngineCompleter            count = Math.min 6, Math.max 3, MultiCompleter.maxResults - existingSuggestions.length            onComplete suggestions[...count] -  getSearchEngineMatches: (queryTerms) -> -    (1 < queryTerms.length and @searchEngines[queryTerms[0]]) or {} +  getSearchEngineMatches: (queryTerms, query = queryTerms.join " ") -> +    # To allow users to write queries with leading search-engine keywords, leading whitespace disables custom +    # search engines; for example, " w" is a regular query. +    return {} if /^\s/.test query +    # Trailing whitespace is significant when activating a custom search engine; for example, "w" (just a +    # regular query) is different from "w " (a custom search engine). +    length = queryTerms.length + (if /\s$/.test query then 1 else 0) +    (1 < length and @searchEngines[queryTerms[0]]) or {}    # Static data and methods for parsing the configured search engines.  We keep a cache of the search-engine    # mapping in @searchEnginesMap. @@ -507,11 +505,12 @@ class MultiCompleter        # other completers.        filter: null -    (queryTerms, onComplete) -> +    (request, onComplete) ->        @debug = true        # Allow only one query to run at a time, and remember the most recent query.        return @mostRecentQuery = arguments if @filterInProgress +      { queryTerms } = request        RegexpCache.clear()        @mostRecentQuery = null        @filterInProgress = true @@ -524,7 +523,7 @@ class MultiCompleter        # results, then calling any continuations.        for completer, index in @completers          do (index) => -          completer.filter queryTerms, (newSuggestions = [], { continuation, filter } = defaultCallbackOptions) => +          completer.filter request, (newSuggestions = [], { continuation, filter } = defaultCallbackOptions) =>              # Store the results.              suggestions.push newSuggestions... @@ -546,7 +545,6 @@ class MultiCompleter                unless suggestions.length == 0 and shouldRunContinuations                  onComplete                    results: @prepareSuggestions queryTerms, suggestions -                  mayCacheResults: continuations.length == 0                    expectMoreResults: shouldRunContinuations                # Run any continuations, unless there's a pending query. @@ -560,7 +558,6 @@ class MultiCompleter                        results: @prepareSuggestions queryTerms, suggestions                        # FIXME(smblott) This currently assumes that there is at most one continuation.  We                        # should really be counting pending/completed continuations. -                      mayCacheResults: true                        expectMoreResults: false                # Admit subsequent queries, and launch any pending query. diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 34db5a20..612f6170 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -61,7 +61,7 @@ completers =  completionHandlers =    filter: (completer, request, port) -> -    completer.filter request.queryTerms, (response) -> +    completer.filter request, (response) ->        port.postMessage extend request, extend response, handler: "completions"    refresh: (completer, _, port) -> completer.refresh port diff --git a/lib/utils.coffee b/lib/utils.coffee index 033fdd2b..4c2a7a14 100644 --- a/lib/utils.coffee +++ b/lib/utils.coffee @@ -201,7 +201,8 @@ Function::curry = ->  Array.copy = (array) -> Array.prototype.slice.call(array, 0)  String::startsWith = (str) -> @indexOf(str) == 0 -String::ltrim = () -> @replace /^\s+/, "" +String::ltrim = -> @replace /^\s+/, "" +String::rtrim = -> @replace /\s+$/, ""  globalRoot = window ? global  globalRoot.extend = (hash1, hash2) -> diff --git a/pages/vomnibar.coffee b/pages/vomnibar.coffee index 4781c273..bc773909 100644 --- a/pages/vomnibar.coffee +++ b/pages/vomnibar.coffee @@ -200,12 +200,14 @@ class VomnibarUI        window.clearTimeout @updateTimer        @updateTimer = null +  isCustomSearch: -> +    queryTerms = @input.value.ltrim().split /\s+/ +    1 < queryTerms.length and queryTerms[0] in @keywords +    update: (updateSynchronously = false, callback = null) => -    # If the query text is a custom search keyword, then we need to force a synchronous update (so that the +    # If the query text becomes a custom search, then we need to force a synchronous update (so that the      # interface is snappy). -    if @keywords? and not @suppressedLeadingKeyword? -      queryTerms = @input.value.ltrim().split /\s+/ -      updateSynchronously ||= 1 < queryTerms.length and queryTerms[0] in @keywords +    updateSynchronously ||= @isCustomSearch() and not @suppressedLeadingKeyword?      if updateSynchronously        @updateCompletions callback      else if not @updateTimer? @@ -242,7 +244,6 @@ class BackgroundCompleter    constructor: (@name) ->      @port = chrome.runtime.connect name: "completions"      @messageId = null -    @cache ?= new SimpleCache 1000 * 60 * 5      @reset()      @port.onMessage.addListener (msg) => @@ -260,33 +261,18 @@ class BackgroundCompleter                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.mayCacheResults -            console.log "cache set:", msg.query if @debug -            @cache.set msg.query, msg.results -          else -            console.log "not setting cache:", msg.query if @debug -            # We ignore messages which arrive too late.            if msg.id == @messageId              @mostRecentCallback msg.results    filter: (query, @mostRecentCallback) -> -    # We retain trailing whitespace so that we can tell the difference between "w" and "w " (for custom search -    # engines). -    queryTerms = query.ltrim().split(/\s+/) -    query = queryTerms.join " " -    if @cache.has query -      console.log "cache hit:", query if @debug -      @mostRecentCallback @cache.get query -    else -      @messageId = Utils.createUniqueId() -      @port.postMessage -        name: @name -        handler: "filter" -        id: @messageId -        query: query -        queryTerms: queryTerms +    queryTerms = query.trim().split(/\s+/).filter (s) -> 0 < s.length +    @port.postMessage +      handler: "filter" +      name: @name +      id: @messageId = Utils.createUniqueId() +      queryTerms: queryTerms +      query: query    refresh: (@lastUI) ->      @reset() @@ -294,8 +280,6 @@ class BackgroundCompleter      @port.postMessage name: @name, handler: "refresh"    reset: -> -    # We only cache results for the duration of a single vomnibar activation, so clear the cache now. -    @cache.clear()    cancel: ->      # Inform the background completer that it may (should it choose to do so) abandon any pending query diff --git a/tests/unit_tests/completion_test.coffee b/tests/unit_tests/completion_test.coffee index b1962daf..b9a062f2 100644 --- a/tests/unit_tests/completion_test.coffee +++ b/tests/unit_tests/completion_test.coffee @@ -486,7 +486,7 @@ context "TabRecency",  # A convenience wrapper around completer.filter() so it can be called synchronously in tests.  filterCompleter = (completer, queryTerms) ->    results = [] -  completer.filter(queryTerms, (completionResults) -> results = completionResults) +  completer.filter({ queryTerms }, (completionResults) -> results = completionResults)    results  hours = (n) -> 1000 * 60 * 60 * n | 
