8192863: jshell tool: /<id><tab> gives "No such command"
authorrfield
Thu, 07 Dec 2017 13:23:18 -0800
changeset 48275 b2190c70a1ac
parent 48274 51772bf1fb0c
child 48276 34f0232538f6
8192863: jshell tool: /<id><tab> gives "No such command" Reviewed-by: jlahoda
src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
test/langtools/jdk/jshell/HistoryUITest.java
test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java
test/langtools/jdk/jshell/ToolShiftTabTest.java
test/langtools/jdk/jshell/ToolTabCommandTest.java
test/langtools/jdk/jshell/ToolTabSnippetTest.java
test/langtools/jdk/jshell/UITesting.java
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Thu Dec 07 13:23:18 2017 -0800
@@ -216,7 +216,7 @@
                 int[] anchor = new int[] {-1};
                 List<Suggestion> suggestions;
                 List<String> doc;
-                boolean command = prefix.isEmpty() && text.trim().startsWith("/");
+                boolean command = prefix.isEmpty() && text.startsWith("/");
                 if (command) {
                     suggestions = repl.commandCompletionSuggestions(text, cursor, anchor);
                     doc = repl.commandDocumentation(text, cursor, true);
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu Dec 07 13:23:18 2017 -0800
@@ -114,6 +114,7 @@
 import jdk.internal.editor.external.ExternalEditor;
 import static java.util.Arrays.asList;
 import static java.util.Arrays.stream;
+import static java.util.Collections.singletonList;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 import static jdk.jshell.Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND;
@@ -135,6 +136,9 @@
 
     private static final Pattern LINEBREAK = Pattern.compile("\\R");
     private static final Pattern ID = Pattern.compile("[se]?\\d+([-\\s].*)?");
+    private static final Pattern RERUN_ID = Pattern.compile("/" + ID.pattern());
+    private static final Pattern RERUN_PREVIOUS = Pattern.compile("/\\-\\d+( .*)?");
+    private static final Pattern SET_SUB = Pattern.compile("/?set .*");
             static final String RECORD_SEPARATOR = "\u241E";
     private static final String RB_NAME_PREFIX  = "jdk.internal.jshell.tool.resources";
     private static final String VERSION_RB_NAME = RB_NAME_PREFIX + ".version";
@@ -1305,8 +1309,8 @@
         Command[] candidates = findCommand(cmd, c -> c.kind.isRealCommand);
         switch (candidates.length) {
             case 0:
-                // not found, it is either a snippet command or an error
-                if (ID.matcher(cmd.substring(1)).matches()) {
+                // not found, it is either a rerun-ID command or an error
+                if (RERUN_ID.matcher(cmd).matches()) {
                     // it is in the form of a snipppet id, see if it is a valid history reference
                     rerunHistoryEntriesById(input);
                 } else {
@@ -1839,7 +1843,7 @@
 
     public List<String> commandDocumentation(String code, int cursor, boolean shortDescription) {
         code = code.substring(0, cursor).replaceAll("\\h+", " ");
-        String stripped = code.replaceFirst("/help ", "");
+        String stripped = code.replaceFirst("/(he(lp?)?|\\?) ", "");
         boolean inHelp = !code.equals(stripped);
         int space = stripped.indexOf(' ');
         String prefix = space != (-1) ? stripped.substring(0, space) : stripped;
@@ -1847,24 +1851,30 @@
 
         List<Entry<String, String>> toShow;
 
-        if (stripped.matches("/set .*") || stripped.matches("set .*")) {
+        if (SET_SUB.matcher(stripped).matches()) {
             String setSubcommand = stripped.replaceFirst("/?set ([^ ]*)($| .*)", "$1");
             toShow =
                 Arrays.stream(SET_SUBCOMMANDS)
                        .filter(s -> s.startsWith(setSubcommand))
-                       .map(s -> new SimpleEntry<>("/set " + s, "help.set." + s))
-                       .collect(Collectors.toList());
+                        .map(s -> new SimpleEntry<>("/set " + s, "help.set." + s))
+                        .collect(toList());
+        } else if (RERUN_ID.matcher(stripped).matches()) {
+            toShow =
+                singletonList(new SimpleEntry<>("/<id>", "help.rerun"));
+        } else if (RERUN_PREVIOUS.matcher(stripped).matches()) {
+            toShow =
+                singletonList(new SimpleEntry<>("/-<n>", "help.rerun"));
         } else {
             toShow =
                 commands.values()
                         .stream()
                         .filter(c -> c.command.startsWith(prefix)
-                                     || c.command.substring(1).startsWith(prefix))
-                        .filter(c -> c.kind.showInHelp ||
-                                     (inHelp && c.kind == CommandKind.HELP_SUBJECT))
+                                  || c.command.substring(1).startsWith(prefix))
+                        .filter(c -> c.kind.showInHelp
+                                  || (inHelp && c.kind == CommandKind.HELP_SUBJECT))
                         .sorted((c1, c2) -> c1.command.compareTo(c2.command))
                         .map(c -> new SimpleEntry<>(c.command, c.helpKey))
-                        .collect(Collectors.toList());
+                        .collect(toList());
         }
 
         if (toShow.size() == 1 && !inHelp) {
--- a/test/langtools/jdk/jshell/HistoryUITest.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/test/langtools/jdk/jshell/HistoryUITest.java	Thu Dec 07 13:23:18 2017 -0800
@@ -45,9 +45,9 @@
     public void testPrevNextSnippet() throws Exception {
         doRunTest((inputSink, out) -> {
             inputSink.write("void test1() {\nSystem.err.println(1);\n}\n");
-            waitOutput(out, "\u0005");
+            waitOutput(out, PROMPT);
             inputSink.write("void test2() {\nSystem.err.println(2);\n}\n");
-            waitOutput(out, "\u0005");
+            waitOutput(out, PROMPT);
             inputSink.write(CTRL_UP);
             waitOutput(out, "^void test2\\(\\) \\{");
             inputSink.write(CTRL_UP);
@@ -63,7 +63,7 @@
             inputSink.write(UP);
             waitOutput(out, "^" + clearOut("System.err.println(2);") + "void test2\\(\\) \\{");
             inputSink.write(UP);
-            waitOutput(out, "^\u0007");
+            waitOutput(out, "^" + BELL);
             inputSink.write(DOWN);
             waitOutput(out, "^" + clearOut("void test2() {") + "System.err.println\\(2\\);");
             inputSink.write(DOWN);
@@ -71,7 +71,7 @@
             inputSink.write(DOWN);
             waitOutput(out, "^" + clearOut("}"));
             inputSink.write(DOWN);
-            waitOutput(out, "^\u0007");
+            waitOutput(out, "^" + BELL);
         });
     }
     //where:
--- a/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java	Thu Dec 07 13:23:18 2017 -0800
@@ -62,11 +62,11 @@
                             "\u0006\u001b\\[6nSystem.err.println\\(1\\);\n" +
                             "\u0006\u001b\\[6n\\}\n" +
                             "\\|  created method test1\\(\\)\n" +
-                            "\u0005\u001b\\[6nvoid test2\\(\\) \\{\n" +
+                            PROMPT + "\u001b\\[6nvoid test2\\(\\) \\{\n" +
                             "\u0006\u001b\\[6nSystem.err.println\\(1\\);\n" +
                             "\u0006\u001b\\[6n\\}\n" +
                             "\\|  created method test2\\(\\)\n" +
-                            "\u0005\u001b\\[6n");
+                            PROMPT + "\u001b\\[6n");
         });
     }
         private static final String ANSI_SUPPORTED_PROPERTY = "test.terminal.ansi.supported";
--- a/test/langtools/jdk/jshell/ToolShiftTabTest.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/test/langtools/jdk/jshell/ToolShiftTabTest.java	Thu Dec 07 13:23:18 2017 -0800
@@ -84,15 +84,15 @@
         doRunTest((inputSink, out) -> {
             inputSink.write("4");
             inputSink.write(FIX + "m");
-            inputSink.write("\u0003 55");
+            inputSink.write(INTERRUPT + " 55");
             inputSink.write(FIX + "m");
-            inputSink.write("\u0003 55");
+            inputSink.write(INTERRUPT + " 55");
             inputSink.write(FIX + "m");
-            inputSink.write("\u0003 55");
+            inputSink.write(INTERRUPT + " 55");
             inputSink.write(FIX + "m");
-            inputSink.write("\u0003 55");
+            inputSink.write(INTERRUPT + " 55");
             inputSink.write(FIX + "m");
-            inputSink.write("\u0003'X'");
+            inputSink.write(INTERRUPT + "'X'");
             inputSink.write(FIX + "m");
             inputSink.write("nl\n");
             waitOutput(out, "|  created method nl()");
--- a/test/langtools/jdk/jshell/ToolTabCommandTest.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/test/langtools/jdk/jshell/ToolTabCommandTest.java	Thu Dec 07 13:23:18 2017 -0800
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 8177076 8185840 8178109
+ * @bug 8177076 8185840 8178109 8192863
  * @modules
  *     jdk.compiler/com.sun.tools.javac.api
  *     jdk.compiler/com.sun.tools.javac.main
@@ -36,8 +36,6 @@
  * @run testng ToolTabCommandTest
  */
 
-import java.util.regex.Pattern;
-
 import org.testng.annotations.Test;
 
 @Test
@@ -49,79 +47,121 @@
 
         doRunTest((inputSink, out) -> {
             inputSink.write("1\n");
-            waitOutput(out, "\u0005");
-            inputSink.write("/\011");
-            waitOutput(out, ".*/edit.*/list.*\n\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n\r\u0005/");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\n/edit\n" + Pattern.quote(getResource("help.edit.summary")) +
-                            "\n.*\n/list\n" + Pattern.quote(getResource("help.list.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/");
-            inputSink.write("\011");
+            waitOutput(out, PROMPT);
+            inputSink.write("/" + TAB);
+            waitOutput(out, ".*/edit.*/list.*\n\n" + resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\n/edit\n" + resource("help.edit.summary") +
+                            "\n.*\n/list\n" + resource("help.list.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/");
+            inputSink.write(TAB);
             waitOutput(out,  "/!\n" +
-                            Pattern.quote(getResource("help.bang")) + "\n" +
+                            resource("help.bang") + "\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.next.command.doc")) + "\n" +
-                            "\r\u0005/");
-            inputSink.write("\011");
+                            resource("jshell.console.see.next.command.doc") +
+                            REDRAW_PROMPT + "/");
+            inputSink.write(TAB);
             waitOutput(out,  "/-<n>\n" +
-                            Pattern.quote(getResource("help.previous")) + "\n" +
+                            resource("help.previous") + "\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.next.command.doc")) + "\n" +
-                            "\r\u0005/");
+                            resource("jshell.console.see.next.command.doc") +
+                            REDRAW_PROMPT + "/");
 
-            inputSink.write("ed\011");
+            inputSink.write("ed" + TAB);
             waitOutput(out, "edit $");
 
-            inputSink.write("\011");
+            inputSink.write(TAB);
             waitOutput(out, ".*-all.*" +
-                            "\n\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n\r\u0005/");
-            inputSink.write("\011");
-            waitOutput(out, Pattern.quote(getResource("help.edit.summary")) + "\n\n" +
-                            Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/edit ");
-            inputSink.write("\011");
-            waitOutput(out, Pattern.quote(getResource("help.edit").replaceAll("\t", "    ")));
+                            "\n\n" + resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.edit.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/edit ");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.edit"));
 
-            inputSink.write("\u0003/env \011");
-            waitOutput(out, "\u0005/env -\n" +
+            inputSink.write(INTERRUPT + "/env " + TAB);
+            waitOutput(out, PROMPT + "/env -\n" +
                             "-add-exports    -add-modules    -class-path     -module-path    \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n" +
-                            "\r\u0005/env -");
+                            resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/env -");
 
-            inputSink.write("\011");
-            waitOutput(out, Pattern.quote(getResource("help.env.summary")) + "\n\n" +
-                            Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/env -");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.env.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/env -");
 
-            inputSink.write("\011");
-            waitOutput(out, Pattern.quote(getResource("help.env").replaceAll("\t", "    ")) + "\n" +
-                            "\r\u0005/env -");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.env") +
+                            REDRAW_PROMPT + "/env -");
 
-            inputSink.write("\011");
+            inputSink.write(TAB);
             waitOutput(out, "-add-exports    -add-modules    -class-path     -module-path    \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n" +
-                            "\r\u0005/env -");
+                            resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/env -");
 
-            inputSink.write("\u0003/exit \011");
-            waitOutput(out, Pattern.quote(getResource("help.exit.summary")) + "\n\n" +
-                            Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/exit ");
-            inputSink.write("\011");
-            waitOutput(out, Pattern.quote(getResource("help.exit").replaceAll("\t", "    ")) + "\n" +
-                            "\r\u0005/exit ");
-            inputSink.write("\011");
-            waitOutput(out, Pattern.quote(getResource("help.exit.summary")) + "\n\n" +
-                            Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/exit ");
-            inputSink.write("\u0003");
+            inputSink.write(INTERRUPT + "/exit " + TAB);
+            waitOutput(out, resource("help.exit.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/exit ");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.exit") +
+                            REDRAW_PROMPT + "/exit ");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.exit.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/exit ");
+            inputSink.write(INTERRUPT);
             inputSink.write("int zebraStripes = 11\n");
             waitOutput(out, "zebraStripes ==> 11\n\u0005");
-            inputSink.write("/exit zeb\011");
+            inputSink.write("/exit zeb" + TAB);
             waitOutput(out, "braStr.*es");
-            inputSink.write("\u0003/doesnotexist\011");
-            waitOutput(out, "\u0005/doesnotexist\n" +
-                            Pattern.quote(getResource("jshell.console.no.such.command")) + "\n" +
-                            "\n" +
-                            "\r\u0005/doesnotexist");
+            inputSink.write(INTERRUPT + "/doesnotexist" + TAB);
+            waitOutput(out, PROMPT + "/doesnotexist\n" +
+                            resource("jshell.console.no.such.command") + "\n" +
+                            REDRAW_PROMPT + "/doesnotexist");
+        });
+    }
+
+    public void testRerunCommands() throws Exception {
+        // set terminal height so that help output won't hit page breaks
+        System.setProperty("test.terminal.height", "1000000");
+
+        doRunTest((inputSink, out) -> {
+            inputSink.write("1\n");
+            waitOutput(out, PROMPT);
+            inputSink.write("2\n");
+            waitOutput(out, PROMPT);
+
+            inputSink.write("/1" + TAB);
+            waitOutput(out, resource("help.rerun.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/1");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.rerun") +
+                            REDRAW_PROMPT + "/1");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.rerun.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/1");
+
+            inputSink.write(INTERRUPT);
+            inputSink.write("/-1" + TAB);
+            waitOutput(out, resource("help.rerun.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/-1");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.rerun") +
+                            REDRAW_PROMPT + "/-1");
+            inputSink.write(TAB);
+            waitOutput(out, resource("help.rerun.summary") + "\n\n" +
+                            resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/-1");
         });
     }
 
@@ -130,62 +170,62 @@
         System.setProperty("test.terminal.height", "1000000");
 
         doRunTest((inputSink, out) -> {
-            inputSink.write("/help \011");
-            waitOutput(out, ".*/edit.*/list.*intro.*\n\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n" +
-                            "\r\u0005/");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\n/edit\n" + Pattern.quote(getResource("help.edit.summary")) +
-                            "\n.*\n/list\n" + Pattern.quote(getResource("help.list.summary")) +
-                            "\n.*\nintro\n" + Pattern.quote(getResource("help.intro.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/");
-            inputSink.write("/env\011");
+            inputSink.write("/help " + TAB);
+            waitOutput(out, ".*/edit.*/list.*intro.*\n\n" + resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\n/edit\n" + resource("help.edit.summary") +
+                            "\n.*\n/list\n" + resource("help.list.summary") +
+                            "\n.*\nintro\n" + resource("help.intro.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/");
+            inputSink.write("/env" + TAB);
             waitOutput(out,   "help /env ");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\n/env\n" + Pattern.quote(getResource("help.env.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/help /env ");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\n/env\n" + Pattern.quote(getResource("help.env").replaceAll("\t", "    ")) + "\n" +
-                            "\r\u0005/help /env ");
-            inputSink.write("\u0003/help intro\011");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\n/env\n" + resource("help.env.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/help /env ");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\n/env\n" + resource("help.env") +
+                            REDRAW_PROMPT + "/help /env ");
+            inputSink.write(INTERRUPT + "/help intro" + TAB);
             waitOutput(out,   "help intro ");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\nintro\n" + Pattern.quote(getResource("help.intro.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/help intro ");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\nintro\n" + Pattern.quote(getResource("help.intro").replaceAll("\t", "    ")) + "\n" +
-                            "\r\u0005/help intro ");
-            inputSink.write("\u0003/help /set \011");
-            waitOutput(out, ".*format.*truncation.*\n\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n" +
-                            "\r\u0005/help /set ");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\n/set format\n" + Pattern.quote(getResource("help.set.format.summary")) +
-                            "\n.*\n/set truncation\n" + Pattern.quote(getResource("help.set.truncation.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/help /set ");
-            inputSink.write("truncation\011");
-            waitOutput(out,   ".*truncation\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n" +
-                            "\r\u0005/help /set truncation");
-            inputSink.write("\011");
-            waitOutput(out,   ".*/set truncation\n" + Pattern.quote(getResource("help.set.truncation.summary")) + "\n" +
-                            "\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/help /set truncation");
-            inputSink.write("\011");
-            waitOutput(out,   ".*/set truncation\n" + Pattern.quote(getResource("help.set.truncation").replaceAll("\t", "    ")) +
-                            "\r\u0005/help /set truncation");
-            inputSink.write("\u0003/help env \011");
-            waitOutput(out,   ".*\n/env\n" + Pattern.quote(getResource("help.env.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/help env ");
-            inputSink.write("\u0003/help set truncation\011");
-            waitOutput(out,   ".*truncation\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n" +
-                            "\r\u0005/help set truncation");
-            inputSink.write("\011");
-            waitOutput(out,   ".*\n/set truncation\n" + Pattern.quote(getResource("help.set.truncation.summary")) +
-                            ".*\n\n" + Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n" +
-                            "\r\u0005/help set truncation");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\nintro\n" + resource("help.intro.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/help intro ");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\nintro\n" + resource("help.intro") +
+                            REDRAW_PROMPT + "/help intro ");
+            inputSink.write(INTERRUPT + "/help /set " + TAB);
+            waitOutput(out, ".*format.*truncation.*\n\n" + resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/help /set ");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\n/set format\n" + resource("help.set.format.summary") +
+                            "\n.*\n/set truncation\n" + resource("help.set.truncation.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/help /set ");
+            inputSink.write("truncation" + TAB);
+            waitOutput(out,   ".*truncation\n" + resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/help /set truncation");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*/set truncation\n" + resource("help.set.truncation.summary") + "\n" +
+                            "\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/help /set truncation");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*/set truncation\n" + resource("help.set.truncation") +
+                           "\r" + PROMPT + "/help /set truncation");
+            inputSink.write(INTERRUPT + "/help env " + TAB);
+            waitOutput(out,   ".*\n/env\n" + resource("help.env.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/help env ");
+            inputSink.write(INTERRUPT + "/help set truncation" + TAB);
+            waitOutput(out,   ".*truncation\n" + resource("jshell.console.see.synopsis") +
+                            REDRAW_PROMPT + "/help set truncation");
+            inputSink.write(TAB);
+            waitOutput(out,   ".*\n/set truncation\n" + resource("help.set.truncation.summary") +
+                            ".*\n\n" + resource("jshell.console.see.full.documentation") +
+                            REDRAW_PROMPT + "/help set truncation");
         });
     }
 }
--- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java	Thu Dec 07 13:23:18 2017 -0800
@@ -46,7 +46,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
-import java.util.regex.Pattern;
 
 import jdk.internal.jshell.tool.ConsoleIOContextTestSupport;
 import org.testng.annotations.Test;
@@ -58,143 +57,148 @@
         Path classes = prepareZip();
         doRunTest((inputSink, out) -> {
             inputSink.write("/env -class-path " + classes.toString() + "\n");
-            waitOutput(out, Pattern.quote(getResource("jshell.msg.set.restore")) + "\n\u0005");
+            waitOutput(out, resource("jshell.msg.set.restore") + "\n\u0005");
             inputSink.write("import jshelltest.*;\n");
             waitOutput(out, "\n\u0005");
 
             //-> <tab>
-            inputSink.write("\011");
+            inputSink.write(TAB);
             waitOutput(out, getMessage("jshell.console.completion.all.completions.number", "[0-9]+"));
-            inputSink.write("\011");
-            waitOutput(out, ".*String.*StringBuilder.*\n\r\u0005");
+            inputSink.write(TAB);
+            waitOutput(out, ".*String.*StringBuilder.*" +
+                            REDRAW_PROMPT + "");
 
             //new JShellTes<tab>
-            inputSink.write("new JShellTes\011");
-            waitOutput(out, "t\nJShellTest\\(      JShellTestAux\\(   \n\r\u0005new JShellTest");
+            inputSink.write("new JShellTes" + TAB);
+            waitOutput(out, "t\nJShellTest\\(      JShellTestAux\\(   " +
+                            REDRAW_PROMPT + "new JShellTest");
 
             //new JShellTest<tab>
-            inputSink.write("\011");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(      JShellTestAux\\(   \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.completion.current.signatures")) + "\n" +
+                            resource("jshell.console.completion.current.signatures") + "\n" +
                             "jshelltest.JShellTest\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.documentation")) + "\n" +
-                            "\r\u0005new JShellTest");
-            inputSink.write("\011");
+                            resource("jshell.console.see.documentation") +
+                            REDRAW_PROMPT + "new JShellTest");
+            inputSink.write(TAB);
             waitOutput(out, "jshelltest.JShellTest\n" +
-                            "JShellTest 0\n" +
-                            "\r\u0005new JShellTest");
-            inputSink.write("\011");
+                            "JShellTest 0" +
+                            REDRAW_PROMPT + "new JShellTest");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(      JShellTestAux\\(   \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.completion.current.signatures")) + "\n" +
+                            resource("jshell.console.completion.current.signatures") + "\n" +
                             "jshelltest.JShellTest\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.documentation")) + "\n" +
-                            "\r\u0005new JShellTest");
+                            resource("jshell.console.see.documentation") +
+                            REDRAW_PROMPT + "new JShellTest");
 
             //new JShellTest(<tab>
-            inputSink.write("(\011");
+            inputSink.write("(" + TAB);
             waitOutput(out, "\\(\n" +
-                            Pattern.quote(getResource("jshell.console.completion.current.signatures")) + "\n" +
+                            resource("jshell.console.completion.current.signatures") + "\n" +
                             "JShellTest\\(String str\\)\n" +
                             "JShellTest\\(String str, int i\\)\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.documentation")) + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
+                            resource("jshell.console.see.documentation") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(String str\\)\n" +
                             "JShellTest 1\n" +
                             "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.next.page")) + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
+                            resource("jshell.console.see.next.page") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
             waitOutput(out, "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.next.javadoc")) + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
+                            resource("jshell.console.see.next.javadoc") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(String str, int i\\)\n" +
                             "JShellTest 2\n" +
                             "\n" +
-                            getMessage("jshell.console.completion.all.completions.number", "[0-9]+") + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
-            waitOutput(out, ".*String.*StringBuilder.*\n\r\u0005new JShellTest\\(");
+                            getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
+            waitOutput(out, ".*String.*StringBuilder.*" +
+                            REDRAW_PROMPT + "new JShellTest\\(");
 
-            inputSink.write("\u0003String str = \"\";\nnew JShellTest(");
-            waitOutput(out, "\u0005new JShellTest\\(");
+            inputSink.write(INTERRUPT + "String str = \"\";\nnew JShellTest(");
+            waitOutput(out, PROMPT + "new JShellTest\\(");
 
-            inputSink.write("\011");
+            inputSink.write(TAB);
             waitOutput(out, "\n" +
                             "str   \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.completion.current.signatures")) + "\n" +
+                            resource("jshell.console.completion.current.signatures") + "\n" +
                             "JShellTest\\(String str\\)\n" +
                             "JShellTest\\(String str, int i\\)\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.documentation")) + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
+                            resource("jshell.console.see.documentation") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(String str\\)\n" +
                             "JShellTest 1\n" +
                             "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.next.page")) + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
+                            resource("jshell.console.see.next.page") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
             waitOutput(out, "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.next.javadoc")) + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
+                            resource("jshell.console.see.next.javadoc") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(String str, int i\\)\n" +
                             "JShellTest 2\n" +
                             "\n" +
-                            getMessage("jshell.console.completion.all.completions.number", "[0-9]+") + "\n" +
-                            "\r\u0005new JShellTest\\(");
-            inputSink.write("\011");
-            waitOutput(out, ".*String.*StringBuilder.*\n\r\u0005new JShellTest\\(");
+                            getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
+                            REDRAW_PROMPT + "new JShellTest\\(");
+            inputSink.write(TAB);
+            waitOutput(out, ".*String.*StringBuilder.*" +
+                            REDRAW_PROMPT + "new JShellTest\\(");
 
-            inputSink.write("\u0003JShellTest t = new JShellTest\011");
-            waitOutput(out, "\u0005JShellTest t = new JShellTest\n" +
+            inputSink.write(INTERRUPT + "JShellTest t = new JShellTest" + TAB);
+            waitOutput(out, PROMPT + "JShellTest t = new JShellTest\n" +
                             "JShellTest\\(   \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.completion.current.signatures")) + "\n" +
+                            resource("jshell.console.completion.current.signatures") + "\n" +
                             "jshelltest.JShellTest\n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.completion.all.completions")) + "\n" +
-                            "\r\u0005JShellTest t = new JShellTest");
-            inputSink.write("\011");
+                            resource("jshell.console.completion.all.completions") +
+                            REDRAW_PROMPT + "JShellTest t = new JShellTest");
+            inputSink.write(TAB);
             waitOutput(out, "JShellTest\\(      JShellTestAux\\(   \n" +
                             "\n" +
-                            Pattern.quote(getResource("jshell.console.see.documentation")) + "\n" +
-                            "\r\u0005JShellTest t = new JShellTest");
+                            resource("jshell.console.see.documentation") +
+                            REDRAW_PROMPT + "JShellTest t = new JShellTest");
 
-            inputSink.write("\u0003JShellTest t = new \011");
-            waitOutput(out, "\u0005JShellTest t = new \n" +
+            inputSink.write(INTERRUPT + "JShellTest t = new " + TAB);
+            waitOutput(out, PROMPT + "JShellTest t = new \n" +
                             "JShellTest\\(   \n" +
                             "\n" +
-                            getMessage("jshell.console.completion.all.completions.number", "[0-9]+") + "\n" +
-                            "\r\u0005JShellTest t = new ");
-            inputSink.write("\011");
-            waitOutput(out, ".*String.*StringBuilder.*\n\r\u0005JShellTest t = new ");
+                            getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
+                            REDRAW_PROMPT + "JShellTest t = new ");
+            inputSink.write(TAB);
+            waitOutput(out, ".*String.*StringBuilder.*" +
+                            REDRAW_PROMPT + "JShellTest t = new ");
 
-            inputSink.write("\u0003class JShelX{}\n");
-            inputSink.write("new JShel\011");
-            waitOutput(out, "\u0005new JShel\n" +
-                            "JShelX\\(\\)         JShellTest\\(      JShellTestAux\\(   \n" +
-                            "\r\u0005new JShel");
+            inputSink.write(INTERRUPT + "class JShelX{}\n");
+            inputSink.write("new JShel" + TAB);
+            waitOutput(out, PROMPT + "new JShel\n" +
+                            "JShelX\\(\\)         JShellTest\\(      JShellTestAux\\(   " +
+                            REDRAW_PROMPT + "new JShel");
 
             //no crash:
-            inputSink.write("\u0003new Stringbuil\011");
-            waitOutput(out, "\u0005new Stringbuil\u0007");
+            inputSink.write(INTERRUPT + "new Stringbuil" + TAB);
+            waitOutput(out, PROMPT + "new Stringbuil" + BELL);
 
             //no crash: 8188072
-            inputSink.write("\u0003for (int:\011");
-            waitOutput(out, "\u0005for \\(int:\u0007");
+            inputSink.write(INTERRUPT + "for (int:" + TAB);
+            waitOutput(out, PROMPT + "for \\(int:" + BELL);
         });
     }
 
@@ -218,15 +222,15 @@
                 }
             };
             //-> <tab>
-            inputSink.write("\011");
+            inputSink.write(TAB);
             testCompleteComputationStarted.await();
             //-> <tab><tab>
-            inputSink.write("\011\011");
+            inputSink.write(TAB + TAB);
             testCompleteComputationContinue.countDown();
-            waitOutput(out, "\u0005");
+            waitOutput(out, PROMPT);
             //-> <tab>
-            inputSink.write("\011");
-            waitOutput(out, "\u0005");
+            inputSink.write(TAB);
+            waitOutput(out, PROMPT);
             ConsoleIOContextTestSupport.IMPL = null;
         });
     }
@@ -234,24 +238,24 @@
     public void testNoRepeat() throws Exception {
         doRunTest((inputSink, out) -> {
             inputSink.write("String xyzAA;\n");
-            waitOutput(out, "\u0005");
+            waitOutput(out, PROMPT);
 
             //xyz<tab>
-            inputSink.write("String s = xyz\011");
+            inputSink.write("String s = xyz" + TAB);
             waitOutput(out, "^String s = xyzAA");
             inputSink.write(".");
             waitOutput(out, "^\\.");
 
-            inputSink.write("\u0003");
-            waitOutput(out, "\u0005");
+            inputSink.write(INTERRUPT);
+            waitOutput(out, PROMPT);
 
             inputSink.write("double xyzAB;\n");
-            waitOutput(out, "\u0005");
+            waitOutput(out, PROMPT);
 
             //xyz<tab>
-            inputSink.write("String s = xyz\011");
+            inputSink.write("String s = xyz" + TAB);
             String allCompletions =
-                    Pattern.quote(getResource("jshell.console.completion.all.completions"));
+                    resource("jshell.console.completion.all.completions");
             waitOutput(out, ".*xyzAA.*" + allCompletions + ".*\u0005String s = xyzA");
         });
     }
--- a/test/langtools/jdk/jshell/UITesting.java	Thu Dec 07 11:55:06 2017 -0800
+++ b/test/langtools/jdk/jshell/UITesting.java	Thu Dec 07 13:23:18 2017 -0800
@@ -41,6 +41,11 @@
 
 public class UITesting {
 
+    protected static final String TAB = "\011";
+    protected static final String INTERRUPT = "\u0003";
+    protected static final String BELL = "\u0007";
+    protected static final String PROMPT = "\u0005";
+    protected static final String REDRAW_PROMPT = "\n\r" + PROMPT;
     private final boolean laxLineEndings;
 
     public UITesting() {
@@ -100,10 +105,10 @@
         runner.start();
 
         try {
-            waitOutput(out, "\u0005");
+            waitOutput(out, PROMPT);
             test.test(inputSink, out);
         } finally {
-            inputSink.write("\003\003/exit");
+            inputSink.write(INTERRUPT + INTERRUPT + "/exit");
 
             runner.join(1000);
             if (runner.isAlive()) {
@@ -198,6 +203,10 @@
         return resources.getString(key);
     }
 
+    protected String resource(String key) {
+        return Pattern.quote(getResource(key).replaceAll("\t", "    "));
+    }
+
     protected String getMessage(String key, Object... args) {
         return MessageFormat.format(resources.getString(key), args);
     }