8142447: JShell tool: Command change: re-run n-th command should be re-run by id
Reviewed-by: rfield
Contributed-by: bitterfoxc@gmail.com
--- 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"));
}