8142447: JShell tool: Command change: re-run n-th command should be re-run by id
authorrfield
Tue, 01 Dec 2015 10:27:14 -0800
changeset 34477 64001b0533a2
parent 34476 9f12a05b4786
child 34478 ded7db333ff1
8142447: JShell tool: Command change: re-run n-th command should be re-run by id Reviewed-by: rfield Contributed-by: bitterfoxc@gmail.com
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/test/jdk/jshell/ToolBasicTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon Nov 30 13:27:57 2015 -0800
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Tue Dec 01 10:27:14 2015 -0800
@@ -86,7 +86,9 @@
 import static java.nio.file.StandardOpenOption.CREATE;
 import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
 import static java.nio.file.StandardOpenOption.WRITE;
+import java.util.Locale;
 import java.util.MissingResourceException;
+import java.util.Optional;
 import java.util.ResourceBundle;
 import static java.util.stream.Collectors.toList;
 
@@ -491,12 +493,14 @@
     }
 
     private void processCommand(String cmd) {
-        try {
-            //handle "/[number]"
-            cmdUseHistoryEntry(Integer.parseInt(cmd.substring(1)));
-            return ;
-        } catch (NumberFormatException ex) {
-            //ignore
+        if (cmd.startsWith("/-")) {
+            try {
+                //handle "/-[number]"
+                cmdUseHistoryEntry(Integer.parseInt(cmd.substring(1)));
+                return ;
+            } catch (NumberFormatException ex) {
+                //ignore
+            }
         }
         String arg = "";
         int idx = cmd.indexOf(' ');
@@ -506,8 +510,10 @@
         }
         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.");
+            if (!rerunHistoryEntryById(cmd.substring(1))) {
+                hard("No such command or snippet id: %s", cmd);
+                fluff("Type /help for help.");
+            }
         } else if (candidates.length == 1) {
             candidates[0].run.accept(arg);
         } else {
@@ -728,7 +734,7 @@
         registerCommand(new Command("/!", "", "re-run last snippet",
                                     arg -> cmdUseHistoryEntry(-1),
                                     EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/<n>", "", "re-run n-th snippet",
+        registerCommand(new Command("/<id>", "", "re-run snippet by id",
                                     arg -> { throw new IllegalStateException(); },
                                     EMPTY_COMPLETION_PROVIDER,
                                     CommandKind.HELP_ONLY));
@@ -1275,15 +1281,29 @@
         else
             index--;
         if (index >= 0 && index < keys.size()) {
-            String source = keys.get(index).source();
-            cmdout.printf("%s\n", source);
-            input.replaceLastHistoryEntry(source);
-            processSourceCatchingReset(source);
+            rerunSnippet(keys.get(index));
         } else {
             hard("Cannot find snippet %d", index + 1);
         }
     }
 
+    private boolean rerunHistoryEntryById(String id) {
+        Optional<Snippet> snippet = state.snippets().stream()
+            .filter(s -> s.id().equals(id))
+            .findFirst();
+        return snippet.map(s -> {
+            rerunSnippet(s);
+            return true;
+        }).orElse(false);
+    }
+
+    private void rerunSnippet(Snippet snippet) {
+        String source = snippet.source();
+        cmdout.printf("%s\n", source);
+        input.replaceLastHistoryEntry(source);
+        processSourceCatchingReset(source);
+    }
+
     /**
      * Filter diagnostics for only errors (no warnings, ...)
      * @param diagnostics input list
--- a/langtools/test/jdk/jshell/ToolBasicTest.java	Mon Nov 30 13:27:57 2015 -0800
+++ b/langtools/test/jdk/jshell/ToolBasicTest.java	Tue Dec 01 10:27:14 2015 -0800
@@ -41,7 +41,9 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Scanner;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.prefs.BackingStoreException;
 import java.util.prefs.Preferences;
 import java.util.stream.Collectors;
@@ -215,8 +217,8 @@
     @Test(enabled = false) // TODO 8130450
     public void testRerun() {
         test(false, new String[] {"-nostartup"},
-                (a) -> assertCommand(a, "/0", "|  Cannot find snippet 0\n"),
-                (a) -> assertCommand(a, "/5", "|  Cannot find snippet 5\n")
+                (a) -> assertCommand(a, "/0", "|  No such command or snippet id: /0\n|  Type /help for help.\n"),
+                (a) -> assertCommand(a, "/5", "|  No such command or snippet id: /5\n|  Type /help for help.\n")
         );
         String[] codes = new String[] {
                 "int a = 0;", // var
@@ -252,6 +254,35 @@
                 tests.toArray(new ReplTest[tests.size()]));
     }
 
+    public void test8142447() {
+        Function<String, BiFunction<String, Integer, ReplTest>> assertRerun = cmd -> (code, assertionCount) ->
+                (a) -> assertCommandCheckOutput(a, cmd, s -> {
+                            String[] ss = s.split("\n");
+                            assertEquals(ss[0], code);
+                            loadVariable(a, "int", "assertionCount", Integer.toString(assertionCount), Integer.toString(assertionCount));
+                        });
+        ReplTest assertVariables = (a) -> assertCommandCheckOutput(a, "/v", assertVariables());
+
+        Compiler compiler = new Compiler();
+        Path startup = compiler.getPath("StartupFileOption/startup.txt");
+        compiler.writeToFile(startup, "int assertionCount = 0;\n" + // id: s1
+                "void add(int n) { assertionCount += n; }");
+        test(new String[]{"-startup", startup.toString()},
+                (a) -> assertCommand(a, "add(1)", ""), // id: 1
+                (a) -> assertCommandCheckOutput(a, "add(ONE)", s -> assertEquals(s.split("\n")[0], "|  Error:")), // id: e1
+                (a) -> assertVariable(a, "int", "ONE", "1", "1"),
+                assertRerun.apply("/1").apply("add(1)", 2), assertVariables,
+                assertRerun.apply("/e1").apply("add(ONE)", 3), assertVariables,
+                assertRerun.apply("/s1").apply("int assertionCount = 0;", 0), assertVariables
+        );
+
+        test(false, new String[] {"-nostartup"},
+                (a) -> assertCommand(a, "/s1", "|  No such command or snippet id: /s1\n|  Type /help for help.\n"),
+                (a) -> assertCommand(a, "/1", "|  No such command or snippet id: /1\n|  Type /help for help.\n"),
+                (a) -> assertCommand(a, "/e1", "|  No such command or snippet id: /e1\n|  Type /help for help.\n")
+        );
+    }
+
     public void testRemaining() {
         test(
                 (a) -> assertCommand(a, "int z; z =", "|  Added variable z of type int\n"),
@@ -574,7 +605,7 @@
 
     public void testUnknownCommand() {
         test((a) -> assertCommand(a, "/unknown",
-                "|  No such command: /unknown\n" +
+                "|  No such command or snippet id: /unknown\n" +
                 "|  Type /help for help.\n"));
     }