8158738: jshell tool: Save does not affect jshell if started from another editor

Reviewed-by: jlahoda
This commit is contained in:
Robert Field 2016-08-26 11:36:08 -07:00
parent 61fab7c849
commit 0b92f87233
4 changed files with 52 additions and 13 deletions
langtools
src/jdk.jshell/share/classes/jdk/internal/jshell/tool
test/jdk/jshell

@ -34,6 +34,7 @@ import java.nio.file.Path;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Arrays;
import java.util.Scanner;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
@ -46,17 +47,22 @@ import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
public class ExternalEditor {
private final Consumer<String> errorHandler;
private final Consumer<String> saveHandler;
private final Consumer<String> printHandler;
private final IOContext input;
private final boolean wait;
private WatchService watcher;
private Thread watchedThread;
private Path dir;
private Path tmpfile;
ExternalEditor(Consumer<String> errorHandler, Consumer<String> saveHandler, IOContext input) {
ExternalEditor(Consumer<String> errorHandler, Consumer<String> saveHandler,
IOContext input, boolean wait, Consumer<String> printHandler) {
this.errorHandler = errorHandler;
this.saveHandler = saveHandler;
this.printHandler = printHandler;
this.input = input;
this.wait = wait;
}
private void edit(String[] cmd, String initialText) {
@ -121,7 +127,16 @@ public class ExternalEditor {
try {
input.suspend();
Process process = pb.start();
process.waitFor();
// wait to exit edit mode in one of these ways...
if (wait) {
// -wait option -- ignore process exit, wait for carriage-return
Scanner scanner = new Scanner(System.in);
printHandler.accept("jshell.msg.press.return.to.leave.edit.mode");
scanner.nextLine();
} else {
// wait for process to exit
process.waitFor();
}
} catch (IOException ex) {
errorHandler.accept("process IO failure: " + ex.getMessage());
} catch (InterruptedException ex) {
@ -148,8 +163,8 @@ public class ExternalEditor {
}
static void edit(String[] cmd, Consumer<String> errorHandler, String initialText,
Consumer<String> saveHandler, IOContext input) {
ExternalEditor ed = new ExternalEditor(errorHandler, saveHandler, input);
Consumer<String> saveHandler, IOContext input, boolean wait, Consumer<String> printHandler) {
ExternalEditor ed = new ExternalEditor(errorHandler, saveHandler, input, wait, printHandler);
ed.edit(cmd, initialText);
}
}

@ -185,6 +185,7 @@ public class JShellTool implements MessageHandler {
private String cmdlineClasspath = null;
private String startup = null;
private String[] editor = null;
private boolean editorWait = false;
// Commands and snippets which should be replayed
private List<String> replayableHistory;
@ -481,6 +482,11 @@ public class JShellTool implements MessageHandler {
if (editorString == null || editorString.isEmpty()) {
editor = null;
} else {
char waitMarker = editorString.charAt(0);
if (waitMarker == '-' || waitMarker == '*') {
editorWait = waitMarker == '-';
editorString = editorString.substring(1);
}
editor = editorString.split(RECORD_SEPARATOR);
}
@ -1260,7 +1266,7 @@ public class JShellTool implements MessageHandler {
// retain editor setting
prefs.put(EDITOR_KEY, (editor == null)
? ""
: String.join(RECORD_SEPARATOR, editor));
: (editorWait? "-" : "*") + String.join(RECORD_SEPARATOR, editor));
return true;
case "start": {
if (!setStart(cmd, at, false)) {
@ -1315,7 +1321,7 @@ public class JShellTool implements MessageHandler {
// The sub-command: /set editor <editor-command-line>>
boolean setEditor(ArgTokenizer at, boolean argsRequired) {
at.allowedOptions("-default");
at.allowedOptions("-default", "-wait");
String prog = at.next();
List<String> ed = new ArrayList<>();
while (at.val() != null) {
@ -1326,14 +1332,20 @@ public class JShellTool implements MessageHandler {
return false;
}
boolean defaultOption = at.hasOption("-default");
boolean waitOption = at.hasOption("-wait");
if (prog != null) {
if (defaultOption) {
errormsg("jshell.err.default.option.or.program", at.whole());
return false;
}
editor = ed.toArray(new String[ed.size()]);
editorWait = waitOption;
fluffmsg("jshell.msg.set.editor.set", prog);
} else if (defaultOption) {
if (waitOption) {
errormsg("jshell.err.wait.applies.to.external.editor", at.whole());
return false;
}
editor = null;
} else if (argsRequired) {
errormsg("jshell.err.set.editor.arg");
@ -1720,7 +1732,8 @@ public class JShellTool implements MessageHandler {
return false;
}
} else {
ExternalEditor.edit(editor, errorHandler, src, saveHandler, input);
ExternalEditor.edit(editor, errorHandler, src, saveHandler, input,
editorWait, this::hardrb);
}
return true;
}

@ -56,6 +56,8 @@ jshell.err.set.editor.arg = The ''/set editor'' command requires a path argument
jshell.msg.set.editor.set = Editor set to: {0}
jshell.err.cant.launch.editor = Cannot launch editor -- unexpected exception: {0}
jshell.msg.try.set.editor = Try /set editor to use external editor.
jshell.msg.press.return.to.leave.edit.mode = Press return to leave edit mode.
jshell.err.wait.applies.to.external.editor = -wait applies to external editors, cannot be used with -default
jshell.msg.try.command.without.args = Try ''{0}'' without arguments.
jshell.msg.no.active = There are no active definitions.
@ -358,7 +360,7 @@ Set jshell configuration information, including:\n\
the external editor to use, the start-up definitions to use, a new feedback mode,\n\
the command prompt, the feedback mode to use, or the format of output.\n\
\n\
/set editor <command> <optional-arg>...\n\t\
/set editor [-wait] <command> <optional-arg>...\n\t\
Specify the command to launch for the /edit command.\n\t\
The <command> is an operating system dependent string.\n\n\
/set start <file>\n\t\
@ -602,12 +604,19 @@ The continuation-prompt is used on the second and subsequent lines of a multi-li
help.set.editor =\
Specify the command to launch for the /edit command.\n\
\n\t\
/set editor <command>|-default\n\
/set editor [-wait] <command>|-default\n\
\n\
The <command> is an operating system dependent string.\n\
The <command> may include space-separated arguments (such as flags)\n\
When /edit is used, the temporary file to edit will be appended as the last argument.\n\
If instead the -default option is specified, the built-in default editor will be used.
The <command> may include space-separated arguments (such as flags)\n\n\
If the -default option is specified, the built-in default editor will be used.\n\n\
Otherwise an external editor should be specified in <command>. When <command>\n\
is used, the temporary file to edit will be appended as the last argument.\n\
Normally, edit mode will last until the external editor exits. Some external editors\n\
will exit immediately (for example, if the edit window exists) either external editor\n\
flags should be used to prevent immediate exit, or the -wait option should be used to\n\
prompt the user to indicate when edit mode should end.\n\n\
Note: while in edit mode no command inputs are seen. After leaving edit mode changes\n\
to the edited snippets are not seen.
help.set.start =\
Set the start-up configuration -- a sequence of snippets and commands read at start-up.\n\

@ -23,7 +23,7 @@
/*
* @test
* @bug 8157395 8157393 8157517
* @bug 8157395 8157393 8157517 8158738
* @summary Tests of jshell comand options, and undoing operations
* @modules jdk.jshell/jdk.internal.jshell.tool
* @build ToolCommandOptionTest ReplToolTesting
@ -148,6 +148,8 @@ public class ToolCommandOptionTest extends ReplToolTesting {
"| Unknown option: -furball -mattress -- /retain editor -furball -mattress"),
(a) -> assertCommand(a, "/retain editor -default prog",
"| Specify -default option or program, not both -- /retain editor -default prog"),
(a) -> assertCommand(a, "/retain editor -default -wait",
"| -wait applies to external editors, cannot be used with -default"),
(a) -> assertCommand(a, "/retain editor prog",
"| Editor set to: prog"),
(a) -> assertCommand(a, "/retain editor prog -default",