diff options
| author | Stephen Blott | 2015-05-10 06:45:37 +0100 | 
|---|---|---|
| committer | Stephen Blott | 2015-05-10 06:45:37 +0100 | 
| commit | 198dd8fa89148f3389c289bf71c40b9ab1a5681f (patch) | |
| tree | 754824aa284c75b46c19db0a76d49fe0a23ff9e0 | |
| parent | 5fdbb8e579c068a54e9a397097d87063a3d8a146 (diff) | |
| download | vimium-198dd8fa89148f3389c289bf71c40b9ab1a5681f.tar.bz2 | |
Search completion; refactor job-running logic.
| -rw-r--r-- | background_scripts/completion.coffee | 130 | ||||
| -rw-r--r-- | lib/utils.coffee | 16 | 
2 files changed, 76 insertions, 70 deletions
| diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 024ea54c..40123337 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -499,76 +499,66 @@ class MultiCompleter    cancel: (port) ->      completer.cancel? port for completer in @completers -  filter: do -> -    defaultCallbackOptions = -      # Completers may provide a continuation function.  This will be run after all completers have posted -      # their suggestions, and is used to post additional (slow) asynchronous suggestions (e.g. search-engine -      # completions fetched over HTTP). -      continuation: null -      # Completers may provide a filter function.  This allows one completer to filter out suggestions from -      # other completers. -      filter: null - -    (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 -      suggestions = [] -      continuations = [] -      filters = [] -      activeCompleters = [0...@completers.length] - -      # Call filter() on every completer and wait for them all to finish before filtering and posting the -      # results, then calling any continuations. -      for completer, index in @completers -        do (index) => -          completer.filter request, (newSuggestions = [], { continuation, filter } = defaultCallbackOptions) => - -            # Store the results. -            suggestions.push newSuggestions... -            continuations.push continuation if continuation? -            filters.push filter if filter? - -            activeCompleters = activeCompleters.filter (i) -> i != index -            if activeCompleters.length == 0 -              # All the completers have now yielded their (initial) results, we're good to go. - -              # Apply filters. -              suggestions = suggestions.filter filter for filter in filters - -              # Should we run continuations? -              shouldRunContinuations = 0 < continuations.length and not @mostRecentQuery? - -              # Post results, unless there are none AND we will be running a continuation.  This avoids -              # collapsing the vomnibar briefly before expanding it again, which looks ugly. -              unless suggestions.length == 0 and shouldRunContinuations -                onComplete -                  results: @prepareSuggestions queryTerms, suggestions -                  mayCacheResults: continuations.length == 0 - -              # Run any continuations, unless there's a pending query. -              if shouldRunContinuations -                for continuation in continuations -                  console.log "launching continuation..." if @debug -                  continuation suggestions, (newSuggestions) => -                    console.log "posting continuation" if @debug -                    suggestions.push newSuggestions... -                    onComplete -                      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 - -              # Admit subsequent queries, and launch any pending query. -              @filterInProgress = false -              if @mostRecentQuery -                console.log "running pending query:", @mostRecentQuery[0] if @debug -                @filter @mostRecentQuery... +  filter: (request, onComplete) -> +    @debug = true +    # Allow only one query to run at a time. +    return @mostRecentQuery = arguments if @filterInProgress + +    RegexpCache.clear() +    { queryTerms } = request + +    @mostRecentQuery = null +    @filterInProgress = true + +    suggestions = [] +    continuations = [] +    filters = [] + +    # Run each of the completers (asynchronously). +    jobs = new JobRunner @completers.map (completer) -> +      (callback) -> +        completer.filter request, (newSuggestions = [], { continuation, filter } = {}) -> +          suggestions.push newSuggestions... +          continuations.push continuation if continuation? +          filters.push filter if filter? +          callback() + +    # Once all completers have finished, process and post the results, and run any continuations or pending +    # queries. +    jobs.onReady => +      # Apply filters. +      suggestions = suggestions.filter filter for filter in filters + +      # Should we run continuations? +      shouldRunContinuations = 0 < continuations.length and not @mostRecentQuery? + +      # Post results, unless there are none AND we will be running a continuation.  This avoids +      # collapsing the vomnibar briefly before expanding it again, which looks ugly. +      unless suggestions.length == 0 and shouldRunContinuations +        onComplete +          results: @prepareSuggestions queryTerms, suggestions +          mayCacheResults: continuations.length == 0 + +      # Run any continuations (asynchronously). +      if shouldRunContinuations +        continuationJobs = new JobRunner continuations.map (continuation) -> +          (callback) -> +            continuation suggestions, (newSuggestions) -> +              suggestions.push newSuggestions... +              callback() + +        continuationJobs.onReady => +          # We post these results even if a new query has started.  The vomnibar will not display the +          # completions, but will cache the results. +          onComplete +            results: @prepareSuggestions queryTerms, suggestions +            mayCacheResults: true + +      # Admit subsequent queries, and launch any pending query. +      @filterInProgress = false +      if @mostRecentQuery +        console.log "running pending query:", @mostRecentQuery[0] if @debug +        @filter @mostRecentQuery...    prepareSuggestions: (queryTerms, suggestions) ->      suggestion.computeRelevancy queryTerms for suggestion in suggestions diff --git a/lib/utils.coffee b/lib/utils.coffee index b0abfd8f..16adc305 100644 --- a/lib/utils.coffee +++ b/lib/utils.coffee @@ -278,7 +278,23 @@ class AsyncDataFetcher    use: (callback) ->      if @data? then callback @data else @queue.push callback +# This takes a list of jobs (functions) and runs them, asynchronously.  Functions queued with @onReady() are +# run once all of the jobs have completed. +class JobRunner +  constructor: (@jobs) -> +    @fetcher = new AsyncDataFetcher (callback) => +      for job in @jobs +        do (job) => +          Utils.nextTick => +            job => +              @jobs = @jobs.filter (j) -> j != job +              callback true if @jobs.length == 0 + +  onReady: (callback) -> +    @fetcher.use callback +  root = exports ? window  root.Utils = Utils  root.SimpleCache = SimpleCache  root.AsyncDataFetcher = AsyncDataFetcher +root.JobRunner = JobRunner | 
