--- /dev/null 2015-04-26 06:51:08.003313989 -0700
+++ new/jdk/src/jdk.jline/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java 2015-06-18 03:05:16.883897040 -0700
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jline.console.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Completer which contains multiple completers and aggregates them together.
+ *
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public class AggregateCompleter
+ implements Completer
+{
+ private final List completers = new ArrayList();
+
+ public AggregateCompleter() {
+ // empty
+ }
+
+ /**
+ * Construct an AggregateCompleter with the given collection of completers.
+ * The completers will be used in the iteration order of the collection.
+ *
+ * @param completers the collection of completers
+ */
+ public AggregateCompleter(final Collection completers) {
+ checkNotNull(completers);
+ this.completers.addAll(completers);
+ }
+
+ /**
+ * Construct an AggregateCompleter with the given completers.
+ * The completers will be used in the order given.
+ *
+ * @param completers the completers
+ */
+ public AggregateCompleter(final Completer... completers) {
+ this(Arrays.asList(completers));
+ }
+
+ /**
+ * Retrieve the collection of completers currently being aggregated.
+ *
+ * @return the aggregated completers
+ */
+ public Collection getCompleters() {
+ return completers;
+ }
+
+ /**
+ * Perform a completion operation across all aggregated completers.
+ *
+ * @see Completer#complete(String, int, java.util.List)
+ * @return the highest completion return value from all completers
+ */
+ public int complete(final String buffer, final int cursor, final List candidates) {
+ // buffer could be null
+ checkNotNull(candidates);
+
+ List completions = new ArrayList(completers.size());
+
+ // Run each completer, saving its completion results
+ int max = -1;
+ for (Completer completer : completers) {
+ Completion completion = new Completion(candidates);
+ completion.complete(completer, buffer, cursor);
+
+ // Compute the max cursor position
+ max = Math.max(max, completion.cursor);
+
+ completions.add(completion);
+ }
+
+ // Append candidates from completions which have the same cursor position as max
+ for (Completion completion : completions) {
+ if (completion.cursor == max) {
+ candidates.addAll(completion.candidates);
+ }
+ }
+
+ return max;
+ }
+
+ /**
+ * @return a string representing the aggregated completers
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" +
+ "completers=" + completers +
+ '}';
+ }
+
+ private class Completion
+ {
+ public final List candidates;
+
+ public int cursor;
+
+ public Completion(final List candidates) {
+ checkNotNull(candidates);
+ this.candidates = new LinkedList(candidates);
+ }
+
+ public void complete(final Completer completer, final String buffer, final int cursor) {
+ checkNotNull(completer);
+ this.cursor = completer.complete(buffer, cursor, candidates);
+ }
+ }
+}