8151755: jshell tool: properly cover resolution issues in output configuration
8152246: jshell tool: history overflow
Reviewed-by: jlahoda
--- 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<String, Mode> modeMap = new HashMap<>();
+ // Mapping selector enum names to enums
+ private final Map<String, Selector<?>> 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<String> 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<FormatCase, EnumMap<FormatAction, EnumMap<FormatWhen, String>>> cases;
-
- // action names: add. modified, replaced, ...
- final EnumMap<FormatAction, EnumMap<FormatWhen, String>> actions;
-
- // resolution status description format with %s for unresolved
- final EnumMap<FormatResolve, EnumMap<FormatWhen, String>> resolves;
-
- // primary snippet vs update
- final EnumMap<FormatWhen, String> whens;
-
- // fixed map of how to get format string for a field, given a specific formatting contet
- final EnumMap<FormatField, Function<Context, String>> 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<String, List<Setting>> 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<FormatAction, EnumMap<FormatWhen, String>> ac = new EnumMap<>(FormatAction.class);
- cases.put(fc, ac);
- for (FormatAction fa : FormatAction.values()) {
- EnumMap<FormatWhen, String> 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<FormatWhen, String> 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<FormatWhen, String> 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<FormatAction, EnumMap<FormatWhen, String>> ac = new EnumMap<>(FormatAction.class);
- EnumMap<FormatAction, EnumMap<FormatWhen, String>> mc = m.cases.get(fc);
- cases.put(fc, ac);
- for (FormatAction fa : FormatAction.values()) {
- EnumMap<FormatWhen, String> aw = new EnumMap<>(mc.get(fa));
- ac.put(fa, aw);
- }
- }
+ cases = new HashMap<>();
- actions = new EnumMap<>(FormatAction.class);
- for (FormatAction fa : FormatAction.values()) {
- EnumMap<FormatWhen, String> 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<FormatWhen, String> 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<FormatCase> cc, Collection<FormatAction> ca, Collection<FormatWhen> cw) {
- for (FormatCase fc : cc) {
- EnumMap<FormatAction, EnumMap<FormatWhen, String>> ma = cases.get(fc);
- for (FormatAction fa : ca) {
- EnumMap<FormatWhen, String> mw = ma.get(fa);
- for (FormatWhen fw : cw) {
- mw.put(fw, format);
- }
- }
+ private boolean add(String field, Setting ing) {
+ List<Setting> settings = cases.computeIfAbsent(field, k -> new ArrayList<>());
+ if (settings == null) {
+ return false;
}
+ settings.add(ing);
+ return true;
}
- void setActions(String format, Collection<FormatAction> ca, Collection<FormatWhen> cw) {
- for (FormatAction fa : ca) {
- EnumMap<FormatWhen, String> mw = actions.get(fa);
- for (FormatWhen fw : cw) {
- mw.put(fw, format);
- }
- }
+ void set(String field,
+ Collection<FormatCase> cc, Collection<FormatAction> ca, Collection<FormatWhen> cw,
+ Collection<FormatResolve> cr, Collection<FormatUnresolved> cu, Collection<FormatErrors> ce,
+ String format) {
+ long bits = bits(cc, ca, cw, cr, cu, ce);
+ set(field, bits, format);
}
- void setResolves(String format, Collection<FormatResolve> cr, Collection<FormatWhen> cw) {
- for (FormatResolve fr : cr) {
- EnumMap<FormatWhen, String> mw = resolves.get(fr);
- for (FormatWhen fw : cw) {
- mw.put(fw, format);
- }
- }
- }
-
- void setWhens(String format, Collection<FormatWhen> 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<Setting> 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<String> 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<FormatCase> cc, Collection<FormatAction> ca, Collection<FormatWhen> cw,
+ Collection<FormatResolve> cr, Collection<FormatUnresolved> cu, Collection<FormatErrors> 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<E extends Enum<E> & Selector<E>> {
+ SelectorCollector<E> 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<FormatCase> {
+ 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<FormatCase> all = EnumSet.allOf(FormatCase.class);
+ static final int count = all.size();
+
+ @Override
+ public SelectorCollector<FormatCase> 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<FormatAction> {
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<FormatAction> all = EnumSet.allOf(FormatAction.class);
+ static final int count = all.size();
+
+ @Override
+ public SelectorCollector<FormatAction> 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<FormatWhen> {
PRIMARY("the entered snippet"),
UPDATE("an update to a dependent snippet");
String doc;
+ static final EnumSet<FormatWhen> all = EnumSet.allOf(FormatWhen.class);
+ static final int count = all.size();
+
+ @Override
+ public SelectorCollector<FormatWhen> 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<FormatResolve> {
OK("resolved correctly"),
DEFINED("defined despite recoverably unresolved references"),
NOTDEFINED("not defined because of recoverably unresolved references");
String doc;
+ static final EnumSet<FormatResolve> all = EnumSet.allOf(FormatResolve.class);
+ static final int count = all.size();
+
+ @Override
+ public SelectorCollector<FormatResolve> 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<FormatUnresolved> {
+ UNRESOLVED0("no names are unresolved"),
+ UNRESOLVED1("one name is unresolved"),
+ UNRESOLVED2("two or more names are unresolved");
+ String doc;
+ static final EnumSet<FormatUnresolved> all = EnumSet.allOf(FormatUnresolved.class);
+ static final int count = all.size();
+
+ @Override
+ public SelectorCollector<FormatUnresolved> 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<FormatErrors> {
+ ERROR0("no errors"),
+ ERROR1("one error"),
+ ERROR2("two or more errors");
+ String doc;
+ static final EnumSet<FormatErrors> all = EnumSet.allOf(FormatErrors.class);
+ static final int count = all.size();
+
+ @Override
+ public SelectorCollector<FormatErrors> collector(Setter.SelectorList sl) {
+ return sl.errorCounts;
+ }
+
+ @Override
+ public String doc() {
+ return doc;
+ }
+
+ private FormatErrors(String doc) {
+ this.doc = doc;
+ }
+ }
+
+ class SelectorCollector<E extends Enum<E> & Selector<E>> {
+ final EnumSet<E> all;
+ EnumSet<E> set = null;
+ SelectorCollector(EnumSet<E> 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<E> 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<E1 extends Enum<E1>, E2 extends Enum<E2>, E3 extends Enum<E3>> {
-
- Set<E1> e1;
- Set<E2> e2;
- Set<E3> e3;
-
- Case(Set<E1> e1, Set<E2> e2, Set<E3> e3) {
- this.e1 = e1;
- this.e2 = e2;
- this.e3 = e3;
- }
-
- Case(Set<E1> e1, Set<E2> 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);
+ }
+
<E extends Enum<E>> void hardEnums(EnumSet<E> es, Function<E, String> e2s) {
hardPairs(es.stream(), ev -> ev.name().toLowerCase(Locale.US), e2s);
}
@@ -681,137 +651,31 @@
// For /set format <mode> "<format>" <selector>...
boolean setFormat() {
Mode m = nextMode();
- String format = nextFormat();
- if (valid) {
- List<Case<FormatCase, FormatAction, FormatWhen>> 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<SelectorList> 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 <field> "<format>" <selector>...
- 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<Case<FormatAction, FormatWhen, FormatWhen>> 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<Case<FormatResolve, FormatWhen, FormatWhen>> 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<Case<FormatWhen, FormatWhen, FormatWhen>> 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<FormatCase> parseFormatCase(String[] s, int i) {
- return parseFormatSelectorStar(s, i, FormatCase.class, EnumSet.allOf(FormatCase.class), "case");
- }
-
- final Set<FormatAction> parseFormatAction(String[] s, int i) {
- return parseFormatSelectorStar(s, i, FormatAction.class,
- EnumSet.of(FormatAction.ADDED, FormatAction.MODIFIED, FormatAction.REPLACED), "action");
- }
+ class SelectorList {
- final Set<FormatResolve> parseFormatResolve(String[] s, int i) {
- return parseFormatSelectorStar(s, i, FormatResolve.class,
- EnumSet.of(FormatResolve.DEFINED, FormatResolve.NOTDEFINED), "resolve");
- }
-
- final Set<FormatWhen> parseFormatWhen(String[] s, int i) {
- return parseFormatSelectorStar(s, i, FormatWhen.class, EnumSet.of(FormatWhen.PRIMARY), "when");
- }
+ SelectorCollector<FormatCase> cases = new SelectorCollector<>(FormatCase.all);
+ SelectorCollector<FormatAction> actions = new SelectorCollector<>(FormatAction.all);
+ SelectorCollector<FormatWhen> whens = new SelectorCollector<>(FormatWhen.all);
+ SelectorCollector<FormatResolve> resolves = new SelectorCollector<>(FormatResolve.all);
+ SelectorCollector<FormatUnresolved> unresolvedCounts = new SelectorCollector<>(FormatUnresolved.all);
+ SelectorCollector<FormatErrors> 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 <E> 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 <E extends Enum<E>> Set<E> parseFormatSelectorStar(String[] sa, int i, Class<E> klass, EnumSet<E> defaults, String label) {
- String s = sa.length > i
- ? sa[i]
- : null;
- if (s == null || s.isEmpty()) {
- return defaults;
- }
- Set<E> set = EnumSet.noneOf(klass);
- EnumSet<E> 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 <E> 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 extends Enum<E>> E parseFormatSelector(String s, EnumSet<E> 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 <mode> \"<format>\" <selector>...");
- hard("");
- hard("Where <mode> is the name of a previously defined feedback mode -- see '/help /set newmode'.");
- hard("Where <format> 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 <selector> is the context in which the format is applied.");
- hard("The structure of selector is: <case>[-<action>[-<when>]]");
- 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 <mode> <field> \"<format>\" <selector>...");
- hard("");
- hard("Where <mode> is the name of a previously defined feedback mode -- see '/set newmode'.");
- hard("Where <field> is context-specific format to set, each with its own selector structure:");
- hard(" action == The action. The selector: <action>-<when>.");
- 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: <resolve>-<when>.");
- hard(" result == The result value. '%%s' is the result value. No selectors.");
- hard(" when == The entered snippet or a resultant update. The selector: <when>");
- 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 <format> is a quoted string -- see the description specific to the field (above).");
- hard("Where <selector> 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 <mode>");
- hard("");
- hard("Where <mode> 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 <new-mode> [command|quiet [<old-mode>]]");
- hard("");
- hard("Where <new-mode> is the name of a mode you wish to create.");
- hard("Where <old-mode> is the name of a previously defined feedback mode.");
- hard("If <old-mode> 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 <mode> \"<prompt>\" \"<continuation-propmt>\"");
- hard("");
- hard("Where <mode> is the name of a previously defined feedback mode.");
- hard("Where <prompt> and <continuation-propmt> 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");
}
}
}
--- 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(
"((?<cmd>(all|history|start))(\\z|\\p{javaWhitespace}+))?(?<filename>.*)");
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);
+ }
+
<T> void hardPairs(Stream<T> stream, Function<T, String> a, Function<T, String> b) {
Map<String, String> 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 <mode> \"<prompt>\" \"<continuation-prompt>\"\n" +
" -- Set the displayed prompts for a given feedback mode.\n" +
"\n" +
- "/set format <mode> \"<format>\" <selector>...\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 \"<format>\" <format-case>...\n" +
- " -- Set the format of a field within the <format-string> of a \"/set format\" command\n" +
+ "/set format <mode> <field> \"<format>\" <selector>...\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<Diag> diagnostics, boolean embed) {
- String padding = embed? " " : "";
- for (Diag diag : diagnostics) {
- //assert diag.getSource().equals(source);
+ void displayDiagnostics(String source, Diag diag, List<String> 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<String> 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<Diag> other = errorsOnly(diagnostics);
- List<Diag> 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<Diag> 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<String> 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<String> 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<Diag> 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<Diag> 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<String> 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)";
}
--- /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 <mode> <field> "<format>" <selector>...\n\
+\n\
+Where <mode> is the name of a previously defined feedback mode -- see '/help /set newmode'.\n\
+Where <field> is the name of context-specific format to define.\n\
+Where <format> 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 <selector> 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 <mode>\n\
+\n\
+Where <mode> 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 <new-mode> [command|quiet [<old-mode>]]\n\
+\n\
+Where <new-mode> is the name of a mode you wish to create.\n\
+Where <old-mode> is the name of a previously defined feedback mode.\n\
+If <old-mode> 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 <mode> \"<prompt>\" \"<continuation-propmt>\"\n\
+\n\
+Where <mode> is the name of a previously defined feedback mode.\n\
+Where <prompt> and <continuation-propmt> 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
--- 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<String, ? extends MemberInfo> map) {
- assertCommand(after, cmd, "");
+ private void dropKey(boolean after, String cmd, String name, Map<String, ? extends MemberInfo> 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");
}
}
--- 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()),
--- 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<ReplTest> 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")
--- 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()),