# HG changeset patch # User jlahoda # Date 1448901115 -3600 # Node ID 7af94fd75ede254c7dd487407b88c6aa70ebdcca # Parent 14deea5f86f1cb22069164d5481cfd079fe87868 8143037: JShell should determine commands by prefix Reviewed-by: rfield, mcimadamore, briangoetz diff -r 14deea5f86f1 -r 7af94fd75ede langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Thu Nov 26 17:38:15 2015 +0530 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Mon Nov 30 17:31:55 2015 +0100 @@ -97,8 +97,8 @@ public class JShellTool { private static final Pattern LINEBREAK = Pattern.compile("\\R"); - private static final Pattern HISTORY_ALL_FILENAME = Pattern.compile( - "((?(all|history))(\\z|\\p{javaWhitespace}+))?(?.*)"); + private static final Pattern HISTORY_ALL_START_FILENAME = Pattern.compile( + "((?(all|history|start))(\\z|\\p{javaWhitespace}+))?(?.*)"); final InputStream cmdin; final PrintStream cmdout; @@ -504,15 +504,30 @@ arg = cmd.substring(idx + 1).trim(); cmd = cmd.substring(0, idx); } - Command command = commands.get(cmd); - if (command == null || command.kind == CommandKind.HELP_ONLY) { + Command[] candidates = findCommand(cmd, c -> c.kind != CommandKind.HELP_ONLY); + if (candidates.length == 0) { hard("No such command: %s", cmd); fluff("Type /help for help."); + } else if (candidates.length == 1) { + candidates[0].run.accept(arg); } else { - command.run.accept(arg); + hard("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); + fluff("Type /help for help."); } } + private Command[] findCommand(String cmd, Predicate filter) { + Command exact = commands.get(cmd); + if (exact != null) + return new Command[] {exact}; + + return commands.values() + .stream() + .filter(filter) + .filter(command -> command.command.startsWith(cmd)) + .toArray(size -> new Command[size]); + } + private static Path toPathResolvingUserHome(String pathString) { if (pathString.replace(File.separatorChar, '/').startsWith("~/")) return Paths.get(System.getProperty("user.home"), pathString.substring(2)); @@ -521,19 +536,19 @@ } static final class Command { - public final String[] aliases; + public final String command; public final String params; public final String description; public final Consumer run; public final CompletionProvider completions; public final CommandKind kind; - public Command(String command, String alias, String params, String description, Consumer run, CompletionProvider completions) { - this(command, alias, params, description, run, completions, CommandKind.NORMAL); + public Command(String command, String params, String description, Consumer run, CompletionProvider completions) { + this(command, params, description, run, completions, CommandKind.NORMAL); } - public Command(String command, String alias, String params, String description, Consumer run, CompletionProvider completions, CommandKind kind) { - this.aliases = alias != null ? new String[] {command, alias} : new String[] {command}; + public Command(String command, String params, String description, Consumer run, CompletionProvider completions, CommandKind kind) { + this.command = command; this.params = params; this.description = description; this.run = run; @@ -582,9 +597,7 @@ private static final CompletionProvider FILE_COMPLETION_PROVIDER = fileCompletions(p -> true); private final Map commands = new LinkedHashMap<>(); private void registerCommand(Command cmd) { - for (String str : cmd.aliases) { - commands.put(str, cmd); - } + commands.put(cmd.command, cmd); } private static CompletionProvider fileCompletions(Predicate accept) { return (code, cursor, anchor) -> { @@ -632,7 +645,7 @@ } private static CompletionProvider saveCompletion() { - CompletionProvider keyCompletion = new FixedCompletionProvider("all ", "history "); + CompletionProvider keyCompletion = new FixedCompletionProvider("all ", "history ", "start "); return (code, cursor, anchor) -> { List result = new ArrayList<>(); int space = code.indexOf(' '); @@ -648,75 +661,78 @@ // Table of commands -- with command forms, argument kinds, help message, implementation, ... { - registerCommand(new Command("/list", "/l", "[all]", "list the source you have typed", + registerCommand(new Command("/list", "[all]", "list the source you have typed", arg -> cmdList(arg), new FixedCompletionProvider("all"))); - registerCommand(new Command("/seteditor", null, "", "set the external editor command to use", + registerCommand(new Command("/seteditor", "", "set the external editor command to use", arg -> cmdSetEditor(arg), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/edit", "/e", "", "edit a source entry referenced by name or id", + registerCommand(new Command("/edit", "", "edit a source entry referenced by name or id", arg -> cmdEdit(arg), editCompletion())); - registerCommand(new Command("/drop", "/d", "", "delete a source entry referenced by name or id", + registerCommand(new Command("/drop", "", "delete a source entry referenced by name or id", arg -> cmdDrop(arg), editCompletion())); - registerCommand(new Command("/save", "/s", "[all|history] ", "save the source you have typed", + registerCommand(new Command("/save", "[all|history|start] ", "save: - current source;\n" + + " all - source including overwritten, failed, and start-up code;\n" + + " history - editing history;\n" + + " start - default start-up definitions", arg -> cmdSave(arg), saveCompletion())); - registerCommand(new Command("/open", "/o", "", "open a file as source input", + registerCommand(new Command("/open", "", "open a file as source input", arg -> cmdOpen(arg), FILE_COMPLETION_PROVIDER)); - registerCommand(new Command("/vars", "/v", null, "list the declared variables and their values", + registerCommand(new Command("/vars", null, "list the declared variables and their values", arg -> cmdVars(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/methods", "/m", null, "list the declared methods and their signatures", + registerCommand(new Command("/methods", null, "list the declared methods and their signatures", arg -> cmdMethods(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/classes", "/c", null, "list the declared classes", + registerCommand(new Command("/classes", null, "list the declared classes", arg -> cmdClasses(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/imports", "/i", null, "list the imported items", + registerCommand(new Command("/imports", null, "list the imported items", arg -> cmdImports(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/exit", "/x", null, "exit the REPL", + registerCommand(new Command("/exit", null, "exit the REPL", arg -> cmdExit(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/reset", "/r", null, "reset everything in the REPL", + registerCommand(new Command("/reset", null, "reset everything in the REPL", arg -> cmdReset(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/feedback", "/f", "", "feedback information: off, concise, normal, verbose, default, or ?", + registerCommand(new Command("/feedback", "", "feedback information: off, concise, normal, verbose, default, or ?", arg -> cmdFeedback(arg), new FixedCompletionProvider("off", "concise", "normal", "verbose", "default", "?"))); - registerCommand(new Command("/prompt", "/p", null, "toggle display of a prompt", + registerCommand(new Command("/prompt", null, "toggle display of a prompt", arg -> cmdPrompt(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/classpath", "/cp", "", "add a path to the classpath", + registerCommand(new Command("/classpath", "", "add a path to the classpath", arg -> cmdClasspath(arg), classPathCompletion())); - registerCommand(new Command("/history", "/h", null, "history of what you have typed", + registerCommand(new Command("/history", null, "history of what you have typed", arg -> cmdHistory(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/setstart", null, "", "read file and set as the new start-up definitions", + registerCommand(new Command("/setstart", "", "read file and set as the new start-up definitions", arg -> cmdSetStart(arg), FILE_COMPLETION_PROVIDER)); - registerCommand(new Command("/savestart", null, "", "save the default start-up definitions to the file", - arg -> cmdSaveStart(arg), - FILE_COMPLETION_PROVIDER)); - registerCommand(new Command("/debug", "/db", "", "toggle debugging of the REPL", + registerCommand(new Command("/debug", "", "toggle debugging of the REPL", arg -> cmdDebug(arg), EMPTY_COMPLETION_PROVIDER, CommandKind.HIDDEN)); - registerCommand(new Command("/help", "/?", "", "this help message", + registerCommand(new Command("/help", "", "this help message", arg -> cmdHelp(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/!", null, "", "re-run last snippet", + registerCommand(new Command("/?", "", "this help message", + arg -> cmdHelp(), + EMPTY_COMPLETION_PROVIDER)); + registerCommand(new Command("/!", "", "re-run last snippet", arg -> cmdUseHistoryEntry(-1), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/", null, "", "re-run n-th snippet", + registerCommand(new Command("/", "", "re-run n-th snippet", arg -> { throw new IllegalStateException(); }, EMPTY_COMPLETION_PROVIDER, CommandKind.HELP_ONLY)); - registerCommand(new Command("/-", null, "", "re-run n-th previous snippet", + registerCommand(new Command("/-", "", "re-run n-th previous snippet", arg -> { throw new IllegalStateException(); }, EMPTY_COMPLETION_PROVIDER, CommandKind.HELP_ONLY)); @@ -732,16 +748,16 @@ .stream() .distinct() .filter(cmd -> cmd.kind != CommandKind.HIDDEN && cmd.kind != CommandKind.HELP_ONLY) - .map(cmd -> cmd.aliases[0]) + .map(cmd -> cmd.command) .filter(key -> key.startsWith(prefix)) .map(key -> new Suggestion(key + " ", false)); anchor[0] = 0; } else { String arg = prefix.substring(space + 1); String cmd = prefix.substring(0, space); - Command command = commands.get(cmd); - if (command != null) { - result = command.completions.completionSuggestions(arg, cursor - space, anchor).stream(); + Command[] candidates = findCommand(cmd, c -> true); + if (candidates.length == 1) { + result = candidates[0].completions.completionSuggestions(arg, cursor - space, anchor).stream(); anchor[0] += space + 1; } else { result = Stream.empty(); @@ -885,12 +901,7 @@ if (cmd.kind == CommandKind.HIDDEN) continue; StringBuilder synopsis = new StringBuilder(); - if (cmd.aliases.length > 1) { - synopsis.append(String.format("%-3s or ", cmd.aliases[1])); - } else { - synopsis.append(" "); - } - synopsis.append(cmd.aliases[0]); + synopsis.append(cmd.command); if (cmd.params != null) synopsis.append(" ").append(cmd.params); synopsis2Description.put(synopsis.toString(), cmd.description); @@ -901,7 +912,9 @@ for (Entry e : synopsis2Description.entrySet()) { cmdout.print(String.format("%-" + synopsisLen + "s", e.getKey())); cmdout.print(" -- "); - cmdout.println(e.getValue()); + String indentedNewLine = System.getProperty("line.separator") + + String.format("%-" + (synopsisLen + 4) + "s", ""); + cmdout.println(e.getValue().replace("\n", indentedNewLine)); } cmdout.println(); cmdout.println("Supported shortcuts include:"); @@ -1141,13 +1154,14 @@ } private void cmdSave(String arg_filename) { - Matcher mat = HISTORY_ALL_FILENAME.matcher(arg_filename); + Matcher mat = HISTORY_ALL_START_FILENAME.matcher(arg_filename); if (!mat.find()) { hard("Malformed argument to the /save command: %s", arg_filename); return; } boolean useHistory = false; boolean saveAll = false; + boolean saveStart = false; String cmd = mat.group("cmd"); if (cmd != null) switch (cmd) { case "all": @@ -1156,6 +1170,9 @@ case "history": useHistory = true; break; + case "start": + saveStart = true; + break; } String filename = mat.group("filename"); if (filename == null ||filename.isEmpty()) { @@ -1170,6 +1187,8 @@ writer.write(s); writer.write("\n"); } + } else if (saveStart) { + writer.append(DEFAULT_STARTUP); } else { for (Snippet sn : state.snippets()) { if (saveAll || notInStartUp(sn)) { @@ -1203,22 +1222,6 @@ } } - private void cmdSaveStart(String filename) { - if (filename.isEmpty()) { - hard("The /savestart command requires a filename argument."); - } else { - try { - Files.write(toPathResolvingUserHome(filename), DEFAULT_STARTUP.getBytes()); - } catch (AccessDeniedException e) { - hard("File '%s' for /savestart is not accessible.", filename); - } catch (NoSuchFileException e) { - hard("File '%s' for /savestart cannot be located.", filename); - } catch (Exception e) { - hard("Exception while saving default startup file: %s", e); - } - } - } - private void cmdVars() { for (VarSnippet vk : state.variables()) { String val = state.status(vk) == Status.VALID diff -r 14deea5f86f1 -r 7af94fd75ede langtools/test/jdk/jshell/CommandCompletionTest.java --- a/langtools/test/jdk/jshell/CommandCompletionTest.java Thu Nov 26 17:38:15 2015 +0530 +++ b/langtools/test/jdk/jshell/CommandCompletionTest.java Mon Nov 30 17:31:55 2015 +0100 @@ -100,9 +100,9 @@ public void testSave() throws IOException { Compiler compiler = new Compiler(); - assertCompletion("/s|", false, "/save ", "/savestart ", "/seteditor ", "/setstart "); + assertCompletion("/s|", false, "/save ", "/seteditor ", "/setstart "); List p1 = listFiles(Paths.get("")); - Collections.addAll(p1, "all ", "history "); + Collections.addAll(p1, "all ", "history ", "start "); FileSystems.getDefault().getRootDirectories().forEach(s -> p1.add(s.toString())); Collections.sort(p1); assertCompletion("/save |", false, p1.toArray(new String[p1.size()])); diff -r 14deea5f86f1 -r 7af94fd75ede langtools/test/jdk/jshell/ToolBasicTest.java --- a/langtools/test/jdk/jshell/ToolBasicTest.java Thu Nov 26 17:38:15 2015 +0530 +++ b/langtools/test/jdk/jshell/ToolBasicTest.java Mon Nov 30 17:31:55 2015 +0100 @@ -23,6 +23,7 @@ /* * @test + * @bug 8143037 * @summary Tests for Basic tests for REPL tool * @ignore 8139873 * @library /tools/lib @@ -124,28 +125,28 @@ interrupt, (a) -> assertCommand(a, "int a\u0003", ""), (a) -> assertCommand(a, "int a = 2 + 2\u0003", ""), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), (a) -> evaluateExpression(a, "int", "2", "2"), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), (a) -> assertCommand(a, "void f() {", ""), (a) -> assertCommand(a, "int q = 10;" + s, ""), interrupt, (a) -> assertCommand(a, "void f() {}\u0003", ""), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertCommand(a, "class A {" + s, ""), interrupt, (a) -> assertCommand(a, "class A {}\u0003", ""), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertClass(a, "interface A {}", "interface", "A"), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertCommand(a, "import java.util.stream." + s, ""), interrupt, (a) -> assertCommand(a, "import java.util.stream.\u0003", ""), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), (a) -> assertImport(a, "import java.util.stream.Stream", "", "java.util.stream.Stream"), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()) + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) ); } } @@ -265,10 +266,10 @@ public void testDebug() { test( - (a) -> assertCommand(a, "/db", "| Debugging on\n"), + (a) -> assertCommand(a, "/deb", "| Debugging on\n"), (a) -> assertCommand(a, "/debug", "| Debugging off\n"), (a) -> assertCommand(a, "/debug", "| Debugging on\n"), - (a) -> assertCommand(a, "/db", "| Debugging off\n") + (a) -> assertCommand(a, "/deb", "| Debugging off\n") ); } @@ -295,106 +296,70 @@ public void defineVariables() { test( - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), (a) -> assertVariable(a, "int", "a"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), (a) -> assertVariable(a, "double", "a", "1", "1.0"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), (a) -> evaluateExpression(a, "double", "2 * a", "2.0"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()) ); } public void defineMethods() { test( - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertMethod(a, "void g() {}", "()void", "g"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) ); } public void defineClasses() { test( - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertClass(a, "class A { }", "class", "A"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertClass(a, "interface A { }", "interface", "A"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertClass(a, "enum A { }", "enum", "A"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertClass(a, "@interface A { }", "@interface", "A"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()) ); } public void defineImports() { test( - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"), - (a) -> assertCommandCheckOutput(a, "/l", assertList()), (a) -> assertCommandCheckOutput(a, "/list", assertList()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) ); } @@ -405,7 +370,7 @@ compiler.compile(outDir, "package pkg; public class A { public String toString() { return \"A\"; } }"); Path classpath = compiler.getPath(outDir); test( - (a) -> assertCommand(a, "/cp " + classpath, String.format("| Path %s added to classpath\n", classpath)), + (a) -> assertCommand(a, "/classpath " + classpath, String.format("| Path %s added to classpath\n", classpath)), (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"A\"") ); test(new String[] { "-cp", classpath.toString() }, @@ -471,20 +436,20 @@ public void testReset() { test( (a) -> assertReset(a, "/r"), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertVariable(a, "int", "x"), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), (a) -> assertMethod(a, "void f() { }", "()void", "f"), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), (a) -> assertClass(a, "class A { }", "class", "A"), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), (a) -> assertReset(a, "/reset"), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), - (a) -> assertCommandCheckOutput(a, "/c", assertClasses()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()) + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/classes", assertClasses()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) ); } @@ -508,11 +473,11 @@ loadClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"); loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*"); - assertCommandCheckOutput(a, "/c", assertClasses()); + assertCommandCheckOutput(a, "/classes", assertClasses()); }, - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()) + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) ); Path unknown = compiler.getPath("UNKNOWN.repl"); test( @@ -531,15 +496,13 @@ "int a;", "class A { public String toString() { return \"A\"; } }" ); - for (String s : new String[]{"/s", "/save"}) { - test( - (a) -> assertVariable(a, "int", "a"), - (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), - (a) -> assertCommand(a, s + " " + path.toString(), "") - ); - assertEquals(Files.readAllLines(path), list); - } - for (String s : new String[]{"/s", "/save"}) { + test( + (a) -> assertVariable(a, "int", "a"), + (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), + (a) -> assertCommand(a, "/save " + path.toString(), "") + ); + assertEquals(Files.readAllLines(path), list); + { List output = new ArrayList<>(); test( (a) -> assertCommand(a, "int a;", null), @@ -550,24 +513,22 @@ .map(str -> str.substring(str.indexOf(':') + 2)) .filter(str -> !str.startsWith("/")) .collect(Collectors.toList()))), - (a) -> assertCommand(a, s + " all " + path.toString(), "") + (a) -> assertCommand(a, "/save all " + path.toString(), "") ); assertEquals(Files.readAllLines(path), output); } - for (String s : new String[]{"/s", "/save"}) { - List output = new ArrayList<>(); - test( - (a) -> assertVariable(a, "int", "a"), - (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), - (a) -> assertCommandCheckOutput(a, "/h", (out) -> - output.addAll(Stream.of(out.split("\n")) - .filter(str -> !str.isEmpty()) - .collect(Collectors.toList()))), - (a) -> assertCommand(a, s + " history " + path.toString(), "") - ); - output.add(s + " history " + path.toString()); - assertEquals(Files.readAllLines(path), output); - } + List output = new ArrayList<>(); + test( + (a) -> assertVariable(a, "int", "a"), + (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), + (a) -> assertCommandCheckOutput(a, "/history", (out) -> + output.addAll(Stream.of(out.split("\n")) + .filter(str -> !str.isEmpty()) + .collect(Collectors.toList()))), + (a) -> assertCommand(a, "/save history " + path.toString(), "") + ); + output.add("/save history " + path.toString()); + assertEquals(Files.readAllLines(path), output); } public void testStartSet() throws BackingStoreException { @@ -579,7 +540,7 @@ (a) -> assertVariable(a, "double", "b", "10", "10.0"), (a) -> assertMethod(a, "void f() {}", "()V", "f"), (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - (a) -> assertCommand(a, "/s " + startUpFile.toString(), null), + (a) -> assertCommand(a, "/save " + startUpFile.toString(), null), (a) -> assertCommand(a, "/setstart " + startUpFile.toString(), null) ); Path unknown = compiler.getPath("UNKNOWN"); @@ -593,11 +554,11 @@ 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, "/c", assertClasses()); + assertCommandCheckOutput(a, "/classes", assertClasses()); }, - (a) -> assertCommandCheckOutput(a, "/v", assertVariables()), - (a) -> assertCommandCheckOutput(a, "/m", assertMethods()), - (a) -> assertCommandCheckOutput(a, "/i", assertImports()) + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), + (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) ); } finally { removeStartup(); @@ -618,24 +579,14 @@ } public void testEmptyClassPath() { - String[] commands = {"/cp", "/classpath"}; - test(Stream.of(commands) - .map(cmd -> (ReplTest) after -> assertCommand(after, cmd, "| /classpath requires a path argument\n")) - .toArray(ReplTest[]::new)); - + test(after -> assertCommand(after, "/classpath", "| /classpath requires a path argument\n")); } public void testNoArgument() { - String[] commands = {"/s", "/save", "/o", "/open", "/setstart", "/savestart"}; + String[] commands = {"/save", "/open", "/setstart"}; test(Stream.of(commands) .map(cmd -> { String c = cmd; - if ("/s".equals(cmd)) { - c = "/save"; - } - if ("/o".equals(cmd)) { - c = "/open"; - } final String finalC = c; return (ReplTest) after -> assertCommand(after, cmd, "| The " + finalC + " command requires a filename argument.\n"); @@ -646,7 +597,7 @@ public void testStartSave() throws IOException { Compiler compiler = new Compiler(); Path startSave = compiler.getPath("startSave.txt"); - test(a -> assertCommand(a, "/savestart " + startSave.toString(), null)); + test(a -> assertCommand(a, "/save start " + startSave.toString(), null)); List lines = Files.lines(startSave) .filter(s -> !s.isEmpty()) .collect(Collectors.toList()); @@ -673,49 +624,42 @@ public void testRemoteExit() { test( a -> assertVariable(a, "int", "x"), - a -> assertCommandCheckOutput(a, "/v", assertVariables()), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), a -> assertCommandCheckOutput(a, "System.exit(5);", s -> assertTrue(s.contains("terminated"), s)), - a -> assertCommandCheckOutput(a, "/v", s -> + a -> assertCommandCheckOutput(a, "/vars", s -> assertTrue(s.trim().isEmpty(), s)), a -> assertMethod(a, "void f() { }", "()void", "f"), - a -> assertCommandCheckOutput(a, "/m", assertMethods()) + a -> assertCommandCheckOutput(a, "/methods", assertMethods()) ); } public void testListArgs() { - Consumer assertList = s -> assertTrue(s.split("\n").length >= 7, s); + Consumer assertList = s -> assertTrue(s.split("\n").length >= 4, s); String arg = "qqqq"; Consumer assertError = s -> assertEquals(s, "| Invalid /list argument: " + arg + "\n"); test( - a -> assertCommandCheckOutput(a, "/l all", assertList), a -> assertCommandCheckOutput(a, "/list all", assertList), - a -> assertCommandCheckOutput(a, "/l " + arg, assertError), a -> assertCommandCheckOutput(a, "/list " + arg, assertError), a -> assertVariable(a, "int", "a"), - a -> assertCommandCheckOutput(a, "/l history", assertList), a -> assertCommandCheckOutput(a, "/list history", assertList) ); } public void testFeedbackNegative() { - for (String feedback : new String[]{"/f", "/feedback"}) { - test(a -> assertCommandCheckOutput(a, feedback + " aaaa", - assertStartsWith("| Follow /feedback with of the following"))); - } + test(a -> assertCommandCheckOutput(a, "/feedback aaaa", + assertStartsWith("| Follow /feedback with of the following"))); } public void testFeedbackOff() { - for (String feedback : new String[]{"/f", "/feedback"}) { - for (String off : new String[]{"o", "off"}) { - test( - a -> assertCommand(a, feedback + " " + off, ""), - a -> assertCommand(a, "int a", ""), - a -> assertCommand(a, "void f() {}", ""), - a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("| Error:")), - a -> assertCommandCheckOutput(a, "public void f() {}", assertStartsWith("| Warning:")) - ); - } + for (String off : new String[]{"o", "off"}) { + test( + a -> assertCommand(a, "/feedback " + off, ""), + a -> assertCommand(a, "int a", ""), + a -> assertCommand(a, "void f() {}", ""), + a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("| Error:")), + a -> assertCommandCheckOutput(a, "public void f() {}", assertStartsWith("| Warning:")) + ); } } @@ -724,17 +668,15 @@ Path testConciseFile = compiler.getPath("testConciseFeedback"); String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; compiler.writeToFile(testConciseFile, sources); - for (String feedback : new String[]{"/f", "/feedback"}) { - for (String concise : new String[]{"c", "concise"}) { - test( - a -> assertCommand(a, feedback + " " + concise, ""), - a -> assertCommand(a, sources[0], ""), - a -> assertCommand(a, sources[1], ""), - a -> assertCommand(a, sources[2], ""), - a -> assertCommand(a, sources[3], "| a : 10\n"), - a -> assertCommand(a, "/o " + testConciseFile.toString(), "| a : 10\n") - ); - } + for (String concise : new String[]{"c", "concise"}) { + test( + a -> assertCommand(a, "/feedback " + concise, ""), + a -> assertCommand(a, sources[0], ""), + a -> assertCommand(a, sources[1], ""), + a -> assertCommand(a, sources[2], ""), + a -> assertCommand(a, sources[3], "| a : 10\n"), + a -> assertCommand(a, "/o " + testConciseFile.toString(), "| a : 10\n") + ); } } @@ -788,65 +730,59 @@ "| Variable a has been assigned the value 10\n" }; compiler.writeToFile(testDefaultFile, sources); - for (String feedback : new String[]{"/f", "/feedback"}) { - for (String defaultFeedback : new String[]{"", "d", "default"}) { - test( - a -> assertCommand(a, "/f o", ""), - a -> assertCommand(a, "int x", ""), - a -> assertCommand(a, feedback + " " + defaultFeedback, "| Feedback mode: default\n"), - a -> assertCommand(a, sources[0], output[0]), - a -> assertCommand(a, sources[1], output[1]), - a -> assertCommand(a, sources[2], output[2]), - a -> assertCommand(a, sources[3], output[3]), - a -> assertCommand(a, "/o " + testDefaultFile.toString(), "") - ); - } + for (String defaultFeedback : new String[]{"", "d", "default"}) { + test( + a -> assertCommand(a, "/feedback o", ""), + a -> assertCommand(a, "int x", ""), + a -> assertCommand(a, "/feedback " + defaultFeedback, "| Feedback mode: default\n"), + a -> assertCommand(a, sources[0], output[0]), + a -> assertCommand(a, sources[1], output[1]), + a -> assertCommand(a, sources[2], output[2]), + a -> assertCommand(a, sources[3], output[3]), + a -> assertCommand(a, "/o " + testDefaultFile.toString(), "") + ); } } public void testDrop() { - for (String drop : new String[]{"/d", "/drop"}) { - test(false, new String[]{"-nostartup"}, - a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, drop + " 1", "int a = 0"), - a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, drop + " 2", "b ()I"), - a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, drop + " 3", "class A"), - a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - a -> dropImport(a, drop + " 4", "import java.util.stream.*"), - a -> assertCommandCheckOutput(a, "/v", assertVariables()), - a -> assertCommandCheckOutput(a, "/m", assertMethods()), - a -> assertCommandCheckOutput(a, "/c", assertClasses()), - a -> assertCommandCheckOutput(a, "/i", assertImports()) - ); - test(false, new String[]{"-nostartup"}, - a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, drop + " a", "int a = 0"), - a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, drop + " b", "b ()I"), - a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, drop + " A", "class A"), - a -> assertCommandCheckOutput(a, "/v", assertVariables()), - a -> assertCommandCheckOutput(a, "/m", assertMethods()), - a -> assertCommandCheckOutput(a, "/c", assertClasses()), - a -> assertCommandCheckOutput(a, "/i", assertImports()) - ); - } + test(false, new String[]{"-nostartup"}, + a -> assertVariable(a, "int", "a"), + a -> dropVariable(a, "/drop 1", "int a = 0"), + a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), + a -> dropMethod(a, "/drop 2", "b ()I"), + a -> assertClass(a, "class A {}", "class", "A"), + a -> dropClass(a, "/drop 3", "class A"), + a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), + 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, "/imports", assertImports()) + ); + test(false, new String[]{"-nostartup"}, + a -> assertVariable(a, "int", "a"), + a -> dropVariable(a, "/drop a", "int a = 0"), + a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), + a -> dropMethod(a, "/drop b", "b ()I"), + a -> assertClass(a, "class A {}", "class", "A"), + a -> dropClass(a, "/drop A", "class A"), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()), + a -> assertCommandCheckOutput(a, "/classes", assertClasses()), + a -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); } public void testDropNegative() { - for (String drop : new String[]{"/d", "/drop"}) { - test(false, new String[]{"-nostartup"}, - a -> assertCommand(a, drop + " 0", "| No definition or id named 0 found. See /classes /methods /vars or /list\n"), - a -> assertCommand(a, drop + " a", "| No definition or id named a found. See /classes /methods /vars or /list\n"), - a -> assertCommandCheckOutput(a, drop, - assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")), - a -> assertVariable(a, "int", "a"), - a -> assertCommand(a, "a", "| Variable a of type int has value 0\n"), - a -> assertCommand(a, drop + " 2", "| The argument did not specify an import, variable, method, or class to drop.\n") - ); - } + test(false, new String[]{"-nostartup"}, + a -> assertCommand(a, "/drop 0", "| No definition or id named 0 found. See /classes /methods /vars or /list\n"), + a -> assertCommand(a, "/drop a", "| No definition or id named a found. See /classes /methods /vars or /list\n"), + a -> assertCommandCheckOutput(a, "/drop", + assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")), + a -> assertVariable(a, "int", "a"), + a -> assertCommand(a, "a", "| Variable a of type int has value 0\n"), + a -> assertCommand(a, "/drop 2", "| The argument did not specify an import, variable, method, or class to drop.\n") + ); } public void testAmbiguousDrop() { @@ -855,25 +791,23 @@ int lines = s.split("\n").length; assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s); }; - for (String drop : new String[]{"/d", "/drop"}) { - test( - a -> assertVariable(a, "int", "a"), - a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), - a -> assertClass(a, "class a {}", "class", "a"), - a -> assertCommandCheckOutput(a, drop + " a", check), - a -> assertCommandCheckOutput(a, "/v", assertVariables()), - a -> assertCommandCheckOutput(a, "/m", assertMethods()), - a -> assertCommandCheckOutput(a, "/c", assertClasses()), - a -> assertCommandCheckOutput(a, "/i", assertImports()) - ); - test( - a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), - a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"), - a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"), - a -> assertCommandCheckOutput(a, drop + " a", check), - a -> assertCommandCheckOutput(a, "/m", assertMethods()) - ); - } + test( + a -> assertVariable(a, "int", "a"), + a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), + a -> assertClass(a, "class a {}", "class", "a"), + a -> assertCommandCheckOutput(a, "/drop a", check), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()), + a -> assertCommandCheckOutput(a, "/classes", assertClasses()), + a -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); + test( + a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), + a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"), + a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"), + a -> assertCommandCheckOutput(a, "/drop a", check), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()) + ); } public void testHistoryReference() { @@ -893,4 +827,14 @@ a -> assertCommand(a, "/1", "System.err.println(1)\n", "", null, "", "1\n") ); } + + public void testCommandPrefix() { + test(a -> assertCommandCheckOutput(a, "/s", + assertStartsWith("| Command: /s is ambiguous: /seteditor, /save, /setstart")), + a -> assertCommand(a, "int var", "| Added variable var of type int\n"), + a -> assertCommandCheckOutput(a, "/va", + assertStartsWith("| int var = 0")), + a -> assertCommandCheckOutput(a, "/save", + assertStartsWith("| The /save command requires a filename argument."))); + } }