diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index 6182aaea3027b067d8eab55aeec7bb2269ffaf03..8b8c6ddf0b7e9b26d7623a7a837adf9637b7086d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -132,7 +132,7 @@ class ConsoleIOContext extends IOContext { } catch (IOException ex) { throw new IllegalStateException(ex); } - result.add(""); + result.add(repl.messageFormat("jshell.console.see.more")); return cursor; //anchor should not be used. } @@ -337,7 +337,7 @@ class ConsoleIOContext extends IOContext { fixes.add(0, new Fix() { @Override public String displayName() { - return "Do nothing"; + return repl.messageFormat("jshell.console.do.nothing"); } @Override @@ -353,7 +353,7 @@ class ConsoleIOContext extends IOContext { char2Fix.put((char) ('0' + i), fix); in.println("" + i + ": " + fixes.get(i).displayName()); } - in.print("Choice: "); + in.print(repl.messageFormat("jshell.console.choice")); in.flush(); int read; @@ -438,7 +438,7 @@ class ConsoleIOContext extends IOContext { return new FixResult(Collections.singletonList(new Fix() { @Override public String displayName() { - return "Create variable"; + return repl.messageFormat("jshell.console.create.variable"); } @Override public void perform(ConsoleReader in) throws IOException { @@ -472,14 +472,14 @@ class ConsoleIOContext extends IOContext { } if (res.isResolvable()) { return new FixResult(Collections.emptyList(), - "\nThe identifier is resolvable in this context."); + repl.messageFormat("jshell.console.resolvable")); } else { String error = ""; if (fixes.isEmpty()) { - error = "\nNo candidate fully qualified names found to import."; + error = repl.messageFormat("jshell.console.no.candidate"); } if (!res.isUpToDate()) { - error += "\nResults may be incomplete; try again later for complete results."; + error += repl.messageFormat("jshell.console.incomplete"); } return new FixResult(fixes, error); } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java index 1fb1f60f227bd8aabb16860b0ad2a81bc1f7bc4b..8ebf1216611c7c9194848c2c55c7cfd4b3ab7d3c 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -33,10 +33,8 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Stream; import static java.util.stream.Collectors.joining; /** @@ -113,22 +111,6 @@ class Feedback { return new Setter(tool, at).setPrompt(); } - public void printFeedbackHelp(JShellTool tool) { - new Setter(tool, null).printFeedbackHelp(); - } - - public void printFormatHelp(JShellTool tool) { - new Setter(tool, null).printFormatHelp(); - } - - public void printNewModeHelp(JShellTool tool) { - new Setter(tool, null).printNewModeHelp(); - } - - public void printPromptHelp(JShellTool tool) { - new Setter(tool, null).printPromptHelp(); - } - { for (FormatCase e : EnumSet.allOf(FormatCase.class)) selectorMap.put(e.name().toLowerCase(Locale.US), e); @@ -555,38 +537,18 @@ class Feedback { this.at = at; } - void hard(String format, Object... args) { - tool.hard(format, args); - } - - void hardrb(String key) { - tool.hardrb(key); - } - - > void hardEnums(EnumSet es, Function e2s) { - hardPairs(es.stream(), ev -> ev.name().toLowerCase(Locale.US), e2s); - } - - void hardPairs(Stream stream, Function a, Function b) { - tool.hardPairs(stream, a, b); - } - void fluff(String format, Object... args) { tool.fluff(format, args); } - void error(String format, Object... args) { - tool.error(format, args); + void fluffmsg(String format, Object... args) { + tool.fluffmsg(format, args); } - void errorat(String format, Object... args) { - Object[] a2 = Arrays.copyOf(args, args.length + 1); - a2[args.length] = at.whole(); - tool.error(format + " -- /set %s", a2); - } - - void fluffRaw(String format, Object... args) { - tool.fluffRaw(format, args); + void errorat(String messageKey, Object... args) { + Object[] a2 = Arrays.copyOf(args, args.length + 2); + a2[args.length] = "/set " + at.whole(); + tool.errormsg(messageKey, a2); } // For /set prompt "" "" @@ -597,7 +559,7 @@ class Feedback { if (valid) { m.setPrompts(prompt, continuationPrompt); } else { - fluff("See '/help /set prompt' for help"); + fluffmsg("jshell.msg.see", "/help /set prompt"); } return valid; } @@ -606,17 +568,17 @@ class Feedback { boolean setNewMode() { String umode = at.next(); if (umode == null) { - errorat("Expected new feedback mode"); + errorat("jshell.err.feedback.expected.new.feedback.mode"); valid = false; } if (modeMap.containsKey(umode)) { - errorat("Expected a new feedback mode name. %s is a known feedback mode", umode); + errorat("jshell.err.feedback.expected.mode.name", umode); valid = false; } String[] fluffOpt = at.next("command", "quiet"); boolean fluff = fluffOpt == null || fluffOpt.length != 1 || "command".equals(fluffOpt[0]); if (fluffOpt != null && fluffOpt.length != 1) { - errorat("Specify either 'command' or 'quiet'"); + errorat("jshell.err.feedback.command.quiet"); valid = false; } Mode om = null; @@ -629,9 +591,9 @@ class Feedback { ? new Mode(umode, fluff, om) : new Mode(umode, fluff); modeMap.put(umode, nm); - fluff("Created new feedback mode: %s", nm.name); + fluffmsg("jshell.msg.feedback.new.mode", nm.name); } else { - fluff("See '/help /set newmode' for help"); + fluffmsg("jshell.msg.see", "/help /set newmode"); } return valid; } @@ -641,9 +603,9 @@ class Feedback { Mode m = nextMode(); if (valid && m != null) { mode = m; - fluff("Feedback mode: %s", mode.name); + fluffmsg("jshell.msg.feedback.mode", mode.name); } else { - fluff("See '/help /set feedback' for help"); + fluffmsg("jshell.msg.see", "/help /set feedback"); } return valid; } @@ -653,7 +615,7 @@ class Feedback { Mode m = nextMode(); String field = at.next(); if (field == null || at.isQuoted()) { - errorat("Expected field name missing"); + errorat("jshell.err.feedback.expected.field"); valid = false; } String format = valid? nextFormat() : null; @@ -675,7 +637,7 @@ class Feedback { format)); } } else { - fluff("See '/help /set format' for help"); + fluffmsg("jshell.msg.see", "/help /set format"); } return valid; } @@ -687,7 +649,7 @@ class Feedback { Mode toMode(String umode) { if (umode == null) { - errorat("Expected a feedback mode"); + errorat("jshell.err.feedback.expected.mode"); valid = false; return null; } @@ -705,11 +667,11 @@ class Feedback { } else { valid = false; if (matches.length == 0) { - errorat("Does not match any current feedback mode: %s", umode); + errorat("jshell.err.feedback.does.not.match.mode", umode); } else { - errorat("Matches more then one current feedback mode: %s", umode); + errorat("jshell.err.feedback.ambiguous.mode", umode); } - fluff("The feedback mode should be one of the following:"); + fluffmsg("jshell.msg.feedback.mode.following"); modeMap.keySet().stream() .forEach(mk -> fluff(" %s", mk)); return null; @@ -720,12 +682,12 @@ class Feedback { final String nextFormat() { String format = at.next(); if (format == null) { - errorat("Expected format missing"); + errorat("jshell.err.feedback.expected.format"); valid = false; return null; } if (!at.isQuoted()) { - errorat("Format '%s' must be quoted", format); + errorat("jshell.err.feedback.must.be.quoted", format); valid = false; return null; } @@ -748,19 +710,19 @@ class Feedback { if (!as.isEmpty()) { Selector sel = selectorMap.get(as); if (sel == null) { - errorat("Not a valid selector %s in %s", as, s); + errorat("jshell.err.feedback.not.a.valid.selector", as, s); valid = false; return; } SelectorCollector collector = sel.collector(this); if (lastCollector == null) { if (!collector.isEmpty()) { - errorat("Selector kind in multiple sections of selector list %s in %s", as, s); + errorat("jshell.err.feedback.multiple.sections", as, s); valid = false; return; } } else if (collector != lastCollector) { - errorat("Different selector kinds in same sections of selector list %s in %s", as, s); + errorat("jshell.err.feedback.different.selector.kinds", as, s); valid = false; return; } @@ -771,36 +733,5 @@ class Feedback { } } } - - final void printFormatHelp() { - hardrb("help.set.format"); - hardrb("help.set.format.case"); - hardEnums(EnumSet.allOf(FormatCase.class), ev -> ev.doc); - hardrb("help.set.format.action"); - hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); - hardrb("help.set.format.when"); - hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); - hardrb("help.set.format.resolve"); - hardEnums(EnumSet.allOf(FormatResolve.class), ev -> ev.doc); - hardrb("help.set.format.unresolved"); - hardEnums(EnumSet.allOf(FormatUnresolved.class), ev -> ev.doc); - hardrb("help.set.format.errors"); - hardEnums(EnumSet.allOf(FormatErrors.class), ev -> ev.doc); - hardrb("help.set.format.end"); - } - - final void printFeedbackHelp() { - hardrb("help.set.feedback"); - modeMap.keySet().stream() - .forEach(m -> hard(" %s", m)); - } - - final void printNewModeHelp() { - hardrb("help.set.newmode"); - } - - final void printPromptHelp() { - hardrb("help.set.prompt"); - } } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 480c7e0617d9268608bc70f9c57e31284f6fe00f..712f5e458ee032cdda245b1f280088a8f0a48f79 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -42,6 +42,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -49,6 +50,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; @@ -128,6 +130,7 @@ public class JShellTool { final PrintStream userout; final PrintStream usererr; final Preferences prefs; + final Locale locale; final Feedback feedback = new Feedback(); @@ -141,11 +144,13 @@ public class JShellTool { * @param userin code execution input (not yet functional) * @param userout code execution output -- System.out.printf("hi") * @param usererr code execution error stream -- System.err.printf("Oops") + * @param prefs preferences to use + * @param locale locale to use */ public JShellTool(InputStream cmdin, PrintStream cmdout, PrintStream cmderr, PrintStream console, InputStream userin, PrintStream userout, PrintStream usererr, - Preferences prefs) { + Preferences prefs, Locale locale) { this.cmdin = cmdin; this.cmdout = cmdout; this.cmderr = cmderr; @@ -154,6 +159,7 @@ public class JShellTool { this.userout = userout; this.usererr = usererr; this.prefs = prefs; + this.locale = locale; } private IOContext input = null; @@ -292,17 +298,95 @@ public class JShellTool { return s; } + /** + * Add prefixing to embedded newlines in a string, leading with the normal + * prefix + * + * @param s the string to prefix + */ + String prefix(String s) { + return prefix(s, feedback.getPre()); + } + + /** + * Add prefixing to embedded newlines in a string + * + * @param s the string to prefix + * @param leading the string to prepend + */ + String prefix(String s, String leading) { + if (s == null || s.isEmpty()) { + return ""; + } + return leading + + s.substring(0, s.length() - 1).replaceAll("\\R", System.getProperty("line.separator") + feedback.getPre()) + + s.substring(s.length() - 1, s.length()); + } + /** * Print using resource bundle look-up and adding prefix and postfix * * @param key the resource key */ void hardrb(String key) { - String s = getResourceString(key); - String out = feedback.getPre() - + s.substring(0, s.length() - 1).replaceAll("\\R", "\n" + feedback.getPre()) - + s.substring(s.length() - 1, s.length()); - cmdout.print(out); + String s = prefix(getResourceString(key)); + cmdout.println(s); + } + + /** + * Format using resource bundle look-up using MessageFormat + * + * @param key the resource key + * @param args + */ + String messageFormat(String key, Object... args) { + String rs = getResourceString(key); + return MessageFormat.format(rs, args); + } + + /** + * Print using resource bundle look-up, MessageFormat, and add prefix and + * postfix + * + * @param key the resource key + * @param args + */ + void hardmsg(String key, Object... args) { + cmdout.println(prefix(messageFormat(key, args))); + } + + /** + * Print error using resource bundle look-up, MessageFormat, and add prefix + * and postfix + * + * @param key the resource key + * @param args + */ + void errormsg(String key, Object... args) { + cmdout.println(prefix(messageFormat(key, args), feedback.getErrorPre())); + } + + /** + * Print command-line error using resource bundle look-up, MessageFormat + * + * @param key the resource key + * @param args + */ + void startmsg(String key, Object... args) { + cmderr.println(prefix(messageFormat(key, args), "")); + } + + /** + * Print (fluff) using resource bundle look-up, MessageFormat, and add + * prefix and postfix + * + * @param key the resource key + * @param args + */ + void fluffmsg(String key, Object... args) { + if (feedback.shouldDisplayCommandFluff() && interactive()) { + hardmsg(key, args); + } } void hardPairs(Stream stream, Function a, Function b) { @@ -348,7 +432,8 @@ public class JShellTool { public static void main(String[] args) throws Exception { new JShellTool(System.in, System.out, System.err, System.out, new ByteArrayInputStream(new byte[0]), System.out, System.err, - Preferences.userRoot().node("tool/JShell")) + Preferences.userRoot().node("tool/JShell"), + Locale.getDefault()) .start(args); } @@ -373,12 +458,11 @@ public class JShellTool { } for (String loadFile : loadList) { - cmdOpen(loadFile); + runFile(loadFile, "jshell"); } if (regenerateOnDeath) { - hard("Welcome to JShell -- Version %s", version()); - hard("Type /help for help"); + hardmsg("jshell.msg.welcome", version()); } try { @@ -409,13 +493,13 @@ public class JShellTool { case "-classpath": case "-cp": if (cmdlineClasspath != null) { - cmderr.printf("Conflicting -classpath option.\n"); + startmsg("jshell.err.opt.classpath.conflict"); return null; } if (ai.hasNext()) { cmdlineClasspath = ai.next(); } else { - cmderr.printf("Argument to -classpath missing.\n"); + startmsg("jshell.err.opt.classpath.arg"); return null; } break; @@ -430,35 +514,23 @@ public class JShellTool { return null; case "-startup": if (cmdlineStartup != null) { - cmderr.printf("Conflicting -startup or -nostartup option.\n"); + startmsg("jshell.err.opt.startup.conflict"); return null; } - if (ai.hasNext()) { - String filename = ai.next(); - try { - byte[] encoded = Files.readAllBytes(Paths.get(filename)); - cmdlineStartup = new String(encoded); - } catch (AccessDeniedException e) { - hard("File '%s' for start-up is not accessible.", filename); - } catch (NoSuchFileException e) { - hard("File '%s' for start-up is not found.", filename); - } catch (Exception e) { - hard("Exception while reading start-up file: %s", e); - } - } else { - cmderr.printf("Argument to -startup missing.\n"); + cmdlineStartup = readFile(ai.hasNext()? ai.next() : null, "'-startup'"); + if (cmdlineStartup == null) { return null; } break; case "-nostartup": if (cmdlineStartup != null && !cmdlineStartup.isEmpty()) { - cmderr.printf("Conflicting -startup option.\n"); + startmsg("jshell.err.opt.startup.conflict"); return null; } cmdlineStartup = ""; break; default: - cmderr.printf("Unknown option: %s\n", arg); + startmsg("jshell.err.opt.unknown", arg); printUsage(); return null; } @@ -470,14 +542,7 @@ public class JShellTool { } private void printUsage() { - rawout("Usage: jshell \n"); - rawout("where possible options include:\n"); - rawout(" -classpath Specify where to find user class files\n"); - rawout(" -cp Specify where to find user class files\n"); - rawout(" -startup One run replacement for the start-up definitions\n"); - rawout(" -nostartup Do not run the start-up definitions\n"); - rawout(" -help Print a synopsis of standard options\n"); - rawout(" -version Version information\n"); + cmdout.print(getResourceString("help.usage")); } private void resetState() { @@ -505,8 +570,7 @@ public class JShellTool { .build(); shutdownSubscription = state.onShutdown((JShell deadState) -> { if (deadState == state) { - hard("State engine terminated."); - hard("Restore definitions with: /reload restore"); + hardmsg("jshell.msg.terminated"); live = false; } }); @@ -539,7 +603,7 @@ public class JShellTool { try (IOContext suin = new FileScannerIOContext(new StringReader(start))) { run(suin); } catch (Exception ex) { - hard("Unexpected exception reading start-up: %s\n", ex); + hardmsg("jshell.err.startup.unexpected.exception", ex); } } @@ -604,7 +668,7 @@ public class JShellTool { } } } catch (IOException ex) { - hard("Unexpected exception: %s\n", ex); + errormsg("jshell.err.unexpected.exception", ex); } finally { input = oldInput; } @@ -649,8 +713,8 @@ public class JShellTool { switch (candidates.length) { case 0: if (!rerunHistoryEntryById(cmd.substring(1))) { - error("No such command or snippet id: %s", cmd); - fluff("Type /help for help."); + errormsg("jshell.err.no.such.command.or.snippet.id", cmd); + fluffmsg("jshell.msg.help.for.help"); } break; case 1: Command command = candidates[0]; @@ -659,8 +723,9 @@ public class JShellTool { addToReplayHistory((command.command + " " + arg).trim()); } break; default: - error("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); - fluff("Type /help for help."); + errormsg("jshell.err.command.ambiguous", cmd, + Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); + fluffmsg("jshell.msg.help.for.help"); break; } } @@ -686,35 +751,33 @@ public class JShellTool { static final class Command { public final String command; - public final String params; - public final String description; - public final String help; + public final String helpKey; public final Function run; public final CompletionProvider completions; public final CommandKind kind; // NORMAL Commands - public Command(String command, String params, String description, String help, - Function run, CompletionProvider completions) { - this(command, params, description, help, - run, completions, CommandKind.NORMAL); + public Command(String command, Function run, CompletionProvider completions) { + this(command, run, completions, CommandKind.NORMAL); + } + + // Special kinds of Commands + public Command(String command, Function run, CompletionProvider completions, CommandKind kind) { + this(command, "help." + command.substring(1), + run, completions, kind); } // Documentation pseudo-commands - public Command(String command, String description, String help, - CommandKind kind) { - this(command, null, description, help, + public Command(String command, String helpKey, CommandKind kind) { + this(command, helpKey, arg -> { throw new IllegalStateException(); }, EMPTY_COMPLETION_PROVIDER, kind); } - public Command(String command, String params, String description, String help, - Function run, CompletionProvider completions, CommandKind kind) { + public Command(String command, String helpKey, Function run, CompletionProvider completions, CommandKind kind) { this.command = command; - this.params = params; - this.description = description; - this.help = help; + this.helpKey = helpKey; this.run = run; this.completions = completions; this.kind = kind; @@ -853,221 +916,86 @@ public class JShellTool { }; } - // Table of commands -- with command forms, argument kinds, help message, implementation, ... + // Table of commands -- with command forms, argument kinds, helpKey message, implementation, ... { - registerCommand(new Command("/list", "[all|start|]", "list the source you have typed", - "Show the source of snippets, prefaced with the snippet id.\n\n" + - "/list\n" + - " -- List the currently active snippets of code that you typed or read with /open\n" + - "/list start\n" + - " -- List the automatically evaluated start-up snippets\n" + - "/list all\n" + - " -- List all snippets including failed, overwritten, dropped, and start-up\n" + - "/list \n" + - " -- List snippets with the specified name (preference for active snippets)\n" + - "/list \n" + - " -- List the snippet with the specified snippet id\n", + registerCommand(new Command("/list", arg -> cmdList(arg), editKeywordCompletion())); - registerCommand(new Command("/edit", "", "edit a source entry referenced by name or id", - "Edit a snippet or snippets of source in an external editor.\n" + - "The editor to use is set with /set editor.\n" + - "If no editor has been set, a simple editor will be launched.\n\n" + - "/edit \n" + - " -- Edit the snippet or snippets with the specified name (preference for active snippets)\n" + - "/edit \n" + - " -- Edit the snippet with the specified snippet id\n" + - "/edit\n" + - " -- Edit the currently active snippets of code that you typed or read with /open\n", + registerCommand(new Command("/edit", arg -> cmdEdit(arg), editCompletion())); - registerCommand(new Command("/drop", "", "delete a source entry referenced by name or id", - "Drop a snippet -- making it inactive.\n\n" + - "/drop \n" + - " -- Drop the snippet with the specified name\n" + - "/drop \n" + - " -- Drop the snippet with the specified snippet id\n", + registerCommand(new Command("/drop", arg -> cmdDrop(arg), editCompletion(), CommandKind.REPLAY)); - registerCommand(new Command("/save", "[all|history|start] ", "Save snippet source to a file.", - "Save the specified snippets and/or commands to the specified file.\n\n" + - "/save \n" + - " -- Save the source of current active snippets to the file\n" + - "/save all \n" + - " -- Save the source of all snippets to the file\n" + - " Includes source including overwritten, failed, and start-up code\n" + - "/save history \n" + - " -- Save the sequential history of all commands and snippets entered since jshell was launched\n" + - "/save start \n" + - " -- Save the default start-up definitions to the file\n", + registerCommand(new Command("/save", arg -> cmdSave(arg), saveCompletion())); - registerCommand(new Command("/open", "", "open a file as source input", - "Open a file and read its contents as snippets and commands.\n\n" + - "/open \n" + - " -- Read the specified file as jshell input.\n", + registerCommand(new Command("/open", arg -> cmdOpen(arg), FILE_COMPLETION_PROVIDER)); - registerCommand(new Command("/vars", null, "list the declared variables and their values", - "List the type, name, and value of the current active jshell variables.\n", + registerCommand(new Command("/vars", arg -> cmdVars(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/methods", null, "list the declared methods and their signatures", - "List the name, parameter types, and return type of the current active jshell methods.\n", + registerCommand(new Command("/methods", arg -> cmdMethods(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/classes", null, "list the declared classes", - "List the current active jshell classes, interfaces, and enums.\n", + registerCommand(new Command("/classes", arg -> cmdClasses(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/imports", null, "list the imported items", - "List the current active jshell imports.\n", + registerCommand(new Command("/imports", arg -> cmdImports(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/exit", null, "exit jshell", - "Leave the jshell tool. No work is saved.\n" + - "Save any work before using this command\n", + registerCommand(new Command("/exit", arg -> cmdExit(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/reset", null, "reset jshell", - "Reset the jshell tool code and execution state:\n" + - " * All entered code is lost.\n" + - " * Start-up code is re-executed.\n" + - " * The execution state is restarted.\n" + - " * The classpath is cleared.\n" + - "Tool settings are maintained, as set with: /set ...\n" + - "Save any work before using this command\n", + registerCommand(new Command("/reset", arg -> cmdReset(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/reload", "[restore] [quiet]", "reset and replay relevant history -- current or previous (restore)", - "Reset the jshell tool code and execution state then replay each\n" + - "jshell valid command and valid snippet in the order they were entered.\n\n" + - "/reload\n" + - " -- Reset and replay the valid history since jshell was entered, or\n" + - " a /reset, or /reload command was executed -- whichever is most\n" + - " recent.\n" + - "/reload restore\n" + - " -- Reset and replay the valid history between the previous and most\n" + - " recent time that jshell was entered, or a /reset, or /reload\n" + - " command was executed. This can thus be used to restore a previous\n" + - " jshell tool sesson.\n" + - "/reload [restore] quiet\n" + - " -- With the 'quiet' argument the replay is not shown. Errors will display.\n", + registerCommand(new Command("/reload", arg -> cmdReload(arg), reloadCompletion())); - registerCommand(new Command("/classpath", "", "add a path to the classpath", - "Append a additional path to the classpath.\n", + registerCommand(new Command("/classpath", arg -> cmdClasspath(arg), classPathCompletion(), CommandKind.REPLAY)); - registerCommand(new Command("/history", null, "history of what you have typed", - "Display the history of snippet and command input since this jshell was launched.\n", + registerCommand(new Command("/history", arg -> cmdHistory(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/debug", null, "toggle debugging of the jshell", - "Display debugging information for the jshelll implementation.\n" + - "0: Debugging off\n" + - "r: Debugging on\n" + - "g: General debugging on\n" + - "f: File manager debugging on\n" + - "c': Completion analysis debugging on\n" + - "d': Dependency debugging on\n" + - "e': Event debugging on\n", + registerCommand(new Command("/debug", arg -> cmdDebug(arg), EMPTY_COMPLETION_PROVIDER, CommandKind.HIDDEN)); - registerCommand(new Command("/help", "[|]", "get information about jshell", - "Display information about jshell.\n" + - "/help\n" + - " -- List the jshell commands and help subjects.\n" + - "/help \n" + - " -- Display information about the specified comand. The slash must be included.\n" + - " Only the first few letters of the command are needed -- if more than one\n" + - " each will be displayed. Example: /help /li\n" + - "/help \n" + - " -- Display information about the specified help subject. Example: /help intro\n", + registerCommand(new Command("/help", arg -> cmdHelp(arg), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/set", "editor|start|feedback|newmode|prompt|format ...", "set jshell configuration information", - "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 ...\n" + - " -- Specify the command to launch for the /edit command.\n" + - " The is an operating system dependent string.\n" + - "\n" + - "/set start \n" + - " -- The contents of the specified become the default start-up snippets and commands.\n" + - "\n" + - "/set feedback \n" + - " -- Set the feedback mode describing displayed feedback for entered snippets and commands.\n" + - "\n" + - "/set newmode [command|quiet []]\n" + - " -- Create a user-defined feedback mode, optionally copying from an existing mode.\n" + - "\n" + - "/set prompt \"\" \"\"\n" + - " -- Set the displayed prompts for a given feedback mode.\n" + - "\n" + - "/set format \"\" ...\n" + - " -- Configure a feedback mode by setting the format of a field when the selector matchs.\n" + - "\n" + - "To get more information about one of these forms, use /help with the form specified.\n" + - "For example: /help /set format\n", + registerCommand(new Command("/set", arg -> cmdSet(arg), new FixedCompletionProvider("format", "feedback", "prompt", "newmode", "start", "editor"))); - registerCommand(new Command("/?", "", "get information about jshell", - "Display information about jshell (abbreviation for /help).\n" + - "/?\n" + - " -- Display list of commands and help subjects.\n" + - "/? \n" + - " -- Display information about the specified comand. The slash must be included.\n" + - " Only the first few letters of the command are needed -- if more than one\n" + - " match, each will be displayed. Example: /? /li\n" + - "/? \n" + - " -- Display information about the specified help subject. Example: /? intro\n", + registerCommand(new Command("/?", + "help.quest", arg -> cmdHelp(arg), - EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/!", "", "re-run last snippet", - "Reevaluate the most recently entered snippet.\n", + EMPTY_COMPLETION_PROVIDER, + CommandKind.NORMAL)); + registerCommand(new Command("/!", + "help.bang", arg -> cmdUseHistoryEntry(-1), - EMPTY_COMPLETION_PROVIDER)); + EMPTY_COMPLETION_PROVIDER, + CommandKind.NORMAL)); // Documentation pseudo-commands - - registerCommand(new Command("/", "re-run snippet by id", - "", + registerCommand(new Command("/", + "help.id", CommandKind.HELP_ONLY)); - registerCommand(new Command("/-", "re-run n-th previous snippet", - "", + registerCommand(new Command("/-", + "help.previous", CommandKind.HELP_ONLY)); - registerCommand(new Command("intro", "An introduction to the jshell tool", - "The jshell tool allows you to execute Java code, getting immediate results.\n" + - "You can enter a Java definition (variable, method, class, etc), like: int x = 8\n" + - "or a Java expression, like: x + x\n" + - "or a Java statement or import.\n" + - "These little chunks of Java code are called 'snippets'.\n\n" + - "There are also jshell commands that allow you to understand and\n" + - "control what you are doing, like: /list\n\n" + - "For a list of commands: /help", + registerCommand(new Command("intro", + "help.intro", CommandKind.HELP_SUBJECT)); - registerCommand(new Command("shortcuts", "Describe shortcuts", - "Supported shortcuts include:\n\n" + - " -- After entering the first few letters of a Java identifier,\n" + - " a jshell command, or, in some cases, a jshell command argument,\n" + - " press the key to complete the input.\n" + - " If there is more than one completion, show possible completions.\n" + - "Shift- -- After the name and open parenthesis of a method or constructor invocation,\n" + - " hold the key and press the to see a synopsis of all\n" + - " matching methods/constructors.\n" + - " v -- After a complete expression, press \" v\" to introduce a new variable\n" + - " whose type is based on the type of the expression.\n" + - " The \"\" is either Alt-F1 or Alt-Enter, depending on the platform.\n" + - " i -- After an unresolvable identifier, press \" i\" and jshell will propose\n" + - " possible fully qualified names based on the content of the specified classpath.\n" + - " The \"\" is either Alt-F1 or Alt-Enter, depending on the platform.\n", + registerCommand(new Command("shortcuts", + "help.shortcuts", CommandKind.HELP_SUBJECT)); } @@ -1109,7 +1037,7 @@ public class JShellTool { String cmd = code.substring(0, space); Command command = commands.get(cmd); if (command != null) { - return command.description; + return getResourceString(command.helpKey + ".summary"); } } @@ -1139,7 +1067,7 @@ public class JShellTool { case "editor": { String prog = at.next(); if (prog == null) { - hard("The '/set editor' command requires a path argument"); + errormsg("jshell.err.set.editor.arg"); return false; } else { List ed = new ArrayList<>(); @@ -1149,34 +1077,21 @@ public class JShellTool { ed.add(n); } editor = ed.toArray(new String[ed.size()]); - fluff("Editor set to: %s", arg); + fluffmsg("jshell.msg.set.editor.set", arg); return true; } } case "start": { - String filename = at.next(); - if (filename == null) { - hard("The '/set start' command requires a filename argument."); + String init = readFile(at.next(), "'/set start'"); + if (init == null) { + return false; } else { - try { - byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename)); - String init = new String(encoded); - prefs.put(STARTUP_KEY, init); - } catch (AccessDeniedException e) { - hard("File '%s' for /set start is not accessible.", filename); - return false; - } catch (NoSuchFileException e) { - hard("File '%s' for /set start is not found.", filename); - return false; - } catch (Exception e) { - hard("Exception while reading start set file: %s", e); - return false; - } + prefs.put(STARTUP_KEY, init); + return true; } - return true; } default: - hard("Error: Invalid /set argument: %s", which); + errormsg("jshell.err.arg", "/set", at.val()); return false; } } @@ -1186,56 +1101,26 @@ public class JShellTool { if (which == null) { return false; } - switch (which) { - case "format": - feedback.printFormatHelp(this); - return true; - case "feedback": - feedback.printFeedbackHelp(this); - return true; - case "newmode": - feedback.printNewModeHelp(this); - return true; - case "prompt": - feedback.printPromptHelp(this); - return true; - case "editor": - hard("Specify the command to launch for the /edit command."); - hard(""); - hard("/set editor ..."); - hard(""); - hard("The is an operating system dependent string."); - hard("The may include space-separated arguments (such as flags) -- ...."); - hard("When /edit is used, the temporary file to edit will be appended as the last argument."); - return true; - case "start": - hard("Set the start-up configuration -- a sequence of snippets and commands read at start-up."); - hard(""); - hard("/set start "); - hard(""); - hard("The contents of the specified become the default start-up snippets and commands --"); - hard("which are run when the jshell tool is started or reset."); - return true; - default: - hard("Error: Invalid /set argument: %s", which); - return false; - } + hardrb("help.set." + which); + return true; } String setSubCommand(ArgTokenizer at) { String[] matches = at.next(SET_SUBCOMMANDS); if (matches == null) { - error("The /set command requires arguments. See: /help /set"); + errormsg("jshell.err.set.arg"); return null; - } else if (matches.length == 0) { - error("Not a valid argument to /set: %s", at.val()); - fluff("/set is followed by one of: %s", Arrays.stream(SET_SUBCOMMANDS) + } + if (matches.length == 0) { + errormsg("jshell.err.arg", "/set", at.val()); + fluffmsg("jshell.msg.use.one.of", Arrays.stream(SET_SUBCOMMANDS) .collect(Collectors.joining(", ")) ); return null; - } else if (matches.length > 1) { - error("Ambiguous argument to /set: %s", at.val()); - fluff("Use one of: %s", Arrays.stream(matches) + } + if (matches.length > 1) { + errormsg("jshell.err.set.ambiguous", at.val()); + fluffmsg("jshell.msg.use.one.of", Arrays.stream(matches) .collect(Collectors.joining(", ")) ); return null; @@ -1245,11 +1130,11 @@ public class JShellTool { boolean cmdClasspath(String arg) { if (arg.isEmpty()) { - hard("/classpath requires a path argument"); + errormsg("jshell.err.classpath.arg"); return false; } else { state.addToClasspath(toPathResolvingUserHome(arg).toString()); - fluff("Path %s added to classpath", arg); + fluffmsg("jshell.msg.classpath", arg); return true; } } @@ -1322,7 +1207,7 @@ public class JShellTool { .get(); prefs.put(REPLAY_RESTORE_KEY, hist); } - fluff("Goodbye\n"); + fluffmsg("jshell.msg.goodbye"); return true; } @@ -1344,31 +1229,24 @@ public class JShellTool { hard(""); hard("%s", c.command); hard(""); - hard("%s", c.help.replaceAll("\n", LINE_SEP + feedback.getPre())); + hardrb(c.helpKey); } return true; } else { - error("No commands or subjects start with the provided argument: %s\n\n", arg); + errormsg("jshell.err.help.arg", arg); } } - hard("Type a Java language expression, statement, or declaration."); - hard("Or type one of the following commands:"); - hard(""); + hardmsg("jshell.msg.help.begin"); hardPairs(commands.values().stream() .filter(cmd -> cmd.kind.showInHelp), - cmd -> (cmd.params != null) - ? cmd.command + " " + cmd.params - : cmd.command, - cmd -> cmd.description + cmd -> cmd.command + " " + getResourceString(cmd.helpKey + ".args"), + cmd -> getResourceString(cmd.helpKey + ".summary") ); - hard(""); - hard("For more information type '/help' followed by the name of command or a subject."); - hard("For example '/help /list' or '/help intro'. Subjects:"); - hard(""); + hardmsg("jshell.msg.help.subject"); hardPairs(commands.values().stream() .filter(cmd -> cmd.kind == CommandKind.HELP_SUBJECT), cmd -> cmd.command, - cmd -> cmd.description + cmd -> getResourceString(cmd.helpKey + ".summary") ); return true; } @@ -1460,28 +1338,28 @@ public class JShellTool { private boolean cmdDrop(String arg) { if (arg.isEmpty()) { - hard("In the /drop argument, please specify an import, variable, method, or class to drop."); - hard("Specify by id or name. Use /list to see ids. Use /reset to reset all state."); + errormsg("jshell.err.drop.arg"); return false; } Stream stream = argToSnippets(arg, false); if (stream == null) { - hard("No definition or id named %s found. See /classes, /methods, /vars, or /list", arg); + errormsg("jshell.err.def.or.id.not.found", arg); + fluffmsg("jshell.msg.see.classes.etc"); return false; } List snippets = stream .filter(sn -> state.status(sn).isActive && sn instanceof PersistentSnippet) .collect(toList()); if (snippets.isEmpty()) { - hard("The argument did not specify an active import, variable, method, or class to drop."); + errormsg("jshell.err.drop.active"); return false; } if (snippets.size() > 1) { - hard("The argument references more than one import, variable, method, or class."); - hard("Try again with one of the ids below:"); - for (Snippet sn : snippets) { - cmdout.printf("%4s : %s\n", sn.id(), sn.source().replace("\n", "\n ")); - } + errormsg("jshell.err.drop.ambiguous"); + fluffmsg("jshell.msg.use.one.of", snippets.stream() + .map(sn -> String.format("\n%4s : %s", sn.id(), sn.source().replace("\n", "\n "))) + .collect(Collectors.joining(", ")) + ); return false; } PersistentSnippet psn = (PersistentSnippet) snippets.get(0); @@ -1492,7 +1370,8 @@ public class JShellTool { private boolean cmdEdit(String arg) { Stream stream = argToSnippets(arg, true); if (stream == null) { - hard("No definition or id named %s found. See /classes, /methods, /vars, or /list", arg); + errormsg("jshell.err.def.or.id.not.found", arg); + fluffmsg("jshell.msg.see.classes.etc"); return false; } Set srcSet = new LinkedHashSet<>(); @@ -1565,7 +1444,7 @@ public class JShellTool { } currSrcs = nextSrcs; } catch (IllegalStateException ex) { - hard("Resetting..."); + hardmsg("jshell.msg.resetting"); resetState(); currSrcs = new LinkedHashSet<>(); // re-process everything } @@ -1591,11 +1470,12 @@ public class JShellTool { } Stream stream = argToSnippets(arg, true); if (stream == null) { + errormsg("jshell.err.def.or.id.not.found", arg); // Check if there are any definitions at all if (argToSnippets("", false).iterator().hasNext()) { - hard("No definition or id named %s found. Try /list without arguments.", arg); + fluffmsg("jshell.msg.try.list.without.args"); } else { - hard("No definition or id named %s found. There are no active definitions.", arg); + hardmsg("jshell.msg.no.active"); } return false; } @@ -1613,26 +1493,54 @@ public class JShellTool { } private boolean cmdOpen(String filename) { - if (filename.isEmpty()) { - hard("The /open command requires a filename argument."); - return false; - } else { + return runFile(filename, "'/open'"); + } + + private boolean runFile(String filename, String context) { + if (!filename.isEmpty()) { try { run(new FileScannerIOContext(toPathResolvingUserHome(filename).toString())); + return true; } catch (FileNotFoundException e) { - hard("File '%s' is not found: %s", filename, e.getMessage()); - return false; + errormsg("jshell.err.file.not.found", context, filename, e.getMessage()); } catch (Exception e) { - hard("Exception while reading file: %s", e); - return false; + errormsg("jshell.err.file.exception", context, filename, e); } + } else { + errormsg("jshell.err.file.filename", context); } - return true; + return false; + } + + /** + * Read an external file. Error messages accessed via keyPrefix + * + * @param filename file to access or null + * @param context printable non-natural language context for errors + * @return contents of file as string + */ + String readFile(String filename, String context) { + if (filename != null) { + try { + byte[] encoded = Files.readAllBytes(Paths.get(filename)); + return new String(encoded); + } catch (AccessDeniedException e) { + errormsg("jshell.err.file.not.accessible", context, filename, e.getMessage()); + } catch (NoSuchFileException e) { + errormsg("jshell.err.file.not.found", context, filename, e.getMessage()); + } catch (Exception e) { + errormsg("jshell.err.file.exception", context, filename, e); + } + } else { + errormsg("jshell.err.file.filename", context); + } + return null; + } private boolean cmdReset() { live = false; - fluff("Resetting state."); + fluffmsg("jshell.msg.resetting.state"); return true; } @@ -1642,21 +1550,20 @@ public class JShellTool { if (arg.length() > 0) { if ("restore".startsWith(arg)) { if (replayableHistoryPrevious == null) { - hard("No previous history to restore\n", arg); + errormsg("jshell.err.reload.no.previous"); return false; } history = replayableHistoryPrevious; } else if ("quiet".startsWith(arg)) { echo = false; } else { - hard("Invalid argument to reload command: %s\nUse 'restore', 'quiet', or no argument\n", arg); + errormsg("jshell.err.arg", "/reload", arg); return false; } } - fluff("Restarting and restoring %s.", - history == replayableHistoryPrevious - ? "from previous state" - : "state"); + fluffmsg(history == replayableHistoryPrevious + ? "jshell.err.reload.restarting.previous.state" + : "jshell.err.reload.restarting.state"); resetState(); run(new ReloadIOContext(history, echo? cmdout : null)); @@ -1666,7 +1573,7 @@ public class JShellTool { private boolean cmdSave(String arg_filename) { Matcher mat = HISTORY_ALL_START_FILENAME.matcher(arg_filename); if (!mat.find()) { - hard("Malformed argument to the /save command: %s", arg_filename); + errormsg("jshell.err.arg", arg_filename); return false; } boolean useHistory = false; @@ -1686,7 +1593,7 @@ public class JShellTool { } String filename = mat.group("filename"); if (filename == null ||filename.isEmpty()) { - hard("The /save command requires a filename argument."); + errormsg("jshell.err.file.filename", "/save"); return false; } try (BufferedWriter writer = Files.newBufferedWriter(toPathResolvingUserHome(filename), @@ -1709,10 +1616,10 @@ public class JShellTool { } } } catch (FileNotFoundException e) { - hard("File '%s' for save is not accessible: %s", filename, e.getMessage()); + errormsg("jshell.err.file.not.found", "/save", filename, e.getMessage()); return false; } catch (Exception e) { - hard("Exception while saving: %s", e); + errormsg("jshell.err.file.exception", "/save", filename, e); return false; } return true; @@ -1722,7 +1629,7 @@ public class JShellTool { for (VarSnippet vk : state.variables()) { String val = state.status(vk) == Status.VALID ? state.varValue(vk) - : "(not-active)"; + : "jshell.msg.vars.not.active"; hard(" %s %s = %s", vk.typeName(), vk.name(), val); } return true; @@ -1777,7 +1684,7 @@ public class JShellTool { if (index >= 0 && index < keys.size()) { rerunSnippet(keys.get(index)); } else { - hard("Cannot find snippet %d", index + 1); + errormsg("jshell.err.out.of.range"); return false; } return true; @@ -1912,11 +1819,7 @@ public class JShellTool { if (ste.causeSnippet() == null) { // main event for (Diag d : diagnostics) { - if (d.isError()) { - hard("Error:"); - } else { - hard("Warning:"); - } + hardmsg(d.isError()? "jshell.msg.error" : "jshell.msg.warning"); List disp = new ArrayList<>(); displayDiagnostics(source, d, disp); disp.stream() @@ -1939,7 +1842,7 @@ public class JShellTool { } } else { if (diagnostics.isEmpty()) { - hard("Failed."); + errormsg("jshell.err.failed"); } return true; } @@ -1975,9 +1878,9 @@ public class JShellTool { String fileName = ste.getFileName(); int lineNumber = ste.getLineNumber(); String loc = ste.isNativeMethod() - ? "Native Method" + ? getResourceString("jshell.msg.native.method") : fileName == null - ? "Unknown Source" + ? getResourceString("jshell.msg.unknown.source") : lineNumber >= 0 ? fileName + ":" + lineNumber : fileName; diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index bd1d02fbce09f3ed2281feb85a8364f5251c891a..e4c4fb7510072c20dcea63ba2c1281148bf54d91 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -23,9 +23,359 @@ # questions. # +jshell.msg.welcome =\ +Welcome to JShell -- Version {0}\n\ +For an introduction type: /help intro\n +jshell.err.opt.classpath.conflict = Conflicting -classpath option. +jshell.err.opt.classpath.arg = Argument to -classpath missing. +jshell.err.opt.startup.conflict = Conflicting -startup or -nostartup option. +jshell.err.opt.unknown = Unknown option: {0} + +jshell.msg.terminated =\ +State engine terminated.\n\ +Restore definitions with: /reload restore + +jshell.msg.use.one.of = Use one of: {0} +jshell.err.def.or.id.not.found = No definition or id found named: {0} +jshell.msg.see.classes.etc = See /classes, /methods, /vars, or /list +jshell.err.arg = Invalid ''{0}'' argument: {1} +jshell.msg.see = See {0} for help. + +jshell.err.file.not.accessible = File ''{1}'' for ''{0}'' is not accessible: {2} +jshell.err.file.not.found = File ''{1}'' for ''{0}'' is not found: {2} +jshell.err.file.exception = File ''{1}'' for ''{0}'' threw exception: {2} +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.command.ambiguous = Command: ''{0}'' is ambiguous: {1} +jshell.err.set.editor.arg = The ''/set editor'' command requires a path argument +jshell.msg.set.editor.set = Editor set to: {0} + +jshell.msg.try.list.without.args = Try ''/list'' without arguments. +jshell.msg.no.active = There are no active definitions. + +jshell.msg.resetting = Resetting... +jshell.msg.resetting.state = Resetting state. + +jshell.err.reload.no.previous = No previous history to restore +jshell.err.reload.restarting.previous.state = Restarting and restoring from previous state. +jshell.err.reload.restarting.state = Restarting and restoring state. + +jshell.msg.vars.not.active = (not-active) + +jshell.err.out.of.range = Out of range + +jshell.msg.error = Error: +jshell.msg.warning = Warning: + +jshell.err.set.arg = The ''/set'' command requires a sub-command and arguments. See: ''/help /set'' +jshell.err.set.ambiguous = Ambiguous sub-command argument to ''/set'': {0} + +jshell.err.classpath.arg = The /classpath command requires a path argument. +jshell.msg.classpath = Path ''{0}'' added to classpath + +jshell.err.help.arg = No commands or subjects start with the provided argument: {0} +jshell.msg.help.begin =\ +Type a Java language expression, statement, or declaration.\n\ +Or type one of the following commands:\n +jshell.msg.help.subject =\n\ +For more information type ''/help'' followed by the name of command or a subject.\n\ +For example ''/help /list'' or ''/help intro''. Subjects:\n + +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.msg.drop.not.active = The argument did not specify an active import, variable, method, or class to drop. +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 +jshell.msg.goodbye = Goodbye + +jshell.msg.help.for.help = Type /help for help. + +jshell.err.feedback.expected.new.feedback.mode = Expected new feedback mode -- {0} +jshell.err.feedback.expected.mode.name = Expected a new feedback mode name. ''{0}'' is a known feedback mode -- {1} +jshell.err.feedback.command.quiet = Specify either ''command'' or ''quiet'' -- {0} +jshell.err.feedback.expected.field = Expected field name missing -- {0} +jshell.err.feedback.expected.mode = Expected a feedback mode -- {0} +jshell.err.feedback.does.not.match.mode = Does not match any current feedback mode: {0} -- {1} +jshell.err.feedback.ambiguous.mode = Matches more then one current feedback mode: {0} -- {1} +jshell.err.feedback.expected.format = Expected format missing -- {0} +jshell.err.feedback.must.be.quoted = Format ''{0}'' must be quoted -- {1} +jshell.err.feedback.not.a.valid.selector = Not a valid selector ''{0}'' in ''{1}'' -- {2} +jshell.err.feedback.multiple.sections = Selector kind in multiple sections of selector list ''{0}'' in ''{1}'' -- {2} +jshell.err.feedback.different.selector.kinds = Different selector kinds in same sections of selector list ''{0}'' in ''{1}'' -- {2} + +jshell.msg.feedback.new.mode = Created new feedback mode: {0} +jshell.msg.feedback.mode = Feedback mode: {0} +jshell.msg.feedback.mode.following = The feedback mode should be one of the following: + +jshell.console.see.more = +jshell.console.do.nothing = Do nothing +jshell.console.choice = Choice: \ + +jshell.console.create.variable = Create variable +jshell.console.resolvable = \nThe identifier is resolvable in this context. +jshell.console.no.candidate = \nNo candidate fully qualified names found to import. +jshell.console.incomplete = \nResults may be incomplete; try again later for complete results. + + +help.usage = \ +Usage: jshell \n\ +where possible options include:\n\t\ + -classpath Specify where to find user class files\n\t\ + -cp Specify where to find user class files\n\t\ + -startup One run replacement for the start-up definitions\n\t\ + -nostartup Do not run the start-up definitions\n\t\ + -help Print a synopsis of standard options\n\t\ + -version Version information\n + +help.list.summary = list the source you have typed +help.list.args = [all|start|] +help.list =\ +Show the source of snippets, prefaced with the snippet id.\n\ +\n\ +/list\n\t\ + List the currently active snippets of code that you typed or read with /open\n\n\ +/list start\n\t\ + List the automatically evaluated start-up snippets\n\n\ +/list all\n\t\ + List all snippets including failed, overwritten, dropped, and start-up\n\n\ +/list \n\t\ + List snippets with the specified name (preference for active snippets)\n\n\ +/list \n\t\ + List the snippet with the specified snippet id + +help.edit.summary = edit a source entry referenced by name or id +help.edit.args = +help.edit =\ +Edit a snippet or snippets of source in an external editor.\n\ +The editor to use is set with /set editor.\n\ +If no editor has been set, a simple editor will be launched.\n\ +\n\ +/edit \n\t\ + Edit the snippet or snippets with the specified name (preference for active snippets)\n\n\ +/edit \n\t\ + Edit the snippet with the specified snippet id\n\n\ +/edit\n\t\ + Edit the currently active snippets of code that you typed or read with /open + +help.drop.summary = delete a source entry referenced by name or id +help.drop.args = +help.drop =\ +Drop a snippet -- making it inactive.\n\ +\n\ +/drop \n\t\ + Drop the snippet with the specified name\n\n\ +/drop \n\t\ + Drop the snippet with the specified snippet id + +help.save.summary = Save snippet source to a file. +help.save.args = [all|history|start] +help.save =\ +Save the specified snippets and/or commands to the specified file.\n\ +\n\ +/save \n\t\ + Save the source of current active snippets to the file.\n\n\ +/save all \n\t\ + Save the source of all snippets to the file.\n\t\ + Includes source including overwritten, failed, and start-up code.\n\n\ +/save history \n\t\ + Save the sequential history of all commands and snippets entered since jshell was launched.\n\n\ +/save start \n\t\ + Save the default start-up definitions to the file. + +help.open.summary = open a file as source input +help.open.args = +help.open =\ +Open a file and read its contents as snippets and commands.\n\ +\n\ +/open \n\t\ + Read the specified file as jshell input. + +help.vars.summary = list the declared variables and their values +help.vars.args = +help.vars =\ +List the type, name, and value of the current active jshell variables. + +help.methods.summary = list the declared methods and their signatures +help.methods.args = +help.methods =\ +List the name, parameter types, and return type of the current active jshell methods. + +help.classes.summary = list the declared classes +help.classes.args = +help.classes =\ +List the current active jshell classes, interfaces, and enums. + +help.imports.summary = list the imported items +help.imports.args = +help.imports =\ +List the current active jshell imports. + +help.exit.summary = exit jshell +help.exit.args = +help.exit =\ +Leave the jshell tool. No work is saved.\n\ +Save any work before using this command + +help.reset.summary = reset jshell +help.reset.args = +help.reset =\ +Reset the jshell tool code and execution state:\n\t\ + * All entered code is lost.\n\t\ + * Start-up code is re-executed.\n\t\ + * The execution state is restarted.\n\t\ + * The classpath is cleared.\n\ +Tool settings are maintained, as set with: /set ...\n\ +Save any work before using this command + +help.reload.summary = reset and replay relevant history -- current or previous (restore) +help.reload.args = [restore] [quiet] +help.reload =\ +Reset the jshell tool code and execution state then replay each\n\ +jshell valid command and valid snippet in the order they were entered.\n\ +\n\ +/reload\n\t\ + Reset and replay the valid history since jshell was entered, or\n\t\ + a /reset, or /reload command was executed -- whichever is most\n\t\ + recent.\n\n\ +/reload restore\n\t\ + Reset and replay the valid history between the previous and most\n\t\ + recent time that jshell was entered, or a /reset, or /reload\n\t\ + command was executed. This can thus be used to restore a previous\n\t\ + jshell tool sesson.\n\n\ +/reload [restore] quiet\n\t\ + With the 'quiet' argument the replay is not shown. Errors will display. + +help.classpath.summary = add a path to the classpath +help.classpath.args = +help.classpath =\ +Append a additional path to the classpath. + +help.history.summary = history of what you have typed +help.history.args = +help.history =\ +Display the history of snippet and command input since this jshell was launched. + +help.debug.summary = toggle debugging of the jshell +help.debug.args = [0][r][g][f][c][d][e] +help.debug =\ +Display debugging information for the jshell implementation.\n\ +0: Debugging off\n\ +r: Tool level debugging on\n\ +g: General debugging on\n\ +f: File manager debugging on\n\ +c: Completion analysis debugging on\n\ +d: Dependency debugging on\n\ +e: Event debugging on + +help.help.summary = get information about jshell +help.help.args = [|] +help.help =\ +Display information about jshell.\n\ +/help\n\t\ + List the jshell commands and help subjects.\n\n\ +/help \n\t\ + Display information about the specified comand. The slash must be included.\n\t\ + Only the first few letters of the command are needed -- if more than one\n\t\ + each will be displayed. Example: /help /li\n\n\ +/help \n\t\ + Display information about the specified help subject. Example: /help intro + +help.set.summary = set jshell configuration information +help.set.args = editor|start|feedback|newmode|prompt|format ... +help.set =\ +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 ...\n\t\ + Specify the command to launch for the /edit command.\n\t\ + The is an operating system dependent string.\n\n\ +/set start \n\t\ + The contents of the specified become the default start-up snippets and commands.\n\n\ +/set feedback \n\t\ + Set the feedback mode describing displayed feedback for entered snippets and commands.\n\n\ +/set newmode [command|quiet []]\n\t\ + Create a user-defined feedback mode, optionally copying from an existing mode.\n\n\ +/set prompt "" ""\n\t\ + Set the displayed prompts for a given feedback mode.\n\n\ +/set format "" ...\n\t\ + Configure a feedback mode by setting the format of a field when the selector matchs.\n\n\ +To get more information about one of these forms, use /help with the form specified.\n\ +For example: /help /set format + +help.quest.summary = get information about jshell +help.quest.args = [|] +help.quest =\ +Display information about jshell (abbreviation for /help).\n\ +/?\n\t\ + Display list of commands and help subjects.\n\ +/? \n\t\ + Display information about the specified comand. The slash must be included.\n\t\ + Only the first few letters of the command are needed -- if more than one\n\t\ + match, each will be displayed. Example: /? /li\n\ +/? \n\t\ + Display information about the specified help subject. Example: /? intro + +help.bang.summary = re-run last snippet +help.bang.args = +help.bang =\ +Reevaluate the most recently entered snippet. + +help.id.summary = re-run snippet by id +help.id.args = +help.id =\ +Reevaluate the snippet specified by the id. + +help.previous.summary = re-run n-th previous snippet +help.previous.args = +help.previous =\ +Reevaluate the n-th most recently entered snippet. + +help.intro.summary = an introduction to the jshell tool +help.intro =\ +The jshell tool allows you to execute Java code, getting immediate results.\n\ +You can enter a Java definition (variable, method, class, etc), like: int x = 8\n\ +or a Java expression, like: x + x\n\ +or a Java statement or import.\n\ +These little chunks of Java code are called 'snippets'.\n\ +\n\ +There are also jshell commands that allow you to understand and\n\ +control what you are doing, like: /list\n\ +\n\ +For a list of commands: /help + +help.shortcuts.summary = a description of shortcuts +help.shortcuts =\ +Supported shortcuts include:\n\ +\n\ +\n\t\t\ + After entering the first few letters of a Java identifier,\n\t\t\ + a jshell command, or, in some cases, a jshell command argument,\n\t\t\ + press the key to complete the input.\n\t\t\ + If there is more than one completion, show possible completions.\n\n\ +Shift-\n\t\t\ + After the name and open parenthesis of a method or constructor invocation,\n\t\t\ + hold the key and press the to see a synopsis of all\n\t\t\ + matching methods/constructors.\n\n\ + v\n\t\t\ + After a complete expression, press " v" to introduce a new variable\n\t\t\ + whose type is based on the type of the expression.\n\t\t\ + The "" is either Alt-F1 or Alt-Enter, depending on the platform.\n\n\ + i\n\t\t\ + After an unresolvable identifier, press " i" and jshell will propose\n\t\t\ + possible fully qualified names based on the content of the specified classpath.\n\t\t\ + The "" is either Alt-F1 or Alt-Enter, depending on the platform. + help.set.format = \ Set the format for reporting a snippet event.\n\ -\n\ +\n\t\ /set format "" ...\n\ \n\ Where is the name of a previously defined feedback mode -- see '/help /set newmode'.\n\ @@ -56,14 +406,42 @@ Where is the context in which the format is applied.\n\ The structure of selector is a hyphen separated list of selector kind lists.\n\ A selector kind list is a comma separated list of values of one selector kind.\n\ A selector matches if each selector kind list matches; A selector kind list\n\ -matches if one of the values matches.\n -help.set.format.case = The case selector kind describes the kind of snippet. The values are:\n -help.set.format.action = The action selector kind describes what happened to the snippet. The values are:\n -help.set.format.when = The when-did-it-occur selector kind describes if this is a direct or indirect action. The values are:\n -help.set.format.resolve = The resolution-state selector kind describes the state of resolution/definition of the snippet. The values are:\n -help.set.format.unresolved = The unresolved-count selector kind describes the number of unresolved references. The values are:\n -help.set.format.errors = The errors-count selector kind describes the number of errors. The values are:\n -help.set.format.end = \n\ +matches if one of the values matches.\n\n\ +The case selector kind describes the kind of snippet. The values are:\n\t\ + import -- import declaration\n\t\ + class -- class declaration\n\t\ + interface -- interface declaration\n\t\ + enum -- enum declaration\n\t\ + annotation -- annotation interface declaration\n\t\ + method -- method declaration -- note: {type}==parameter-types\n\t\ + vardecl -- variable declaration without init\n\t\ + varinit -- variable declaration with init\n\t\ + expression -- expression -- note: {name}==scratch-variable-name\n\t\ + varvalue -- variable value expression\n\t\ + assignment -- assign variable\n\t\ + statement -- statement\n\ +The action selector kind describes what happened to the snippet. The values are:\n\t\ + added -- snippet has been added\n\t\ + modified -- an existing snippet has been modified\n\t\ + replaced -- an existing snippet has been replaced with a new snippet\n\t\ + overwrote -- an existing snippet has been overwritten\n\t\ + dropped -- snippet has been dropped\n\t\ + used -- snippet was used when it cannot be\n\ +The when-did-it-occur selector kind describes if this is a direct or indirect action. The values are:\n\t\ + primary -- the entered snippet\n\t\ + update -- an update to a dependent snippet\n\ +The resolution-state selector kind describes the state of resolution/definition of the snippet. The values are:\n\t\ + ok -- resolved correctly\n\t\ + defined -- defined despite recoverably unresolved references\n\t\ + notdefined -- not defined because of recoverably unresolved references\n\ +The unresolved-count selector kind describes the number of unresolved references. The values are:\n\t\ + unresolved0 -- no names are unresolved\n\t\ + unresolved1 -- one name is unresolved\n\t\ + unresolved2 -- two or more names are unresolved\n\ +The errors-count selector kind describes the number of errors. The values are:\n\t\ + error0 -- no errors\n\t\ + error1 -- one error\n\t\ + error2 -- two or more errors\n\n\ Examples:\n\t\ /set format myformat action 'Created' added-primary\n\t\ /set format myformat action 'Update replaced' replaced-update\n\t\ @@ -73,7 +451,7 @@ Note that subsequent selectors for a field may overwrite some or all of previous help.set.feedback = \ Set the feedback mode describing displayed feedback for entered snippets and commands.\n\ -\n\ +\n\t\ /set feedback \n\ \n\ Where is the name of a previously defined feedback mode.\n\ @@ -83,7 +461,7 @@ Currently defined feedback modes:\n help.set.newmode = \ Create a user-defined feedback mode, optionally copying from an existing mode.\n\ -\n\ +\n\t\ /set newmode [command|quiet []]\n\ \n\ Where is the name of a mode you wish to create.\n\ @@ -96,15 +474,32 @@ Use '/set feedback' to use the new mode.\n\ help.set.prompt = \ Set the prompts. Both the normal prompt and the continuation-prompt must be set.\n\ -\n\ -/set prompt \"\" \"\"\n\ +\n\t\ +/set prompt \"\" \"\"\n\ \n\ Where is the name of a previously defined feedback mode.\n\ -Where and are quoted strings printed as input prompts;\n\ +Where and are quoted strings printed as input prompts;\n\ Both may optionally contain '%s' which will be substituted with the next snippet id --\n\ note that what is entered may not be assigned that id, for example it may be an error or command.\n\ The continuation-prompt is used on the second and subsequent lines of a multi-line snippet.\n +help.set.editor =\ +Specify the command to launch for the /edit command.\n\ +\n\t\ +/set editor ...\n\ +\n\ +The is an operating system dependent string.\n\ +The 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. + +help.set.start =\ +Set the start-up configuration -- a sequence of snippets and commands read at start-up.\n\ +\n\t\ +/set start \n\ +\n\ +The contents of the specified become the default start-up snippets and commands --\n\ +which are run when the jshell tool is started or reset. + startup.feedback = \ /set newmode normal command \n\ /set prompt normal '\\n-> ' '>> ' \n\ diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index 64b4d98fc7f1356925037643ad7f27017a896c27..8c83ac4cbd95c0b699317789b15e47134fb7596e 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -651,17 +651,19 @@ class Eval { ModifierDiagnostic(List list, boolean fatal) { this.fatal = fatal; StringBuilder sb = new StringBuilder(); - sb.append((list.size() > 1) ? "Modifiers " : "Modifier "); for (Modifier mod : list) { sb.append("'"); sb.append(mod.toString()); sb.append("' "); } - sb.append("not permitted in top-level declarations"); - if (!fatal) { - sb.append(", ignored"); - } - this.message = sb.toString(); + String key = (list.size() > 1) + ? fatal + ? "jshell.diag.modifier.plural.fatal" + : "jshell.diag.modifier.plural.ignore" + : fatal + ? "jshell.diag.modifier.single.fatal" + : "jshell.diag.modifier.single.ignore"; + this.message = state.messageFormat(key, sb.toString()); } @Override diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java index 2c731f5ba0cdbf8f8937627855b7e295f3a060cb..6a93708caccd7315a90acbf4d7d8181a4cdd6b05 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java @@ -29,12 +29,14 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.util.ArrayList; +import java.text.MessageFormat; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.MissingResourceException; import java.util.Objects; +import java.util.ResourceBundle; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -42,7 +44,6 @@ import java.util.function.Supplier; import jdk.internal.jshell.debug.InternalDebugControl; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT; import static jdk.jshell.Util.expunge; import jdk.jshell.Snippet.Status; @@ -91,10 +92,11 @@ public class JShell implements AutoCloseable { private final Map> keyStatusListeners = new HashMap<>(); private boolean closed = false; - private ExecutionControl executionControl = null; private SourceCodeAnalysisImpl sourceCodeAnalysis = null; + private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n"; + private static ResourceBundle outputRB = null; JShell(Builder b) { this.in = b.in; @@ -558,8 +560,8 @@ public class JShell implements AutoCloseable { checkIfAlive(); checkValidSnippet(snippet); if (snippet.status() != Status.VALID) { - throw new IllegalArgumentException("Snippet parameter of varValue() '" + - snippet + "' must be VALID, it is: " + snippet.status()); + throw new IllegalArgumentException( + messageFormat("jshell.exc.var.not.valid", snippet, snippet.status())); } String value = executionControl().commandVarValue(maps.classFullName(snippet), snippet.name()); return expunge(value); @@ -680,7 +682,7 @@ public class JShell implements AutoCloseable { */ private void checkIfAlive() throws IllegalStateException { if (closed) { - throw new IllegalStateException("JShell (" + this + ") has been closed."); + throw new IllegalStateException(messageFormat("jshell.exc.closed", this)); } } @@ -693,13 +695,36 @@ public class JShell implements AutoCloseable { */ private Snippet checkValidSnippet(Snippet sn) { if (sn == null) { - throw new NullPointerException("Snippet must not be null"); + throw new NullPointerException(messageFormat("jshell.exc.null")); } else { if (sn.key().state() != this) { - throw new IllegalArgumentException("Snippet not from this JShell"); + throw new IllegalArgumentException(messageFormat("jshell.exc.alien")); } return sn; } } + /** + * Format using resource bundle look-up using MessageFormat + * + * @param key the resource key + * @param args + */ + String messageFormat(String key, Object... args) { + if (outputRB == null) { + try { + outputRB = ResourceBundle.getBundle(L10N_RB_NAME); + } catch (MissingResourceException mre) { + throw new InternalError("Cannot find ResourceBundle: " + L10N_RB_NAME); + } + } + String s; + try { + s = outputRB.getString(key); + } catch (MissingResourceException mre) { + throw new InternalError("Missing resource: " + key + " in " + L10N_RB_NAME); + } + return MessageFormat.format(s, args); + } + } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties new file mode 100644 index 0000000000000000000000000000000000000000..12452c765d49889f6d9747b121131e579dfa21c4 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +jshell.diag.modifier.plural.fatal = Modifiers {0} not permitted in top-level declarations +jshell.diag.modifier.plural.ignore = Modifiers {0} not permitted in top-level declarations, ignored +jshell.diag.modifier.single.fatal = Modifier {0} not permitted in top-level declarations +jshell.diag.modifier.single.ignore = Modifier {0} not permitted in top-level declarations, ignored + +jshell.exc.null = Snippet must not be null +jshell.exc.alien = Snippet not from this JShell +jshell.exc.closed = JShell ({0}) has been closed. +jshell.exc.var.not.valid = Snippet parameter of varValue() {0} must be VALID, it is: {1} diff --git a/langtools/test/jdk/jshell/ReplToolTesting.java b/langtools/test/jdk/jshell/ReplToolTesting.java index 26dbd4e5aa0538d687eb84539d0e053412a2b0a9..0c288ccdee66ec0c4002b719844820847bea2b2d 100644 --- a/langtools/test/jdk/jshell/ReplToolTesting.java +++ b/langtools/test/jdk/jshell/ReplToolTesting.java @@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; @@ -194,10 +195,10 @@ public class ReplToolTesting { } public void test(boolean isDefaultStartUp, String[] args, ReplTest... tests) { - test(isDefaultStartUp, args, DEFAULT_STARTUP_MESSAGE, tests); + test(Locale.ROOT, isDefaultStartUp, args, DEFAULT_STARTUP_MESSAGE, tests); } - public void test(boolean isDefaultStartUp, String[] args, String startUpMessage, ReplTest... tests) { + public void test(Locale locale, boolean isDefaultStartUp, String[] args, String startUpMessage, ReplTest... tests) { this.isDefaultStartUp = isDefaultStartUp; initSnippets(); ReplTest[] wtests = new ReplTest[tests.length + 3]; @@ -206,7 +207,7 @@ public class ReplToolTesting { wtests[1] = a -> assertCommand(a, "/debug 0", null); System.arraycopy(tests, 0, wtests, 2, tests.length); wtests[tests.length + 2] = a -> assertCommand(a, "/exit", null); - testRaw(args, wtests); + testRaw(locale, args, wtests); } private void initSnippets() { @@ -230,7 +231,7 @@ public class ReplToolTesting { prefs = new MemoryPreferences(); } - public void testRaw(String[] args, ReplTest... tests) { + public void testRaw(Locale locale, String[] args, ReplTest... tests) { cmdin = new WaitingTestingInputStream(); cmdout = new ByteArrayOutputStream(); cmderr = new ByteArrayOutputStream(); @@ -246,7 +247,8 @@ public class ReplToolTesting { userin, new PrintStream(userout), new PrintStream(usererr), - prefs); + prefs, + locale); repl.testPrompt = true; try { repl.start(args); @@ -258,7 +260,7 @@ public class ReplToolTesting { String ceos = getCommandErrorOutput(); String uos = getUserOutput(); String ueos = getUserErrorOutput(); - assertTrue((cos.isEmpty() || cos.startsWith("| Goodbye")), + assertTrue((cos.isEmpty() || cos.startsWith("| Goodbye") || !locale.equals(Locale.ROOT)), "Expected a goodbye, but got: " + cos); assertTrue(ceos.isEmpty(), "Expected empty error output, got: " + ceos); assertTrue(uos.isEmpty(), "Expected empty output, got: " + uos); @@ -459,7 +461,7 @@ public class ReplToolTesting { private List computeCompletions(String code, boolean isSmart) { JShellTool js = this.repl != null ? this.repl - : new JShellTool(null, null, null, null, null, null, null, prefs); + : new JShellTool(null, null, null, null, null, null, null, prefs, Locale.ROOT); int cursor = code.indexOf('|'); code = code.replace("|", ""); assertTrue(cursor > -1, "'|' not found: " + code); diff --git a/langtools/test/jdk/jshell/StartOptionTest.java b/langtools/test/jdk/jshell/StartOptionTest.java index 1eb2163f64cf3dd0be0855a5b5348b223d389a61..e9d85b5dd8f634e7e34e7413c9a92a9ff3bf9958 100644 --- a/langtools/test/jdk/jshell/StartOptionTest.java +++ b/langtools/test/jdk/jshell/StartOptionTest.java @@ -37,6 +37,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.util.Locale; import java.util.function.Consumer; import jdk.internal.jshell.tool.JShellTool; @@ -55,7 +56,8 @@ public class StartOptionTest { private JShellTool getShellTool() { return new JShellTool(null, new PrintStream(out), new PrintStream(err), null, null, null, - null, new ReplToolTesting.MemoryPreferences()); + null, new ReplToolTesting.MemoryPreferences(), + Locale.ROOT); } private String getOutput() { @@ -116,10 +118,10 @@ public class StartOptionTest { Compiler compiler = new Compiler(); Path p = compiler.getPath("file.txt"); compiler.writeToFile(p); - start("", "Argument to -startup missing.\n", "-startup"); + start("", "'-startup' requires a filename argument.\n", "-startup"); start("", "Conflicting -startup or -nostartup option.\n", "-startup", p.toString(), "-startup", p.toString()); start("", "Conflicting -startup or -nostartup option.\n", "-nostartup", "-startup", p.toString()); - start("", "Conflicting -startup option.\n", "-startup", p.toString(), "-nostartup"); + start("", "Conflicting -startup or -nostartup option.\n", "-startup", p.toString(), "-nostartup"); } @Test diff --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index 6542830d0ee15815e0fe09c71c68b4157a0860f1..6b59aa24a68e3fe1375eba974974e9a88ffaa70c 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -43,6 +43,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Scanner; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -463,7 +464,7 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertCommandCheckOutput(a, "printf(\"\")", assertStartsWith("| Error:\n| cannot find symbol")) ); test((a) -> assertCommand(a, "printf(\"A\")", "", "", null, "A", "")); - test(false, new String[]{"-startup", "UNKNOWN"}, "| File 'UNKNOWN' for start-up is not found."); + test(Locale.ROOT, false, new String[]{"-startup", "UNKNOWN"}, "| File 'UNKNOWN' for start-up is not found."); } finally { removeStartup(); } @@ -478,9 +479,9 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertCommand(a, "a", "| Variable a of type double has value 10.0\n") ); Path unknown = compiler.getPath("UNKNOWN.jar"); - test(true, new String[]{unknown.toString()}, - "| File '" + unknown - + "' is not found: " + unresolvableMessage(unknown) + "\n"); + test(Locale.ROOT, true, new String[]{unknown.toString()}, + "| File " + unknown + + " is not found: " + unresolvableMessage(unknown) + "\n"); } public void testReset() { diff --git a/langtools/test/jdk/jshell/ToolFormatTest.java b/langtools/test/jdk/jshell/ToolFormatTest.java index 6ed38b9507df2bd4c9b85d486fee62d78c96af0e..6d61fba4671f37ff02c5b75b98de33710146e2d8 100644 --- a/langtools/test/jdk/jshell/ToolFormatTest.java +++ b/langtools/test/jdk/jshell/ToolFormatTest.java @@ -62,7 +62,7 @@ public class ToolFormatTest extends ReplToolTesting { (a) -> assertCommand(a, "/set format test result '={value} ' expression", ""), (a) -> assertCommand(a, "/set format test display '{pre}{action}{ftype}{fname}{result}{resolve}'", ""), (a) -> assertCommand(a, "/set format test display '{pre}HI this is enum' enum", ""), - (a) -> assertCommand(a, "/set feedback test", "$ Feedback mode: test"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback test", "$ Feedback mode: test"), (a) -> assertCommand(a, "class D {}", "$ ADD :D OK"), (a) -> assertCommand(a, "void m() {}", "$ ADD []:m OK"), (a) -> assertCommand(a, "interface EX extends EEX {}", "$ ADD :EX NODEF"), @@ -184,18 +184,18 @@ public class ToolFormatTest extends ReplToolTesting { (a) -> assertCommandOutputStartsWith(a, "/set newmode te2", "| Created new feedback mode: te2"), (a) -> assertCommandOutputStartsWith(a, "/set newmode te2 command", - "| Expected a new feedback mode name. te2 is a known feedback mode"), + "| Expected a new feedback mode name. 'te2' is a known feedback mode"), (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), (a) -> assertCommand(a, "/set format te errorpre 'ERROR: '", ""), (a) -> assertCommandOutputStartsWith(a, "/set feedback te", ""), (a) -> assertCommandOutputStartsWith(a, "/set ", - "ERROR: The /set command requires arguments"), + "ERROR: The '/set' command requires a sub-command and arguments"), (a) -> assertCommandOutputStartsWith(a, "/set xyz", - "ERROR: Not a valid argument to /set"), + "ERROR: Invalid '/set' argument: xyz"), (a) -> assertCommandOutputStartsWith(a, "/set f", - "ERROR: Ambiguous argument to /set"), + "ERROR: Ambiguous sub-command argument to '/set': f"), (a) -> assertCommandOutputStartsWith(a, "/set feedback", "ERROR: Expected a feedback mode"), (a) -> assertCommandOutputStartsWith(a, "/set feedback xyz", @@ -266,19 +266,4 @@ public class ToolFormatTest extends ReplToolTesting { }); } } - - public void testSetHelpError() { - try { - test( - (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), - (a) -> assertCommand(a, "/set format te errorpre 'ERROR: '", ""), - (a) -> assertCommandOutputStartsWith(a, "/set feedback te", "| Feedback mode: te"), - (a) -> assertCommandOutputContains(a, "/help /set xyz", "ERROR: Not a valid argument to /set: xyz"), - (a) -> assertCommandOutputContains(a, "/help /set f", "ERROR: Ambiguous argument to /set: f") - ); - } finally { - assertCommandCheckOutput(false, "/set feedback normal", s -> { - }); - } - } } diff --git a/langtools/test/jdk/jshell/ToolLocaleMessageTest.java b/langtools/test/jdk/jshell/ToolLocaleMessageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..08e856528419b93c36d4735bf047909754d29cfe --- /dev/null +++ b/langtools/test/jdk/jshell/ToolLocaleMessageTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8147515 + * @summary Tests for output customization + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * jdk.jshell/jdk.internal.jshell.tool + * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler + * @run testng ToolLocaleMessageTest + */ + +import java.util.Locale; +import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +@Test +public class ToolLocaleMessageTest extends ReplToolTesting { + + void testLocale(ReplTest... tests) { + test(Locale.getDefault(), false, new String[]{"-nostartup"}, "", tests); + } + + void assertCommandOK(boolean after, String cmd, String... contains) { + assertCommandCheckOutput(after, cmd, s -> { + assertFalse(s.contains("Exception"), "Output of '" + cmd + "' has Exception: " + s); + assertFalse(s.contains("ERROR:"), "Output of '" + cmd + "' has error: " + s); + for (String m : contains) { + assertTrue(s.contains(m), "Expected to find '" + m + "' in output of '" + cmd + "' -- output: " + s); + } + }); + } + + void assertCommandFail(boolean after, String cmd, String... contains) { + assertCommandCheckOutput(after, cmd, s -> { + assertFalse(s.contains("Exception"), "Output of '" + cmd + "' has Exception: " + s); + assertTrue(s.contains("ERROR:"), "Expected to find error in output of '" + cmd + "' has error: " + s); + for (String m : contains) { + assertTrue(s.contains(m), "Expected to find '" + m + "' in output of '" + cmd + "' -- output: " + s); + } + }); + } + + public void testTerminate() { + testLocale( + (a) -> assertCommandOK(a, "System.exit(1)", "/reload") + ); + } + + public void testSample() { + try { + testLocale( + (a) -> assertCommandOK(a, "/set newmode test command normal", "test"), + (a) -> assertCommandOK(a, "/set format test errorpre 'ERROR: '"), + (a) -> assertCommandOK(a, "/set feedback test", "test"), + + (a) -> assertCommandFail(a, "/turkey", "/turkey"), + (a) -> assertCommandFail(a, "/s", "/set"), + (a) -> assertCommandOK(a, "void m() { blah(); }", "blah"), + (a) -> assertCommandOK(a, "void m() {}"), + (a) -> assertCommandOK(a, "class C {}"), + (a) -> assertCommandOK(a, "47"), + (a) -> assertCommandOK(a, "double d"), + (a) -> assertCommandOK(a, "/drop m", "m"), + (a) -> assertCommandOK(a, "void dup() {}"), + (a) -> assertCommandOK(a, "int dup"), + + (a) -> assertCommandOK(a, "/set feedback normal", "normal") + ); + } finally { + assertCommandOK(false, "/set feedback normal"); + } + } + + public void testCommand() { + try { + testLocale( + (a) -> assertCommandOK(a, "/set newmode test command normal", "test"), + (a) -> assertCommandOK(a, "/set format test errorpre 'ERROR: '"), + (a) -> assertCommandOK(a, "/set feedback test", "test"), + + (a) -> assertCommandFail(a, "/list zebra"), + (a) -> assertCommandFail(a, "/set editor", "/set editor"), + (a) -> assertCommandFail(a, "/set snowball", "/set", "snowball"), + (a) -> assertCommandFail(a, "/set", "/set", "/help"), + (a) -> assertCommandFail(a, "/set f", "feedback"), + (a) -> assertCommandFail(a, "/classpath", "/classpath"), + (a) -> assertCommandFail(a, "/help rabbits", "rabbits"), + (a) -> assertCommandFail(a, "/drop"), + (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", "/list"), + (a) -> assertCommandFail(a, "/open", "/open"), + (a) -> assertCommandFail(a, "/open zebra", "zebra", "/open"), + (a) -> assertCommandFail(a, "/reload zebra", "zebra", "/reload"), + (a) -> assertCommandFail(a, "/save", "/save"), + (a) -> assertCommandFail(a, "/-99"), + + (a) -> assertCommandOK(a, "/set feedback normal", "normal") + ); + } finally { + assertCommandOK(false, "/set feedback normal"); + } + } + + public void testHelp() { + testLocale( + (a) -> assertCommandOK(a, "/help", "/list", "/save", "/set", "[restore]"), + (a) -> assertCommandOK(a, "/help /list", "start", "all"), + (a) -> assertCommandOK(a, "/help /edit", "/set editor"), + (a) -> assertCommandOK(a, "/help /drop", "/drop"), + (a) -> assertCommandOK(a, "/help /save", "all", "start"), + (a) -> assertCommandOK(a, "/help /open", "/open"), + (a) -> assertCommandOK(a, "/help /reload", "restore"), + (a) -> assertCommandOK(a, "/help /help", "intro"), + (a) -> assertCommandOK(a, "/help /set", "newmode"), + (a) -> assertCommandOK(a, "/help /?", "intro"), + (a) -> assertCommandOK(a, "/help intro", "/help"), + (a) -> assertCommandOK(a, "/help /set format", "import", "case", "{value}", "added"), + (a) -> assertCommandOK(a, "/help /set feedback", "newmode"), + (a) -> assertCommandOK(a, "/help /set newmode", "feedback"), + (a) -> assertCommandOK(a, "/help /set prompt", "/set prompt"), + (a) -> assertCommandOK(a, "/help /set editor", "/edit") + ); + } + + public void testFeedbackError() { + try { + testLocale( + (a) -> assertCommandOK(a, "/set newmode tee command foo", "foo"), + (a) -> assertCommandOK(a, "/set newmode tee flurb", "command", "quiet"), + (a) -> assertCommandOK(a, "/set newmode te2", "te2"), + (a) -> assertCommandOK(a, "/set newmode te2 command", "te2"), + (a) -> assertCommandOK(a, "/set newmode te command normal", "te"), + (a) -> assertCommandOK(a, "/set format te errorpre 'ERROR: '"), + (a) -> assertCommandOK(a, "/set feedback te"), + + (a) -> assertCommandFail(a, "/set "), + (a) -> assertCommandFail(a, "/set xyz", "xyz"), + (a) -> assertCommandFail(a, "/set f", "/set", "f"), + (a) -> assertCommandFail(a, "/set feedback"), + (a) -> assertCommandFail(a, "/set feedback xyz"), + (a) -> assertCommandFail(a, "/set format"), + (a) -> assertCommandFail(a, "/set format xyz"), + (a) -> assertCommandFail(a, "/set format t"), + (a) -> assertCommandFail(a, "/set format te"), + (a) -> assertCommandFail(a, "/set format te fld"), + (a) -> assertCommandFail(a, "/set format te fld aaa", "aaa"), + (a) -> assertCommandFail(a, "/set format te fld 'aaa' frog"), + (a) -> assertCommandFail(a, "/set format te fld 'aaa' import-frog"), + (a) -> assertCommandFail(a, "/set format te fld 'aaa' import-import"), + (a) -> assertCommandFail(a, "/set format te fld 'aaa' import,added"), + (a) -> assertCommandFail(a, "/set newmode"), + (a) -> assertCommandFail(a, "/set newmode te"), + (a) -> assertCommandFail(a, "/set newmode x xyz"), + (a) -> assertCommandFail(a, "/set newmode x quiet y"), + (a) -> assertCommandFail(a, "/set prompt"), + (a) -> assertCommandFail(a, "/set prompt te"), + (a) -> assertCommandFail(a, "/set prompt te aaa xyz", "aaa"), + (a) -> assertCommandFail(a, "/set prompt te 'aaa' xyz", "xyz"), + (a) -> assertCommandFail(a, "/set prompt"), + (a) -> assertCommandFail(a, "/set prompt te"), + (a) -> assertCommandFail(a, "/set prompt te aaa"), + (a) -> assertCommandFail(a, "/set prompt te 'aaa'"), + + (a) -> assertCommandOK(a, "/set feedback normal") + ); + } finally { + assertCommandOK(false, "/set feedback normal"); + } + } + + +} diff --git a/langtools/test/jdk/jshell/ToolReloadTest.java b/langtools/test/jdk/jshell/ToolReloadTest.java index d394d862c536a6bb8e53fd0df6cb350954b34690..1dfb8b775b11a72872e184819562f25656f19b18 100644 --- a/langtools/test/jdk/jshell/ToolReloadTest.java +++ b/langtools/test/jdk/jshell/ToolReloadTest.java @@ -71,7 +71,7 @@ public class ToolReloadTest extends ReplToolTesting { Path classpath = compiler.getPath(outDir); test( (a) -> assertCommand(a, "/classpath " + classpath, - String.format("| Path %s added to classpath\n", classpath)), + String.format("| Path '%s' added to classpath\n", classpath)), (a) -> assertMethod(a, "String foo() { return (new pkg.A()).toString(); }", "()String", "foo"), (a) -> assertVariable(a, "String", "v", "foo()", "\"A\""),