View Javadoc

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 }