FELIX-1757: Completer for session scopes

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@825825 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/completer/SessionScopeCompleter.java b/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/completer/SessionScopeCompleter.java
new file mode 100644
index 0000000..34ba244
--- /dev/null
+++ b/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/completer/SessionScopeCompleter.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.karaf.shell.console.completer;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import org.apache.felix.karaf.shell.console.Completer;
+import org.osgi.service.command.CommandSession;
+
+/**
+ * Completer which uses the session scopes automatically appended in front of buffer.
+ *
+ * @version $Rev: $ $Date: $
+ */
+public class SessionScopeCompleter implements Completer
+{
+
+    private final CommandSession session;
+    private final Completer completer;
+
+    public SessionScopeCompleter( final CommandSession session,
+                                  final Completer completer )
+    {
+        this.session = session;
+        this.completer = completer;
+    }
+
+    public int complete( String buffer, int cursor, List<String> candidates )
+    {
+        // buffer could be null
+        assert candidates != null;
+
+        try
+        {
+            final List<Completion> completions = new ArrayList<Completion>();
+
+            final String scope = (String) session.get( "SCOPE" );
+            if( scope != null )
+            {
+                final String[] segments = scope.split( ":" );
+
+                // Run completer for each segment, saving its completion results
+                int max = -1;
+                for( String segment : segments )
+                {
+                    Completion completion = new Completion( candidates );
+                    completion.complete( completer, segment + ":" + buffer, ( segment + ":" ).length() + 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 )
+                    {
+                        // noinspection unchecked
+                        candidates.addAll( completion.candidates );
+                    }
+                }
+
+                return max;
+            }
+        }
+        catch( Exception ignore )
+        {
+        }
+        return -1;
+    }
+
+    private class Completion
+    {
+
+        public final List<String> candidates;
+
+        public int cursor;
+
+        public Completion( final List candidates )
+        {
+            assert candidates != null;
+
+            // noinspection unchecked
+            this.candidates = new LinkedList<String>( candidates );
+        }
+
+        public void complete( final Completer completer, final String buffer, final int cursor )
+        {
+            assert completer != null;
+
+            this.cursor = completer.complete( buffer, cursor, candidates );
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/jline/Console.java b/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/jline/Console.java
index 9a172ae..fe27da1 100644
--- a/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/jline/Console.java
+++ b/karaf/shell/console/src/main/java/org/apache/felix/karaf/shell/console/jline/Console.java
@@ -24,6 +24,7 @@
 import java.io.InterruptedIOException;
 import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.Properties;
 import java.util.concurrent.Callable;
 import java.util.regex.Pattern;
@@ -36,6 +37,8 @@
 import jline.UnsupportedTerminal;
 import jline.AnsiWindowsTerminal;
 import org.apache.felix.karaf.shell.console.Completer;
+import org.apache.felix.karaf.shell.console.completer.AggregateCompleter;
+import org.apache.felix.karaf.shell.console.completer.SessionScopeCompleter;
 import org.osgi.service.command.CommandProcessor;
 import org.osgi.service.command.CommandSession;
 import org.osgi.service.command.Converter;
@@ -90,7 +93,16 @@
         file.getParentFile().mkdirs();
         reader.getHistory().setHistoryFile(file);
         if (completer != null) {
-            reader.addCompletor(new CompleterAsCompletor(completer));
+            reader.addCompletor(
+                new CompleterAsCompletor(
+                    new AggregateCompleter(
+                        Arrays.asList(
+                            completer,
+                            new SessionScopeCompleter( session, completer )
+                        )
+                    )
+                )
+            );
         }
         pipe = new Thread(new Pipe());
         pipe.setName("gogo shell pipe thread");