8153920: jshell tool: allow a parameter on the /vars /methods /classes commands
authorrfield
Mon, 16 May 2016 21:46:32 -0700
changeset 38514 f7df9ab653b0
parent 38513 0ae85633d035
child 38515 6ae7f7d9b44c
8153920: jshell tool: allow a parameter on the /vars /methods /classes commands Reviewed-by: vromero
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
langtools/test/jdk/jshell/CommandCompletionTest.java
langtools/test/jdk/jshell/EditorTestBase.java
langtools/test/jdk/jshell/ReplToolTesting.java
langtools/test/jdk/jshell/ToolBasicTest.java
langtools/test/jdk/jshell/ToolReloadTest.java
langtools/test/jdk/jshell/ToolSimpleTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon May 16 21:46:32 2016 -0700
@@ -917,11 +917,10 @@
                                     p.getFileName().toString().endsWith(".jar"));
     }
 
-    private CompletionProvider editCompletion() {
+    private CompletionProvider snippetCompletion(Supplier<List<? extends Snippet>> snippetsSupplier) {
         return (prefix, cursor, anchor) -> {
             anchor[0] = 0;
-            return state.snippets()
-                        .stream()
+            return snippetsSupplier.get()                        .stream()
                         .flatMap(k -> (k instanceof DeclarationSnippet)
                                 ? Stream.of(String.valueOf(k.id()), ((DeclarationSnippet) k).name())
                                 : Stream.of(String.valueOf(k.id())))
@@ -931,11 +930,11 @@
         };
     }
 
-    private CompletionProvider editKeywordCompletion() {
+    private CompletionProvider snippetKeywordCompletion(Supplier<List<? extends Snippet>> snippetsSupplier) {
         return (code, cursor, anchor) -> {
             List<Suggestion> result = new ArrayList<>();
             result.addAll(KEYWORD_COMPLETION_PROVIDER.completionSuggestions(code, cursor, anchor));
-            result.addAll(editCompletion().completionSuggestions(code, cursor, anchor));
+            result.addAll(snippetCompletion(snippetsSupplier).completionSuggestions(code, cursor, anchor));
             return result;
         };
     }
@@ -963,18 +962,51 @@
         };
     }
 
+    // Snippet lists
+
+    List<Snippet> allSnippets() {
+        return state.snippets();
+    }
+
+    List<Snippet> dropableSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> state.status(sn).isActive)
+                .collect(toList());
+    }
+
+    List<VarSnippet> allVarSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> sn.kind() == Snippet.Kind.VAR)
+                .map(sn -> (VarSnippet) sn)
+                .collect(toList());
+    }
+
+    List<MethodSnippet> allMethodSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> sn.kind() == Snippet.Kind.METHOD)
+                .map(sn -> (MethodSnippet) sn)
+                .collect(toList());
+    }
+
+    List<TypeDeclSnippet> allTypeSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> sn.kind() == Snippet.Kind.TYPE_DECL)
+                .map(sn -> (TypeDeclSnippet) sn)
+                .collect(toList());
+    }
+
     // Table of commands -- with command forms, argument kinds, helpKey message, implementation, ...
 
     {
         registerCommand(new Command("/list",
                 arg -> cmdList(arg),
-                editKeywordCompletion()));
+                snippetKeywordCompletion(this::allSnippets)));
         registerCommand(new Command("/edit",
                 arg -> cmdEdit(arg),
-                editCompletion()));
+                snippetCompletion(this::allSnippets)));
         registerCommand(new Command("/drop",
                 arg -> cmdDrop(arg),
-                editCompletion(),
+                snippetCompletion(this::dropableSnippets),
                 CommandKind.REPLAY));
         registerCommand(new Command("/save",
                 arg -> cmdSave(arg),
@@ -983,14 +1015,14 @@
                 arg -> cmdOpen(arg),
                 FILE_COMPLETION_PROVIDER));
         registerCommand(new Command("/vars",
-                arg -> cmdVars(),
-                EMPTY_COMPLETION_PROVIDER));
+                arg -> cmdVars(arg),
+                snippetKeywordCompletion(this::allVarSnippets)));
         registerCommand(new Command("/methods",
-                arg -> cmdMethods(),
-                EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/classes",
-                arg -> cmdClasses(),
-                EMPTY_COMPLETION_PROVIDER));
+                arg -> cmdMethods(arg),
+                snippetKeywordCompletion(this::allMethodSnippets)));
+        registerCommand(new Command("/types",
+                arg -> cmdTypes(arg),
+                snippetKeywordCompletion(this::allTypeSnippets)));
         registerCommand(new Command("/imports",
                 arg -> cmdImports(),
                 EMPTY_COMPLETION_PROVIDER));
@@ -1312,7 +1344,7 @@
     /**
      * Avoid parameterized varargs possible heap pollution warning.
      */
-    private interface SnippetPredicate extends Predicate<Snippet> { }
+    private interface SnippetPredicate<T extends Snippet> extends Predicate<T> { }
 
     /**
      * Apply filters to a stream until one that is non-empty is found.
@@ -1322,10 +1354,11 @@
      * @param filters Filters to attempt
      * @return The non-empty filtered Stream, or null
      */
-    private static Stream<Snippet> nonEmptyStream(Supplier<Stream<Snippet>> supplier,
-            SnippetPredicate... filters) {
-        for (SnippetPredicate filt : filters) {
-            Iterator<Snippet> iterator = supplier.get().filter(filt).iterator();
+    @SafeVarargs
+    private static <T extends Snippet> Stream<T> nonEmptyStream(Supplier<Stream<T>> supplier,
+            SnippetPredicate<T>... filters) {
+        for (SnippetPredicate<T> filt : filters) {
+            Iterator<T> iterator = supplier.get().filter(filt).iterator();
             if (iterator.hasNext()) {
                 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
             }
@@ -1354,11 +1387,27 @@
      * Convert a user argument to a Stream of snippets referenced by that argument
      * (or lack of argument).
      *
-     * @param arg The user's argument to the command, maybe be the empty string
+     * @param snippets the base list of possible snippets
+     * @param arg the user's argument to the command, maybe be the empty string
+     * @param allowAll if true, allow the use of 'all' and 'start'
      * @return a Stream of referenced snippets or null if no matches to specific arg
      */
-    private Stream<Snippet> argToSnippets(String arg, boolean allowAll) {
-        List<Snippet> snippets = state.snippets();
+    private <T extends Snippet> Stream<T> argToSnippets(List<T> snippets, String arg, boolean allowAll) {
+        return argToSnippets(snippets, this::mainActive, arg, allowAll);
+    }
+
+    /**
+     * Convert a user argument to a Stream of snippets referenced by that argument
+     * (or lack of argument).
+     *
+     * @param snippets the base list of possible snippets
+     * @param defFilter the filter to apply to the arguments if no argument
+     * @param arg the user's argument to the command, maybe be the empty string
+     * @param allowAll if true, allow the use of 'all' and 'start'
+     * @return a Stream of referenced snippets or null if no matches to specific arg
+     */
+    private <T extends Snippet> Stream<T> argToSnippets(List<T> snippets,
+            Predicate<Snippet> defFilter, String arg, boolean allowAll) {
         if (allowAll && arg.equals("all")) {
             // all snippets including start-up, failed, and overwritten
             return snippets.stream();
@@ -1369,9 +1418,9 @@
         } else if (arg.isEmpty()) {
             // Default is all active user snippets
             return snippets.stream()
-                    .filter(this::mainActive);
+                    .filter(defFilter);
         } else {
-            Stream<Snippet> result =
+            Stream<T> result =
                     nonEmptyStream(
                             () -> snippets.stream(),
                             // look for active user declarations matching the name
@@ -1385,12 +1434,39 @@
         }
     }
 
+    /**
+     * Convert a user argument to a Stream of snippets referenced by that
+     * argument, printing an informative message if no matches. Allow 'all' and
+     * 'start'.
+     *
+     * @param snippets the base list of possible snippets
+     * @param defFilter the filter to apply to the arguments if no argument
+     * @param arg the user's argument to the command, maybe be the empty string
+     * @param cmd the name of the command (for use in a help message
+     * @return a Stream of referenced snippets or null if no matches to specific
+     * arg
+     */
+    private <T extends Snippet> Stream<T> argToSnippetsWithMessage(List<T> snippets,
+            Predicate<Snippet> defFilter, String arg, String cmd) {
+        Stream<T> stream = argToSnippets(snippets, defFilter, arg, true);
+        if (stream == null) {
+            errormsg("jshell.err.def.or.id.not.found", arg);
+            // Check if there are any definitions at all
+            if (argToSnippets(snippets, "", false).iterator().hasNext()) {
+                fluffmsg("jshell.msg.try.command.without.args", cmd);
+            } else {
+                hardmsg("jshell.msg.no.active");
+            }
+        }
+        return stream;
+    }
+
     private boolean cmdDrop(String arg) {
         if (arg.isEmpty()) {
             errormsg("jshell.err.drop.arg");
             return false;
         }
-        Stream<Snippet> stream = argToSnippets(arg, false);
+        Stream<Snippet> stream = argToSnippets(dropableSnippets(), arg, false);
         if (stream == null) {
             errormsg("jshell.err.def.or.id.not.found", arg);
             fluffmsg("jshell.msg.see.classes.etc");
@@ -1417,10 +1493,9 @@
     }
 
     private boolean cmdEdit(String arg) {
-        Stream<Snippet> stream = argToSnippets(arg, true);
+        Stream<Snippet> stream = argToSnippetsWithMessage(state.snippets(),
+                this::mainActive, arg, "/edit");
         if (stream == null) {
-            errormsg("jshell.err.def.or.id.not.found", arg);
-            fluffmsg("jshell.msg.see.classes.etc");
             return false;
         }
         Set<String> srcSet = new LinkedHashSet<>();
@@ -1523,15 +1598,9 @@
         if (arg.equals("history")) {
             return cmdHistory();
         }
-        Stream<Snippet> stream = argToSnippets(arg, true);
+        Stream<Snippet> stream = argToSnippetsWithMessage(state.snippets(),
+                this::mainActive, arg, "/list");
         if (stream == null) {
-            errormsg("jshell.err.def.or.id.not.found", arg);
-            // Check if there are any definitions at all
-            if (argToSnippets("", false).iterator().hasNext()) {
-                fluffmsg("jshell.msg.try.list.without.args");
-            } else {
-                hardmsg("jshell.msg.no.active");
-            }
             return false;
         }
 
@@ -1662,7 +1731,7 @@
             } else if (saveStart) {
                 writer.append(DEFAULT_STARTUP);
             } else {
-                Stream<Snippet> stream = argToSnippets(saveAll, true);
+                Stream<Snippet> stream = argToSnippets(state.snippets(), saveAll, true);
                 if (stream != null) {
                     for (Snippet sn : stream.collect(toList())) {
                         writer.write(sn.source());
@@ -1680,25 +1749,42 @@
         return true;
     }
 
-    private boolean cmdVars() {
-        for (VarSnippet vk : state.variables()) {
+    private boolean cmdVars(String arg) {
+        Stream<VarSnippet> stream = argToSnippetsWithMessage(allVarSnippets(),
+                this::isActive, arg, "/vars");
+        if (stream == null) {
+            return false;
+        }
+        stream.forEachOrdered(vk ->
+        {
             String val = state.status(vk) == Status.VALID
                     ? state.varValue(vk)
                     : "jshell.msg.vars.not.active";
             hard("  %s %s = %s", vk.typeName(), vk.name(), val);
-        }
+        });
         return true;
     }
 
-    private boolean cmdMethods() {
-        for (MethodSnippet mk : state.methods()) {
-            hard("  %s %s", mk.name(), mk.signature());
+    private boolean cmdMethods(String arg) {
+        Stream<MethodSnippet> stream = argToSnippetsWithMessage(allMethodSnippets(),
+                this::isActive, arg, "/methods");
+        if (stream == null) {
+            return false;
         }
+        stream.forEachOrdered(mk
+                -> hard("  %s %s", mk.name(), mk.signature())
+        );
         return true;
     }
 
-    private boolean cmdClasses() {
-        for (TypeDeclSnippet ck : state.types()) {
+    private boolean cmdTypes(String arg) {
+        Stream<TypeDeclSnippet> stream = argToSnippetsWithMessage(allTypeSnippets(),
+                this::isActive, arg, "/types");
+        if (stream == null) {
+            return false;
+        }
+        stream.forEachOrdered(ck
+        -> {
             String kind;
             switch (ck.subKind()) {
                 case INTERFACE_SUBKIND:
@@ -1719,7 +1805,7 @@
                     break;
             }
             hard("  %s %s", kind, ck.name());
-        }
+        });
         return true;
     }
 
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Mon May 16 21:46:32 2016 -0700
@@ -37,8 +37,8 @@
 Restore definitions with: /reload restore
 
 jshell.msg.use.one.of = Use one of: {0}
-jshell.err.def.or.id.not.found = No definition or id found named: {0}
-jshell.msg.see.classes.etc = See /classes, /methods, /vars, or /list
+jshell.err.def.or.id.not.found = No applicable definition or id found named: {0}
+jshell.msg.see.classes.etc = See /types, /methods, /vars, or /list
 jshell.err.arg = Invalid ''{0}'' argument: {1}
 jshell.msg.see = See {0} for help.
 
@@ -57,7 +57,7 @@
 jshell.err.cant.launch.editor = Cannot launch editor -- unexpected exception: {0}
 jshell.msg.try.set.editor = Try /set editor to use external editor.
 
-jshell.msg.try.list.without.args = Try ''/list'' without arguments.
+jshell.msg.try.command.without.args = Try ''{0}'' without arguments.
 jshell.msg.no.active = There are no active definitions.
 
 jshell.msg.resetting = Resetting...
@@ -151,7 +151,7 @@
 \    -version             Version information\n
 
 help.list.summary = list the source you have typed
-help.list.args = [all|start|<name or id>]
+help.list.args = [<name or id>|all|start]
 help.list =\
 Show the source of snippets, prefaced with the snippet id.\n\
 \n\
@@ -214,19 +214,52 @@
     Read the specified file as jshell input.
 
 help.vars.summary = list the declared variables and their values
-help.vars.args =
+help.vars.args = [<name or id>|all|start]
 help.vars =\
-List the type, name, and value of the current active jshell variables.
+List the type, name, and value of jshell variables.\n\
+\n\
+/vars\n\t\
+    List the type, name, and value of the current active jshell variables\n\n\
+/vars <name>\n\t\
+    List jshell variables with the specified name (preference for active variables)\n\n\
+/vars <id>\n\t\
+    List the jshell variable with the specified snippet id\n\n\
+/vars start\n\t\
+    List the automatically added start-up jshell variables\n\n\
+/vars all\n\t\
+    List all jshell variables including failed, overwritten, dropped, and start-up
 
 help.methods.summary = list the declared methods and their signatures
-help.methods.args =
+help.methods.args = [<name or id>|all|start]
 help.methods =\
-List the name, parameter types, and return type of the current active jshell methods.
+List the name, parameter types, and return type of jshell methods.\n\
+\n\
+/methods\n\t\
+    List the name, parameter types, and return type of the current active jshell methods\n\n\
+/methods <name>\n\t\
+    List jshell methods with the specified name (preference for active methods)\n\n\
+/methods <id>\n\t\
+    List the jshell method with the specified snippet id\n\n\
+/methods start\n\t\
+    List the automatically added start-up jshell methods\n\n\
+/methods all\n\t\
+    List all snippets including failed, overwritten, dropped, and start-up
 
-help.classes.summary = list the declared classes
-help.classes.args =
-help.classes =\
-List the current active jshell classes, interfaces, and enums.
+help.types.summary = list the declared types
+help.types.args =[<name or id>|all|start]
+help.types =\
+List jshell classes, interfaces, and enums.\n\
+\n\
+/types\n\t\
+    List the current active jshell classes, interfaces, and enums.\n\n\
+/types <name>\n\t\
+    List jshell types with the specified name (preference for active types)\n\n\
+/types <id>\n\t\
+    List the jshell type with the specified snippet id\n\n\
+/types start\n\t\
+    List the automatically added start-up jshell types\n\n\
+/types all\n\t\
+    List all jshell types including failed, overwritten, dropped, and start-up
 
 help.imports.summary = list the imported items
 help.imports.args =
@@ -304,7 +337,7 @@
      Display information about the specified help subject. Example: /help intro
 
 help.set.summary = set jshell configuration information
-help.set.args = editor|start|feedback|newmode|prompt|format ...
+help.set.args = editor|start|feedback|newmode|prompt|truncation|format ...
 help.set =\
 Set jshell configuration information, including:\n\
 the external editor to use, the start-up definitions to use, a new feedback mode,\n\
--- a/langtools/test/jdk/jshell/CommandCompletionTest.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/test/jdk/jshell/CommandCompletionTest.java	Mon May 16 21:46:32 2016 -0700
@@ -53,7 +53,7 @@
 
     public void testCommand() {
         assertCompletion("/deb|", false);
-        assertCompletion("/c|", false, "/classes ", "/classpath ");
+        assertCompletion("/re|", false, "/reload ", "/reset ");
         assertCompletion("/h|", false, "/help ", "/history ");
     }
 
--- a/langtools/test/jdk/jshell/EditorTestBase.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/test/jdk/jshell/EditorTestBase.java	Mon May 16 21:46:32 2016 -0700
@@ -142,7 +142,7 @@
                     exit();
                     loadClass(true, "enum A {}", "enum", "A");
                 }),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses())
+                a -> assertCommandCheckOutput(a, "/types", assertClasses())
         );
     }
 
@@ -161,7 +161,7 @@
                     exit();
                     loadClass(true, "enum A {}", "enum", "A");
                 }),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses())
+                a -> assertCommandCheckOutput(a, "/types", assertClasses())
         );
     }
 
--- a/langtools/test/jdk/jshell/ReplToolTesting.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/test/jdk/jshell/ReplToolTesting.java	Mon May 16 21:46:32 2016 -0700
@@ -70,6 +70,9 @@
                     new MethodInfo("void printf(String format, Object... args) { System.out.printf(format, args); }",
                             "(String,Object...)void", "printf"))
                     .collect(toList());
+    final static List<String> START_UP_CMD_METHOD = Stream.of(
+                    "|    printf (String,Object...)void")
+                    .collect(toList());
     final static List<String> START_UP = Collections.unmodifiableList(
             Stream.concat(START_UP_IMPORTS.stream(), START_UP_METHODS.stream())
             .map(s -> s.getSource())
--- a/langtools/test/jdk/jshell/ToolBasicTest.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/test/jdk/jshell/ToolBasicTest.java	Mon May 16 21:46:32 2016 -0700
@@ -118,9 +118,9 @@
                     (a) -> assertCommand(a, "class A {" + s, ""),
                     interrupt,
                     (a) -> assertCommand(a, "class A {}\u0003", ""),
-                    (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                    (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                     (a) -> assertClass(a, "interface A {}", "interface", "A"),
-                    (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                    (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                     (a) -> assertCommand(a, "import java.util.stream." + s, ""),
                     interrupt,
                     (a) -> assertCommand(a, "import java.util.stream.\u0003", ""),
@@ -338,13 +338,13 @@
                 (a) -> assertMethod(a, "void f() { }", "()void", "f"),
                 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
                 (a) -> assertClass(a, "class A { }", "class", "A"),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
                 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
                 (a) -> assertReset(a, "/reset"),
                 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 (a) -> assertCommandCheckOutput(a, "/imports", assertImports())
         );
     }
@@ -369,7 +369,7 @@
                         loadClass(a, "class A { public String toString() { return \"A\"; } }",
                                 "class", "A");
                         loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*");
-                        assertCommandCheckOutput(a, "/classes", assertClasses());
+                        assertCommandCheckOutput(a, "/types", assertClasses());
                     },
                     (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
                     (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
@@ -451,7 +451,7 @@
                         loadVariable(a, "double", "b", "10.0", "10.0");
                         loadMethod(a, "void f() {}", "()void", "f");
                         loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*");
-                        assertCommandCheckOutput(a, "/classes", assertClasses());
+                        assertCommandCheckOutput(a, "/types", assertClasses());
                     },
                     (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                     (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
--- a/langtools/test/jdk/jshell/ToolReloadTest.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/test/jdk/jshell/ToolReloadTest.java	Mon May 16 21:46:32 2016 -0700
@@ -107,7 +107,7 @@
                         "-: /drop A\n"),
                 a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 a -> assertCommandCheckOutput(a, "/imports", assertImports())
         );
     }
@@ -124,7 +124,7 @@
                         "|  Restarting and restoring state."),
                 a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 a -> assertCommandCheckOutput(a, "/imports", assertImports())
         );
     }
--- a/langtools/test/jdk/jshell/ToolSimpleTest.java	Mon May 16 21:25:44 2016 -0700
+++ b/langtools/test/jdk/jshell/ToolSimpleTest.java	Mon May 16 21:46:32 2016 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955 8151754 8150382
+ * @bug 8153716 8143955 8151754 8150382 8153920
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -101,22 +101,22 @@
         );
     }
 
-    public void defineClasses() {
+    public void defineTypes() {
         test(
                 (a) -> assertCommandCheckOutput(a, "/list", assertList()),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 (a) -> assertClass(a, "class A { }", "class", "A"),
                 (a) -> assertCommandCheckOutput(a, "/list", assertList()),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 (a) -> assertClass(a, "interface A { }", "interface", "A"),
                 (a) -> assertCommandCheckOutput(a, "/list", assertList()),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 (a) -> assertClass(a, "enum A { }", "enum", "A"),
                 (a) -> assertCommandCheckOutput(a, "/list", assertList()),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 (a) -> assertClass(a, "@interface A { }", "@interface", "A"),
                 (a) -> assertCommandCheckOutput(a, "/list", assertList()),
-                (a) -> assertCommandCheckOutput(a, "/classes", assertClasses())
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses())
         );
     }
 
@@ -211,7 +211,7 @@
                 a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""),
                 a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 a -> assertCommandCheckOutput(a, "/imports", assertImports())
         );
         test(false, new String[]{"-nostartup"},
@@ -223,15 +223,15 @@
                 a -> dropClass(a, "/drop A", "class A", "|  dropped class A"),
                 a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 a -> assertCommandCheckOutput(a, "/imports", assertImports())
         );
     }
 
     public void testDropNegative() {
         test(false, new String[]{"-nostartup"},
-                a -> assertCommandOutputStartsWith(a, "/drop 0", "|  No definition or id found named: 0"),
-                a -> assertCommandOutputStartsWith(a, "/drop a", "|  No definition or id found named: a"),
+                a -> assertCommandOutputStartsWith(a, "/drop 0", "|  No applicable definition or id found named: 0"),
+                a -> assertCommandOutputStartsWith(a, "/drop a", "|  No applicable definition or id found named: a"),
                 a -> assertCommandCheckOutput(a, "/drop",
                         assertStartsWith("|  In the /drop argument, please specify an import, variable, method, or class to drop.")),
                 a -> assertVariable(a, "int", "a"),
@@ -253,7 +253,7 @@
                 a -> assertCommandCheckOutput(a, "/drop a", check),
                 a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses()),
+                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
                 a -> assertCommandCheckOutput(a, "/imports", assertImports())
         );
         test(
@@ -299,7 +299,10 @@
 
     // Check that each line of output contains the corresponding string from the list
     private void checkLineToList(String in, List<String> match) {
-        String[] res = in.trim().split("\n");
+        String trimmed = in.trim();
+        String[] res = trimmed.isEmpty()
+                ? new String[0]
+                : trimmed.split("\n");
         assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res));
         for (int i = 0; i < match.size(); ++i) {
             assertTrue(res[i].contains(match.get(i)));
@@ -314,7 +317,7 @@
                 a -> assertCommandCheckOutput(a, "/list all",
                         s -> checkLineToList(s, START_UP)),
                 a -> assertCommandOutputStartsWith(a, "/list " + arg,
-                        "|  No definition or id found named: " + arg),
+                        "|  No applicable definition or id found named: " + arg),
                 a -> assertVariable(a, "int", "aardvark"),
                 a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"),
                 a -> assertCommandCheckOutput(a, "/list start",
@@ -324,10 +327,118 @@
                 a -> assertCommandCheckOutput(a, "/list printf",
                         s -> assertTrue(s.contains("void printf"))),
                 a -> assertCommandOutputStartsWith(a, "/list " + arg,
-                        "|  No definition or id found named: " + arg)
+                        "|  No applicable definition or id found named: " + arg)
+        );
+    }
+
+    public void testVarsArgs() {
+        String arg = "qqqq";
+        List<String> startVarList = new ArrayList<>();
+        test(
+                a -> assertCommandCheckOutput(a, "/vars all",
+                        s -> checkLineToList(s, startVarList)),
+                a -> assertCommandOutputStartsWith(a, "/vars " + arg,
+                        "|  No applicable definition or id found named: " + arg),
+                a -> assertVariable(a, "int", "aardvark"),
+                a -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
+                a -> assertVariable(a, "int", "a"),
+                a -> assertVariable(a, "double", "a", "1", "1.0"),
+                a -> assertCommandOutputStartsWith(a, "/vars aardvark", "|    int aardvark = 0"),
+                a -> assertCommandCheckOutput(a, "/vars start",
+                        s -> checkLineToList(s, startVarList)),
+                a -> assertCommandOutputStartsWith(a, "/vars all",
+                        "|    int aardvark = 0\n|    int a = "),
+                a -> assertCommandOutputStartsWith(a, "/vars printf",
+                        "|  No applicable definition or id found named: printf"),
+                a -> assertCommandOutputStartsWith(a, "/vars " + arg,
+                        "|  No applicable definition or id found named: " + arg)
         );
     }
 
+    public void testMethodsArgs() {
+        String arg = "qqqq";
+        List<String> startMethodList = new ArrayList<>(START_UP_CMD_METHOD);
+        test(
+                a -> assertCommandCheckOutput(a, "/methods all",
+                        s -> checkLineToList(s, startMethodList)),
+                a -> assertCommandCheckOutput(a, "/methods start",
+                        s -> checkLineToList(s, startMethodList)),
+                a -> assertCommandCheckOutput(a, "/methods printf",
+                        s -> checkLineToList(s, startMethodList)),
+                a -> assertCommandCheckOutput(a, "/methods",
+                        s -> checkLineToList(s, startMethodList)),
+                a -> assertCommandOutputStartsWith(a, "/methods " + arg,
+                        "|  No applicable definition or id found named: " + arg),
+                a -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
+                a -> assertVariable(a, "int", "aardvark"),
+                a -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"),
+                a -> assertMethod(a, "void g() {}", "()void", "g"),
+                a -> assertCommandOutputStartsWith(a, "/methods " + arg,
+                        "|  No applicable definition or id found named: " + arg),
+                a -> assertCommandOutputStartsWith(a, "/methods aardvark",
+                        "|  No applicable definition or id found named: aardvark"),
+                a -> assertCommandCheckOutput(a, "/methods start",
+                        s -> checkLineToList(s, startMethodList)),
+                a -> assertCommandCheckOutput(a, "/methods printf",
+                        s -> checkLineToList(s, startMethodList)),
+                a -> assertCommandOutputStartsWith(a, "/methods g",
+                        "|    g ()void"),
+                a -> assertCommandOutputStartsWith(a, "/methods f",
+                        "|    f ()int\n" +
+                        "|    f (int)void")
+        );
+    }
+
+    public void testTypesArgs() {
+        String arg = "qqqq";
+        List<String> startTypeList = new ArrayList<>();
+        test(
+                a -> assertCommandCheckOutput(a, "/types all",
+                        s -> checkLineToList(s, startTypeList)),
+                a -> assertCommandCheckOutput(a, "/types start",
+                        s -> checkLineToList(s, startTypeList)),
+                a -> assertCommandOutputStartsWith(a, "/types " + arg,
+                        "|  No applicable definition or id found named: " + arg),
+                a -> assertVariable(a, "int", "aardvark"),
+                (a) -> assertClass(a, "class A { }", "class", "A"),
+                (a) -> assertClass(a, "interface A { }", "interface", "A"),
+                a -> assertCommandOutputStartsWith(a, "/types all",
+                        "|    class A\n" +
+                        "|    interface A"),
+                (a) -> assertClass(a, "enum E { }", "enum", "E"),
+                (a) -> assertClass(a, "@interface B { }", "@interface", "B"),
+                a -> assertCommandOutputStartsWith(a, "/types aardvark",
+                        "|  No applicable definition or id found named: aardvark"),
+                a -> assertCommandOutputStartsWith(a, "/types A",
+                        "|    interface A"),
+                a -> assertCommandOutputStartsWith(a, "/types E",
+                        "|    enum E"),
+                a -> assertCommandOutputStartsWith(a, "/types B",
+                        "|    @interface B"),
+                a -> assertCommandOutputStartsWith(a, "/types " + arg,
+                        "|  No applicable definition or id found named: " + arg),
+                a -> assertCommandCheckOutput(a, "/types start",
+                        s -> checkLineToList(s, startTypeList))
+        );
+    }
+    public void defineClasses() {
+        test(
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
+                (a) -> assertClass(a, "class A { }", "class", "A"),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
+                (a) -> assertClass(a, "interface A { }", "interface", "A"),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
+                (a) -> assertClass(a, "enum A { }", "enum", "A"),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
+                (a) -> assertClass(a, "@interface A { }", "@interface", "A"),
+                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
+                (a) -> assertCommandCheckOutput(a, "/types", assertClasses())
+        );
+    }
     public void testCommandPrefix() {
         test(a -> assertCommandCheckOutput(a, "/s",
                       assertStartsWith("|  Command: '/s' is ambiguous: /save, /set")),