# HG changeset patch # User rfield # Date 1458956179 25200 # Node ID bf40906bf49de61033e77b9fb7ac24a6fc4eba6a # Parent 66bc9949f8b3ee1b6ce8654729c3be26a5f8599c 8151755: jshell tool: properly cover resolution issues in output configuration 8152246: jshell tool: history overflow Reviewed-by: jlahoda diff -r 66bc9949f8b3 -r bf40906bf49d langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java Wed Mar 23 21:44:24 2016 -0700 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java Fri Mar 25 18:36:19 2016 -0700 @@ -28,18 +28,16 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.stream.Collectors.joining; /** * Feedback customization support @@ -57,29 +55,38 @@ // Mapping of mode names to mode modes private final Map modeMap = new HashMap<>(); + // Mapping selector enum names to enums + private final Map> selectorMap = new HashMap<>(); + + private static final long ALWAYS = bits(FormatCase.all, FormatAction.all, FormatWhen.all, + FormatResolve.all, FormatUnresolved.all, FormatErrors.all); + private static final long ANY = 0L; + public boolean shouldDisplayCommandFluff() { return mode.commandFluff; } public String getPre() { - return mode.pre; + return mode.format("pre", ANY); } public String getPost() { - return mode.post; + return mode.format("post", ANY); } public String getErrorPre() { - return mode.errorPre; + return mode.format("errorpre", ANY); } public String getErrorPost() { - return mode.errorPost; + return mode.format("errorpost", ANY); } - public String getFormat(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, - boolean hasName, boolean hasType, boolean hasResult) { - return mode.getFormat(fc, fw, fa, fr, hasName, hasType, hasResult); + public String format(FormatCase fc, FormatAction fa, FormatWhen fw, + FormatResolve fr, FormatUnresolved fu, FormatErrors fe, + String name, String type, String value, String unresolved, List errorLines) { + return mode.format(fc, fa, fw, fr, fu, fe, + name, type, value, unresolved, errorLines); } public String getPrompt(String nextId) { @@ -91,184 +98,76 @@ } public boolean setFeedback(JShellTool tool, ArgTokenizer at) { - return new FormatSetter(tool, at).setFeedback(); - } - - public boolean setField(JShellTool tool, ArgTokenizer at) { - return new FormatSetter(tool, at).setField(); + return new Setter(tool, at).setFeedback(); } public boolean setFormat(JShellTool tool, ArgTokenizer at) { - return new FormatSetter(tool, at).setFormat(); + return new Setter(tool, at).setFormat(); } public boolean setNewMode(JShellTool tool, ArgTokenizer at) { - return new FormatSetter(tool, at).setNewMode(); + return new Setter(tool, at).setNewMode(); } public boolean setPrompt(JShellTool tool, ArgTokenizer at) { - return new FormatSetter(tool, at).setPrompt(); + return new Setter(tool, at).setPrompt(); } public void printFeedbackHelp(JShellTool tool) { - new FormatSetter(tool, null).printFeedbackHelp(); - } - - public void printFieldHelp(JShellTool tool) { - new FormatSetter(tool, null).printFieldHelp(); + new Setter(tool, null).printFeedbackHelp(); } public void printFormatHelp(JShellTool tool) { - new FormatSetter(tool, null).printFormatHelp(); + new Setter(tool, null).printFormatHelp(); } public void printNewModeHelp(JShellTool tool) { - new FormatSetter(tool, null).printNewModeHelp(); + new Setter(tool, null).printNewModeHelp(); } public void printPromptHelp(JShellTool tool) { - new FormatSetter(tool, null).printPromptHelp(); + new Setter(tool, null).printPromptHelp(); + } + + { + for (FormatCase e : EnumSet.allOf(FormatCase.class)) + selectorMap.put(e.name().toLowerCase(Locale.US), e); + for (FormatAction e : EnumSet.allOf(FormatAction.class)) + selectorMap.put(e.name().toLowerCase(Locale.US), e); + for (FormatResolve e : EnumSet.allOf(FormatResolve.class)) + selectorMap.put(e.name().toLowerCase(Locale.US), e); + for (FormatUnresolved e : EnumSet.allOf(FormatUnresolved.class)) + selectorMap.put(e.name().toLowerCase(Locale.US), e); + for (FormatErrors e : EnumSet.allOf(FormatErrors.class)) + selectorMap.put(e.name().toLowerCase(Locale.US), e); + for (FormatWhen e : EnumSet.allOf(FormatWhen.class)) + selectorMap.put(e.name().toLowerCase(Locale.US), e); } /** * Holds all the context of a mode mode */ - private class Mode { + private static class Mode { - // Use name of mode mode - + // Name of mode final String name; // Display command verification/information final boolean commandFluff; - // event cases: class, method - final EnumMap>> cases; - - // action names: add. modified, replaced, ... - final EnumMap> actions; - - // resolution status description format with %s for unresolved - final EnumMap> resolves; - - // primary snippet vs update - final EnumMap whens; - - // fixed map of how to get format string for a field, given a specific formatting contet - final EnumMap> fields; - - // format wrappers for name, type, and result - String fname = "%s"; - String ftype = "%s"; - String fresult = "%s"; - - // start and end, also used by hard-coded output - String pre = "| "; - String post = "\n"; - String errorPre = "| Error: "; - String errorPost = "\n"; + // Event cases: class, method, expression, ... + final Map> cases; String prompt = "\n-> "; String continuationPrompt = ">> "; - /** - * The context of a specific mode to potentially display. - */ - class Context { - - final FormatCase fc; - final FormatAction fa; - final FormatResolve fr; - final FormatWhen fw; - final boolean hasName; - final boolean hasType; - final boolean hasResult; - - Context(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, - boolean hasName, boolean hasType, boolean hasResult) { - this.fc = fc; - this.fa = fa; - this.fr = fr; - this.fw = fw; - this.hasName = hasName; - this.hasType = hasType; - this.hasResult = hasResult; - } - - String when() { - return whens.get(fw); - } - - String action() { - return actions.get(fa).get(fw); - } - - String resolve() { - return String.format(resolves.get(fr).get(fw), FormatField.RESOLVE.form); - } - - String name() { - return hasName - ? String.format(fname, FormatField.NAME.form) - : ""; - } - - String type() { - return hasType - ? String.format(ftype, FormatField.TYPE.form) - : ""; + static class Setting { + final long enumBits; + final String format; + Setting(long enumBits, String format) { + this.enumBits = enumBits; + this.format = format; } - - String result() { - return hasResult - ? String.format(fresult, FormatField.RESULT.form) - : ""; - } - - /** - * Lookup format based on case, action, and whether it update. - * Replace fields with context specific formats. - * - * @return format string - */ - String format() { - String format = cases.get(fc).get(fa).get(fw); - if (format == null) { - return ""; - } - Matcher m = FIELD_PATTERN.matcher(format); - StringBuffer sb = new StringBuffer(format.length()); - while (m.find()) { - String fieldName = m.group(1).toUpperCase(Locale.US); - String sub = null; - for (FormatField f : FormatField.values()) { - if (f.name().startsWith(fieldName)) { - sub = fields.get(f).apply(this); - break; - } - } - if (sub != null) { - m.appendReplacement(sb, Matcher.quoteReplacement(sub)); - } - } - m.appendTail(sb); - return sb.toString(); - } - } - - { - // set fixed mappings of fields - fields = new EnumMap<>(FormatField.class); - fields.put(FormatField.WHEN, c -> c.when()); - fields.put(FormatField.ACTION, c -> c.action()); - fields.put(FormatField.RESOLVE, c -> c.resolve()); - fields.put(FormatField.NAME, c -> c.name()); - fields.put(FormatField.TYPE, c -> c.type()); - fields.put(FormatField.RESULT, c -> c.result()); - fields.put(FormatField.PRE, c -> pre); - fields.put(FormatField.POST, c -> post); - fields.put(FormatField.ERRORPRE, c -> errorPre); - fields.put(FormatField.ERRORPOST, c -> errorPost); } /** @@ -280,41 +179,20 @@ Mode(String name, boolean commandFluff) { this.name = name; this.commandFluff = commandFluff; - cases = new EnumMap<>(FormatCase.class); - for (FormatCase fc : FormatCase.values()) { - EnumMap> ac = new EnumMap<>(FormatAction.class); - cases.put(fc, ac); - for (FormatAction fa : FormatAction.values()) { - EnumMap aw = new EnumMap<>(FormatWhen.class); - ac.put(fa, aw); - for (FormatWhen fw : FormatWhen.values()) { - aw.put(fw, ""); - } - } - } + cases = new HashMap<>(); + add("name", new Setting(ALWAYS, "%1$s")); + add("type", new Setting(ALWAYS, "%2$s")); + add("value", new Setting(ALWAYS, "%3$s")); + add("unresolved", new Setting(ALWAYS, "%4$s")); + add("errors", new Setting(ALWAYS, "%5$s")); + add("err", new Setting(ALWAYS, "%6$s")); - actions = new EnumMap<>(FormatAction.class); - for (FormatAction fa : FormatAction.values()) { - EnumMap afw = new EnumMap<>(FormatWhen.class); - actions.put(fa, afw); - for (FormatWhen fw : FormatWhen.values()) { - afw.put(fw, fa.name() + "-" + fw.name()); - } - } + add("errorline", new Setting(ALWAYS, " {err}%n")); - resolves = new EnumMap<>(FormatResolve.class); - for (FormatResolve fr : FormatResolve.values()) { - EnumMap arw = new EnumMap<>(FormatWhen.class); - resolves.put(fr, arw); - for (FormatWhen fw : FormatWhen.values()) { - arw.put(fw, fr.name() + "-" + fw.name() + ": %s"); - } - } - - whens = new EnumMap<>(FormatWhen.class); - for (FormatWhen fw : FormatWhen.values()) { - whens.put(fw, fw.name()); - } + add("pre", new Setting(ALWAYS, "| ")); + add("post", new Setting(ALWAYS, "%n")); + add("errorpre", new Setting(ALWAYS, "| ")); + add("errorpost", new Setting(ALWAYS, "%n")); } /** @@ -322,132 +200,91 @@ * * @param name * @param commandFluff True if should display command fluff messages - * @param m Mode to copy + * @param m Mode to copy, or null for no fresh */ Mode(String name, boolean commandFluff, Mode m) { this.name = name; this.commandFluff = commandFluff; - cases = new EnumMap<>(FormatCase.class); - for (FormatCase fc : FormatCase.values()) { - EnumMap> ac = new EnumMap<>(FormatAction.class); - EnumMap> mc = m.cases.get(fc); - cases.put(fc, ac); - for (FormatAction fa : FormatAction.values()) { - EnumMap aw = new EnumMap<>(mc.get(fa)); - ac.put(fa, aw); - } - } + cases = new HashMap<>(); - actions = new EnumMap<>(FormatAction.class); - for (FormatAction fa : FormatAction.values()) { - EnumMap afw = new EnumMap<>(m.actions.get(fa)); - actions.put(fa, afw); - } + m.cases.entrySet().stream() + .forEach(fes -> fes.getValue() + .forEach(ing -> add(fes.getKey(), ing))); - resolves = new EnumMap<>(FormatResolve.class); - for (FormatResolve fr : FormatResolve.values()) { - EnumMap arw = new EnumMap<>(m.resolves.get(fr)); - resolves.put(fr, arw); - } - - whens = new EnumMap<>(m.whens); - - this.fname = m.fname; - this.ftype = m.ftype; - this.fresult = m.fresult; - this.pre = m.pre; - this.post = m.post; - this.errorPre = m.errorPre; - this.errorPost = m.errorPost; this.prompt = m.prompt; this.continuationPrompt = m.continuationPrompt; } - String getFormat(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, - boolean hasName, boolean hasType, boolean hasResult) { - Context context = new Context(fc, fw, fa, fr, - hasName, hasType, hasResult); - return context.format(); - } - - void setCases(String format, Collection cc, Collection ca, Collection cw) { - for (FormatCase fc : cc) { - EnumMap> ma = cases.get(fc); - for (FormatAction fa : ca) { - EnumMap mw = ma.get(fa); - for (FormatWhen fw : cw) { - mw.put(fw, format); - } - } + private boolean add(String field, Setting ing) { + List settings = cases.computeIfAbsent(field, k -> new ArrayList<>()); + if (settings == null) { + return false; } + settings.add(ing); + return true; } - void setActions(String format, Collection ca, Collection cw) { - for (FormatAction fa : ca) { - EnumMap mw = actions.get(fa); - for (FormatWhen fw : cw) { - mw.put(fw, format); - } - } + void set(String field, + Collection cc, Collection ca, Collection cw, + Collection cr, Collection cu, Collection ce, + String format) { + long bits = bits(cc, ca, cw, cr, cu, ce); + set(field, bits, format); } - void setResolves(String format, Collection cr, Collection cw) { - for (FormatResolve fr : cr) { - EnumMap mw = resolves.get(fr); - for (FormatWhen fw : cw) { - mw.put(fw, format); - } - } - } - - void setWhens(String format, Collection cw) { - for (FormatWhen fw : cw) { - whens.put(fw, format); - } + void set(String field, long bits, String format) { + add(field, new Setting(bits, format)); } - void setName(String s) { - fname = s; - } - - void setType(String s) { - ftype = s; - } - - void setResult(String s) { - fresult = s; - } - - void setPre(String s) { - pre = s; - } - - void setPost(String s) { - post = s; + /** + * Lookup format Replace fields with context specific formats. + * + * @return format string + */ + String format(String field, long bits) { + List settings = cases.get(field); + if (settings == null) { + return ""; //TODO error? + } + String format = null; + for (int i = settings.size() - 1; i >= 0; --i) { + Setting ing = settings.get(i); + long mask = ing.enumBits; + if ((bits & mask) == bits) { + format = ing.format; + break; + } + } + if (format == null || format.isEmpty()) { + return ""; + } + Matcher m = FIELD_PATTERN.matcher(format); + StringBuffer sb = new StringBuffer(format.length()); + while (m.find()) { + String fieldName = m.group(1); + String sub = format(fieldName, bits); + m.appendReplacement(sb, Matcher.quoteReplacement(sub)); + } + m.appendTail(sb); + return sb.toString(); } - void setErrorPre(String s) { - errorPre = s; - } - - void setErrorPost(String s) { - errorPost = s; - } - - String getPre() { - return pre; - } - - String getPost() { - return post; - } - - String getErrorPre() { - return errorPre; - } - - String getErrorPost() { - return errorPost; + String format(FormatCase fc, FormatAction fa, FormatWhen fw, + FormatResolve fr, FormatUnresolved fu, FormatErrors fe, + String name, String type, String value, String unresolved, List errorLines) { + long bits = bits(fc, fa, fw, fr, fu, fe); + String fname = name==null? "" : name; + String ftype = type==null? "" : type; + String fvalue = value==null? "" : value; + String funresolved = unresolved==null? "" : unresolved; + String errors = errorLines.stream() + .map(el -> String.format( + format("errorline", bits), + fname, ftype, fvalue, funresolved, "*cannot-use-errors-here*", el)) + .collect(joining()); + return String.format( + format("display", bits), + fname, ftype, fvalue, funresolved, errors, "*cannot-use-err-here*"); } void setPrompts(String prompt, String continuationPrompt) { @@ -464,50 +301,82 @@ } } - /** - * The brace delimited substitutions - */ - public enum FormatField { - WHEN, - ACTION, - RESOLVE("%1$s"), - NAME("%2$s"), - TYPE("%3$s"), - RESULT("%4$s"), - PRE, - POST, - ERRORPRE, - ERRORPOST; - String form; + // Representation of one instance of all the enum values as bits in a long + private static long bits(FormatCase fc, FormatAction fa, FormatWhen fw, + FormatResolve fr, FormatUnresolved fu, FormatErrors fe) { + long res = 0L; + res |= 1 << fc.ordinal(); + res <<= FormatAction.count; + res |= 1 << fa.ordinal(); + res <<= FormatWhen.count; + res |= 1 << fw.ordinal(); + res <<= FormatResolve.count; + res |= 1 << fr.ordinal(); + res <<= FormatUnresolved.count; + res |= 1 << fu.ordinal(); + res <<= FormatErrors.count; + res |= 1 << fe.ordinal(); + return res; + } - FormatField(String s) { - this.form = s; - } + // Representation of a space of enum values as or'edbits in a long + private static long bits(Collection cc, Collection ca, Collection cw, + Collection cr, Collection cu, Collection ce) { + long res = 0L; + for (FormatCase fc : cc) + res |= 1 << fc.ordinal(); + res <<= FormatAction.count; + for (FormatAction fa : ca) + res |= 1 << fa.ordinal(); + res <<= FormatWhen.count; + for (FormatWhen fw : cw) + res |= 1 << fw.ordinal(); + res <<= FormatResolve.count; + for (FormatResolve fr : cr) + res |= 1 << fr.ordinal(); + res <<= FormatUnresolved.count; + for (FormatUnresolved fu : cu) + res |= 1 << fu.ordinal(); + res <<= FormatErrors.count; + for (FormatErrors fe : ce) + res |= 1 << fe.ordinal(); + return res; + } - FormatField() { - this.form = null; - } + interface Selector & Selector> { + SelectorCollector collector(Setter.SelectorList sl); + String doc(); } /** * The event cases */ - public enum FormatCase { - IMPORT("import declaration: {action} {name}"), - CLASS("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), - INTERFACE("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), - ENUM("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), - ANNOTATION("annotation interface declaration: {action} {name} {resolve}"), - METHOD("method declaration: {action} {name} {type}==parameter-types {resolve}"), - VARDECL("variable declaration: {action} {name} {type} {resolve}"), - VARDECLRECOVERABLE("recoverably failed variable declaration: {action} {name} {resolve}"), - VARINIT("variable declaration with init: {action} {name} {type} {resolve} {result}"), - VARRESET("variable reset on update: {action} {name}"), - EXPRESSION("expression: {action}=='Saved to scratch variable' {name} {type} {result}"), - VARVALUE("variable value expression: {action} {name} {type} {result}"), - ASSIGNMENT("assign variable: {action} {name} {type} {result}"), - STATEMENT("statement: {action}"); + public enum FormatCase implements Selector { + IMPORT("import declaration"), + CLASS("class declaration"), + INTERFACE("interface declaration"), + ENUM("enum declaration"), + ANNOTATION("annotation interface declaration"), + METHOD("method declaration -- note: {type}==parameter-types"), + VARDECL("variable declaration without init"), + VARINIT("variable declaration with init"), + EXPRESSION("expression -- note: {name}==scratch-variable-name"), + VARVALUE("variable value expression"), + ASSIGNMENT("assign variable"), + STATEMENT("statement"); String doc; + static final EnumSet all = EnumSet.allOf(FormatCase.class); + static final int count = all.size(); + + @Override + public SelectorCollector collector(Setter.SelectorList sl) { + return sl.cases; + } + + @Override + public String doc() { + return doc; + } private FormatCase(String doc) { this.doc = doc; @@ -517,14 +386,26 @@ /** * The event actions */ - public enum FormatAction { + public enum FormatAction implements Selector { ADDED("snippet has been added"), MODIFIED("an existing snippet has been modified"), REPLACED("an existing snippet has been replaced with a new snippet"), OVERWROTE("an existing snippet has been overwritten"), DROPPED("snippet has been dropped"), - REJECTED("snippet has failed and been rejected"); + USED("snippet was used when it cannot be"); String doc; + static final EnumSet all = EnumSet.allOf(FormatAction.class); + static final int count = all.size(); + + @Override + public SelectorCollector collector(Setter.SelectorList sl) { + return sl.actions; + } + + @Override + public String doc() { + return doc; + } private FormatAction(String doc) { this.doc = doc; @@ -534,10 +415,22 @@ /** * When the event occurs: primary or update */ - public enum FormatWhen { + public enum FormatWhen implements Selector { PRIMARY("the entered snippet"), UPDATE("an update to a dependent snippet"); String doc; + static final EnumSet all = EnumSet.allOf(FormatWhen.class); + static final int count = all.size(); + + @Override + public SelectorCollector collector(Setter.SelectorList sl) { + return sl.whens; + } + + @Override + public String doc() { + return doc; + } private FormatWhen(String doc) { this.doc = doc; @@ -545,46 +438,119 @@ } /** - * Resolution problems with event + * Resolution problems */ - public enum FormatResolve { + public enum FormatResolve implements Selector { OK("resolved correctly"), DEFINED("defined despite recoverably unresolved references"), NOTDEFINED("not defined because of recoverably unresolved references"); String doc; + static final EnumSet all = EnumSet.allOf(FormatResolve.class); + static final int count = all.size(); + + @Override + public SelectorCollector collector(Setter.SelectorList sl) { + return sl.resolves; + } + + @Override + public String doc() { + return doc; + } private FormatResolve(String doc) { this.doc = doc; } } + /** + * Count of unresolved references + */ + public enum FormatUnresolved implements Selector { + UNRESOLVED0("no names are unresolved"), + UNRESOLVED1("one name is unresolved"), + UNRESOLVED2("two or more names are unresolved"); + String doc; + static final EnumSet all = EnumSet.allOf(FormatUnresolved.class); + static final int count = all.size(); + + @Override + public SelectorCollector collector(Setter.SelectorList sl) { + return sl.unresolvedCounts; + } + + @Override + public String doc() { + return doc; + } + + private FormatUnresolved(String doc) { + this.doc = doc; + } + } + + /** + * Count of unresolved references + */ + public enum FormatErrors implements Selector { + ERROR0("no errors"), + ERROR1("one error"), + ERROR2("two or more errors"); + String doc; + static final EnumSet all = EnumSet.allOf(FormatErrors.class); + static final int count = all.size(); + + @Override + public SelectorCollector collector(Setter.SelectorList sl) { + return sl.errorCounts; + } + + @Override + public String doc() { + return doc; + } + + private FormatErrors(String doc) { + this.doc = doc; + } + } + + class SelectorCollector & Selector> { + final EnumSet all; + EnumSet set = null; + SelectorCollector(EnumSet all) { + this.all = all; + } + void add(Object o) { + @SuppressWarnings("unchecked") + E e = (E) o; + if (set == null) { + set = EnumSet.of(e); + } else { + set.add(e); + } + } + + boolean isEmpty() { + return set == null; + } + + EnumSet getSet() { + return set == null + ? all + : set; + } + } + // Class used to set custom eval output formats - // For both /set format and /set field -- Parse arguments, setting custom format, or printing error - private class FormatSetter { + // For both /set format -- Parse arguments, setting custom format, or printing error + private class Setter { private final ArgTokenizer at; private final JShellTool tool; boolean valid = true; - class Case, E2 extends Enum, E3 extends Enum> { - - Set e1; - Set e2; - Set e3; - - Case(Set e1, Set e2, Set e3) { - this.e1 = e1; - this.e2 = e2; - this.e3 = e3; - } - - Case(Set e1, Set e2) { - this.e1 = e1; - this.e2 = e2; - } - } - - FormatSetter(JShellTool tool, ArgTokenizer at) { + Setter(JShellTool tool, ArgTokenizer at) { this.tool = tool; this.at = at; } @@ -593,6 +559,10 @@ 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); } @@ -681,137 +651,31 @@ // For /set format "" ... boolean setFormat() { Mode m = nextMode(); - String format = nextFormat(); - if (valid) { - List> specs = new ArrayList<>(); - String s; - while ((s = at.next()) != null) { - String[] d = s.split("-"); - specs.add(new Case<>( - parseFormatCase(d, 0), - parseFormatAction(d, 1), - parseFormatWhen(d, 2) - )); - } - if (valid && specs.isEmpty()) { - errorat("At least one selector required"); - valid = false; - } - if (valid) { - // set the format in the specified cases - specs.stream() - .forEach(c -> m.setCases(format, c.e1, c.e2, c.e3)); - } + String field = at.next(); + if (field == null || at.isQuoted()) { + errorat("Expected field name missing"); + valid = false; } - if (!valid) { - fluff("See '/help /set format' for help"); + String format = valid? nextFormat() : null; + String slRaw; + List slList = new ArrayList<>(); + while (valid && (slRaw = at.next()) != null) { + SelectorList sl = new SelectorList(); + sl.parseSelectorList(slRaw); + slList.add(sl); } - return valid; - } - - // For /set field mode "" ... - boolean setField() { - Mode m = nextMode(); - String fieldName = at.next(); - FormatField field = parseFormatSelector(fieldName, EnumSet.allOf(FormatField.class), "field"); - String format = nextFormat(); if (valid) { - switch (field) { - case ACTION: { - List> specs = new ArrayList<>(); - String s; - while ((s = at.next()) != null) { - String[] d = s.split("-"); - specs.add(new Case<>( - parseFormatAction(d, 0), - parseFormatWhen(d, 1) - )); - } - if (valid && specs.isEmpty()) { - errorat("At least one selector required"); - valid = false; - } - if (valid) { - // set the format of the specified actions - specs.stream() - .forEach(c -> m.setActions(format, c.e1, c.e2)); - } - break; - } - case RESOLVE: { - List> specs = new ArrayList<>(); - String s; - while ((s = at.next()) != null) { - String[] d = s.split("-"); - specs.add(new Case<>( - parseFormatResolve(d, 0), - parseFormatWhen(d, 1) - )); - } - if (valid && specs.isEmpty()) { - errorat("At least one selector required"); - valid = false; - } - if (valid) { - // set the format of the specified resolves - specs.stream() - .forEach(c -> m.setResolves(format, c.e1, c.e2)); - } - break; - } - case WHEN: { - List> specs = new ArrayList<>(); - String s; - while ((s = at.next()) != null) { - String[] d = s.split("-"); - specs.add(new Case<>( - parseFormatWhen(d, 1), - null - )); - } - if (valid && specs.isEmpty()) { - errorat("At least one selector required"); - valid = false; - } - if (valid) { - // set the format of the specified whens - specs.stream() - .forEach(c -> m.setWhens(format, c.e1)); - } - break; - } - case NAME: { - m.setName(format); - break; - } - case TYPE: { - m.setType(format); - break; - } - case RESULT: { - m.setResult(format); - break; - } - case PRE: { - m.setPre(format); - break; - } - case POST: { - m.setPost(format); - break; - } - case ERRORPRE: { - m.setErrorPre(format); - break; - } - case ERRORPOST: { - m.setErrorPost(format); - break; - } + if (slList.isEmpty()) { + m.set(field, ALWAYS, format); + } else { + slList.stream() + .forEach(sl -> m.set(field, + sl.cases.getSet(), sl.actions.getSet(), sl.whens.getSet(), + sl.resolves.getSet(), sl.unresolvedCounts.getSet(), sl.errorCounts.getSet(), + format)); } - } - if (!valid) { - fluff("See '/help /set field' for help"); + } else { + fluff("See '/help /set format' for help"); } return valid; } @@ -843,12 +707,11 @@ if (matches.length == 0) { errorat("Does not match any current feedback mode: %s", umode); } else { - errorat("Matchs more then one current feedback mode: %s", umode); + errorat("Matches more then one current feedback mode: %s", umode); } fluff("The feedback mode should be one of the following:"); modeMap.keySet().stream() .forEach(mk -> fluff(" %s", mk)); - fluff("You may also use just enough letters to make it unique."); return null; } } @@ -869,181 +732,75 @@ return format; } - final Set parseFormatCase(String[] s, int i) { - return parseFormatSelectorStar(s, i, FormatCase.class, EnumSet.allOf(FormatCase.class), "case"); - } - - final Set parseFormatAction(String[] s, int i) { - return parseFormatSelectorStar(s, i, FormatAction.class, - EnumSet.of(FormatAction.ADDED, FormatAction.MODIFIED, FormatAction.REPLACED), "action"); - } + class SelectorList { - final Set parseFormatResolve(String[] s, int i) { - return parseFormatSelectorStar(s, i, FormatResolve.class, - EnumSet.of(FormatResolve.DEFINED, FormatResolve.NOTDEFINED), "resolve"); - } - - final Set parseFormatWhen(String[] s, int i) { - return parseFormatSelectorStar(s, i, FormatWhen.class, EnumSet.of(FormatWhen.PRIMARY), "when"); - } + SelectorCollector cases = new SelectorCollector<>(FormatCase.all); + SelectorCollector actions = new SelectorCollector<>(FormatAction.all); + SelectorCollector whens = new SelectorCollector<>(FormatWhen.all); + SelectorCollector resolves = new SelectorCollector<>(FormatResolve.all); + SelectorCollector unresolvedCounts = new SelectorCollector<>(FormatUnresolved.all); + SelectorCollector errorCounts = new SelectorCollector<>(FormatErrors.all); - /** - * In a selector x-y-z , parse x, y, or z -- whether they are missing, - * or a comma separated list of identifiers and stars. - * - * @param The enum this selector should belong to - * @param sa The array of selector strings - * @param i The index of which selector string to use - * @param klass The class of the enum that should be used - * @param defaults The set of enum values to use if the selector is - * missing - * @return The set of enum values specified by this selector - */ - final > Set parseFormatSelectorStar(String[] sa, int i, Class klass, EnumSet defaults, String label) { - String s = sa.length > i - ? sa[i] - : null; - if (s == null || s.isEmpty()) { - return defaults; - } - Set set = EnumSet.noneOf(klass); - EnumSet values = EnumSet.allOf(klass); - for (String as : s.split(",")) { - if (as.equals("*")) { - set.addAll(values); - } else if (!as.isEmpty()) { - set.add(parseFormatSelector(as, values, label)); + final void parseSelectorList(String sl) { + for (String s : sl.split("-")) { + SelectorCollector lastCollector = null; + for (String as : s.split(",")) { + if (!as.isEmpty()) { + Selector sel = selectorMap.get(as); + if (sel == null) { + errorat("Not a valid selector %s in %s", 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); + valid = false; + return; + } + } else if (collector != lastCollector) { + errorat("Different selector kinds in same sections of selector list %s in %s", as, s); + valid = false; + return; + } + collector.add(sel); + lastCollector = collector; + } + } } } - return set; - } - - /** - * In a x-y-a,b selector, parse an x, y, a, or b -- that is an - * identifier - * - * @param The enum this selector should belong to - * @param s The string to parse: x, y, or z - * @param values The allowed of this enum - * @return The enum value - */ - final > E parseFormatSelector(String s, EnumSet values, String label) { - if (s == null) { - valid = false; - return null; - } - String u = s.toUpperCase(Locale.US); - for (E c : values) { - if (c.name().startsWith(u)) { - return c; - } - } - - errorat("Not a valid %s: %s, must be one of: %s", label, s, - values.stream().map(v -> v.name().toLowerCase(Locale.US)).collect(Collectors.joining(" "))); - valid = false; - return values.iterator().next(); } final void printFormatHelp() { - hard("Set the format for reporting a snippet event."); - hard(""); - hard("/set format \"\" ..."); - hard(""); - hard("Where is the name of a previously defined feedback mode -- see '/help /set newmode'."); - hard("Where is a quoted string which will have these field substitutions:"); - hard(" {action} == The action, e.g.: Added, Modified, Assigned, ..."); - hard(" {name} == The name, e.g.: the variable name, ..."); - hard(" {type} == The type name"); - hard(" {resolve} == Unresolved info, e.g.: ', however, it cannot be invoked until'"); - hard(" {result} == The result value"); - hard(" {when} == The entered snippet or a resultant update"); - hard(" {pre} == The feedback prefix"); - hard(" {post} == The feedback postfix"); - hard(" {errorpre} == The error prefix"); - hard(" {errorpost} == The error postfix"); - hard("Use '/set field' to set the format of these substitutions."); - hard("Where is the context in which the format is applied."); - hard("The structure of selector is: [-[-]]"); - hard("Where each field component may be missing (indicating defaults),"); - hard("star (indicating all), or a comma separated list of field values."); - hard("For case, the field values are:"); + hardrb("help.set.format"); + hardrb("help.set.format.case"); hardEnums(EnumSet.allOf(FormatCase.class), ev -> ev.doc); - hard("For action, the field values are:"); + hardrb("help.set.format.action"); hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); - hard("For when, the field values are:"); + hardrb("help.set.format.when"); hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); - hard(""); - hard("Example:"); - hard(" /set format example '{pre}{action} variable {name}, reset to null{post}' varreset-*-update"); - } - - final void printFieldHelp() { - hard("Set the format of a field substitution as used in '/set format'."); - hard(""); - hard("/set field \"\" ..."); - hard(""); - hard("Where is the name of a previously defined feedback mode -- see '/set newmode'."); - hard("Where is context-specific format to set, each with its own selector structure:"); - hard(" action == The action. The selector: -."); - hard(" name == The name. '%%s' is the name. No selectors."); - hard(" type == The type name. '%%s' is the type. No selectors."); - hard(" resolve == Unresolved info. '%%s' is the unresolved list. The selector: -."); - hard(" result == The result value. '%%s' is the result value. No selectors."); - hard(" when == The entered snippet or a resultant update. The selector: "); - hard(" pre == The feedback prefix. No selectors."); - hard(" post == The feedback postfix. No selectors."); - hard(" errorpre == The error prefix. No selectors."); - hard(" errorpost == The error postfix. No selectors."); - hard("Where is a quoted string -- see the description specific to the field (above)."); - hard("Where is the context in which the format is applied (see above)."); - hard("For action, the field values are:"); - hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); - hard("For when, the field values are:"); - hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); - hard("For resolve, the field values are:"); + hardrb("help.set.format.resolve"); hardEnums(EnumSet.allOf(FormatResolve.class), ev -> ev.doc); - hard(""); - hard("Example:"); - hard(" /set field example resolve ' which cannot be invoked until%%s is declared' defined-update"); + 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() { - hard("Set the feedback mode describing displayed feedback for entered snippets and commands."); - hard(""); - hard("/set feedback "); - hard(""); - hard("Where is the name of a previously defined feedback mode."); - hard("Currently defined feedback modes:"); + hardrb("help.set.feedback"); modeMap.keySet().stream() .forEach(m -> hard(" %s", m)); - hard("User-defined modes can be added, see '/help /set newmode'"); } final void printNewModeHelp() { - hard("Create a user-defined feedback mode, optionally copying from an existing mode."); - hard(""); - hard("/set newmode [command|quiet []]"); - hard(""); - hard("Where is the name of a mode you wish to create."); - hard("Where is the name of a previously defined feedback mode."); - hard("If is present, its settings are copied to the new mode."); - hard("'command' vs 'quiet' determines if informative/verifying command feedback is displayed."); - hard(""); - hard("Once the new mode is created, use '/set format', '/set field', and '/set prompt' to configure it."); - hard("Use '/set feedback' to use the new mode."); + hardrb("help.set.newmode"); } final void printPromptHelp() { - hard("Set the prompts. Both the normal prompt and the continuation-prompt must be set."); - hard(""); - hard("/set prompt \"\" \"\""); - hard(""); - hard("Where is the name of a previously defined feedback mode."); - hard("Where and are quoted strings printed as input promptds;"); - hard("Both may optionally contain '%%s' which will be substituted with the next snippet id --"); - hard("note that what is entered may not be assigned that id, for example it may be an error or command."); - hard("The continuation-prompt is used on the second and subsequent lines of a multi-line snippet."); + hardrb("help.set.prompt"); } } } diff -r 66bc9949f8b3 -r bf40906bf49d langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Wed Mar 23 21:44:24 2016 -0700 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Fri Mar 25 18:36:19 2016 -0700 @@ -75,7 +75,6 @@ import jdk.jshell.PersistentSnippet; import jdk.jshell.Snippet; import jdk.jshell.Snippet.Status; -import jdk.jshell.Snippet.SubKind; import jdk.jshell.SnippetEvent; import jdk.jshell.SourceCodeAnalysis; import jdk.jshell.SourceCodeAnalysis.CompletionInfo; @@ -95,10 +94,11 @@ import java.util.function.Supplier; import jdk.internal.jshell.tool.Feedback.FormatAction; import jdk.internal.jshell.tool.Feedback.FormatCase; +import jdk.internal.jshell.tool.Feedback.FormatErrors; import jdk.internal.jshell.tool.Feedback.FormatResolve; +import jdk.internal.jshell.tool.Feedback.FormatUnresolved; import jdk.internal.jshell.tool.Feedback.FormatWhen; import static java.util.stream.Collectors.toList; -import static jdk.jshell.Snippet.Kind.METHOD; import static java.util.stream.Collectors.toMap; import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; @@ -113,6 +113,12 @@ private static final Pattern HISTORY_ALL_START_FILENAME = Pattern.compile( "((?(all|history|start))(\\z|\\p{javaWhitespace}+))?(?.*)"); private 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"; + private static final String L10N_RB_NAME = RB_NAME_PREFIX + ".l10n"; + private static ResourceBundle versionRB = null; + private static ResourceBundle outputRB = null; + final InputStream cmdin; final PrintStream cmdout; @@ -148,82 +154,18 @@ this.userout = userout; this.usererr = usererr; this.prefs = prefs; - initializeFeedbackModes(); - } - - /** - * Create the default set of feedback modes - */ - final void initializeFeedbackModes() { - // Initialize normal feedback mode - cmdSet("newmode normal command"); - cmdSet("prompt normal '\n-> ' '>> '"); - cmdSet("field normal pre '| '"); - cmdSet("field normal post '%n'"); - cmdSet("field normal errorpre '| '"); - cmdSet("field normal errorpost '%n'"); - cmdSet("field normal action 'Added' added-primary"); - cmdSet("field normal action 'Modified' modified-primary"); - cmdSet("field normal action 'Replaced' replaced-primary"); - cmdSet("field normal action 'Overwrote' overwrote-primary"); - cmdSet("field normal action 'Dropped' dropped-primary"); - cmdSet("field normal action 'Rejected' rejected-primary"); - cmdSet("field normal action ' Update added' added-update"); - cmdSet("field normal action ' Update modified' modified-update"); - cmdSet("field normal action ' Update replaced' replaced-update"); - cmdSet("field normal action ' Update overwrote' overwrote-update"); - cmdSet("field normal action ' Update dropped' dropped-update"); - cmdSet("field normal action ' Update rejected' rejected-update"); - cmdSet("field normal resolve '' ok-*"); - cmdSet("field normal resolve ', however, it cannot be invoked until%s is declared' defined-primary"); - cmdSet("field normal resolve ', however, it cannot be referenced until%s is declared' notdefined-primary"); - cmdSet("field normal resolve ' which cannot be invoked until%s is declared' defined-update"); - cmdSet("field normal resolve ' which cannot be referenced until%s is declared' notdefined-update"); - cmdSet("field normal name '%s'"); - cmdSet("field normal type '%s'"); - cmdSet("field normal result '%s'"); - - cmdSet("format normal '' *-*-*"); - - cmdSet("format normal '{pre}{action} class {name}{resolve}{post}' class"); - cmdSet("format normal '{pre}{action} interface {name}{resolve}{post}' interface"); - cmdSet("format normal '{pre}{action} enum {name}{resolve}{post}' enum"); - cmdSet("format normal '{pre}{action} annotation interface {name}{resolve}{post}' annotation"); - - cmdSet("format normal '{pre}{action} method {name}({type}){resolve}{post}' method"); - - cmdSet("format normal '{pre}{action} variable {name} of type {type}{resolve}{post}' vardecl"); - cmdSet("format normal '{pre}{action} variable {name} of type {type} with initial value {result}{resolve}{post}' varinit"); - cmdSet("format normal '{pre}{action} variable {name}{resolve}{post}' vardeclrecoverable"); - cmdSet("format normal '{pre}{action} variable {name}, reset to null{post}' varreset-*-update"); - - cmdSet("format normal '{pre}Expression value is: {result}{post}" + - "{pre} assigned to temporary variable {name} of type {type}{post}' expression"); - cmdSet("format normal '{pre}Variable {name} of type {type} has value {result}{post}' varvalue"); - cmdSet("format normal '{pre}Variable {name} has been assigned the value {result}{post}' assignment"); - - cmdSet("feedback normal"); - - // Initialize off feedback mode - cmdSet("newmode off quiet"); - cmdSet("prompt off '-> ' '>> '"); - cmdSet("field off pre '| '"); - cmdSet("field off post '%n'"); - cmdSet("field off errorpre '| '"); - cmdSet("field off errorpost '%n'"); - cmdSet("format off '' *-*-*"); } private IOContext input = null; private boolean regenerateOnDeath = true; private boolean live = false; + private boolean feedbackInitialized = false; SourceCodeAnalysis analysis; JShell state = null; Subscription shutdownSubscription = null; private boolean debug = false; - private boolean displayPrompt = true; public boolean testPrompt = false; private String cmdlineClasspath = null; private String cmdlineStartup = null; @@ -326,6 +268,43 @@ } } + /** + * Print using resource bundle look-up and adding prefix and postfix + * + * @param key the resource key + */ + String getResourceString(String key) { + if (outputRB == null) { + try { + outputRB = ResourceBundle.getBundle(L10N_RB_NAME); + } catch (MissingResourceException mre) { + error("Cannot find ResourceBundle: %s", L10N_RB_NAME); + return ""; + } + } + String s; + try { + s = outputRB.getString(key); + } catch (MissingResourceException mre) { + error("Missing resource: %s in %s", key, L10N_RB_NAME); + return ""; + } + return s; + } + + /** + * 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); + } + void hardPairs(Stream stream, Function a, Function b) { Map a2b = stream.collect(toMap(a, b, (m1, m2) -> m1, @@ -343,26 +322,6 @@ } /** - * User custom feedback mode only - * - * @param fcase Event to report - * @param update Is this an update (rather than primary) - * @param fa Action - * @param fr Resolution status - * @param name Name string - * @param type Type string or null - * @param result Result value or null - * @param unresolved The unresolved symbols - */ - void custom(FormatCase fcase, boolean update, FormatAction fa, FormatResolve fr, - String name, String type, String unresolved, String result) { - String format = feedback.getFormat(fcase, - (update ? FormatWhen.UPDATE : FormatWhen.PRIMARY), fa, fr, - name != null, type != null, result != null); - fluffRaw(format, unresolved, name, type, result); - } - - /** * Trim whitespace off end of string * * @param s @@ -544,7 +503,6 @@ ? currentNameSpace.tid(sn) : errorNamespace.tid(sn)) .build(); - analysis = state.sourceCodeAnalysis(); shutdownSubscription = state.onShutdown((JShell deadState) -> { if (deadState == state) { hard("State engine terminated."); @@ -552,7 +510,12 @@ live = false; } }); + analysis = state.sourceCodeAnalysis(); live = true; + if (!feedbackInitialized) { + startUpRun(getResourceString("startup.feedback")); + feedbackInitialized = true; + } if (cmdlineClasspath != null) { state.addToClasspath(cmdlineClasspath); @@ -568,12 +531,16 @@ } else { start = cmdlineStartup; } + startUpRun(start); + currentNameSpace = mainNamespace; + } + //where + private void startUpRun(String start) { try (IOContext suin = new FileScannerIOContext(new StringReader(start))) { run(suin); } catch (Exception ex) { hard("Unexpected exception reading start-up: %s\n", ex); } - currentNameSpace = mainNamespace; } private void closeState() { @@ -596,7 +563,7 @@ String incomplete = ""; while (live) { String prompt; - if (displayPrompt) { + if (currentNameSpace == mainNamespace) { prompt = testPrompt ? incomplete.isEmpty() ? "\u0005" //ENQ @@ -679,21 +646,22 @@ cmd = cmd.substring(0, idx); } Command[] candidates = findCommand(cmd, c -> c.kind.isRealCommand); - if (candidates.length == 0) { - if (!rerunHistoryEntryById(cmd.substring(1))) { - error("No such command or snippet id: %s", cmd); + switch (candidates.length) { + case 0: + if (!rerunHistoryEntryById(cmd.substring(1))) { + error("No such command or snippet id: %s", cmd); + fluff("Type /help for help."); + } 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; + default: + error("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); fluff("Type /help for help."); - } - } else if (candidates.length == 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()); - } - } else { - error("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); - fluff("Type /help for help."); + break; } } @@ -1022,7 +990,7 @@ " -- Display information about the specified help subject. Example: /help intro\n", arg -> cmdHelp(arg), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/set", "editor|start|feedback|newmode|prompt|format|field ...", "set jshell configuration information", + 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" + @@ -1043,16 +1011,13 @@ "/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 to use in a specified set of cases.\n" + - "\n" + - "/set field name|type|result|when|action|resolve|pre|post|errorpre|errorpost \"\" ...\n" + - " -- Set the format of a field within the of a \"/set format\" command\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", arg -> cmdSet(arg), - new FixedCompletionProvider("format", "field", "feedback", "prompt", "newmode", "start", "editor"))); + new FixedCompletionProvider("format", "feedback", "prompt", "newmode", "start", "editor"))); registerCommand(new Command("/?", "", "get information about jshell", "Display information about jshell (abbreviation for /help).\n" + "/?\n" + @@ -1153,11 +1118,9 @@ // --- Command implementations --- - private static final String[] setSub = new String[]{ - "format", "field", "feedback", "newmode", "prompt", "editor", "start"}; + private static final String[] SET_SUBCOMMANDS = new String[]{ + "format", "feedback", "newmode", "prompt", "editor", "start"}; - // The /set command. Currently /set format, /set field and /set feedback. - // Other commands will fold here, see: 8148317 final boolean cmdSet(String arg) { ArgTokenizer at = new ArgTokenizer(arg.trim()); String which = setSubCommand(at); @@ -1167,8 +1130,6 @@ switch (which) { case "format": return feedback.setFormat(this, at); - case "field": - return feedback.setField(this, at); case "feedback": return feedback.setFeedback(this, at); case "newmode": @@ -1229,9 +1190,6 @@ case "format": feedback.printFormatHelp(this); return true; - case "field": - feedback.printFieldHelp(this); - return true; case "feedback": feedback.printFeedbackHelp(this); return true; @@ -1265,13 +1223,13 @@ } String setSubCommand(ArgTokenizer at) { - String[] matches = at.next(setSub); + String[] matches = at.next(SET_SUBCOMMANDS); if (matches == null) { error("The /set command requires arguments. See: /help /set"); 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(setSub) + fluff("/set is followed by one of: %s", Arrays.stream(SET_SUBCOMMANDS) .collect(Collectors.joining(", ")) ); return null; @@ -1349,8 +1307,20 @@ regenerateOnDeath = false; live = false; if (!replayableHistory.isEmpty()) { - prefs.put(REPLAY_RESTORE_KEY, replayableHistory.stream().reduce( - (a, b) -> a + RECORD_SEPARATOR + b).get()); + // Prevent history overflow by calculating what will fit, starting + // with must recent + int sepLen = RECORD_SEPARATOR.length(); + int length = 0; + int first = replayableHistory.size(); + while(length < Preferences.MAX_VALUE_LENGTH && --first >= 0) { + length += replayableHistory.get(first).length() + sepLen; + } + String hist = replayableHistory + .subList(first + 1, replayableHistory.size()) + .stream() + .reduce( (a, b) -> a + RECORD_SEPARATOR + b) + .get(); + prefs.put(REPLAY_RESTORE_KEY, hist); } fluff("Goodbye\n"); return true; @@ -1841,68 +1811,55 @@ .collect(toList()); } - void printDiagnostics(String source, List diagnostics, boolean embed) { - String padding = embed? " " : ""; - for (Diag diag : diagnostics) { - //assert diag.getSource().equals(source); + void displayDiagnostics(String source, Diag diag, List toDisplay) { + for (String line : diag.getMessage(null).split("\\r?\\n")) { // TODO: Internationalize + if (!line.trim().startsWith("location:")) { + toDisplay.add(line); + } + } - if (!embed) { - if (diag.isError()) { - hard("Error:"); - } else { - hard("Warning:"); - } + int pstart = (int) diag.getStartPosition(); + int pend = (int) diag.getEndPosition(); + Matcher m = LINEBREAK.matcher(source); + int pstartl = 0; + int pendl = -2; + while (m.find(pstartl)) { + pendl = m.start(); + if (pendl >= pstart) { + break; + } else { + pstartl = m.end(); } - - for (String line : diag.getMessage(null).split("\\r?\\n")) { // TODO: Internationalize - if (!line.trim().startsWith("location:")) { - hard("%s%s", padding, line); - } - } + } + if (pendl < pstart) { + pendl = source.length(); + } + toDisplay.add(source.substring(pstartl, pendl)); - int pstart = (int) diag.getStartPosition(); - int pend = (int) diag.getEndPosition(); - Matcher m = LINEBREAK.matcher(source); - int pstartl = 0; - int pendl = -2; - while (m.find(pstartl)) { - pendl = m.start(); - if (pendl >= pstart) { - break; - } else { - pstartl = m.end(); - } + StringBuilder sb = new StringBuilder(); + int start = pstart - pstartl; + for (int i = 0; i < start; ++i) { + sb.append(' '); + } + sb.append('^'); + boolean multiline = pend > pendl; + int end = (multiline ? pendl : pend) - pstartl - 1; + if (end > start) { + for (int i = start + 1; i < end; ++i) { + sb.append('-'); } - if (pendl < pstart) { - pendl = source.length(); + if (multiline) { + sb.append("-..."); + } else { + sb.append('^'); } - fluff("%s%s", padding, source.substring(pstartl, pendl)); + } + toDisplay.add(sb.toString()); - StringBuilder sb = new StringBuilder(); - int start = pstart - pstartl; - for (int i = 0; i < start; ++i) { - sb.append(' '); - } - sb.append('^'); - boolean multiline = pend > pendl; - int end = (multiline ? pendl : pend) - pstartl - 1; - if (end > start) { - for (int i = start + 1; i < end; ++i) { - sb.append('-'); - } - if (multiline) { - sb.append("-..."); - } else { - sb.append('^'); - } - } - fluff("%s%s", padding, sb.toString()); - - debug("printDiagnostics start-pos = %d ==> %d -- wrap = %s", diag.getStartPosition(), start, this); - debug("Code: %s", diag.getCode()); - debug("Pos: %d (%d - %d)", diag.getPosition(), - diag.getStartPosition(), diag.getEndPosition()); - } + debug("printDiagnostics start-pos = %d ==> %d -- wrap = %s", diag.getStartPosition(), start, this); + debug("Code: %s", diag.getCode()); + debug("Pos: %d (%d - %d)", diag.getPosition(), + diag.getStartPosition(), diag.getEndPosition()); } private String processSource(String srcInput) throws IllegalStateException { @@ -1943,6 +1900,7 @@ return failed; } + // Handle incoming snippet events -- return true on failure private boolean handleEvent(SnippetEvent ste) { Snippet sn = ste.snippet(); if (sn == null) { @@ -1953,162 +1911,49 @@ String source = sn.source(); if (ste.causeSnippet() == null) { // main event - printDiagnostics(source, diagnostics, false); - if (ste.status().isActive) { + for (Diag d : diagnostics) { + if (d.isError()) { + hard("Error:"); + } else { + hard("Warning:"); + } + List disp = new ArrayList<>(); + displayDiagnostics(source, d, disp); + disp.stream() + .forEach(l -> hard(l)); + } + + if (ste.status() != Status.REJECTED) { if (ste.exception() != null) { if (ste.exception() instanceof EvalException) { printEvalException((EvalException) ste.exception()); return true; } else if (ste.exception() instanceof UnresolvedReferenceException) { - printUnresolved((UnresolvedReferenceException) ste.exception()); + printUnresolvedException((UnresolvedReferenceException) ste.exception()); } else { hard("Unexpected execution exception: %s", ste.exception()); return true; } } else { - displayDeclarationAndValue(ste, false, ste.value()); + new DisplayEvent(ste, false, ste.value(), diagnostics).displayDeclarationAndValue(); } - } else if (ste.status() == Status.REJECTED) { + } else { if (diagnostics.isEmpty()) { hard("Failed."); } return true; } - } else if (ste.status() == Status.REJECTED) { - //TODO -- I don't believe updates can cause failures any more - hard("Caused failure of dependent %s --", ((DeclarationSnippet) sn).name()); - printDiagnostics(source, diagnostics, true); } else { // Update if (sn instanceof DeclarationSnippet) { - // display update information - displayDeclarationAndValue(ste, true, ste.value()); + List other = errorsOnly(diagnostics); - List other = errorsOnly(diagnostics); - if (other.size() > 0) { - printDiagnostics(source, other, true); - } + // display update information + new DisplayEvent(ste, true, ste.value(), other).displayDeclarationAndValue(); } } return false; } - - @SuppressWarnings("fallthrough") - private void displayDeclarationAndValue(SnippetEvent ste, boolean update, String value) { - Snippet key = ste.snippet(); - FormatAction action; - Status status = ste.status(); - switch (status) { - case VALID: - case RECOVERABLE_DEFINED: - case RECOVERABLE_NOT_DEFINED: - if (ste.previousStatus().isActive) { - action = ste.isSignatureChange() - ? FormatAction.REPLACED - : FormatAction.MODIFIED; - } else { - action = FormatAction.ADDED; - } - break; - case OVERWRITTEN: - action = FormatAction.OVERWROTE; - break; - case DROPPED: - action = FormatAction.DROPPED; - break; - case REJECTED: - action = FormatAction.REJECTED; - break; - case NONEXISTENT: - default: - // Should not occur - error("Unexpected status: " + ste.previousStatus().toString() + "=>" + status.toString()); - return; - } - FormatResolve resolution; - String unresolved; - if (key instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) { - resolution = (status == Status.RECOVERABLE_NOT_DEFINED) - ? FormatResolve.NOTDEFINED - : FormatResolve.DEFINED; - unresolved = unresolved((DeclarationSnippet) key); - } else { - resolution = FormatResolve.OK; - unresolved = ""; - } - switch (key.subKind()) { - case CLASS_SUBKIND: - custom(FormatCase.CLASS, update, action, resolution, - ((TypeDeclSnippet) key).name(), null, unresolved, null); - break; - case INTERFACE_SUBKIND: - custom(FormatCase.INTERFACE, update, action, resolution, - ((TypeDeclSnippet) key).name(), null, unresolved, null); - break; - case ENUM_SUBKIND: - custom(FormatCase.ENUM, update, action, resolution, - ((TypeDeclSnippet) key).name(), null, unresolved, null); - break; - case ANNOTATION_TYPE_SUBKIND: - custom(FormatCase.ANNOTATION, update, action, resolution, - ((TypeDeclSnippet) key).name(), null, unresolved, null); - break; - case METHOD_SUBKIND: - custom(FormatCase.METHOD, update, action, resolution, - ((MethodSnippet) key).name(), ((MethodSnippet) key).parameterTypes(), unresolved, null); - break; - case VAR_DECLARATION_SUBKIND: - case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: { - VarSnippet vk = (VarSnippet) key; - if (status == Status.RECOVERABLE_NOT_DEFINED) { - custom(FormatCase.VARDECLRECOVERABLE, update, action, resolution, - vk.name(), null, unresolved, null); - } else if (update && ste.isSignatureChange()) { - custom(FormatCase.VARRESET, update, action, resolution, - vk.name(), null, unresolved, value); - } else if (key.subKind() == SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND) { - custom(FormatCase.VARINIT, update, action, resolution, - vk.name(), vk.typeName(), unresolved, value); - } else { - custom(FormatCase.VARDECL, update, action, resolution, - vk.name(), vk.typeName(), unresolved, value); - } - break; - } - case TEMP_VAR_EXPRESSION_SUBKIND: { - VarSnippet vk = (VarSnippet) key; - custom(FormatCase.EXPRESSION, update, action, resolution, - vk.name(), vk.typeName(), null, value); - break; - } - case OTHER_EXPRESSION_SUBKIND: - error("Unexpected expression form -- value is: %s", (value)); - break; - case VAR_VALUE_SUBKIND: { - ExpressionSnippet ek = (ExpressionSnippet) key; - custom(FormatCase.VARVALUE, update, action, resolution, - ek.name(), ek.typeName(), null, value); - break; - } - case ASSIGNMENT_SUBKIND: { - ExpressionSnippet ek = (ExpressionSnippet) key; - custom(FormatCase.ASSIGNMENT, update, action, resolution, - ek.name(), ek.typeName(), null, value); - break; - } - case SINGLE_TYPE_IMPORT_SUBKIND: - case TYPE_IMPORT_ON_DEMAND_SUBKIND: - case SINGLE_STATIC_IMPORT_SUBKIND: - case STATIC_IMPORT_ON_DEMAND_SUBKIND: - custom(FormatCase.IMPORT, update, action, resolution, - ((ImportSnippet) key).name(), null, null, null); - break; - case STATEMENT_SUBKIND: - custom(FormatCase.STATEMENT, update, action, resolution, - null, null, null, null); - break; - } - } //where void printStackTrace(StackTraceElement[] stes) { for (StackTraceElement ste : stes) { @@ -2141,31 +1986,11 @@ } } //where - void printUnresolved(UnresolvedReferenceException ex) { + void printUnresolvedException(UnresolvedReferenceException ex) { DeclarationSnippet corralled = ex.getSnippet(); List otherErrors = errorsOnly(state.diagnostics(corralled)); - StringBuilder sb = new StringBuilder(); - if (otherErrors.size() > 0) { - if (state.unresolvedDependencies(corralled).size() > 0) { - sb.append(" and"); - } - if (otherErrors.size() == 1) { - sb.append(" this error is addressed --"); - } else { - sb.append(" these errors are addressed --"); - } - } else { - sb.append("."); - } - - String format = corralled.kind() == METHOD - ? "Attempted to call %s which cannot be invoked until%s" - : "Attempted to use %s which cannot be accessed until%s"; - hard(format, corralled.name(), - unresolved(corralled), sb.toString()); - if (otherErrors.size() > 0) { - printDiagnostics(corralled.source(), otherErrors, true); - } + new DisplayEvent(corralled, state.status(corralled), FormatAction.USED, true, null, otherErrors) + .displayDeclarationAndValue(); } //where void printEvalException(EvalException ex) { @@ -2176,26 +2001,180 @@ } printStackTrace(ex.getStackTrace()); } - //where - String unresolved(DeclarationSnippet key) { - List unr = state.unresolvedDependencies(key); - StringBuilder sb = new StringBuilder(); - int fromLast = unr.size(); - if (fromLast > 0) { - sb.append(" "); + + private FormatAction toAction(Status status, Status previousStatus, boolean isSignatureChange) { + FormatAction act; + switch (status) { + case VALID: + case RECOVERABLE_DEFINED: + case RECOVERABLE_NOT_DEFINED: + if (previousStatus.isActive) { + act = isSignatureChange + ? FormatAction.REPLACED + : FormatAction.MODIFIED; + } else { + act = FormatAction.ADDED; + } + break; + case OVERWRITTEN: + act = FormatAction.OVERWROTE; + break; + case DROPPED: + act = FormatAction.DROPPED; + break; + case REJECTED: + case NONEXISTENT: + default: + // Should not occur + error("Unexpected status: " + previousStatus.toString() + "=>" + status.toString()); + act = FormatAction.DROPPED; + } + return act; + } + + class DisplayEvent { + private final Snippet sn; + private final FormatAction action; + private final boolean update; + private final String value; + private final List errorLines; + private final FormatResolve resolution; + private final String unresolved; + private final FormatUnresolved unrcnt; + private final FormatErrors errcnt; + + DisplayEvent(SnippetEvent ste, boolean update, String value, List errors) { + this(ste.snippet(), ste.status(), toAction(ste.status(), ste.previousStatus(), ste.isSignatureChange()), update, value, errors); } - for (String u : unr) { - --fromLast; - sb.append(u); - if (fromLast == 0) { - // No suffix - } else if (fromLast == 1) { - sb.append(", and "); + + DisplayEvent(Snippet sn, Status status, FormatAction action, boolean update, String value, List errors) { + this.sn = sn; + this.action = action; + this.update = update; + this.value = value; + this.errorLines = new ArrayList<>(); + for (Diag d : errors) { + displayDiagnostics(sn.source(), d, errorLines); + } + int unresolvedCount; + if (sn instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) { + resolution = (status == Status.RECOVERABLE_NOT_DEFINED) + ? FormatResolve.NOTDEFINED + : FormatResolve.DEFINED; + unresolved = unresolved((DeclarationSnippet) sn); + unresolvedCount = state.unresolvedDependencies((DeclarationSnippet) sn).size(); } else { - sb.append(", "); + resolution = FormatResolve.OK; + unresolved = ""; + unresolvedCount = 0; + } + unrcnt = unresolvedCount == 0 + ? FormatUnresolved.UNRESOLVED0 + : unresolvedCount == 1 + ? FormatUnresolved.UNRESOLVED1 + : FormatUnresolved.UNRESOLVED2; + errcnt = errors.isEmpty() + ? FormatErrors.ERROR0 + : errors.size() == 1 + ? FormatErrors.ERROR1 + : FormatErrors.ERROR2; + } + + private String unresolved(DeclarationSnippet key) { + List unr = state.unresolvedDependencies(key); + StringBuilder sb = new StringBuilder(); + int fromLast = unr.size(); + if (fromLast > 0) { + sb.append(" "); + } + for (String u : unr) { + --fromLast; + sb.append(u); + switch (fromLast) { + // No suffix + case 0: + break; + case 1: + sb.append(", and "); + break; + default: + sb.append(", "); + break; + } + } + return sb.toString(); + } + + private void custom(FormatCase fcase, String name) { + custom(fcase, name, null); + } + + private void custom(FormatCase fcase, String name, String type) { + String display = feedback.format(fcase, action, (update ? FormatWhen.UPDATE : FormatWhen.PRIMARY), + resolution, unrcnt, errcnt, + name, type, value, unresolved, errorLines); + if (interactive()) { + cmdout.print(display); } } - return sb.toString(); + + @SuppressWarnings("fallthrough") + private void displayDeclarationAndValue() { + switch (sn.subKind()) { + case CLASS_SUBKIND: + custom(FormatCase.CLASS, ((TypeDeclSnippet) sn).name()); + break; + case INTERFACE_SUBKIND: + custom(FormatCase.INTERFACE, ((TypeDeclSnippet) sn).name()); + break; + case ENUM_SUBKIND: + custom(FormatCase.ENUM, ((TypeDeclSnippet) sn).name()); + break; + case ANNOTATION_TYPE_SUBKIND: + custom(FormatCase.ANNOTATION, ((TypeDeclSnippet) sn).name()); + break; + case METHOD_SUBKIND: + custom(FormatCase.METHOD, ((MethodSnippet) sn).name(), ((MethodSnippet) sn).parameterTypes()); + break; + case VAR_DECLARATION_SUBKIND: { + VarSnippet vk = (VarSnippet) sn; + custom(FormatCase.VARDECL, vk.name(), vk.typeName()); + break; + } + case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: { + VarSnippet vk = (VarSnippet) sn; + custom(FormatCase.VARINIT, vk.name(), vk.typeName()); + break; + } + case TEMP_VAR_EXPRESSION_SUBKIND: { + VarSnippet vk = (VarSnippet) sn; + custom(FormatCase.EXPRESSION, vk.name(), vk.typeName()); + break; + } + case OTHER_EXPRESSION_SUBKIND: + error("Unexpected expression form -- value is: %s", (value)); + break; + case VAR_VALUE_SUBKIND: { + ExpressionSnippet ek = (ExpressionSnippet) sn; + custom(FormatCase.VARVALUE, ek.name(), ek.typeName()); + break; + } + case ASSIGNMENT_SUBKIND: { + ExpressionSnippet ek = (ExpressionSnippet) sn; + custom(FormatCase.ASSIGNMENT, ek.name(), ek.typeName()); + break; + } + case SINGLE_TYPE_IMPORT_SUBKIND: + case TYPE_IMPORT_ON_DEMAND_SUBKIND: + case SINGLE_STATIC_IMPORT_SUBKIND: + case STATIC_IMPORT_ON_DEMAND_SUBKIND: + custom(FormatCase.IMPORT, ((ImportSnippet) sn).name()); + break; + case STATEMENT_SUBKIND: + custom(FormatCase.STATEMENT, null); + break; + } + } } /** The current version number as a string. @@ -2210,13 +2189,10 @@ return version("full"); // mm.mm.oo[-milestone]-build } - private static final String versionRBName = "jdk.internal.jshell.tool.resources.version"; - private static ResourceBundle versionRB; - private static String version(String key) { if (versionRB == null) { try { - versionRB = ResourceBundle.getBundle(versionRBName); + versionRB = ResourceBundle.getBundle(VERSION_RB_NAME); } catch (MissingResourceException e) { return "(version info not available)"; } diff -r 66bc9949f8b3 -r bf40906bf49d langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties Fri Mar 25 18:36:19 2016 -0700 @@ -0,0 +1,179 @@ +# +# 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. +# + +help.set.format = \ +Set the format for reporting a snippet event.\n\ +\n\ +/set format "" ...\n\ +\n\ +Where is the name of a previously defined feedback mode -- see '/help /set newmode'.\n\ +Where is the name of context-specific format to define.\n\ +Where is a quoted string which will be the value of the field if one of\n\ +the selectors matches (or there are no selectors). When the format is used,\n\ +field names enclosed in braces are replaced with the value of the field at that\n\ +time. These fields may have been previously defined with this command or may be\n\ +one of these predefined fields specific to the context:\n\t\ +{name} == The name, e.g.: the variable name, ...\n\t\ +{type} == The type name. The type of a variable or expression, the\n\t\t\t\ + parameter types of a method\n\t\ +{value} == The result value of an expression or variable initialization\n\t\ +{unresolved} == The list of unresolved references\n\t\ +{errors} == The list of recoverable errors (during the processing of the\n\t\t\t\ + "display" field only)\n\t\ +{err} == An unformatted error line (during the processing of the\n\t\t\t\ + "errorline" field only)\n\ +The following fields are accessed by the tool to determine the displayed feedback:\n\t\ +{display} == The displayed message for a snippet event\n\t\ +{errorline} == The format of one error line within the "errors" field\n\t\ +{pre} == The feedback prefix (begins command feedback)\n\t\ +{post} == The feedback postfix (ends command feedback)\n\t\ +{errorpre} == The error prefix (begins error feedback)\n\t\ +{errorpost} == The error postfix (ends error feedback)\n\ +These fields have default settings (which may be overwritten).\n\ +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\ +Examples:\n\t\ +/set format myformat action 'Created' added-primary\n\t\ +/set format myformat action 'Update replaced' replaced-update\n\t\ +/set format myformat display '{pre}{action} class {name}{post}' class-ok\n\t\ +/set format myformat display '{pre}{action} variable {name}, reset to null{post}' replaced-vardecl,varinit-ok-update\n\n\ +Note that subsequent selectors for a field may overwrite some or all of previous used selectors -- last one wins\n + +help.set.feedback = \ +Set the feedback mode describing displayed feedback for entered snippets and commands.\n\ +\n\ +/set feedback \n\ +\n\ +Where is the name of a previously defined feedback mode.\n\ +You may use just enough letters to make it unique.\n\ +User-defined modes can be added, see '/help /set newmode'\n\ +Currently defined feedback modes:\n + +help.set.newmode = \ +Create a user-defined feedback mode, optionally copying from an existing mode.\n\ +\n\ +/set newmode [command|quiet []]\n\ +\n\ +Where is the name of a mode you wish to create.\n\ +Where is the name of a previously defined feedback mode.\n\ +If is present, its settings are copied to the new mode.\n\ +'command' vs 'quiet' determines if informative/verifying command feedback is displayed.\n\ +\n\ +Once the new mode is created, use '/set format' and '/set prompt' to configure it.\n\ +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\ +Where is the name of a previously defined feedback mode.\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 + +startup.feedback = \ +/set newmode normal command \n\ +/set prompt normal '\\n-> ' '>> ' \n\ +/set format normal pre '| ' \n\ +/set format normal post '%n' \n\ +/set format normal errorpre '| ' \n\ +/set format normal errorpost '%n' \n\ + \n\ +/set format normal errorline '{post}{pre} {err}' \n\ + \n\ +/set format normal action 'Added' added-primary \n\ +/set format normal action 'Modified' modified-primary \n\ +/set format normal action 'Replaced' replaced-primary \n\ +/set format normal action 'Overwrote' overwrote-primary \n\ +/set format normal action 'Dropped' dropped-primary \n\ +/set format normal action ' Update added' added-update \n\ +/set format normal action ' Update modified' modified-update \n\ +/set format normal action ' Update replaced' replaced-update \n\ +/set format normal action ' Update overwrote' overwrote-update \n\ +/set format normal action ' Update dropped' dropped-update \n\ + \n\ +/set format normal until ', however, it cannot be instanciated or its methods invoked until' defined-class-primary \n\ +/set format normal until ', however, its methods cannot be invoked until' defined-interface-primary \n\ +/set format normal until ', however, it cannot be used until' defined-enum,annotation-primary \n\ +/set format normal until ', however, it cannot be invoked until' defined-method-primary \n\ +/set format normal until ', however, it cannot be referenced until' notdefined-primary \n\ +/set format normal until ' which cannot be instanciated or its methods invoked until' defined-class-update \n\ +/set format normal until ' whose methods cannot be invoked until' defined-interface-update \n\ +/set format normal until ' which cannot be invoked until' defined-method-update \n\ +/set format normal until ' which cannot be referenced until' notdefined-update \n\ + \n\ +/set format normal unrerr '{unresolved} is declared' unresolved1-error0 \n\ +/set format normal unrerr '{unresolved} are declared' unresolved2-error0 \n\ +/set format normal unrerr ' this error is corrected: {errors}' unresolved0-error1 \n\ +/set format normal unrerr '{unresolved} is declared and this error is corrected: {errors}' unresolved1-error1 \n\ +/set format normal unrerr '{unresolved} are declared and this error is corrected: {errors}' unresolved2-error1 \n\ +/set format normal unrerr ' these errors are corrected: {errors}' unresolved0-error2 \n\ +/set format normal unrerr '{unresolved} is declared and these errors are corrected: {errors}' unresolved1-error2 \n\ +/set format normal unrerr '{unresolved} are declared and these errors are corrected: {errors}' unresolved2-error2 \n\ + \n\ +/set format normal resolve '{until}{unrerr}' added,modified,replaced,used \n\ + \n\ +/set format normal typeKind 'class' class \n\ +/set format normal typeKind 'interface' interface \n\ +/set format normal typeKind 'enum' enum \n\ +/set format normal typeKind 'annotation interface' annotation \n\ + \n\ +/set format normal display '{pre}{action} {typeKind} {name}{resolve}{post}' class,interface,enum,annotation \n\ +/set format normal display '{pre}{action} method {name}({type}){resolve}{post}' method \n\ + \n\ +/set format normal display '{pre}{action} variable {name} of type {type}{resolve}{post}' vardecl \n\ +/set format normal display '{pre}{action} variable {name} of type {type} with initial value {value}{resolve}{post}' varinit \n\ +/set format normal display '{pre}{action} variable {name}, reset to null{post}' replaced-vardecl,varinit-ok-update \n\ +/set format normal display '{pre}{action} variable {name}{resolve}{post}' vardecl,varinit-notdefined \n\ +/set format normal display '{pre}{action} variable {name}{post}' overwrote,dropped-vardecl,varinit \n\ + \n\ +/set format normal display '{pre}Expression value is: {value}{post}{pre} assigned to temporary variable {name} of type {type}{post}' expression \n\ +/set format normal display '{pre}Variable {name} of type {type} has value {value}{post}' varvalue \n\ +/set format normal display '{pre}Variable {name} has been assigned the value {value}{post}' assignment \n\ + \n\ +/set format normal display '{pre}Attempted to use {typeKind} {name}{resolve}{post}' used-class,interface,enum,annotation \n\ +/set format normal display '{pre}Attempted to call method {name}({type}){resolve}{post}' used-method \n\ + \n\ +/set feedback normal \n\ + \n\ +/set newmode off quiet \n\ +/set prompt off '-> ' '>> ' \n\ +/set format off pre '| ' \n\ +/set format off post '%n' \n\ +/set format off errorpre '| ' \n\ +/set format off errorpost '%n' \n\ +/set format off display '' \n diff -r 66bc9949f8b3 -r bf40906bf49d langtools/test/jdk/jshell/ReplToolTesting.java --- a/langtools/test/jdk/jshell/ReplToolTesting.java Wed Mar 23 21:44:24 2016 -0700 +++ b/langtools/test/jdk/jshell/ReplToolTesting.java Fri Mar 25 18:36:19 2016 -0700 @@ -374,8 +374,8 @@ } } - private void dropKey(boolean after, String cmd, String name, Map map) { - assertCommand(after, cmd, ""); + private void dropKey(boolean after, String cmd, String name, Map map, String output) { + assertCommand(after, cmd, output); if (after) { map.remove(name); for (int i = 0; i < keys.size(); ++i) { @@ -389,20 +389,20 @@ } } - public void dropVariable(boolean after, String cmd, String name) { - dropKey(after, cmd, name, variables); + public void dropVariable(boolean after, String cmd, String name, String output) { + dropKey(after, cmd, name, variables, output); } - public void dropMethod(boolean after, String cmd, String name) { - dropKey(after, cmd, name, methods); + public void dropMethod(boolean after, String cmd, String name, String output) { + dropKey(after, cmd, name, methods, output); } - public void dropClass(boolean after, String cmd, String name) { - dropKey(after, cmd, name, classes); + public void dropClass(boolean after, String cmd, String name, String output) { + dropKey(after, cmd, name, classes, output); } - public void dropImport(boolean after, String cmd, String name) { - dropKey(after, cmd, name, imports); + public void dropImport(boolean after, String cmd, String name, String output) { + dropKey(after, cmd, name, imports, output); } public void assertCommand(boolean after, String cmd, String out) { @@ -436,10 +436,10 @@ } setCommandInput(cmd + "\n"); } else { - assertOutput(getCommandOutput(), out, "command"); - assertOutput(getCommandErrorOutput(), err, "command error"); - assertOutput(getUserOutput(), print, "user"); - assertOutput(getUserErrorOutput(), usererr, "user error"); + assertOutput(getCommandOutput(), out, "command output: " + cmd); + assertOutput(getCommandErrorOutput(), err, "command error: " + cmd); + assertOutput(getUserOutput(), print, "user output: " + cmd); + assertOutput(getUserErrorOutput(), usererr, "user error: " + cmd); } } @@ -476,9 +476,9 @@ return (output) -> assertTrue(output.startsWith(prefix), "Output: \'" + output + "' does not start with: " + prefix); } - public void assertOutput(String got, String expected, String kind) { + public void assertOutput(String got, String expected, String display) { if (expected != null) { - assertEquals(got, expected, "Kind: " + kind + ".\n"); + assertEquals(got, expected, display + ".\n"); } } diff -r 66bc9949f8b3 -r bf40906bf49d langtools/test/jdk/jshell/ToolBasicTest.java --- a/langtools/test/jdk/jshell/ToolBasicTest.java Wed Mar 23 21:44:24 2016 -0700 +++ b/langtools/test/jdk/jshell/ToolBasicTest.java Fri Mar 25 18:36:19 2016 -0700 @@ -755,13 +755,13 @@ public void testDrop() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/drop 1", "int a = 0"), + a -> dropVariable(a, "/drop 1", "int a = 0", "| Dropped variable a\n"), a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop 2", "b ()I"), + a -> dropMethod(a, "/drop 2", "b ()I", "| Dropped method b()\n"), a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/drop 3", "class A"), + a -> dropClass(a, "/drop 3", "class A", "| Dropped class A\n"), a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), - a -> dropImport(a, "/drop 4", "import java.util.stream.*"), + a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""), a -> assertCommandCheckOutput(a, "/vars", assertVariables()), a -> assertCommandCheckOutput(a, "/methods", assertMethods()), a -> assertCommandCheckOutput(a, "/classes", assertClasses()), @@ -769,11 +769,11 @@ ); test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/drop a", "int a = 0"), + a -> dropVariable(a, "/drop a", "int a = 0", "| Dropped variable a\n"), a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop b", "b ()I"), + a -> dropMethod(a, "/drop b", "b ()I", "| Dropped method b()\n"), a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/drop A", "class A"), + a -> dropClass(a, "/drop A", "class A", "| Dropped class A\n"), a -> assertCommandCheckOutput(a, "/vars", assertVariables()), a -> assertCommandCheckOutput(a, "/methods", assertMethods()), a -> assertCommandCheckOutput(a, "/classes", assertClasses()), diff -r 66bc9949f8b3 -r bf40906bf49d langtools/test/jdk/jshell/ToolFormatTest.java --- a/langtools/test/jdk/jshell/ToolFormatTest.java Wed Mar 23 21:44:24 2016 -0700 +++ b/langtools/test/jdk/jshell/ToolFormatTest.java Fri Mar 25 18:36:19 2016 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 8148316 8148317 + * @bug 8148316 8148317 8151755 8152246 * @summary Tests for output customization * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -33,6 +33,8 @@ * @build KullaTesting TestingInputStream ToolBox Compiler * @run testng ToolFormatTest */ +import java.util.ArrayList; +import java.util.List; import org.testng.annotations.Test; @Test @@ -42,28 +44,34 @@ try { test( (a) -> assertCommandOutputStartsWith(a, "/set newmode test command", "| Created new feedback mode: test"), - (a) -> assertCommand(a, "/set field test pre '$ '", ""), - (a) -> assertCommand(a, "/set field test post ''", ""), - (a) -> assertCommand(a, "/set field test action 'ADD ' added-primary", ""), - (a) -> assertCommand(a, "/set field test action 'MOD ' modified-primary", ""), - (a) -> assertCommand(a, "/set field test action 'REP ' replaced-primary", ""), - (a) -> assertCommand(a, "/set field test action 'UP-ADD ' added-update", ""), - (a) -> assertCommand(a, "/set field test action 'UP-MOD ' modified-update", ""), - (a) -> assertCommand(a, "/set field test action 'UP-REP ' replaced-update", ""), - (a) -> assertCommand(a, "/set field test resolve 'OK' ok-*", ""), - (a) -> assertCommand(a, "/set field test resolve 'DEF' defined-*", ""), - (a) -> assertCommand(a, "/set field test resolve 'NODEF' notdefined-*", ""), - (a) -> assertCommand(a, "/set field test name ':%s ' ", ""), - (a) -> assertCommand(a, "/set field test type '[%s]' ", ""), - (a) -> assertCommand(a, "/set field test result '=%s ' ", ""), - (a) -> assertCommand(a, "/set format test '{pre}{action}{type}{name}{result}{resolve}' *-*-*", ""), - (a) -> assertCommand(a, "/set format test '{pre}HI this is enum' enum", ""), + (a) -> assertCommand(a, "/set format test pre '$ '", ""), + (a) -> assertCommand(a, "/set format test post ''", ""), + (a) -> assertCommand(a, "/set format test act 'ADD' added", ""), + (a) -> assertCommand(a, "/set format test act 'MOD' modified", ""), + (a) -> assertCommand(a, "/set format test act 'REP' replaced", ""), + (a) -> assertCommand(a, "/set format test act 'OVR' overwrote", ""), + (a) -> assertCommand(a, "/set format test act 'USE' used", ""), + (a) -> assertCommand(a, "/set format test act 'DRP' dropped", ""), + (a) -> assertCommand(a, "/set format test up 'UP-' update", ""), + (a) -> assertCommand(a, "/set format test action '{up}{act} '", ""), + (a) -> assertCommand(a, "/set format test resolve 'OK' ok", ""), + (a) -> assertCommand(a, "/set format test resolve 'DEF' defined", ""), + (a) -> assertCommand(a, "/set format test resolve 'NODEF' notdefined", ""), + (a) -> assertCommand(a, "/set format test fname ':{name} ' ", ""), + (a) -> assertCommand(a, "/set format test ftype '[{type}]' method,expression", ""), + (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) -> 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"), (a) -> assertCommand(a, "56", "$ ADD [int]:$4 =56 OK"), - (a) -> assertCommand(a, "class D { int hh; }", "$ REP :D OK$ OVERWROTE-UPDATE:D OK"), + (a) -> assertCommand(a, "class D { int hh; }", "$ REP :D OK$ UP-OVR :D OK"), + (a) -> assertCommand(a, "enum E {A,B}", "$ HI this is enum"), + (a) -> assertCommand(a, "int z() { return f(); }", "$ ADD []:z DEF"), + (a) -> assertCommand(a, "z()", "$ UP-USE []:z DEF"), + (a) -> assertCommand(a, "/drop z", "$ DRP []:z OK"), (a) -> assertCommandOutputStartsWith(a, "/set feedback normal", "| Feedback mode: normal") ); } finally { @@ -72,7 +80,82 @@ } } - public void testNewModeQuiet() { + public void testSetFormatSelector() { + List tests = new ArrayList<>(); + tests.add((a) -> assertCommandOutputStartsWith(a, "/set newmode ate quiet", + "| Created new feedback mode: ate")); + tests.add((a) -> assertCommand(a, "/set feedback ate", "")); + StringBuilder sb = new StringBuilder(); + class KindList { + final String[] values; + final int matchIndex; + int current; + boolean match; + KindList(String[] values, int matchIndex) { + this.values = values; + this.matchIndex = matchIndex; + this.current = 1 << values.length; + } + boolean next() { + if (current <= 0) { + return false; + } + --current; + return true; + } + boolean append(boolean ahead) { + boolean any = false; + match = false; + for (int i = values.length - 1; i >= 0 ; --i) { + if ((current & (1 << i)) != 0) { + match |= i == matchIndex; + if (any) { + sb.append(","); + } else { + if (ahead) { + sb.append("-"); + } + } + sb.append(values[i]); + any = true; + } + } + match |= !any; + return ahead || any; + } + } + KindList klcase = new KindList(new String[] {"class", "method", "expression", "vardecl"}, 2); + while (klcase.next()) { + KindList klact = new KindList(new String[] {"added", "modified", "replaced"}, 0); + while (klact.next()) { + KindList klwhen = new KindList(new String[] {"update", "primary"}, 1); + while (klwhen.next()) { + sb.setLength(0); + klwhen.append( + klact.append( + klcase.append(false))); + boolean match = klcase.match && klact.match && klwhen.match; + String select = sb.toString(); + String yes = "+++" + select + "+++"; + String no = "---" + select + "---"; + String expect = match? yes : no; + tests.add((a) -> assertCommand(a, "/set format ate display '" + no + "'", "")); + tests.add((a) -> assertCommand(a, "/set format ate display '" + yes + "' " + select, "")); + tests.add((a) -> assertCommand(a, "\"" + select + "\"", expect)); + } + } + } + tests.add((a) -> assertCommandOutputStartsWith(a, "/set feedback normal", "| Feedback mode: normal")); + + try { + test(tests.toArray(new ReplTest[tests.size()])); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetNewModeQuiet() { try { test( (a) -> assertCommandOutputStartsWith(a, "/set newmode nmq quiet normal", "| Created new feedback mode: nmq"), @@ -82,7 +165,8 @@ (a) -> assertCommand(a, "/set newmode nmc command normal", ""), (a) -> assertCommandOutputStartsWith(a, "/set feedback nmc", "| Feedback mode: nmc"), (a) -> assertCommandOutputStartsWith(a, "/set newmode nm", "| Created new feedback mode: nm"), - (a) -> assertCommandOutputStartsWith(a, "/set feedback nm", "| Feedback mode: nm") + (a) -> assertCommandOutputStartsWith(a, "/set feedback nm", "| Feedback mode: nm"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback normal", "| Feedback mode: normal") ); } finally { assertCommandCheckOutput(false, "/set feedback normal", s -> { @@ -93,38 +177,75 @@ public void testSetError() { try { test( - (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), - (a) -> assertCommand(a, "/set field te errorpre 'ERROR: '", ""), - (a) -> assertCommandOutputStartsWith(a, "/set feedback te", ""), - (a) -> assertCommandCheckOutput(a, "/set ", assertStartsWith("ERROR: The /set command requires arguments")), - (a) -> assertCommandCheckOutput(a, "/set xyz", assertStartsWith("ERROR: Not a valid argument to /set")), - (a) -> assertCommandCheckOutput(a, "/set f", assertStartsWith("ERROR: Ambiguous argument to /set")), - (a) -> assertCommandCheckOutput(a, "/set feedback", assertStartsWith("ERROR: Expected a feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set feedback xyz", assertStartsWith("ERROR: Does not match any current feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set format", assertStartsWith("ERROR: Expected a feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set format xyz", assertStartsWith("ERROR: Does not match any current feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set format te", assertStartsWith("ERROR: Expected format missing")), - (a) -> assertCommandCheckOutput(a, "/set format te aaa", assertStartsWith("ERROR: Format 'aaa' must be quoted")), - (a) -> assertCommandCheckOutput(a, "/set format te 'aaa'", assertStartsWith("ERROR: At least one selector required")), - (a) -> assertCommandCheckOutput(a, "/set format te 'aaa' frog", assertStartsWith("ERROR: Not a valid case")), - (a) -> assertCommandCheckOutput(a, "/set format te 'aaa' import-frog", assertStartsWith("ERROR: Not a valid action")), - (a) -> assertCommandCheckOutput(a, "/set newmode", assertStartsWith("ERROR: Expected new feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set newmode te", assertStartsWith("ERROR: Expected a new feedback mode name")), - (a) -> assertCommandCheckOutput(a, "/set newmode x xyz", assertStartsWith("ERROR: Specify either 'command' or 'quiet'")), - (a) -> assertCommandCheckOutput(a, "/set newmode x quiet y", assertStartsWith("ERROR: Does not match any current feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set prompt", assertStartsWith("ERROR: Expected a feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set prompt te", assertStartsWith("ERROR: Expected format missing")), - (a) -> assertCommandCheckOutput(a, "/set prompt te aaa xyz", assertStartsWith("ERROR: Format 'aaa' must be quoted")), - (a) -> assertCommandCheckOutput(a, "/set prompt te 'aaa' xyz", assertStartsWith("ERROR: Format 'xyz' must be quoted")), - (a) -> assertCommandCheckOutput(a, "/set prompt", assertStartsWith("ERROR: Expected a feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set prompt te", assertStartsWith("ERROR: Expected format missing")), - (a) -> assertCommandCheckOutput(a, "/set prompt te aaa", assertStartsWith("ERROR: Format 'aaa' must be quoted")), - (a) -> assertCommandCheckOutput(a, "/set prompt te 'aaa'", assertStartsWith("ERROR: Expected format missing")), - (a) -> assertCommandCheckOutput(a, "/set field", assertStartsWith("ERROR: Expected a feedback mode")), - (a) -> assertCommandCheckOutput(a, "/set field xyz", assertStartsWith("ERROR: Does not match any current feedback mode: xyz")), - (a) -> assertCommandCheckOutput(a, "/set field te xyz", assertStartsWith("ERROR: Not a valid field: xyz, must be one of: when")), - (a) -> assertCommandCheckOutput(a, "/set field te action", assertStartsWith("ERROR: Expected format missing")), - (a) -> assertCommandCheckOutput(a, "/set field te action 'act'", assertStartsWith("ERROR: At least one selector required")) + (a) -> assertCommandOutputStartsWith(a, "/set newmode tee command foo", + "| Does not match any current feedback mode: foo"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode tee flurb", + "| Specify either 'command' or 'quiet'"), + (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"), + (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"), + (a) -> assertCommandOutputStartsWith(a, "/set xyz", + "ERROR: Not a valid argument to /set"), + (a) -> assertCommandOutputStartsWith(a, "/set f", + "ERROR: Ambiguous argument to /set"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback", + "ERROR: Expected a feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback xyz", + "ERROR: Does not match any current feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set format", + "ERROR: Expected a feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set format xyz", + "ERROR: Does not match any current feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set format t", + "ERROR: Matches more then one current feedback mode: t"), + (a) -> assertCommandOutputStartsWith(a, "/set format te", + "ERROR: Expected field name missing"), + (a) -> assertCommandOutputStartsWith(a, "/set format te fld", + "ERROR: Expected format missing"), + (a) -> assertCommandOutputStartsWith(a, "/set format te fld aaa", + "ERROR: Format 'aaa' must be quoted"), + (a) -> assertCommandOutputStartsWith(a, "/set format te fld 'aaa' frog", + "ERROR: Not a valid selector"), + (a) -> assertCommandOutputStartsWith(a, "/set format te fld 'aaa' import-frog", + "ERROR: Not a valid selector"), + (a) -> assertCommandOutputStartsWith(a, "/set format te fld 'aaa' import-import", + "ERROR: Selector kind in multiple sections of"), + (a) -> assertCommandOutputStartsWith(a, "/set format te fld 'aaa' import,added", + "ERROR: Different selector kinds in same sections of"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode", + "ERROR: Expected new feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode te", + "ERROR: Expected a new feedback mode name"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode x xyz", + "ERROR: Specify either 'command' or 'quiet'"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode x quiet y", + "ERROR: Does not match any current feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt", + "ERROR: Expected a feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt te", + "ERROR: Expected format missing"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt te aaa xyz", + "ERROR: Format 'aaa' must be quoted"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt te 'aaa' xyz", + "ERROR: Format 'xyz' must be quoted"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt", + "ERROR: Expected a feedback mode"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt te", + "ERROR: Expected format missing"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt te aaa", + "ERROR: Format 'aaa' must be quoted"), + (a) -> assertCommandOutputStartsWith(a, "/set prompt te 'aaa'", + "ERROR: Expected format missing"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback normal", + "| Feedback mode: normal") ); } finally { assertCommandCheckOutput(false, "/set feedback normal", s -> { @@ -136,7 +257,7 @@ try { test( (a) -> assertCommandOutputContains(a, "/help /set", "command to launch"), - (a) -> assertCommandOutputContains(a, "/help /set format", "vardecl"), + (a) -> assertCommandOutputContains(a, "/help /set format", "display"), (a) -> assertCommandOutputContains(a, "/hel /se for", "vardecl"), (a) -> assertCommandOutputContains(a, "/help /set editor", "temporary file") ); @@ -150,7 +271,7 @@ try { test( (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), - (a) -> assertCommand(a, "/set field te errorpre 'ERROR: '", ""), + (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") diff -r 66bc9949f8b3 -r bf40906bf49d langtools/test/jdk/jshell/ToolReloadTest.java --- a/langtools/test/jdk/jshell/ToolReloadTest.java Wed Mar 23 21:44:24 2016 -0700 +++ b/langtools/test/jdk/jshell/ToolReloadTest.java Fri Mar 25 18:36:19 2016 -0700 @@ -92,11 +92,11 @@ public void testReloadDrop() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/dr 1", "int a = 0"), + a -> dropVariable(a, "/dr 1", "int a = 0", "| Dropped variable a\n"), a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop b", "b ()I"), + a -> dropMethod(a, "/drop b", "b ()I", "| Dropped method b()\n"), a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/dr A", "class A"), + a -> dropClass(a, "/dr A", "class A", "| Dropped class A\n"), a -> assertCommand(a, "/reload", "| Restarting and restoring state.\n" + "-: int a;\n" + @@ -115,11 +115,11 @@ public void testReloadQuiet() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), - a -> dropVariable(a, "/dr 1", "int a = 0"), + a -> dropVariable(a, "/dr 1", "int a = 0", "| Dropped variable a\n"), a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), - a -> dropMethod(a, "/drop b", "b ()I"), + a -> dropMethod(a, "/drop b", "b ()I", "| Dropped method b()\n"), a -> assertClass(a, "class A {}", "class", "A"), - a -> dropClass(a, "/dr A", "class A"), + a -> dropClass(a, "/dr A", "class A", "| Dropped class A\n"), a -> assertCommand(a, "/reload quiet", "| Restarting and restoring state.\n"), a -> assertCommandCheckOutput(a, "/vars", assertVariables()),