1 /*
   2  * Copyright (c) 2002-2012, the original author or authors.
   3  *
   4  * This software is distributable under the BSD license. See the terms of the
   5  * BSD license in the documentation provided with this software.
   6  *
   7  * http://www.opensource.org/licenses/bsd-license.php
   8  */
   9 package jline.console.completer;
  10 
  11 import java.util.ArrayList;
  12 import java.util.Arrays;
  13 import java.util.Collection;
  14 import java.util.LinkedList;
  15 import java.util.List;
  16 
  17 import static jline.internal.Preconditions.checkNotNull;
  18 
  19 /**
  20  * Completer which contains multiple completers and aggregates them together.
  21  *
  22  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  23  * @since 2.3
  24  */
  25 public class AggregateCompleter
  26     implements Completer
  27 {
  28     private final List<Completer> completers = new ArrayList<Completer>();
  29 
  30     public AggregateCompleter() {
  31         // empty
  32     }
  33 
  34     /**
  35      * Construct an AggregateCompleter with the given collection of completers.
  36      * The completers will be used in the iteration order of the collection.
  37      *
  38      * @param completers the collection of completers
  39      */
  40     public AggregateCompleter(final Collection<Completer> completers) {
  41         checkNotNull(completers);
  42         this.completers.addAll(completers);
  43     }
  44 
  45     /**
  46      * Construct an AggregateCompleter with the given completers.
  47      * The completers will be used in the order given.
  48      *
  49      * @param completers the completers
  50      */
  51     public AggregateCompleter(final Completer... completers) {
  52         this(Arrays.asList(completers));
  53     }
  54 
  55     /**
  56      * Retrieve the collection of completers currently being aggregated.
  57      *
  58      * @return the aggregated completers
  59      */
  60     public Collection<Completer> getCompleters() {
  61         return completers;
  62     }
  63 
  64     /**
  65      * Perform a completion operation across all aggregated completers.
  66      *
  67      * @see Completer#complete(String, int, java.util.List)
  68      * @return the highest completion return value from all completers
  69      */
  70     public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
  71         // buffer could be null
  72         checkNotNull(candidates);
  73 
  74         List<Completion> completions = new ArrayList<Completion>(completers.size());
  75 
  76         // Run each completer, saving its completion results
  77         int max = -1;
  78         for (Completer completer : completers) {
  79             Completion completion = new Completion(candidates);
  80             completion.complete(completer, buffer, cursor);
  81 
  82             // Compute the max cursor position
  83             max = Math.max(max, completion.cursor);
  84 
  85             completions.add(completion);
  86         }
  87 
  88         // Append candidates from completions which have the same cursor position as max
  89         for (Completion completion : completions) {
  90             if (completion.cursor == max) {
  91                 candidates.addAll(completion.candidates);
  92             }
  93         }
  94 
  95         return max;
  96     }
  97 
  98     /**
  99      * @return a string representing the aggregated completers
 100      */
 101     @Override
 102     public String toString() {
 103         return getClass().getSimpleName() + "{" +
 104             "completers=" + completers +
 105             '}';
 106     }
 107 
 108     private class Completion
 109     {
 110         public final List<CharSequence> candidates;
 111 
 112         public int cursor;
 113 
 114         public Completion(final List<CharSequence> candidates) {
 115             checkNotNull(candidates);
 116             this.candidates = new LinkedList<CharSequence>(candidates);
 117         }
 118 
 119         public void complete(final Completer completer, final String buffer, final int cursor) {
 120             checkNotNull(completer);
 121             this.cursor = completer.complete(buffer, cursor, candidates);
 122         }
 123     }
 124 }