8154812: jshell tool: value printing truncation

Reviewed-by: vromero
This commit is contained in:
Robert Field 2016-05-16 21:25:44 -07:00
parent 358e25664a
commit f53f69489a
4 changed files with 139 additions and 6 deletions

View File

@ -47,6 +47,9 @@ class Feedback {
// Patern for substituted fields within a customized format string
private static final Pattern FIELD_PATTERN = Pattern.compile("\\{(.*?)\\}");
// Internal field name for truncation length
private static final String TRUNCATION_FIELD = "<truncation>";
// Current mode
private Mode mode = new Mode("", false); // initial value placeholder during start-up
@ -103,6 +106,10 @@ class Feedback {
return new Setter(messageHandler, at).setFormat();
}
public boolean setTruncation(MessageHandler messageHandler, ArgTokenizer at) {
return new Setter(messageHandler, at).setTruncation();
}
public boolean setNewMode(MessageHandler messageHandler, ArgTokenizer at) {
return new Setter(messageHandler, at).setNewMode();
}
@ -251,13 +258,42 @@ class Feedback {
return sb.toString();
}
// Compute the display output given full context and values
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) {
// Convert the context into a bit representation used as selectors for store field formats
long bits = bits(fc, fa, fw, fr, fu, fe);
String fname = name==null? "" : name;
String ftype = type==null? "" : type;
String fvalue = value==null? "" : value;
// Compute the representation of value
String fvalue;
if (value==null) {
fvalue = "";
} else {
// Retrieve the truncation length
String truncField = format(TRUNCATION_FIELD, bits);
if (truncField.isEmpty()) {
// No truncation set, use whole value
fvalue = value;
} else {
// Convert truncation length to int
// this is safe since it has been tested before it is set
int trunc = Integer.parseUnsignedInt(truncField);
if (value.length() > trunc) {
if (trunc <= 5) {
// Very short truncations have no room for "..."
fvalue = value.substring(0, trunc);
} else {
// Normal truncation, make total length equal truncation length
fvalue = value.substring(0, trunc - 4) + " ...";
}
} else {
// Within truncation length, use whole value
fvalue = value;
}
}
}
String funresolved = unresolved==null? "" : unresolved;
String errors = errorLines.stream()
.map(el -> String.format(
@ -619,7 +655,32 @@ class Feedback {
errorat("jshell.err.feedback.expected.field");
valid = false;
}
String format = valid? nextFormat() : null;
String format = valid ? nextFormat() : null;
return installFormat(m, field, format, "/help /set format");
}
// For /set truncation <mode> <length> <selector>...
boolean setTruncation() {
Mode m = nextMode();
String length = at.next();
if (length == null) {
errorat("jshell.err.truncation.expected.length");
valid = false;
} else {
try {
// Assure that integer format is correct
Integer.parseUnsignedInt(length);
} catch (NumberFormatException ex) {
errorat("jshell.err.truncation.length.not.integer", length);
valid = false;
}
}
// install length into an internal format field
return installFormat(m, TRUNCATION_FIELD, length, "/help /set truncation");
}
// install the format of a field under parsed selectors
boolean installFormat(Mode m, String field, String format, String help) {
String slRaw;
List<SelectorList> slList = new ArrayList<>();
while (valid && (slRaw = at.next()) != null) {
@ -629,8 +690,10 @@ class Feedback {
}
if (valid) {
if (slList.isEmpty()) {
// No selectors specified, then always the format
m.set(field, ALWAYS, format);
} else {
// Set the format of the field for specified selector
slList.stream()
.forEach(sl -> m.set(field,
sl.cases.getSet(), sl.actions.getSet(), sl.whens.getSet(),
@ -638,7 +701,7 @@ class Feedback {
format));
}
} else {
fluffmsg("jshell.msg.see", "/help /set format");
fluffmsg("jshell.msg.see", help);
}
return valid;
}

View File

@ -1019,7 +1019,7 @@ public class JShellTool implements MessageHandler {
EMPTY_COMPLETION_PROVIDER));
registerCommand(new Command("/set",
arg -> cmdSet(arg),
new FixedCompletionProvider("format", "feedback", "prompt", "newmode", "start", "editor")));
new FixedCompletionProvider(SET_SUBCOMMANDS)));
registerCommand(new Command("/?",
"help.quest",
arg -> cmdHelp(arg),
@ -1094,7 +1094,7 @@ public class JShellTool implements MessageHandler {
// --- Command implementations ---
private static final String[] SET_SUBCOMMANDS = new String[]{
"format", "feedback", "newmode", "prompt", "editor", "start"};
"format", "truncation", "feedback", "newmode", "prompt", "editor", "start"};
final boolean cmdSet(String arg) {
ArgTokenizer at = new ArgTokenizer("/set ", arg.trim());
@ -1105,6 +1105,8 @@ public class JShellTool implements MessageHandler {
switch (which) {
case "format":
return feedback.setFormat(this, at);
case "truncation":
return feedback.setTruncation(this, at);
case "feedback":
return feedback.setFeedback(this, at);
case "newmode":

View File

@ -117,6 +117,9 @@ jshell.msg.feedback.new.mode = Created new feedback mode: {0}
jshell.msg.feedback.mode = Feedback mode: {0}
jshell.msg.feedback.mode.following = The feedback mode should be one of the following:
jshell.err.truncation.expected.length = Expected truncation length -- {0}
jshell.err.truncation.length.not.integer = Truncation length must be an integer: {0} -- {1}
jshell.console.see.more = <press tab to see more>
jshell.console.do.nothing = Do nothing
jshell.console.choice = Choice: \
@ -318,6 +321,8 @@ the command prompt, the feedback mode to use, or the format of output.\n\
Create a user-defined feedback mode, optionally copying from an existing mode.\n\n\
/set prompt <mode> "<prompt>" "<continuation-prompt>"\n\t\
Set the displayed prompts for a given feedback mode.\n\n\
/set truncation <mode> <length> <selector>...\n\t\
Set the maximum length of a displayed value\n\t\
/set format <mode> <field> "<format>" <selector>...\n\t\
Configure a feedback mode by setting the format of a field when the selector matchs.\n\n\
To get more information about one of these forms, use /help with the form specified.\n\
@ -462,6 +467,37 @@ Examples:\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.truncation = \
Set the max length a displayed value.\n\
\n\t\
/set truncation <mode> <length> <selector>...\n\
\n\
Where <mode> is the name of a previously defined feedback mode -- see '/help /set newmode'.\n\
Where <length> is an unsigned integer representing a maximum length.\n\
Where <format> is a quoted string which will be the value of the field if one of\n\
Where <selector> is only needed if you wish to fine-tune value truncation length\n\
by context, <selector> is the context in which the truncation 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\n\
Below are the relevant selector kinds for truncation.\n\n\
The case selector kind describes the kind of snippet. The values are:\n\t\
vardecl -- variable declaration without init\n\t\
varinit -- variable declaration with init\n\t\
expression -- expression -- note: {name}==scratch-variable-name\n\t\
varvalue -- variable value expression\n\t\
assignment -- assign variable\n\t\
The action selector kind describes what happened to the snippet. The values are:\n\t\
added -- snippet has been added\n\t\
modified -- an existing snippet has been modified\n\t\
replaced -- an existing snippet has been replaced with a new snippet\n\
Examples:\n\t\
/set trunc mymode 80\n\t\
/set truncation mymode 45 expression\n\t\
/set truncation mymode 0 vardecl-modified,replaced\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\t\
@ -578,6 +614,9 @@ startup.feedback = \
/set format verbose display '{pre}attempted to use {typeKind} {name}{resolve}{post}' used-class,interface,enum,annotation \n\
/set format verbose display '{pre}attempted to call method {name}({type}){resolve}{post}' used-method \n\
\n\
/set truncation verbose 80\n\
/set truncation verbose 500 varvalue\n\
\n\
/set newmode normal command verbose \n\
/set format normal display '' added,modified,replaced,overwrote,dropped-update \n\
/set format normal display '{pre}{action} variable {name}, reset to null{post}' replaced-vardecl,varinit-ok-update \n\

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8148316 8148317 8151755 8152246 8153551
* @bug 8148316 8148317 8151755 8152246 8153551 8154812
* @summary Tests for output customization
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
@ -155,6 +155,29 @@ public class ToolFormatTest extends ReplToolTesting {
}
}
public void testSetTruncation() {
try {
test(
(a) -> assertCommandOutputStartsWith(a, "/set feedback normal", ""),
(a) -> assertCommand(a, "String s = java.util.stream.IntStream.range(65, 74)"+
".mapToObj(i -> \"\"+(char)i).reduce((a,b) -> a + b + a).get()",
"s ==> \"ABACABADABACABAEABACABADABACABAFABACABADABACABAEABACABADABACABAGABACABADABA ..."),
(a) -> assertCommandOutputStartsWith(a, "/set newmode test quiet", ""),
(a) -> assertCommandOutputStartsWith(a, "/set feedback test", ""),
(a) -> assertCommand(a, "/set format test display '{type}:{value}' primary", ""),
(a) -> assertCommand(a, "/set truncation test 20", ""),
(a) -> assertCommand(a, "/set trunc test 10 varvalue", ""),
(a) -> assertCommand(a, "/set trunc test 3 assignment", ""),
(a) -> assertCommand(a, "String r = s", "String:\"ABACABADABACABA ..."),
(a) -> assertCommand(a, "r", "String:\"ABACA ..."),
(a) -> assertCommand(a, "r=s", "String:\"AB")
);
} finally {
assertCommandCheckOutput(false, "/set feedback normal", s -> {
});
}
}
public void testShowFeedbackModes() {
test(
(a) -> assertCommandOutputContains(a, "/set feedback", "normal")
@ -226,6 +249,12 @@ public class ToolFormatTest extends ReplToolTesting {
"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 trunc te 20x",
"ERROR: Truncation length must be an integer: 20x"),
(a) -> assertCommandOutputStartsWith(a, "/set trunc te",
"ERROR: Expected truncation length"),
(a) -> assertCommandOutputStartsWith(a, "/set truncation te 111 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",