8167554: jshell tool: re-execute a range and/or sequence of snippets
8180508: jshell tool: support id ranges in all commands with id arguments Reviewed-by: jlahoda
This commit is contained in:
parent
5a0726a47a
commit
08a3a23043
@ -120,6 +120,17 @@ class ArgTokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the specified option allowed.
|
||||
*
|
||||
* @param opt the option to check
|
||||
* @return true if the option is allowed
|
||||
*/
|
||||
boolean isAllowedOption(String opt) {
|
||||
Boolean has = options.get(opt);
|
||||
return has != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the specified option been encountered.
|
||||
*
|
||||
|
@ -90,7 +90,6 @@ 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.MissingResourceException;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Spliterators;
|
||||
@ -126,6 +125,7 @@ import static jdk.internal.jshell.tool.ContinuousCompletionProvider.STARTSWITH_M
|
||||
public class JShellTool implements MessageHandler {
|
||||
|
||||
private static final Pattern LINEBREAK = Pattern.compile("\\R");
|
||||
private static final Pattern ID = Pattern.compile("[se]?\\d+([-\\s].*)?");
|
||||
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";
|
||||
@ -1189,36 +1189,54 @@ public class JShellTool implements MessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void processCommand(String cmd) {
|
||||
if (cmd.startsWith("/-")) {
|
||||
/**
|
||||
* Process a command (as opposed to a snippet) -- things that start with
|
||||
* slash.
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
private void processCommand(String input) {
|
||||
if (input.startsWith("/-")) {
|
||||
try {
|
||||
//handle "/-[number]"
|
||||
cmdUseHistoryEntry(Integer.parseInt(cmd.substring(1)));
|
||||
cmdUseHistoryEntry(Integer.parseInt(input.substring(1)));
|
||||
return ;
|
||||
} catch (NumberFormatException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
String arg = "";
|
||||
int idx = cmd.indexOf(' ');
|
||||
String cmd;
|
||||
String arg;
|
||||
int idx = input.indexOf(' ');
|
||||
if (idx > 0) {
|
||||
arg = cmd.substring(idx + 1).trim();
|
||||
cmd = cmd.substring(0, idx);
|
||||
arg = input.substring(idx + 1).trim();
|
||||
cmd = input.substring(0, idx);
|
||||
} else {
|
||||
cmd = input;
|
||||
arg = "";
|
||||
}
|
||||
// find the command as a "real command", not a pseudo-command or doc subject
|
||||
Command[] candidates = findCommand(cmd, c -> c.kind.isRealCommand);
|
||||
switch (candidates.length) {
|
||||
case 0:
|
||||
if (!rerunHistoryEntryById(cmd.substring(1))) {
|
||||
errormsg("jshell.err.no.such.command.or.snippet.id", cmd);
|
||||
// not found, it is either a snippet command or an error
|
||||
if (ID.matcher(cmd.substring(1)).matches()) {
|
||||
// it is in the form of a snipppet id, see if it is a valid history reference
|
||||
rerunHistoryEntriesById(input);
|
||||
} else {
|
||||
errormsg("jshell.err.invalid.command", cmd);
|
||||
fluffmsg("jshell.msg.help.for.help");
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
Command command = candidates[0];
|
||||
// If comand was successful and is of a replayable kind, add it the replayable history
|
||||
if (command.run.apply(arg) && command.kind == CommandKind.REPLAY) {
|
||||
addToReplayHistory((command.command + " " + arg).trim());
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// command if too short (ambigous), show the possibly matches
|
||||
errormsg("jshell.err.command.ambiguous", cmd,
|
||||
Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", ")));
|
||||
fluffmsg("jshell.msg.help.for.help");
|
||||
@ -1701,6 +1719,9 @@ public class JShellTool implements MessageHandler {
|
||||
registerCommand(new Command("context",
|
||||
"help.context",
|
||||
CommandKind.HELP_SUBJECT));
|
||||
registerCommand(new Command("rerun",
|
||||
"help.rerun",
|
||||
CommandKind.HELP_SUBJECT));
|
||||
|
||||
commandCompletions = new ContinuousCompletionProvider(
|
||||
commands.values().stream()
|
||||
@ -2247,6 +2268,20 @@ public class JShellTool implements MessageHandler {
|
||||
Predicate<Snippet> defFilter, String rawargs, String cmd) {
|
||||
ArgTokenizer at = new ArgTokenizer(cmd, rawargs.trim());
|
||||
at.allowedOptions("-all", "-start");
|
||||
return argsOptionsToSnippets(snippetSupplier, defFilter, at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert user arguments to a Stream of snippets referenced by those
|
||||
* arguments (or lack of arguments).
|
||||
*
|
||||
* @param snippets the base list of possible snippets
|
||||
* @param defFilter the filter to apply to the arguments if no argument
|
||||
* @param at the ArgTokenizer, with allowed options set
|
||||
* @return
|
||||
*/
|
||||
private <T extends Snippet> Stream<T> argsOptionsToSnippets(Supplier<Stream<T>> snippetSupplier,
|
||||
Predicate<Snippet> defFilter, ArgTokenizer at) {
|
||||
List<String> args = new ArrayList<>();
|
||||
String s;
|
||||
while ((s = at.next()) != null) {
|
||||
@ -2263,11 +2298,11 @@ public class JShellTool implements MessageHandler {
|
||||
errormsg("jshell.err.conflicting.options", at.whole());
|
||||
return null;
|
||||
}
|
||||
if (at.hasOption("-all")) {
|
||||
if (at.isAllowedOption("-all") && at.hasOption("-all")) {
|
||||
// all snippets including start-up, failed, and overwritten
|
||||
return snippetSupplier.get();
|
||||
}
|
||||
if (at.hasOption("-start")) {
|
||||
if (at.isAllowedOption("-start") && at.hasOption("-start")) {
|
||||
// start-up snippets
|
||||
return snippetSupplier.get()
|
||||
.filter(this::inStartUp);
|
||||
@ -2277,54 +2312,227 @@ public class JShellTool implements MessageHandler {
|
||||
return snippetSupplier.get()
|
||||
.filter(defFilter);
|
||||
}
|
||||
return argsToSnippets(snippetSupplier, args);
|
||||
return new ArgToSnippets<>(snippetSupplier).argsToSnippets(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert user arguments to a Stream of snippets referenced by those
|
||||
* arguments.
|
||||
* Support for converting arguments that are definition names, snippet ids,
|
||||
* or snippet id ranges into a stream of snippets,
|
||||
*
|
||||
* @param snippetSupplier the base list of possible snippets
|
||||
* @param args the user's argument to the command, maybe be the empty list
|
||||
* @return a Stream of referenced snippets or null if no matches to specific
|
||||
* arg
|
||||
* @param <T> the snipper subtype
|
||||
*/
|
||||
private <T extends Snippet> Stream<T> argsToSnippets(Supplier<Stream<T>> snippetSupplier,
|
||||
List<String> args) {
|
||||
Stream<T> result = null;
|
||||
for (String arg : args) {
|
||||
private class ArgToSnippets<T extends Snippet> {
|
||||
|
||||
// the supplier of snippet streams
|
||||
final Supplier<Stream<T>> snippetSupplier;
|
||||
// these two are parallel, and lazily filled if a range is encountered
|
||||
List<T> allSnippets;
|
||||
String[] allIds = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param snippetSupplier the base list of possible snippets
|
||||
*/
|
||||
ArgToSnippets(Supplier<Stream<T>> snippetSupplier) {
|
||||
this.snippetSupplier = snippetSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert user arguments to a Stream of snippets referenced by those
|
||||
* arguments.
|
||||
*
|
||||
* @param args the user's argument to the command, maybe be the empty
|
||||
* list
|
||||
* @return a Stream of referenced snippets or null if no matches to
|
||||
* specific arg
|
||||
*/
|
||||
Stream<T> argsToSnippets(List<String> args) {
|
||||
Stream<T> result = null;
|
||||
for (String arg : args) {
|
||||
// Find the best match
|
||||
Stream<T> st = argToSnippets(arg);
|
||||
if (st == null) {
|
||||
return null;
|
||||
} else {
|
||||
result = (result == null)
|
||||
? st
|
||||
: Stream.concat(result, st);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a user argument to a Stream of snippets referenced by the
|
||||
* argument.
|
||||
*
|
||||
* @param snippetSupplier the base list of possible snippets
|
||||
* @param arg the user's argument to the command
|
||||
* @return a Stream of referenced snippets or null if no matches to
|
||||
* specific arg
|
||||
*/
|
||||
Stream<T> argToSnippets(String arg) {
|
||||
if (arg.contains("-")) {
|
||||
return range(arg);
|
||||
}
|
||||
// Find the best match
|
||||
Stream<T> st = layeredSnippetSearch(snippetSupplier, arg);
|
||||
if (st == null) {
|
||||
Stream<Snippet> est = layeredSnippetSearch(state::snippets, arg);
|
||||
if (est == null) {
|
||||
errormsg("jshell.err.no.such.snippets", arg);
|
||||
} else {
|
||||
errormsg("jshell.err.the.snippet.cannot.be.used.with.this.command",
|
||||
arg, est.findFirst().get().source());
|
||||
}
|
||||
badSnippetErrormsg(arg);
|
||||
return null;
|
||||
}
|
||||
if (result == null) {
|
||||
result = st;
|
||||
} else {
|
||||
result = Stream.concat(result, st);
|
||||
return st;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private <T extends Snippet> Stream<T> layeredSnippetSearch(Supplier<Stream<T>> snippetSupplier, String arg) {
|
||||
return nonEmptyStream(
|
||||
// the stream supplier
|
||||
snippetSupplier,
|
||||
// look for active user declarations matching the name
|
||||
sn -> isActive(sn) && matchingDeclaration(sn, arg),
|
||||
// else, look for any declarations matching the name
|
||||
sn -> matchingDeclaration(sn, arg),
|
||||
// else, look for an id of this name
|
||||
sn -> sn.id().equals(arg)
|
||||
);
|
||||
/**
|
||||
* Look for inappropriate snippets to give best error message
|
||||
*
|
||||
* @param arg the bad snippet arg
|
||||
* @param errKey the not found error key
|
||||
*/
|
||||
void badSnippetErrormsg(String arg) {
|
||||
Stream<Snippet> est = layeredSnippetSearch(state::snippets, arg);
|
||||
if (est == null) {
|
||||
if (ID.matcher(arg).matches()) {
|
||||
errormsg("jshell.err.no.snippet.with.id", arg);
|
||||
} else {
|
||||
errormsg("jshell.err.no.such.snippets", arg);
|
||||
}
|
||||
} else {
|
||||
errormsg("jshell.err.the.snippet.cannot.be.used.with.this.command",
|
||||
arg, est.findFirst().get().source());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search through the snippets for the best match to the id/name.
|
||||
*
|
||||
* @param <R> the snippet type
|
||||
* @param aSnippetSupplier the supplier of snippet streams
|
||||
* @param arg the arg to match
|
||||
* @return a Stream of referenced snippets or null if no matches to
|
||||
* specific arg
|
||||
*/
|
||||
<R extends Snippet> Stream<R> layeredSnippetSearch(Supplier<Stream<R>> aSnippetSupplier, String arg) {
|
||||
return nonEmptyStream(
|
||||
// the stream supplier
|
||||
aSnippetSupplier,
|
||||
// look for active user declarations matching the name
|
||||
sn -> isActive(sn) && matchingDeclaration(sn, arg),
|
||||
// else, look for any declarations matching the name
|
||||
sn -> matchingDeclaration(sn, arg),
|
||||
// else, look for an id of this name
|
||||
sn -> sn.id().equals(arg)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an id1-id2 range specifier, return a stream of snippets within
|
||||
* our context
|
||||
*
|
||||
* @param arg the range arg
|
||||
* @return a Stream of referenced snippets or null if no matches to
|
||||
* specific arg
|
||||
*/
|
||||
Stream<T> range(String arg) {
|
||||
int dash = arg.indexOf('-');
|
||||
String iid = arg.substring(0, dash);
|
||||
String tid = arg.substring(dash + 1);
|
||||
int iidx = snippetIndex(iid);
|
||||
if (iidx < 0) {
|
||||
return null;
|
||||
}
|
||||
int tidx = snippetIndex(tid);
|
||||
if (tidx < 0) {
|
||||
return null;
|
||||
}
|
||||
if (tidx < iidx) {
|
||||
errormsg("jshell.err.end.snippet.range.less.than.start", iid, tid);
|
||||
return null;
|
||||
}
|
||||
return allSnippets.subList(iidx, tidx+1).stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily initialize the id mapping -- needed only for id ranges.
|
||||
*/
|
||||
void initIdMapping() {
|
||||
if (allIds == null) {
|
||||
allSnippets = snippetSupplier.get()
|
||||
.sorted((a, b) -> order(a) - order(b))
|
||||
.collect(toList());
|
||||
allIds = allSnippets.stream()
|
||||
.map(sn -> sn.id())
|
||||
.toArray(n -> new String[n]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the snippet ids -- within the context, and in order.
|
||||
*
|
||||
* @return the snippet ids
|
||||
*/
|
||||
String[] allIds() {
|
||||
initIdMapping();
|
||||
return allIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish an order on snippet ids. All startup snippets are first,
|
||||
* all error snippets are last -- within that is by snippet number.
|
||||
*
|
||||
* @param id the id string
|
||||
* @return an ordering int
|
||||
*/
|
||||
int order(String id) {
|
||||
try {
|
||||
switch (id.charAt(0)) {
|
||||
case 's':
|
||||
return Integer.parseInt(id.substring(1));
|
||||
case 'e':
|
||||
return 0x40000000 + Integer.parseInt(id.substring(1));
|
||||
default:
|
||||
return 0x20000000 + Integer.parseInt(id);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
return 0x60000000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish an order on snippets, based on its snippet id. All startup
|
||||
* snippets are first, all error snippets are last -- within that is by
|
||||
* snippet number.
|
||||
*
|
||||
* @param sn the id string
|
||||
* @return an ordering int
|
||||
*/
|
||||
int order(Snippet sn) {
|
||||
return order(sn.id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index into the parallel allSnippets and allIds structures.
|
||||
*
|
||||
* @param s the snippet id name
|
||||
* @return the index, or, if not found, report the error and return a
|
||||
* negative number
|
||||
*/
|
||||
int snippetIndex(String s) {
|
||||
int idx = Arrays.binarySearch(allIds(), 0, allIds().length, s,
|
||||
(a, b) -> order(a) - order(b));
|
||||
if (idx < 0) {
|
||||
// the id is not in the snippet domain, find the right error to report
|
||||
if (!ID.matcher(s).matches()) {
|
||||
errormsg("jshell.err.range.requires.id", s);
|
||||
} else {
|
||||
badSnippetErrormsg(s);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean cmdDrop(String rawargs) {
|
||||
@ -2342,24 +2550,13 @@ public class JShellTool implements MessageHandler {
|
||||
errormsg("jshell.err.drop.arg");
|
||||
return false;
|
||||
}
|
||||
Stream<Snippet> stream = argsToSnippets(this::dropableSnippets, args);
|
||||
Stream<Snippet> stream = new ArgToSnippets<>(this::dropableSnippets).argsToSnippets(args);
|
||||
if (stream == null) {
|
||||
// Snippet not found. Error already printed
|
||||
fluffmsg("jshell.msg.see.classes.etc");
|
||||
return false;
|
||||
}
|
||||
List<Snippet> snippets = stream.collect(toList());
|
||||
if (snippets.size() > args.size()) {
|
||||
// One of the args references more thean one snippet
|
||||
errormsg("jshell.err.drop.ambiguous");
|
||||
fluffmsg("jshell.msg.use.one.of", snippets.stream()
|
||||
.map(sn -> String.format("\n/drop %-5s : %s", sn.id(), sn.source().replace("\n", "\n ")))
|
||||
.collect(Collectors.joining(", "))
|
||||
);
|
||||
return false;
|
||||
}
|
||||
snippets.stream()
|
||||
.forEach(sn -> state.drop(sn).forEach(this::handleEvent));
|
||||
stream.forEach(sn -> state.drop(sn).forEach(this::handleEvent));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2690,37 +2887,38 @@ public class JShellTool implements MessageHandler {
|
||||
}
|
||||
|
||||
private boolean cmdSave(String rawargs) {
|
||||
ArgTokenizer at = new ArgTokenizer("/save", rawargs.trim());
|
||||
at.allowedOptions("-all", "-start", "-history");
|
||||
String filename = at.next();
|
||||
if (filename == null) {
|
||||
// The filename to save to is the last argument, extract it
|
||||
String[] args = rawargs.split("\\s");
|
||||
String filename = args[args.length - 1];
|
||||
if (filename.isEmpty()) {
|
||||
errormsg("jshell.err.file.filename", "/save");
|
||||
return false;
|
||||
}
|
||||
if (!checkOptionsAndRemainingInput(at)) {
|
||||
return false;
|
||||
}
|
||||
if (at.optionCount() > 1) {
|
||||
errormsg("jshell.err.conflicting.options", at.whole());
|
||||
// All the non-filename arguments are the specifier of what to save
|
||||
String srcSpec = Arrays.stream(args, 0, args.length - 1)
|
||||
.collect(Collectors.joining("\n"));
|
||||
// From the what to save specifier, compute the snippets (as a stream)
|
||||
ArgTokenizer at = new ArgTokenizer("/save", srcSpec);
|
||||
at.allowedOptions("-all", "-start", "-history");
|
||||
Stream<Snippet> snippetStream = argsOptionsToSnippets(state::snippets, this::mainActive, at);
|
||||
if (snippetStream == null) {
|
||||
// error occurred, already reported
|
||||
return false;
|
||||
}
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(toPathResolvingUserHome(filename),
|
||||
Charset.defaultCharset(),
|
||||
CREATE, TRUNCATE_EXISTING, WRITE)) {
|
||||
if (at.hasOption("-history")) {
|
||||
// they want history (commands and snippets), ignore the snippet stream
|
||||
for (String s : input.currentSessionHistory()) {
|
||||
writer.write(s);
|
||||
writer.write("\n");
|
||||
}
|
||||
} else if (at.hasOption("-start")) {
|
||||
writer.append(startup.toString());
|
||||
} else {
|
||||
String sources = (at.hasOption("-all")
|
||||
? state.snippets()
|
||||
: state.snippets().filter(this::mainActive))
|
||||
// write the snippet stream to the file
|
||||
writer.write(snippetStream
|
||||
.map(Snippet::source)
|
||||
.collect(Collectors.joining("\n"));
|
||||
writer.write(sources);
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
errormsg("jshell.err.file.not.found", "/save", filename, e.getMessage());
|
||||
@ -2837,14 +3035,21 @@ public class JShellTool implements MessageHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean rerunHistoryEntryById(String id) {
|
||||
Optional<Snippet> snippet = state.snippets()
|
||||
.filter(s -> s.id().equals(id))
|
||||
.findFirst();
|
||||
return snippet.map(s -> {
|
||||
rerunSnippet(s);
|
||||
return true;
|
||||
}).orElse(false);
|
||||
/**
|
||||
* Handle snippet reevaluation commands: {@code /<id>}. These commands are a
|
||||
* sequence of ids and id ranges (names are permitted, though not in the
|
||||
* first position. Support for names is purposely not documented).
|
||||
*
|
||||
* @param rawargs the whole command including arguments
|
||||
*/
|
||||
private void rerunHistoryEntriesById(String rawargs) {
|
||||
ArgTokenizer at = new ArgTokenizer("/<id>", rawargs.trim().substring(1));
|
||||
at.allowedOptions();
|
||||
Stream<Snippet> stream = argsOptionsToSnippets(state::snippets, sn -> true, at);
|
||||
if (stream != null) {
|
||||
// successfully parsed, rerun snippets
|
||||
stream.forEach(sn -> rerunSnippet(sn));
|
||||
}
|
||||
}
|
||||
|
||||
private void rerunSnippet(Snippet snippet) {
|
||||
|
@ -50,7 +50,7 @@ jshell.err.file.filename = ''{0}'' requires a filename argument.
|
||||
jshell.err.startup.unexpected.exception = Unexpected exception reading start-up: {0}
|
||||
jshell.err.unexpected.exception = Unexpected exception: {0}
|
||||
|
||||
jshell.err.no.such.command.or.snippet.id = No such command or snippet id: {0}
|
||||
jshell.err.invalid.command = Invalid command: {0}
|
||||
jshell.err.command.ambiguous = Command: ''{0}'' is ambiguous: {1}
|
||||
jshell.msg.set.restore = Setting new options and restoring state.
|
||||
jshell.msg.set.editor.set = Editor set to: {0}
|
||||
@ -105,10 +105,13 @@ For example ''/help /list'' or ''/help intro''.\n\
|
||||
Subjects:\n\
|
||||
\n
|
||||
|
||||
jshell.err.no.snippet.with.id = No snippet with id: {0}
|
||||
jshell.err.end.snippet.range.less.than.start = End of snippet range less than start: {0} - {1}
|
||||
jshell.err.range.requires.id = Snippet ranges require snippet ids: {0}
|
||||
|
||||
jshell.err.drop.arg =\
|
||||
In the /drop argument, please specify an import, variable, method, or class to drop.\n\
|
||||
Specify by id or name. Use /list to see ids. Use /reset to reset all state.
|
||||
jshell.err.drop.ambiguous = The argument references more than one import, variable, method, or class.
|
||||
jshell.err.failed = Failed.
|
||||
jshell.msg.native.method = Native Method
|
||||
jshell.msg.unknown.source = Unknown Source
|
||||
@ -225,7 +228,11 @@ Show the source of snippets, prefaced with the snippet id.\n\
|
||||
/list <name>\n\t\
|
||||
List snippets with the specified name (preference for active snippets)\n\n\
|
||||
/list <id>\n\t\
|
||||
List the snippet with the specified snippet id
|
||||
List the snippet with the specified snippet id\n\n\
|
||||
/list <id> <id>...\n\t\
|
||||
List the snippets with the specified snippet ids\n\n\
|
||||
/list <id>-<id>\n\t\
|
||||
List the snippets within the range of snippet ids
|
||||
|
||||
help.edit.summary = edit a source entry referenced by name or id
|
||||
help.edit.args = <name or id>
|
||||
@ -238,6 +245,10 @@ If no editor has been set, a simple editor will be launched.\n\
|
||||
Edit the snippet or snippets with the specified name (preference for active snippets)\n\n\
|
||||
/edit <id>\n\t\
|
||||
Edit the snippet with the specified snippet id\n\n\
|
||||
/edit <id> <id>...\n\t\
|
||||
Edit the snippets with the specified snippet ids\n\n\
|
||||
/edit <id>-<id>\n\t\
|
||||
Edit the snippets within the range of snippet ids\n\n\
|
||||
/edit\n\t\
|
||||
Edit the currently active snippets of code that you typed or read with /open
|
||||
|
||||
@ -249,7 +260,11 @@ Drop a snippet -- making it inactive.\n\
|
||||
/drop <name>\n\t\
|
||||
Drop the snippet with the specified name\n\n\
|
||||
/drop <id>\n\t\
|
||||
Drop the snippet with the specified snippet id
|
||||
Drop the snippet with the specified snippet id\n\n\
|
||||
/drop <id> <id>...\n\t\
|
||||
Drop the snippets with the specified snippet ids\n\n\
|
||||
/drop <id>-<id>\n\t\
|
||||
Drop the snippets within the range of snippet ids
|
||||
|
||||
help.save.summary = Save snippet source to a file.
|
||||
help.save.args = [-all|-history|-start] <file>
|
||||
@ -264,7 +279,13 @@ Save the specified snippets and/or commands to the specified file.\n\
|
||||
/save -history <file>\n\t\
|
||||
Save the sequential history of all commands and snippets entered since jshell was launched.\n\n\
|
||||
/save -start <file>\n\t\
|
||||
Save the current start-up definitions to the file.
|
||||
Save the current start-up definitions to the file.\n\n\
|
||||
/save <id> <file>\n\t\
|
||||
Save the snippet with the specified snippet id\n\n\
|
||||
/save <id> <id>... <file>\n\t\
|
||||
Save the snippets with the specified snippet ids\n\n\
|
||||
/save <id>-<id> <file>\n\t\
|
||||
Save the snippets within the range of snippet ids
|
||||
|
||||
help.open.summary = open a file as source input
|
||||
help.open.args = <file>
|
||||
@ -285,6 +306,10 @@ List the type, name, and value of jshell variables.\n\
|
||||
List jshell variables with the specified name (preference for active variables)\n\n\
|
||||
/vars <id>\n\t\
|
||||
List the jshell variable with the specified snippet id\n\n\
|
||||
/vars <id> <id>... <file>\n\t\
|
||||
List the jshell variables with the specified snippet ids\n\n\
|
||||
/vars <id>-<id> <file>\n\t\
|
||||
List the jshell variables within the range of snippet ids\n\n\
|
||||
/vars -start\n\t\
|
||||
List the automatically added start-up jshell variables\n\n\
|
||||
/vars -all\n\t\
|
||||
@ -301,6 +326,10 @@ List the name, parameter types, and return type of jshell methods.\n\
|
||||
List jshell methods with the specified name (preference for active methods)\n\n\
|
||||
/methods <id>\n\t\
|
||||
List the jshell method with the specified snippet id\n\n\
|
||||
/methods <id> <id>... <file>\n\t\
|
||||
List jshell methods with the specified snippet ids\n\n\
|
||||
/methods <id>-<id> <file>\n\t\
|
||||
List jshell methods within the range of snippet ids\n\n\
|
||||
/methods -start\n\t\
|
||||
List the automatically added start-up jshell methods\n\n\
|
||||
/methods -all\n\t\
|
||||
@ -317,6 +346,10 @@ List jshell classes, interfaces, and enums.\n\
|
||||
List jshell types with the specified name (preference for active types)\n\n\
|
||||
/types <id>\n\t\
|
||||
List the jshell type with the specified snippet id\n\n\
|
||||
/types <id> <id>... <file>\n\t\
|
||||
List jshell types with the specified snippet ids\n\n\
|
||||
/types <id>-<id> <file>\n\t\
|
||||
List jshell types within the range of snippet ids\n\n\
|
||||
/types -start\n\t\
|
||||
List the automatically added start-up jshell types\n\n\
|
||||
/types -all\n\t\
|
||||
@ -461,17 +494,24 @@ Display information about jshell (abbreviation for /help).\n\
|
||||
/? <subject>\n\t\
|
||||
Display information about the specified help subject. Example: /? intro
|
||||
|
||||
help.bang.summary = re-run last snippet
|
||||
help.bang.summary = rerun last snippet -- see /help rerun
|
||||
help.bang.args =
|
||||
help.bang =\
|
||||
Reevaluate the most recently entered snippet.
|
||||
|
||||
help.id.summary = re-run snippet by id
|
||||
help.id.summary = rerun snippets by id or id range -- see /help rerun
|
||||
help.id.args =
|
||||
help.id =\
|
||||
Reevaluate the snippet specified by the id.
|
||||
/<id> <id> <id>\n\
|
||||
\n\
|
||||
/<id>-<id>\n\
|
||||
\n\
|
||||
Reevaluate the snippets specified by the id or id range.\n\
|
||||
An id range is represented as a two ids separated by a hyphen, e.g.: 3-17\n\
|
||||
Start-up and error snippets maybe used, e.g.: s3-s9 or e1-e4\n\
|
||||
Any number of ids or id ranges may be used, e.g.: /3-7 s4 14-16 e2
|
||||
|
||||
help.previous.summary = re-run n-th previous snippet
|
||||
help.previous.summary = rerun n-th previous snippet -- see /help rerun
|
||||
help.previous.args =
|
||||
help.previous =\
|
||||
Reevaluate the n-th most recently entered snippet.
|
||||
@ -509,7 +549,7 @@ Shift-<tab> i\n\t\t\
|
||||
then release and press "i", and jshell will propose possible imports\n\t\t\
|
||||
which will resolve the identifier based on the content of the specified classpath.
|
||||
|
||||
help.context.summary = the evaluation context options for /env /reload and /reset
|
||||
help.context.summary = a description of the evaluation context options for /env /reload and /reset
|
||||
help.context =\
|
||||
These options configure the evaluation context, they can be specified when\n\
|
||||
jshell is started: on the command-line, or restarted with the commands /env,\n\
|
||||
@ -540,6 +580,38 @@ They are:\n\t\
|
||||
On the command-line these options must have two dashes, e.g.: --module-path\n\
|
||||
On jshell commands they can have one or two dashes, e.g.: -module-path\n\
|
||||
|
||||
help.rerun.summary = a description of ways to re-evaluate previously entered snippets
|
||||
help.rerun =\
|
||||
There are four ways to re-evaluate previously entered snippets.\n\
|
||||
The last snippet can be re-evaluated using: /!\n\
|
||||
The n-th previous snippet can be re-evaluated by slash-minus and the digits of n, e.g.: /-4\n\
|
||||
For example:\n\
|
||||
\n\
|
||||
\tjshell> 2 + 2\n\
|
||||
\t$1 ==> 4\n\
|
||||
\n\
|
||||
\tjshell> /!\n\
|
||||
\t2 + 2\n\
|
||||
\t$2 ==> 4\n\
|
||||
\n\
|
||||
\tjshell> int z\n\
|
||||
\tz ==> 0\n\
|
||||
\n\
|
||||
\tjshell> /-1\n\
|
||||
\tint z;\n\
|
||||
\tz ==> 0\n\
|
||||
\n\
|
||||
\tjshell> /-4\n\
|
||||
\t2 + 2\n\
|
||||
\t$5 ==> 4\n\
|
||||
\n\
|
||||
The snippets to re-evaluate may be specified by snippet id or id range.\n\
|
||||
An id range is represented as a two ids separated by a hyphen, e.g.: 3-17\n\
|
||||
Start-up and error snippets maybe used, e.g.: s3-s9 or e1-e4\n\
|
||||
Any number of ids or id ranges may be used, e.g.: /3-7 s4 14-16 e2\n\
|
||||
\n\
|
||||
Finally, you can search backwards through history by entering ctrl-R followed by the string to search for.
|
||||
|
||||
help.set._retain = \
|
||||
The '-retain' option saves a setting so that it is used in future sessions.\n\
|
||||
The -retain option can be used on the following forms of /set:\n\n\t\
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8144095 8164825 8169818 8153402 8165405 8177079 8178013
|
||||
* @bug 8144095 8164825 8169818 8153402 8165405 8177079 8178013 8167554
|
||||
* @summary Test Command Completion
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
@ -162,13 +162,13 @@ public class CommandCompletionTest extends ReplToolTesting {
|
||||
"/edit ", "/env ", "/exit ",
|
||||
"/help ", "/history ", "/imports ",
|
||||
"/list ", "/methods ", "/open ", "/reload ", "/reset ",
|
||||
"/save ", "/set ", "/types ", "/vars ", "context ", "intro ", "shortcuts "),
|
||||
"/save ", "/set ", "/types ", "/vars ", "context ", "intro ", "rerun ", "shortcuts "),
|
||||
a -> assertCompletion(a, "/? |", false,
|
||||
"/! ", "/-<n> ", "/<id> ", "/? ", "/drop ",
|
||||
"/edit ", "/env ", "/exit ",
|
||||
"/help ", "/history ", "/imports ",
|
||||
"/list ", "/methods ", "/open ", "/reload ", "/reset ",
|
||||
"/save ", "/set ", "/types ", "/vars ", "context ", "intro ", "shortcuts "),
|
||||
"/save ", "/set ", "/types ", "/vars ", "context ", "intro ", "rerun ", "shortcuts "),
|
||||
a -> assertCompletion(a, "/help /s|", false,
|
||||
"/save ", "/set "),
|
||||
a -> assertCompletion(a, "/help /set |", false,
|
||||
|
@ -73,7 +73,7 @@ public abstract class EditorTestBase extends ReplToolTesting {
|
||||
for (String edit : new String[] {"/ed", "/edit"}) {
|
||||
test(new String[]{"--no-startup"},
|
||||
a -> assertCommandOutputStartsWith(a, edit + " 1",
|
||||
"| No such snippet: 1"),
|
||||
"| No snippet with id: 1"),
|
||||
a -> assertCommandOutputStartsWith(a, edit + " unknown",
|
||||
"| No such snippet: unknown")
|
||||
);
|
||||
|
@ -66,17 +66,17 @@ public class MergedTabShiftTabCommandTest extends UITesting {
|
||||
Pattern.quote(getResource("jshell.console.see.next.command.doc")) + "\n" +
|
||||
"\r\u0005/");
|
||||
|
||||
inputSink.write("lis\011");
|
||||
waitOutput(out, "list $");
|
||||
inputSink.write("ed\011");
|
||||
waitOutput(out, "edit $");
|
||||
|
||||
inputSink.write("\011");
|
||||
waitOutput(out, ".*-all.*" +
|
||||
"\n\n" + Pattern.quote(getResource("jshell.console.see.synopsis")) + "\n\r\u0005/");
|
||||
inputSink.write("\011");
|
||||
waitOutput(out, Pattern.quote(getResource("help.list.summary")) + "\n\n" +
|
||||
Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/list ");
|
||||
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.list").replaceAll("\t", " ")));
|
||||
waitOutput(out, Pattern.quote(getResource("help.edit").replaceAll("\t", " ")));
|
||||
|
||||
inputSink.write("\u0003/env \011");
|
||||
waitOutput(out, "\u0005/env -\n" +
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 8166649 8167643 8170162 8172102 8165405 8174796 8174797 8175304
|
||||
* @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 8166649 8167643 8170162 8172102 8165405 8174796 8174797 8175304 8167554 8180508
|
||||
* @summary Tests for Basic tests for REPL tool
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
@ -190,8 +190,8 @@ public class ToolBasicTest extends ReplToolTesting {
|
||||
|
||||
public void testRerun() {
|
||||
test(false, new String[] {"--no-startup"},
|
||||
(a) -> assertCommand(a, "/0", "| No such command or snippet id: /0\n| Type /help for help."),
|
||||
(a) -> assertCommand(a, "/5", "| No such command or snippet id: /5\n| Type /help for help.")
|
||||
(a) -> assertCommand(a, "/0", "| No snippet with id: 0"),
|
||||
(a) -> assertCommand(a, "/5", "| No snippet with id: 5")
|
||||
);
|
||||
String[] codes = new String[] {
|
||||
"int a = 0;", // var
|
||||
@ -252,9 +252,9 @@ public class ToolBasicTest extends ReplToolTesting {
|
||||
);
|
||||
|
||||
test(false, new String[] {"--no-startup"},
|
||||
(a) -> assertCommand(a, "/s1", "| No such command or snippet id: /s1\n| Type /help for help."),
|
||||
(a) -> assertCommand(a, "/1", "| No such command or snippet id: /1\n| Type /help for help."),
|
||||
(a) -> assertCommand(a, "/e1", "| No such command or snippet id: /e1\n| Type /help for help.")
|
||||
(a) -> assertCommand(a, "/s1", "| No snippet with id: s1"),
|
||||
(a) -> assertCommand(a, "/1", "| No snippet with id: 1"),
|
||||
(a) -> assertCommand(a, "/e1", "| No snippet with id: e1")
|
||||
);
|
||||
}
|
||||
|
||||
@ -481,17 +481,19 @@ public class ToolBasicTest extends ReplToolTesting {
|
||||
public void testSave() throws IOException {
|
||||
Compiler compiler = new Compiler();
|
||||
Path path = compiler.getPath("testSave.repl");
|
||||
List<String> list = Arrays.asList(
|
||||
"int a;",
|
||||
"class A { public String toString() { return \"A\"; } }"
|
||||
);
|
||||
test(
|
||||
(a) -> assertVariable(a, "int", "a"),
|
||||
(a) -> assertCommand(a, "()", null, null, null, "", ""),
|
||||
(a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"),
|
||||
(a) -> assertCommand(a, "/save " + path.toString(), "")
|
||||
);
|
||||
assertEquals(Files.readAllLines(path), list);
|
||||
{
|
||||
List<String> list = Arrays.asList(
|
||||
"int a;",
|
||||
"class A { public String toString() { return \"A\"; } }"
|
||||
);
|
||||
test(
|
||||
(a) -> assertVariable(a, "int", "a"),
|
||||
(a) -> assertCommand(a, "()", null, null, null, "", ""),
|
||||
(a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"),
|
||||
(a) -> assertCommand(a, "/save " + path.toString(), "")
|
||||
);
|
||||
assertEquals(Files.readAllLines(path), list);
|
||||
}
|
||||
{
|
||||
List<String> output = new ArrayList<>();
|
||||
test(
|
||||
@ -499,28 +501,47 @@ public class ToolBasicTest extends ReplToolTesting {
|
||||
(a) -> assertCommand(a, "()", null, null, null, "", ""),
|
||||
(a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"),
|
||||
(a) -> assertCommandCheckOutput(a, "/list -all", (out) ->
|
||||
output.addAll(Stream.of(out.split("\n"))
|
||||
.filter(str -> !str.isEmpty())
|
||||
.map(str -> str.substring(str.indexOf(':') + 2))
|
||||
.filter(str -> !str.startsWith("/"))
|
||||
.collect(Collectors.toList()))),
|
||||
output.addAll(Stream.of(out.split("\n"))
|
||||
.filter(str -> !str.isEmpty())
|
||||
.map(str -> str.substring(str.indexOf(':') + 2))
|
||||
.filter(str -> !str.startsWith("/"))
|
||||
.collect(Collectors.toList()))),
|
||||
(a) -> assertCommand(a, "/save -all " + path.toString(), "")
|
||||
);
|
||||
assertEquals(Files.readAllLines(path), output);
|
||||
}
|
||||
List<String> output = new ArrayList<>();
|
||||
test(
|
||||
(a) -> assertVariable(a, "int", "a"),
|
||||
(a) -> assertCommand(a, "()", null, null, null, "", ""),
|
||||
(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);
|
||||
{
|
||||
List<String> output = new ArrayList<>();
|
||||
test(
|
||||
(a) -> assertCommand(a, "int a;", null),
|
||||
(a) -> assertCommand(a, "int b;", null),
|
||||
(a) -> assertCommand(a, "int c;", null),
|
||||
(a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"),
|
||||
(a) -> assertCommandCheckOutput(a, "/list b c a A", (out) ->
|
||||
output.addAll(Stream.of(out.split("\n"))
|
||||
.filter(str -> !str.isEmpty())
|
||||
.map(str -> str.substring(str.indexOf(':') + 2))
|
||||
.filter(str -> !str.startsWith("/"))
|
||||
.collect(Collectors.toList()))),
|
||||
(a) -> assertCommand(a, "/save 2-3 1 4 " + path.toString(), "")
|
||||
);
|
||||
assertEquals(Files.readAllLines(path), output);
|
||||
}
|
||||
{
|
||||
List<String> output = new ArrayList<>();
|
||||
test(
|
||||
(a) -> assertVariable(a, "int", "a"),
|
||||
(a) -> assertCommand(a, "()", null, null, null, "", ""),
|
||||
(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 testStartRetain() {
|
||||
@ -652,6 +673,64 @@ public class ToolBasicTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
public void testRerunIdRange() {
|
||||
Compiler compiler = new Compiler();
|
||||
Path startup = compiler.getPath("rangeStartup");
|
||||
String[] startupSources = new String[] {
|
||||
"boolean go = false",
|
||||
"void println(String s) { if (go) System.out.println(s); }",
|
||||
"void println(int i) { if (go) System.out.println(i); }",
|
||||
"println(\"s4\")",
|
||||
"println(\"s5\")",
|
||||
"println(\"s6\")"
|
||||
};
|
||||
String[] sources = new String[] {
|
||||
"frog",
|
||||
"go = true",
|
||||
"println(2)",
|
||||
"println(3)",
|
||||
"println(4)",
|
||||
"querty"
|
||||
};
|
||||
compiler.writeToFile(startup, startupSources);
|
||||
test(false, new String[]{"--startup", startup.toString()},
|
||||
a -> assertCommandOutputStartsWith(a, sources[0], "| Error:"),
|
||||
a -> assertCommand(a, sources[1], "go ==> true", "", null, "", ""),
|
||||
a -> assertCommand(a, sources[2], "", "", null, "2\n", ""),
|
||||
a -> assertCommand(a, sources[3], "", "", null, "3\n", ""),
|
||||
a -> assertCommand(a, sources[4], "", "", null, "4\n", ""),
|
||||
a -> assertCommandOutputStartsWith(a, sources[5], "| Error:"),
|
||||
a -> assertCommand(a, "/3", "println(3)", "", null, "3\n", ""),
|
||||
a -> assertCommand(a, "/s4", "println(\"s4\")", "", null, "s4\n", ""),
|
||||
a -> assertCommandOutputStartsWith(a, "/e1", "frog\n| Error:"),
|
||||
a -> assertCommand(a, "/2-4",
|
||||
"println(2)\nprintln(3)\nprintln(4)",
|
||||
"", null, "2\n3\n4\n", ""),
|
||||
a -> assertCommand(a, "/s4-s6",
|
||||
startupSources[3] + "\n" +startupSources[4] + "\n" +startupSources[5],
|
||||
"", null, "s4\ns5\ns6\n", ""),
|
||||
a -> assertCommand(a, "/s4-4", null,
|
||||
"", null, "s4\ns5\ns6\n2\n3\n4\n", ""),
|
||||
a -> assertCommandCheckOutput(a, "/e1-e2",
|
||||
s -> {
|
||||
assertTrue(s.trim().startsWith("frog\n| Error:"),
|
||||
"Output: \'" + s + "' does not start with: " + "| Error:");
|
||||
assertTrue(s.trim().lastIndexOf("| Error:") > 10,
|
||||
"Output: \'" + s + "' does not have second: " + "| Error:");
|
||||
}),
|
||||
a -> assertCommand(a, "/4 s4 2",
|
||||
"println(4)\nprintln(\"s4\")\nprintln(2)",
|
||||
"", null, "4\ns4\n2\n", ""),
|
||||
a -> assertCommand(a, "/s5 2-4 3",
|
||||
"println(\"s5\")\nprintln(2)\nprintln(3)\nprintln(4)\nprintln(3)",
|
||||
"", null, "s5\n2\n3\n4\n3\n", ""),
|
||||
a -> assertCommand(a, "/2 ff", "| No such snippet: ff"),
|
||||
a -> assertCommand(a, "/4-2", "| End of snippet range less than start: 4 - 2"),
|
||||
a -> assertCommand(a, "/s5-s3", "| End of snippet range less than start: s5 - s3"),
|
||||
a -> assertCommand(a, "/4-s5", "| End of snippet range less than start: 4 - s5")
|
||||
);
|
||||
}
|
||||
|
||||
@Test(enabled = false) // TODO 8158197
|
||||
public void testHeadlessEditPad() {
|
||||
String prevHeadless = System.getProperty("java.awt.headless");
|
||||
|
@ -117,7 +117,6 @@ public class ToolLocaleMessageTest extends ReplToolTesting {
|
||||
(a) -> assertCommandFail(a, "/drop rats"),
|
||||
(a) -> assertCommandOK(a, "void dup() {}"),
|
||||
(a) -> assertCommandOK(a, "int dup"),
|
||||
(a) -> assertCommandFail(a, "/drop dup"),
|
||||
(a) -> assertCommandFail(a, "/edit zebra", "zebra"),
|
||||
(a) -> assertCommandFail(a, "/list zebra", "zebra", "No such snippet: zebra"),
|
||||
(a) -> assertCommandFail(a, "/open", "/open"),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079
|
||||
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508
|
||||
* @summary Simple jshell tool tests
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
@ -37,6 +37,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -202,7 +203,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
@Test
|
||||
public void testUnknownCommand() {
|
||||
test((a) -> assertCommand(a, "/unknown",
|
||||
"| No such command or snippet id: /unknown\n" +
|
||||
"| Invalid command: /unknown\n" +
|
||||
"| Type /help for help."));
|
||||
}
|
||||
|
||||
@ -274,10 +275,26 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDropRange() {
|
||||
test(false, new String[]{"--no-startup"},
|
||||
a -> assertVariable(a, "int", "a"),
|
||||
a -> assertMethod(a, "int b() { return 0; }", "()int", "b"),
|
||||
a -> assertClass(a, "class A {}", "class", "A"),
|
||||
a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
|
||||
a -> assertCommand(a, "for (int i = 0; i < 10; ++i) {}", ""),
|
||||
a -> assertCommand(a, "/drop 3-5 b 1",
|
||||
"| dropped class A\n" +
|
||||
"| dropped method b()\n" +
|
||||
"| dropped variable a\n"),
|
||||
a -> assertCommand(a, "/list", "")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDropNegative() {
|
||||
test(false, new String[]{"--no-startup"},
|
||||
a -> assertCommandOutputStartsWith(a, "/drop 0", "| No such snippet: 0"),
|
||||
a -> assertCommandOutputStartsWith(a, "/drop 0", "| No snippet with id: 0"),
|
||||
a -> assertCommandOutputStartsWith(a, "/drop a", "| No such snippet: a"),
|
||||
a -> assertCommandCheckOutput(a, "/drop",
|
||||
assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")),
|
||||
@ -292,27 +309,23 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
|
||||
@Test
|
||||
public void testAmbiguousDrop() {
|
||||
Consumer<String> check = s -> {
|
||||
assertTrue(s.startsWith("| The argument references more than one import, variable, method, or class"), s);
|
||||
int lines = s.split("\n").length;
|
||||
assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s);
|
||||
};
|
||||
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, "/types", assertClasses()),
|
||||
a -> assertCommandCheckOutput(a, "/imports", assertImports())
|
||||
a -> assertCommand(a, "/drop a",
|
||||
"| dropped variable a\n" +
|
||||
"| dropped method a()\n" +
|
||||
"| dropped class a")
|
||||
);
|
||||
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())
|
||||
a -> assertCommand(a, "/drop a",
|
||||
"| dropped method a()\n" +
|
||||
"| dropped method a(int)\n" +
|
||||
"| dropped method a(double)\n")
|
||||
);
|
||||
}
|
||||
|
||||
@ -402,12 +415,14 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
String arg = "qqqq";
|
||||
List<String> startVarList = new ArrayList<>(START_UP);
|
||||
startVarList.add("int aardvark");
|
||||
startVarList.add("int weevil");
|
||||
test(
|
||||
a -> assertCommandCheckOutput(a, "/list -all",
|
||||
s -> checkLineToList(s, START_UP)),
|
||||
a -> assertCommandOutputStartsWith(a, "/list " + arg,
|
||||
"| No such snippet: " + arg),
|
||||
a -> assertVariable(a, "int", "aardvark"),
|
||||
a -> assertVariable(a, "int", "weevil"),
|
||||
a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"),
|
||||
a -> assertCommandCheckOutput(a, "/list -start",
|
||||
s -> checkLineToList(s, START_UP)),
|
||||
@ -415,6 +430,11 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
s -> checkLineToList(s, startVarList)),
|
||||
a -> assertCommandOutputStartsWith(a, "/list s3",
|
||||
"s3 : import"),
|
||||
a -> assertCommandCheckOutput(a, "/list 1-2 s3",
|
||||
s -> {
|
||||
assertTrue(Pattern.matches(".*aardvark.*\\R.*weevil.*\\R.*s3.*import.*", s.trim()),
|
||||
"No match: " + s);
|
||||
}),
|
||||
a -> assertCommandOutputStartsWith(a, "/list " + arg,
|
||||
"| No such snippet: " + arg)
|
||||
);
|
||||
@ -439,6 +459,8 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
s -> checkLineToList(s, startVarList)),
|
||||
a -> assertCommandOutputStartsWith(a, "/vars -all",
|
||||
"| int aardvark = 0\n| int a = "),
|
||||
a -> assertCommandOutputStartsWith(a, "/vars 1-4",
|
||||
"| int aardvark = 0\n| int a = "),
|
||||
a -> assertCommandOutputStartsWith(a, "/vars f",
|
||||
"| This command does not accept the snippet 'f'"),
|
||||
a -> assertCommand(a, "/var " + arg,
|
||||
|
Loading…
Reference in New Issue
Block a user