8249566: jshell tool: retained modes from JDK-13 or prior cause confusing messages to be generated for records
Reviewed-by: jlahoda
This commit is contained in:
parent
ee5dc7cbb4
commit
9390446081
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,6 @@ import java.lang.module.ModuleDescriptor;
|
|||||||
import java.lang.module.ModuleFinder;
|
import java.lang.module.ModuleFinder;
|
||||||
import java.lang.module.ModuleReference;
|
import java.lang.module.ModuleReference;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@ -110,12 +109,12 @@ import java.util.Spliterators;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import jdk.internal.joptsimple.*;
|
import jdk.internal.joptsimple.*;
|
||||||
import jdk.internal.jshell.tool.Feedback.FormatAction;
|
import jdk.internal.jshell.tool.Selector.FormatAction;
|
||||||
import jdk.internal.jshell.tool.Feedback.FormatCase;
|
import jdk.internal.jshell.tool.Selector.FormatCase;
|
||||||
import jdk.internal.jshell.tool.Feedback.FormatErrors;
|
import jdk.internal.jshell.tool.Selector.FormatErrors;
|
||||||
import jdk.internal.jshell.tool.Feedback.FormatResolve;
|
import jdk.internal.jshell.tool.Selector.FormatResolve;
|
||||||
import jdk.internal.jshell.tool.Feedback.FormatUnresolved;
|
import jdk.internal.jshell.tool.Selector.FormatUnresolved;
|
||||||
import jdk.internal.jshell.tool.Feedback.FormatWhen;
|
import jdk.internal.jshell.tool.Selector.FormatWhen;
|
||||||
import jdk.internal.editor.spi.BuildInEditorProvider;
|
import jdk.internal.editor.spi.BuildInEditorProvider;
|
||||||
import jdk.internal.editor.external.ExternalEditor;
|
import jdk.internal.editor.external.ExternalEditor;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
@ -231,6 +230,7 @@ public class JShellTool implements MessageHandler {
|
|||||||
static final String STARTUP_KEY = "STARTUP";
|
static final String STARTUP_KEY = "STARTUP";
|
||||||
static final String EDITOR_KEY = "EDITOR";
|
static final String EDITOR_KEY = "EDITOR";
|
||||||
static final String MODE_KEY = "MODE";
|
static final String MODE_KEY = "MODE";
|
||||||
|
static final String MODE2_KEY = "MODE2";
|
||||||
static final String FEEDBACK_KEY = "FEEDBACK";
|
static final String FEEDBACK_KEY = "FEEDBACK";
|
||||||
static final String REPLAY_RESTORE_KEY = "REPLAY_RESTORE";
|
static final String REPLAY_RESTORE_KEY = "REPLAY_RESTORE";
|
||||||
public static final String INDENT_KEY = "INDENT";
|
public static final String INDENT_KEY = "INDENT";
|
||||||
@ -1130,11 +1130,20 @@ public class JShellTool implements MessageHandler {
|
|||||||
// These predefined modes are read-only
|
// These predefined modes are read-only
|
||||||
feedback.markModesReadOnly();
|
feedback.markModesReadOnly();
|
||||||
// Restore user defined modes retained on previous run with /set mode -retain
|
// Restore user defined modes retained on previous run with /set mode -retain
|
||||||
String encoded = prefs.get(MODE_KEY);
|
boolean oldModes = false;
|
||||||
|
String encoded = prefs.get(MODE2_KEY);
|
||||||
|
if (encoded == null || encoded.isEmpty()) {
|
||||||
|
// No new layout modes, see if there are old (JDK-14 and before) modes
|
||||||
|
oldModes = true;
|
||||||
|
encoded = prefs.get(MODE_KEY);
|
||||||
|
}
|
||||||
if (encoded != null && !encoded.isEmpty()) {
|
if (encoded != null && !encoded.isEmpty()) {
|
||||||
if (!feedback.restoreEncodedModes(initmh, encoded)) {
|
if (!feedback.restoreEncodedModes(initmh, encoded)) {
|
||||||
// Catastrophic corruption -- remove the retained modes
|
// Catastrophic corruption -- remove the retained modes
|
||||||
prefs.remove(MODE_KEY);
|
// Leave old mode corruption clean-up to old versions
|
||||||
|
if (!oldModes) {
|
||||||
|
prefs.remove(MODE2_KEY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (initMode != null) {
|
if (initMode != null) {
|
||||||
@ -1989,7 +1998,7 @@ public class JShellTool implements MessageHandler {
|
|||||||
return setFeedback(this, at);
|
return setFeedback(this, at);
|
||||||
case "mode":
|
case "mode":
|
||||||
return feedback.setMode(this, at,
|
return feedback.setMode(this, at,
|
||||||
retained -> prefs.put(MODE_KEY, retained));
|
retained -> prefs.put(MODE2_KEY, retained));
|
||||||
case "prompt":
|
case "prompt":
|
||||||
return feedback.setPrompt(this, at);
|
return feedback.setPrompt(this, at);
|
||||||
case "editor":
|
case "editor":
|
||||||
|
@ -0,0 +1,557 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.internal.jshell.tool;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BinaryOperator;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collector;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector is the representation of the selector in a "/set format" command. This class, among other things, provides
|
||||||
|
* the translation between the various forms that a selector may take: textual (as in the command), group of EnumSets,
|
||||||
|
* or bits.
|
||||||
|
*
|
||||||
|
* @author Robert Field
|
||||||
|
* @since 16
|
||||||
|
*/
|
||||||
|
class Selector {
|
||||||
|
static final Selector ALWAYS = new Selector(FormatCase.ALL, FormatAction.ALL, FormatWhen.ALL,
|
||||||
|
FormatResolve.ALL, FormatUnresolved.ALL, FormatErrors.ALL);
|
||||||
|
static final Selector OLD_ALWAYS = new Selector(FormatCase.SUSPICIOUS, FormatAction.ALL, FormatWhen.ALL,
|
||||||
|
FormatResolve.ALL, FormatUnresolved.ALL, FormatErrors.ALL);
|
||||||
|
static final Selector ANY = new Selector(
|
||||||
|
EnumSet.noneOf(FormatCase.class), EnumSet.noneOf(FormatAction.class), EnumSet.noneOf(FormatWhen.class),
|
||||||
|
EnumSet.noneOf(FormatResolve.class), EnumSet.noneOf(FormatUnresolved.class), EnumSet.noneOf(FormatErrors.class));
|
||||||
|
|
||||||
|
// Mapping selector enum names to enums
|
||||||
|
static final Map<String, SelectorInstanceWithDoc<?>> selectorMap = new HashMap<>();
|
||||||
|
|
||||||
|
private long bits = -1L;
|
||||||
|
private String text = null;
|
||||||
|
private EnumSet<FormatCase> cc = null;
|
||||||
|
private EnumSet<FormatAction> ca;
|
||||||
|
private EnumSet<FormatWhen> cw;
|
||||||
|
private EnumSet<FormatResolve> cr;
|
||||||
|
private EnumSet<FormatUnresolved> cu;
|
||||||
|
private EnumSet<FormatErrors> ce;
|
||||||
|
|
||||||
|
Selector(long bits) {
|
||||||
|
this.bits = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector(Collection<FormatCase> cc, Collection<FormatAction> ca, Collection<FormatWhen> cw,
|
||||||
|
Collection<FormatResolve> cr, Collection<FormatUnresolved> cu, Collection<FormatErrors> ce) {
|
||||||
|
this(EnumSet.copyOf(cc), EnumSet.copyOf(ca), EnumSet.copyOf(cw),
|
||||||
|
EnumSet.copyOf(cr), EnumSet.copyOf(cu), EnumSet.copyOf(ce));
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector(FormatCase fc, FormatAction fa, FormatWhen fw,
|
||||||
|
FormatResolve fr, FormatUnresolved fu, FormatErrors fe) {
|
||||||
|
this(EnumSet.of(fc), EnumSet.of(fa), EnumSet.of(fw),
|
||||||
|
EnumSet.of(fr), EnumSet.of(fu), EnumSet.of(fe));
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector(String text, EnumSet<FormatCase> cc, EnumSet<FormatAction> ca, EnumSet<FormatWhen> cw,
|
||||||
|
EnumSet<FormatResolve> cr, EnumSet<FormatUnresolved> cu, EnumSet<FormatErrors> ce) {
|
||||||
|
this(cc, ca, cw, cr, cu, ce);
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector(EnumSet<FormatCase> cc, EnumSet<FormatAction> ca, EnumSet<FormatWhen> cw,
|
||||||
|
EnumSet<FormatResolve> cr, EnumSet<FormatUnresolved> cu, EnumSet<FormatErrors> ce) {
|
||||||
|
this.cc = cc;
|
||||||
|
this.ca = ca;
|
||||||
|
this.cw = cw;
|
||||||
|
this.cr = cr;
|
||||||
|
this.cu = cu;
|
||||||
|
this.ce = ce;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records were added to Java in JDK-14. They were also added to JShell, and thus to the FormatCase enum.
|
||||||
|
* Unfortunately they were added in the logical place (with the other class forms) but this causes the bitwise
|
||||||
|
* representation to be shifted, distorting the selector. This method shifts back restoring a JDK-13 or before
|
||||||
|
* selector.
|
||||||
|
*
|
||||||
|
* @param os the original, distorted, selector
|
||||||
|
* @param smearClassIntoRecord assume that if a setting applies to class it should apply to record
|
||||||
|
* @return the corrected selector
|
||||||
|
*/
|
||||||
|
static Selector fromPreJDK14(Selector os, boolean smearClassIntoRecord) {
|
||||||
|
EnumSet<FormatCase> cc = EnumSet.noneOf(FormatCase.class);
|
||||||
|
os.unpackEnumSets();
|
||||||
|
os.cc.forEach(fc -> {
|
||||||
|
switch(fc) {
|
||||||
|
case IMPORT -> cc.add(FormatCase.IMPORT);
|
||||||
|
case CLASS -> {
|
||||||
|
cc.add(FormatCase.CLASS);
|
||||||
|
// punt and assume that if class is handled, so is record
|
||||||
|
if (smearClassIntoRecord) cc.add(FormatCase.RECORD);
|
||||||
|
}
|
||||||
|
case INTERFACE -> cc.add(FormatCase.INTERFACE);
|
||||||
|
case ENUM -> cc.add(FormatCase.ENUM);
|
||||||
|
case ANNOTATION -> cc.add(FormatCase.ANNOTATION);
|
||||||
|
// RECORD and beyond shift down, the JDK-13 enum didn't have record
|
||||||
|
case RECORD -> cc.add(FormatCase.METHOD);
|
||||||
|
case METHOD -> cc.add(FormatCase.VARDECL);
|
||||||
|
case VARDECL -> cc.add(FormatCase.VARINIT);
|
||||||
|
case VARINIT -> cc.add(FormatCase.EXPRESSION);
|
||||||
|
case EXPRESSION -> cc.add(FormatCase.VARVALUE);
|
||||||
|
case VARVALUE -> cc.add(FormatCase.ASSIGNMENT);
|
||||||
|
case ASSIGNMENT -> cc.add(FormatCase.STATEMENT);
|
||||||
|
case STATEMENT -> {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new Selector(cc, os.ca, os.cw, os.cr, os.cu, os.ce);
|
||||||
|
}
|
||||||
|
|
||||||
|
long asBits() {
|
||||||
|
if (bits < 0) {
|
||||||
|
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();
|
||||||
|
bits = res;
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string representation.
|
||||||
|
*
|
||||||
|
* @return the original string form, if known, otherwise reconstructed.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (text == null) {
|
||||||
|
unpackEnumSets();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
selectorToString(sb, cc, FormatCase.ALL);
|
||||||
|
selectorToString(sb, ca, FormatAction.ALL);
|
||||||
|
selectorToString(sb, cw, FormatWhen.ALL);
|
||||||
|
selectorToString(sb, cr, FormatResolve.ALL);
|
||||||
|
selectorToString(sb, cu, FormatUnresolved.ALL);
|
||||||
|
selectorToString(sb, ce, FormatErrors.ALL);
|
||||||
|
this.text = sb.toString();
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <E extends Enum<E>> void selectorToString(StringBuilder sb, EnumSet<E> c, EnumSet<E> all) {
|
||||||
|
if (!c.equals(all)) {
|
||||||
|
sb.append(c.stream()
|
||||||
|
.map(v -> v.name().toLowerCase(Locale.US))
|
||||||
|
.collect(new Collector<CharSequence, StringJoiner, String>() {
|
||||||
|
@Override
|
||||||
|
public BiConsumer<StringJoiner, CharSequence> accumulator() {
|
||||||
|
return StringJoiner::add;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Supplier<StringJoiner> supplier() {
|
||||||
|
return () -> new StringJoiner(",", (sb.length() == 0)? "" : "-", "")
|
||||||
|
.setEmptyValue("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryOperator<StringJoiner> combiner() {
|
||||||
|
return StringJoiner::merge;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Function<StringJoiner, String> finisher() {
|
||||||
|
return StringJoiner::toString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Characteristics> characteristics() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the bit representation, and uses it to set the EnumSet representation.
|
||||||
|
*/
|
||||||
|
private class BitUnpacker {
|
||||||
|
|
||||||
|
long b = bits;
|
||||||
|
|
||||||
|
<E extends Enum<E> & SelectorInstanceWithDoc<E>> EnumSet<E> unpackEnumbits(Class<E> k, E[] values) {
|
||||||
|
EnumSet<E> c = EnumSet.noneOf(k);
|
||||||
|
for (int i = 0; i < values.length; ++i) {
|
||||||
|
if ((b & (1 << i)) != 0) {
|
||||||
|
c.add(values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b >>>= values.length;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unpack() {
|
||||||
|
// inverseof the order they were packed
|
||||||
|
ce = unpackEnumbits(FormatErrors.class, FormatErrors.values());
|
||||||
|
cu = unpackEnumbits(FormatUnresolved.class, FormatUnresolved.values());
|
||||||
|
cr = unpackEnumbits(FormatResolve.class, FormatResolve.values());
|
||||||
|
cw = unpackEnumbits(FormatWhen.class, FormatWhen.values());
|
||||||
|
ca = unpackEnumbits(FormatAction.class, FormatAction.values());
|
||||||
|
cc = unpackEnumbits(FormatCase.class, FormatCase.values());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unpackEnumSets() {
|
||||||
|
if (cc == null) {
|
||||||
|
new BitUnpacker().unpack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the provided selector include all settings in ours?
|
||||||
|
*
|
||||||
|
* @param os the provided selector
|
||||||
|
* @return is it included in
|
||||||
|
*/
|
||||||
|
boolean includedIn(Selector os) {
|
||||||
|
return (asBits() & ~os.asBits()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this selector include all the settings in the provided selector?
|
||||||
|
*
|
||||||
|
* @param os the provided selector
|
||||||
|
* @return is it covered
|
||||||
|
*/
|
||||||
|
boolean covers(Selector os) {
|
||||||
|
return (asBits() & os.asBits()) == os.asBits();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof Selector)) return false;
|
||||||
|
Selector selector = (Selector) o;
|
||||||
|
return asBits() == selector.asBits();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (int) (asBits() ^ (asBits() >>> 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of any single value in the Format* enums.
|
||||||
|
*
|
||||||
|
* @param <E> the enum
|
||||||
|
*/
|
||||||
|
interface SelectorInstanceWithDoc<E extends Enum<E> & SelectorInstanceWithDoc<E>> {
|
||||||
|
SelectorKind kind();
|
||||||
|
String doc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SelectorKind {
|
||||||
|
CASE(FormatCase.class),
|
||||||
|
ACTION(FormatAction.class),
|
||||||
|
WHEN(FormatWhen.class),
|
||||||
|
RESOLVE(FormatResolve.class),
|
||||||
|
UNRESOLVED(FormatUnresolved.class),
|
||||||
|
ERRORS(FormatErrors.class);
|
||||||
|
|
||||||
|
EnumSet<? extends SelectorInstanceWithDoc<?>> all;
|
||||||
|
Class<? extends SelectorInstanceWithDoc<?>> k;
|
||||||
|
|
||||||
|
<E extends Enum<E> & SelectorInstanceWithDoc<E>>
|
||||||
|
SelectorKind(Class<E> k) {
|
||||||
|
this.all = EnumSet.allOf(FormatCase.class);;
|
||||||
|
this.k = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event cases
|
||||||
|
*/
|
||||||
|
public enum FormatCase implements SelectorInstanceWithDoc<FormatCase> {
|
||||||
|
IMPORT("import declaration"),
|
||||||
|
CLASS("class declaration"),
|
||||||
|
INTERFACE("interface declaration"),
|
||||||
|
ENUM("enum declaration"),
|
||||||
|
ANNOTATION("annotation interface declaration"),
|
||||||
|
RECORD("record 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");
|
||||||
|
|
||||||
|
private String doc;
|
||||||
|
static final EnumSet<FormatCase> ALL = EnumSet.allOf(FormatCase.class);
|
||||||
|
static final EnumSet<FormatCase> SUSPICIOUS = EnumSet.of(IMPORT, CLASS, INTERFACE, ENUM, ANNOTATION, RECORD,
|
||||||
|
METHOD, VARDECL, VARINIT, EXPRESSION, VARVALUE, ASSIGNMENT);
|
||||||
|
static final int COUNT = ALL.size();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectorKind kind() {
|
||||||
|
return SelectorKind.CASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doc() {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatCase(String doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event actions
|
||||||
|
*/
|
||||||
|
public enum FormatAction implements SelectorInstanceWithDoc<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"),
|
||||||
|
USED("snippet was used when it cannot be");
|
||||||
|
|
||||||
|
private String doc;
|
||||||
|
static final EnumSet<FormatAction> ALL = EnumSet.allOf(FormatAction.class);
|
||||||
|
static final int COUNT = ALL.size();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectorKind kind() {
|
||||||
|
return SelectorKind.ACTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doc() {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatAction(String doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the event occurs: primary or update
|
||||||
|
*/
|
||||||
|
public enum FormatWhen implements SelectorInstanceWithDoc<FormatWhen> {
|
||||||
|
PRIMARY("the entered snippet"),
|
||||||
|
UPDATE("an update to a dependent snippet");
|
||||||
|
|
||||||
|
private String doc;
|
||||||
|
static final EnumSet<FormatWhen> ALL = EnumSet.allOf(FormatWhen.class);
|
||||||
|
static final int COUNT = ALL.size();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectorKind kind() {
|
||||||
|
return SelectorKind.WHEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doc() {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatWhen(String doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolution problems
|
||||||
|
*/
|
||||||
|
public enum FormatResolve implements SelectorInstanceWithDoc<FormatResolve> {
|
||||||
|
OK("resolved correctly"),
|
||||||
|
DEFINED("defined despite recoverably unresolved references"),
|
||||||
|
NOTDEFINED("not defined because of recoverably unresolved references");
|
||||||
|
|
||||||
|
private String doc;
|
||||||
|
static final EnumSet<FormatResolve> ALL = EnumSet.allOf(FormatResolve.class);
|
||||||
|
static final int COUNT = ALL.size();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectorKind kind() {
|
||||||
|
return SelectorKind.RESOLVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doc() {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatResolve(String doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count of unresolved references
|
||||||
|
*/
|
||||||
|
public enum FormatUnresolved implements SelectorInstanceWithDoc<FormatUnresolved> {
|
||||||
|
UNRESOLVED0("no names are unresolved"),
|
||||||
|
UNRESOLVED1("one name is unresolved"),
|
||||||
|
UNRESOLVED2("two or more names are unresolved");
|
||||||
|
|
||||||
|
private String doc;
|
||||||
|
static final EnumSet<FormatUnresolved> ALL = EnumSet.allOf(FormatUnresolved.class);
|
||||||
|
static final int COUNT = ALL.size();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectorKind kind() {
|
||||||
|
return SelectorKind.UNRESOLVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doc() {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatUnresolved(String doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count of unresolved references
|
||||||
|
*/
|
||||||
|
public enum FormatErrors implements SelectorInstanceWithDoc<FormatErrors> {
|
||||||
|
ERROR0("no errors"),
|
||||||
|
ERROR1("one error"),
|
||||||
|
ERROR2("two or more errors");
|
||||||
|
|
||||||
|
private String doc;
|
||||||
|
static final EnumSet<FormatErrors> ALL = EnumSet.allOf(FormatErrors.class);
|
||||||
|
static final int COUNT = ALL.size();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SelectorKind kind() {
|
||||||
|
return SelectorKind.ERRORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doc() {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatErrors(String doc) {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
// map all selector value names to values
|
||||||
|
for (FormatCase e : FormatCase.ALL)
|
||||||
|
selectorMap.put(e.name().toLowerCase(Locale.US), e);
|
||||||
|
for (FormatAction e : FormatAction.ALL)
|
||||||
|
selectorMap.put(e.name().toLowerCase(Locale.US), e);
|
||||||
|
for (FormatResolve e : FormatResolve.ALL)
|
||||||
|
selectorMap.put(e.name().toLowerCase(Locale.US), e);
|
||||||
|
for (FormatUnresolved e : FormatUnresolved.ALL)
|
||||||
|
selectorMap.put(e.name().toLowerCase(Locale.US), e);
|
||||||
|
for (FormatErrors e : FormatErrors.ALL)
|
||||||
|
selectorMap.put(e.name().toLowerCase(Locale.US), e);
|
||||||
|
for (FormatWhen e : FormatWhen.ALL)
|
||||||
|
selectorMap.put(e.name().toLowerCase(Locale.US), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a selector from adds.
|
||||||
|
*/
|
||||||
|
static class SelectorBuilder {
|
||||||
|
final String selectorText;
|
||||||
|
private SelectorCollector<FormatCase> fcase = new SelectorCollector<>(FormatCase.class);
|
||||||
|
private SelectorCollector<FormatAction> faction = new SelectorCollector<>(FormatAction.class);
|
||||||
|
private SelectorCollector<FormatWhen> fwhen = new SelectorCollector<>(FormatWhen.class);
|
||||||
|
private SelectorCollector<FormatResolve> fresolve = new SelectorCollector<>(FormatResolve.class);
|
||||||
|
private SelectorCollector<FormatUnresolved> funresolved = new SelectorCollector<>(FormatUnresolved.class);
|
||||||
|
private SelectorCollector<FormatErrors> ferrors = new SelectorCollector<>(FormatErrors.class);
|
||||||
|
|
||||||
|
private static class SelectorCollector<E extends Enum<E> & SelectorInstanceWithDoc<E>> {
|
||||||
|
final EnumSet<E> all;
|
||||||
|
EnumSet<E> set;
|
||||||
|
|
||||||
|
SelectorCollector(Class<E> k) {
|
||||||
|
this.all = EnumSet.allOf(k);
|
||||||
|
this.set = EnumSet.noneOf(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(E e) {
|
||||||
|
set.add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumSet<E> get() {
|
||||||
|
return set.isEmpty()
|
||||||
|
? all
|
||||||
|
: set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectorBuilder(String selectorText) {
|
||||||
|
this.selectorText = selectorText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(SelectorInstanceWithDoc<?> v) {
|
||||||
|
switch (v.kind()) {
|
||||||
|
case CASE -> fcase.add((FormatCase) v);
|
||||||
|
case ACTION -> faction.add((FormatAction) v);
|
||||||
|
case WHEN -> fwhen.add((FormatWhen) v);
|
||||||
|
case RESOLVE -> fresolve.add((FormatResolve) v);
|
||||||
|
case UNRESOLVED -> funresolved.add((FormatUnresolved) v);
|
||||||
|
case ERRORS -> ferrors.add((FormatErrors) v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector toSelector() {
|
||||||
|
return new Selector(selectorText,
|
||||||
|
fcase.get(), faction.get(), fwhen.get(), fresolve.get(), funresolved.get(), ferrors.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -131,7 +131,7 @@ public class ToolFormatTest extends ReplToolTesting {
|
|||||||
(a) -> assertCommand(a, "/se fo tm x \"iii\" method,class", ""),
|
(a) -> assertCommand(a, "/se fo tm x \"iii\" method,class", ""),
|
||||||
(a) -> assertCommand(a, "/se fo tm x",
|
(a) -> assertCommand(a, "/se fo tm x",
|
||||||
"| /set format tm x \"aaa\" \n" +
|
"| /set format tm x \"aaa\" \n" +
|
||||||
"| /set format tm x \"iii\" class,method"),
|
"| /set format tm x \"iii\" method,class"),
|
||||||
(a) -> assertCommand(a, "/se fo tm x \"jjj\"", ""),
|
(a) -> assertCommand(a, "/se fo tm x \"jjj\"", ""),
|
||||||
(a) -> assertCommand(a, "/se fo tm x",
|
(a) -> assertCommand(a, "/se fo tm x",
|
||||||
"| /set format tm x \"jjj\"")
|
"| /set format tm x \"jjj\"")
|
||||||
|
Loading…
Reference in New Issue
Block a user