diff --git a/.gitignore b/.gitignore index 993fb23a4..4cba33fe4 100644 --- a/.gitignore +++ b/.gitignore @@ -30,11 +30,10 @@ hs_err_pid* target/ .settings **/.checkstyle -target/ bin/ **/lib/ jdt-language-server-latest.tar.gz jdtls/ -!.mvn/wrapper/maven-wrapper.jar \ No newline at end of file +!.mvn/wrapper/maven-wrapper.jar diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java index e3c928332..9efeb04b6 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java @@ -18,6 +18,7 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.annotations.SerializedName; +import com.microsoft.java.debug.core.adapter.formatter.NumericFormatEnum; import com.microsoft.java.debug.core.protocol.JsonUtils; import com.microsoft.java.debug.core.protocol.Requests.ClassFilters; import com.microsoft.java.debug.core.protocol.Requests.StepFilters; @@ -32,7 +33,7 @@ public final class DebugSettings { public int numericPrecision = 0; public boolean showStaticVariables = false; public boolean showQualifiedNames = false; - public boolean showHex = false; + public NumericFormatEnum formatType = NumericFormatEnum.DEC; public boolean showLogicalStructure = true; public boolean showToString = true; public String logLevel; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatEnum.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatEnum.java index c9766d635..1dab7ae40 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatEnum.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatEnum.java @@ -12,6 +12,7 @@ package com.microsoft.java.debug.core.adapter.formatter; public enum NumericFormatEnum { + BIN, HEX, OCT, DEC diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatter.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatter.java index b26667b93..096d0a7ca 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatter.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatter.java @@ -30,18 +30,15 @@ public class NumericFormatter implements IValueFormatter { public static final String NUMERIC_PRECISION_OPTION = "numeric_precision"; private static final NumericFormatEnum DEFAULT_NUMERIC_FORMAT = NumericFormatEnum.DEC; private static final int DEFAULT_NUMERIC_PRECISION = 0; - private static final Map enumFormatMap = new HashMap<>(); - static { - enumFormatMap.put(NumericFormatEnum.DEC, "%d"); - enumFormatMap.put(NumericFormatEnum.HEX, "%#x"); - enumFormatMap.put(NumericFormatEnum.OCT, "%#o"); - } + private static final String HEX_PREFIX = "0x"; + private static final String OCT_PREFIX = "0"; + private static final String BIN_PREFIX = "0b"; /** * Get the string representations for an object. * - * @param obj the value object + * @param obj the value object * @param options extra information for printing * @return the string representations. */ @@ -91,7 +88,6 @@ public Value valueOf(String value, Type type, Map options) { throw new UnsupportedOperationException(String.format("%s is not a numeric type.", type.name())); } - /** * The conditional function for this formatter. * @@ -122,11 +118,21 @@ public Map getDefaultOptions() { static String formatNumber(long value, Map options) { NumericFormatEnum formatEnum = getNumericFormatOption(options); - return String.format(enumFormatMap.get(formatEnum), value); + switch (formatEnum) { + case HEX: + return HEX_PREFIX + Long.toHexString(value); + case OCT: + return OCT_PREFIX + Long.toOctalString(value); + case BIN: + return BIN_PREFIX + Long.toBinaryString(value); + default: + return Long.toString(value); + } } private static long parseNumber(String number) { - return Long.decode(number); + return number.startsWith(BIN_PREFIX) + ? Long.parseLong(number.substring(2), 2) : Long.decode(number); } private static double parseFloatDouble(String number) { diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/EvaluateRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/EvaluateRequestHandler.java index 9cf99742d..35190b28b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/EvaluateRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/EvaluateRequestHandler.java @@ -61,7 +61,7 @@ public CompletableFuture handle(Command command, Arguments arguments, EvaluateArguments evalArguments = (EvaluateArguments) arguments; final boolean showStaticVariables = DebugSettings.getCurrent().showStaticVariables; Map options = context.getVariableFormatter().getDefaultOptions(); - VariableUtils.applyFormatterOptions(options, evalArguments.format != null && evalArguments.format.hex); + VariableUtils.applyFormatterOptions(options, evalArguments.format); String expression = evalArguments.expression; if (StringUtils.isBlank(expression)) { diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshVariablesHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshVariablesHandler.java index 01214b615..070f80139 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshVariablesHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshVariablesHandler.java @@ -18,6 +18,7 @@ import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; +import com.microsoft.java.debug.core.adapter.formatter.NumericFormatEnum; import com.microsoft.java.debug.core.protocol.Events.InvalidatedAreas; import com.microsoft.java.debug.core.protocol.Events.InvalidatedEvent; import com.microsoft.java.debug.core.protocol.Messages.Response; @@ -25,6 +26,7 @@ import com.microsoft.java.debug.core.protocol.Requests.Command; import com.microsoft.java.debug.core.protocol.Requests.RefreshVariablesArguments; + public class RefreshVariablesHandler implements IDebugRequestHandler { @Override @@ -37,7 +39,7 @@ public CompletableFuture handle(Command command, Arguments arguments, IDebugAdapterContext context) { RefreshVariablesArguments refreshArgs = (RefreshVariablesArguments) arguments; if (refreshArgs != null) { - DebugSettings.getCurrent().showHex = refreshArgs.showHex; + DebugSettings.getCurrent().formatType = getFormatType(refreshArgs.showHex, refreshArgs.formatType); DebugSettings.getCurrent().showQualifiedNames = refreshArgs.showQualifiedNames; DebugSettings.getCurrent().showStaticVariables = refreshArgs.showStaticVariables; DebugSettings.getCurrent().showLogicalStructure = refreshArgs.showLogicalStructure; @@ -47,4 +49,15 @@ public CompletableFuture handle(Command command, Arguments arguments, context.getProtocolServer().sendEvent(new InvalidatedEvent(InvalidatedAreas.VARIABLES)); return CompletableFuture.completedFuture(response); } + + private NumericFormatEnum getFormatType(boolean showHex, String formatType) { + if (formatType != null) { + try { + return NumericFormatEnum.valueOf(formatType); + } catch (IllegalArgumentException exp) { + // can't parse format so just return default value; + } + } + return showHex ? NumericFormatEnum.HEX : NumericFormatEnum.DEC; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetVariableRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetVariableRequestHandler.java index c2d3aa1d2..d6735b3a7 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetVariableRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetVariableRequestHandler.java @@ -77,7 +77,7 @@ public CompletableFuture handle(Command command, Arguments arguments, boolean showStaticVariables = DebugSettings.getCurrent().showStaticVariables; IVariableFormatter variableFormatter = context.getVariableFormatter(); Map options = variableFormatter.getDefaultOptions(); - VariableUtils.applyFormatterOptions(options, setVarArguments.format != null && setVarArguments.format.hex); + VariableUtils.applyFormatterOptions(options, setVarArguments.format); Object container = context.getRecyclableIdPool().getObjectById(setVarArguments.variablesReference); // container is null means the stack frame is continued by user manually. diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java index 8f37ef574..d9e257b09 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java @@ -76,7 +76,7 @@ public CompletableFuture handle(Command command, Arguments arguments, boolean showStaticVariables = DebugSettings.getCurrent().showStaticVariables; Map options = variableFormatter.getDefaultOptions(); - VariableUtils.applyFormatterOptions(options, varArgs.format != null && varArgs.format.hex); + VariableUtils.applyFormatterOptions(options, varArgs.format); IEvaluationProvider evaluationEngine = context.getProvider(IEvaluationProvider.class); List list = new ArrayList<>(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableUtils.java index d53e2705c..e54a4a299 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableUtils.java @@ -26,6 +26,7 @@ import com.microsoft.java.debug.core.adapter.formatter.NumericFormatter; import com.microsoft.java.debug.core.adapter.formatter.SimpleTypeFormatter; import com.microsoft.java.debug.core.adapter.formatter.StringObjectFormatter; +import com.microsoft.java.debug.core.protocol.Requests; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.ArrayReference; import com.sun.jdi.ArrayType; @@ -256,13 +257,15 @@ public static List listStaticVariables(StackFrame stackFrame) { * variable view/debug console. * * @param defaultOptions the initial options for adding options from user settings - * @param hexInArgument when request sent by vscode declare hex format explicitly, settings this parameter true to override value in DebugSettings class. + * @param format when request sent by vscode declare format explicitly, settings this parameter true to override value in DebugSettings class. */ - public static void applyFormatterOptions(Map defaultOptions, boolean hexInArgument) { + public static void applyFormatterOptions(Map defaultOptions, Requests.ValueFormat format) { Map options = defaultOptions; boolean showFullyQualifiedNames = DebugSettings.getCurrent().showQualifiedNames; - if (hexInArgument || DebugSettings.getCurrent().showHex) { - options.put(NumericFormatter.NUMERIC_FORMAT_OPTION, NumericFormatEnum.HEX); + if (format == null) { + options.put(NumericFormatter.NUMERIC_FORMAT_OPTION, DebugSettings.getCurrent().formatType); + } else { + options.put(NumericFormatter.NUMERIC_FORMAT_OPTION, parseValueFormat(format)); } if (showFullyQualifiedNames) { options.put(SimpleTypeFormatter.QUALIFIED_CLASS_NAME_OPTION, true); @@ -277,6 +280,17 @@ public static void applyFormatterOptions(Map defaultOptions, boo } } + private static NumericFormatEnum parseValueFormat(Requests.ValueFormat format) { + if (format.type != null) { + try { + return NumericFormatEnum.valueOf(format.type); + } catch (IllegalArgumentException exp) { + // can't parse format so just return default value; + } + } + return format.hex ? NumericFormatEnum.HEX : NumericFormatEnum.DEC; + } + /** * Get the name for evaluation of variable. * diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java index 9b444155c..d98b13f81 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java @@ -25,6 +25,11 @@ public class Requests { public static class ValueFormat { public boolean hex; + /** + * Extension for additional formats. + * Supported formats: ["BIN", "OCT", "HEX", "DEC"] + */ + public String type; } public static class Arguments { @@ -300,7 +305,9 @@ public static class SetVariableArguments extends Arguments { public static class RefreshVariablesArguments extends Arguments { public boolean showStaticVariables = false; public boolean showQualifiedNames = false; + @Deprecated public boolean showHex = false; + public String formatType = null; public boolean showLogicalStructure = true; public boolean showToString = true; } diff --git a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatterTest.java b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatterTest.java index 001b928e9..1989b5f76 100644 --- a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatterTest.java +++ b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/adapter/formatter/NumericFormatterTest.java @@ -102,7 +102,7 @@ public void testToString() throws Exception { } @Test - public void testToHexOctString() throws Exception { + public void testToHexOctBinString() throws Exception { Value i = this.getLocalValue("i"); Map options = formatter.getDefaultOptions(); @@ -113,7 +113,11 @@ public void testToHexOctString() throws Exception { options.put(NUMERIC_FORMAT_OPTION, NumericFormatEnum.OCT); assertEquals("NumericFormatter should be able to format an oct integer.", - "0" +Integer.toOctalString(111), formatter.toString(i, options)); + "0" + Integer.toOctalString(111), formatter.toString(i, options)); + + options.put(NUMERIC_FORMAT_OPTION, NumericFormatEnum.BIN); + assertEquals("NumericFormatter should be able to format an bin integer.", + "0b" + Integer.toBinaryString(111), formatter.toString(i, options)); } @Test @@ -127,7 +131,6 @@ public void testValueOf() throws Exception { assertEquals("Should create an integer with right value.", "111", newValue.toString()); options.put(NUMERIC_FORMAT_OPTION, NumericFormatEnum.HEX); - newValue = formatter.valueOf(formatter.toString(i, options), i.type(), options); assertNotNull("NumericFormatter should be able to create integer by string.", newValue); assertTrue("Should create an integer value.", newValue instanceof IntegerValue); @@ -139,6 +142,12 @@ public void testValueOf() throws Exception { assertTrue("Should create an integer value.", newValue instanceof IntegerValue); assertEquals("Should create an integer with right value.", "111", newValue.toString()); + options.put(NUMERIC_FORMAT_OPTION, NumericFormatEnum.BIN); + newValue = formatter.valueOf(formatter.toString(i, options), i.type(), options); + assertNotNull("NumericFormatter should be able to create integer by string.", newValue); + assertTrue("Should create an integer value.", newValue instanceof IntegerValue); + assertEquals("Should create an integer with right value.", "111", newValue.toString()); + newValue = formatter.valueOf("-12121212", i.type(), options); assertNotNull("NumericFormatter should be able to create integer by string.", newValue);