Skip to content

zzz_614_line3completion

Remko Popma edited this page Jan 29, 2019 · 1 revision
Index: src/main/java/picocli/MyCompleter.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/main/java/picocli/MyCompleter.java	(date 1548756958721)
+++ src/main/java/picocli/MyCompleter.java	(date 1548756958721)
@@ -6,6 +6,7 @@
 import org.jline.reader.ParsedLine;
 import picocli.CommandLine;
 import picocli.CommandLine.Model.CommandSpec;
+import picocli.CommandLine.Model.OptionSpec;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -23,17 +24,13 @@
     public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
         String[] words = new String[line.words().size()];
         words = line.words().toArray(words);
-        List<CharSequence> cs = new ArrayList<CharSequence>();
+        List<Candidate> cs = new ArrayList<Candidate>();
         complete(spec,
                 words,
                 line.wordIndex(),
                 0,
                 line.cursor(),
-                cs);
-        for(CharSequence c: cs){
-            candidates.add(new Candidate((String)c));
-        }
-
+                candidates);
     }
 
     public static int complete(CommandSpec spec,
@@ -41,7 +38,7 @@
                                int argIndex,
                                int positionInArg,
                                int cursor,
-                               List<CharSequence> candidates) {
+                               List<Candidate> candidates) {
         if (spec == null)       { throw new NullPointerException("spec is null"); }
         if (args == null)       { throw new NullPointerException("args is null"); }
         if (candidates == null) { throw new NullPointerException("candidates list is null"); }
@@ -70,19 +67,27 @@
                 if (obj instanceof CommandSpec) { // subcommand
                     addCandidatesForArgsFollowing(((CommandSpec) obj).parent(), candidates);
 
-                } else if (obj instanceof CommandLine.Model.OptionSpec) { // option
+                } else if (obj instanceof OptionSpec) { // option
                     int sep = currentArg.indexOf(spec.parser().separator());
                     if (sep < 0 || positionInArg < sep) { // no '=' or cursor before '='
-                        addCandidatesForArgsFollowing(findCommandFor((CommandLine.Model.OptionSpec) obj, spec), candidates);
+                        addCandidatesForArgsFollowing(findCommandFor((OptionSpec) obj, spec), candidates);
                     } else {
-                        addCandidatesForArgsFollowing((CommandLine.Model.OptionSpec) obj, candidates);
+                        addCandidatesForArgsFollowing((OptionSpec) obj, candidates);
 
                         int sepLength = spec.parser().separator().length();
                         if (positionInArg < sep + sepLength) {
                             int posInSeparator = positionInArg - sep;
                             String prefix = spec.parser().separator().substring(posInSeparator);
                             for (int i = 0; i < candidates.size(); i++) {
-                                candidates.set(i, prefix + candidates.get(i));
+                                Candidate old = candidates.get(i);
+                                Candidate replace = new Candidate(prefix + old.value(),
+                                        prefix + old.displ(),
+                                        old.group(),
+                                        old.descr(),
+                                        old.suffix(),
+                                        old.key(),
+                                        old.complete());
+                                candidates.set(i, replace);
                             }
                             committedPrefix = currentArg.substring(sep, positionInArg);
                         } else {
@@ -101,12 +106,23 @@
                     addCandidatesForArgsFollowing(parseResult.tentativeMatch.get(i), candidates);
                 }
             }
-            filterAndTrimMatchingPrefix(committedPrefix, candidates);
+            // TODO filterAndTrimMatchingPrefix(committedPrefix, candidates);
             return candidates.isEmpty() ? -1 : cursor;
         } finally {
             spec.parser().collectErrors(reset);
         }
     }
+
+    private static void filterAndTrimMatchingPrefix(String prefix, List<CharSequence> candidates) {
+        List<CharSequence> replace = new ArrayList<CharSequence>();
+        for (CharSequence seq : candidates) {
+            if (seq.toString().startsWith(prefix)) {
+                replace.add(seq.subSequence(prefix.length(), seq.length()));
+            }
+        }
+        candidates.clear();
+        candidates.addAll(replace);
+    }
     private static Object findCompletionStartPoint(CommandLine.ParseResult parseResult) {
         List<Object> tentativeMatches = parseResult.tentativeMatch;
         for (int i = 1; i <= tentativeMatches.size(); i++) {
@@ -127,10 +143,10 @@
     }
 
     private static CommandSpec findCommandFor(CommandLine.Model.ArgSpec arg, CommandSpec cmd) {
-        return (arg instanceof CommandLine.Model.OptionSpec) ? findCommandFor((CommandLine.Model.OptionSpec) arg, cmd) : findCommandFor((CommandLine.Model.PositionalParamSpec) arg, cmd);
+        return (arg instanceof OptionSpec) ? findCommandFor((OptionSpec) arg, cmd) : findCommandFor((CommandLine.Model.PositionalParamSpec) arg, cmd);
     }
-    private static CommandSpec findCommandFor(CommandLine.Model.OptionSpec option, CommandSpec commandSpec) {
-        for (CommandLine.Model.OptionSpec defined : commandSpec.options()) {
+    private static CommandSpec findCommandFor(OptionSpec option, CommandSpec commandSpec) {
+        for (OptionSpec defined : commandSpec.options()) {
             if (defined == option) { return commandSpec; }
         }
         for (CommandLine sub : commandSpec.subcommands().values()) {
@@ -150,53 +166,82 @@
         return null;
     }
     private static boolean isPicocliModelObject(Object obj) {
-        return obj instanceof CommandSpec || obj instanceof CommandLine.Model.OptionSpec || obj instanceof CommandLine.Model.PositionalParamSpec;
+        return obj instanceof CommandSpec || obj instanceof OptionSpec || obj instanceof CommandLine.Model.PositionalParamSpec;
     }
-
-    private static void filterAndTrimMatchingPrefix(String prefix, List<CharSequence> candidates) {
-        List<CharSequence> replace = new ArrayList<CharSequence>();
-        for (CharSequence seq : candidates) {
-            if (seq.toString().startsWith(prefix)) {
-                replace.add(seq.subSequence(prefix.length(), seq.length()));
-            }
-        }
-        candidates.clear();
-        candidates.addAll(replace);
-    }
-    private static void addCandidatesForArgsFollowing(Object obj, List<CharSequence> candidates) {
+    private static void addCandidatesForArgsFollowing(Object obj, List<Candidate> candidates) {
         if (obj == null) { return; }
         if (obj instanceof CommandSpec) {
             addCandidatesForArgsFollowing((CommandSpec) obj, candidates);
-        } else if (obj instanceof CommandLine.Model.OptionSpec) {
-            addCandidatesForArgsFollowing((CommandLine.Model.OptionSpec) obj, candidates);
+        } else if (obj instanceof OptionSpec) {
+            addCandidatesForArgsFollowing((OptionSpec) obj, candidates);
         } else if (obj instanceof CommandLine.Model.PositionalParamSpec) {
             addCandidatesForArgsFollowing((CommandLine.Model.PositionalParamSpec) obj, candidates);
         }
     }
-    private static void addCandidatesForArgsFollowing(CommandSpec commandSpec, List<CharSequence> candidates) {
+    private static void addCandidatesForArgsFollowing(CommandSpec commandSpec, List<Candidate> candidates) {
         if (commandSpec == null) { return; }
+
+        // the commandSpec.subcommands() Map contains an entry for every alias of each subcommand
         for (Map.Entry<String, CommandLine> entry : commandSpec.subcommands().entrySet()) {
-            candidates.add(entry.getKey());
-            candidates.addAll(Arrays.asList(entry.getValue().getCommandSpec().aliases()));
+            CommandSpec subSpec = entry.getValue().getCommandSpec();
+            Candidate cmd = new Candidate(entry.getKey(),
+                    entry.getKey(), // display
+                    subSpec.name(), // group
+                    join(subSpec.usageMessage().description(), " "), //desc
+                    null,
+                    subSpec.name(),
+                    true);
+            candidates.add(cmd);
         }
-        candidates.addAll(commandSpec.optionsMap().keySet());
+        for (Map.Entry<String, OptionSpec> entry : commandSpec.optionsMap().entrySet()) {
+            OptionSpec option = entry.getValue();
+            Candidate optionCandidate = new Candidate(entry.getKey(),
+                    entry.getKey(), // display
+                    option.longestName(), // group
+                    join(option.description(), " "), //desc
+                    null,
+                    option.longestName(),
+                    option.arity().max < 1);
+            candidates.add(optionCandidate);
+        }
         for (CommandLine.Model.PositionalParamSpec positional : commandSpec.positionalParameters()) {
             addCandidatesForArgsFollowing(positional, candidates);
         }
     }
-    private static void addCandidatesForArgsFollowing(CommandLine.Model.OptionSpec optionSpec, List<CharSequence> candidates) {
+
+    private static String join(String[] parts, String sep) {
+
+        StringBuilder result = new StringBuilder();
+        for (String part : parts) {
+            if (result.length() > 0) {
+                result.append(sep);
+            }
+            result.append(CommandLine.Help.Ansi.AUTO.string(part));
+        }
+        return result.toString();
+    }
+
+    private static void addCandidatesForArgsFollowing(OptionSpec optionSpec, List<Candidate> candidates) {
         if (optionSpec != null) {
-            addCompletionCandidates(optionSpec.completionCandidates(), candidates);
+            addCompletionCandidates(optionSpec, candidates);
         }
     }
-    private static void addCandidatesForArgsFollowing(CommandLine.Model.PositionalParamSpec positionalSpec, List<CharSequence> candidates) {
+    private static void addCandidatesForArgsFollowing(CommandLine.Model.PositionalParamSpec positionalSpec, List<Candidate> candidates) {
         if (positionalSpec != null) {
-            addCompletionCandidates(positionalSpec.completionCandidates(), candidates);
+            addCompletionCandidates(positionalSpec, candidates);
         }
     }
-    private static void addCompletionCandidates(Iterable<String> completionCandidates, List<CharSequence> candidates) {
-        if (completionCandidates != null) {
-            for (String candidate : completionCandidates) { candidates.add(candidate); }
+    private static void addCompletionCandidates(CommandLine.Model.ArgSpec argSpec, List<Candidate> candidates) {
+        if (argSpec.completionCandidates() != null) {
+            for (String candidate : argSpec.completionCandidates()) {
+                candidates.add(new Candidate(candidate,
+                        candidate, // display
+                        argSpec.paramLabel(), // group
+                        null, //join(argSpec.description(), " "),
+                        null,
+                        null,
+                        true));
+            }
         }
     }
 }