Skip to content

Commit

Permalink
Support VS Code formatter scheme
Browse files Browse the repository at this point in the history
Signed-off-by: Shi Chen <[email protected]>
  • Loading branch information
CsCherrYY committed Apr 14, 2023
1 parent 693610b commit 934f22e
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.eclipse.jdt.internal.ui.preferences.formatter.ProfileVersionerCore;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.preferences.FormatterPreferences;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
Expand Down Expand Up @@ -150,6 +151,7 @@ public static Map<String, String> getOptions(FormattingOptions options, ICompila
Map<String, String> customOptions = options.entrySet().stream().filter(map -> chekIfValueIsNotNull(map.getValue())).collect(toMap(e -> e.getKey(), e -> getOptionValue(e.getValue())));

eclipseOptions.putAll(customOptions);
eclipseOptions.putAll(FormatterPreferences.toEclipseOptions(JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getFormatterSettings()));

Integer tabSize = options.getTabSize();
if (tabSize != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.preferences;

import java.util.Map;
import java.util.stream.Collectors;

import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;

public class FormatterPreferences {

// @formatter:off
// < JDTLS settings, eclipse settings >
private static Map<String, String> eclipseOptions = Map.ofEntries(
Map.entry("lineSplit", DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT),
Map.entry("comment.line.length", DefaultCodeFormatterConstants.FORMATTER_COMMENT_LINE_LENGTH),
Map.entry("join.wrapped.lines", DefaultCodeFormatterConstants.FORMATTER_JOIN_WRAPPED_LINES),
Map.entry("use.on.off.tags", DefaultCodeFormatterConstants.FORMATTER_USE_ON_OFF_TAGS),
Map.entry("disabling.tag", DefaultCodeFormatterConstants.FORMATTER_DISABLING_TAG),
Map.entry("enabling.tag", DefaultCodeFormatterConstants.FORMATTER_ENABLING_TAG),
Map.entry("indent.parameter.description", DefaultCodeFormatterConstants.FORMATTER_COMMENT_INDENT_PARAMETER_DESCRIPTION),
Map.entry("indent.root.tags", DefaultCodeFormatterConstants.FORMATTER_COMMENT_INDENT_ROOT_TAGS),
Map.entry("align.tags.descriptions.grouped", DefaultCodeFormatterConstants.FORMATTER_COMMENT_ALIGN_TAGS_DESCREIPTIONS_GROUPED),
Map.entry("align.tags.names.descriptions", DefaultCodeFormatterConstants.FORMATTER_COMMENT_ALIGN_TAGS_NAMES_DESCRIPTIONS),
Map.entry("clear.blank.lines.in.javadoc.comment", DefaultCodeFormatterConstants.FORMATTER_COMMENT_CLEAR_BLANK_LINES_IN_JAVADOC_COMMENT),
Map.entry("blank.lines.between.import.groups", DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BETWEEN_IMPORT_GROUPS),
Map.entry("format.line.comments", DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_LINE_COMMENT),
Map.entry("format.block.comments", DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_BLOCK_COMMENT),
Map.entry("format.javadoc.comments", DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_JAVADOC_COMMENT),
Map.entry("keep.loop.body.block.on.one.line", DefaultCodeFormatterConstants.FORMATTER_KEEP_LOOP_BODY_BLOCK_ON_ONE_LINE),
Map.entry("keep.anonymous.type.declaration.on.one.line", DefaultCodeFormatterConstants.FORMATTER_KEEP_ANONYMOUS_TYPE_DECLARATION_ON_ONE_LINE),
Map.entry("keep.type.declaration.on.one.line", DefaultCodeFormatterConstants.FORMATTER_KEEP_TYPE_DECLARATION_ON_ONE_LINE),
Map.entry("keep.method.body.on.one.line", DefaultCodeFormatterConstants.FORMATTER_KEEP_METHOD_BODY_ON_ONE_LINE),
Map.entry("insert.space.after.closing.angle.bracket.in.type.arguments", DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENTS),
Map.entry("insert.space.after.opening.brace.in.array.initializer", DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER),
Map.entry("insert.space.before.closing.brace.in.array.initializer", DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER),
Map.entry("brace.position.for.block", DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK),
Map.entry("alignment.for.enum.constants", DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS),
Map.entry("alignment.for.parameters.in.method.declaration", DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION)
);

// < JDTLS camelCase value, eclipse underline value>
private static Map<String, String> valueMap = Map.ofEntries(
Map.entry("commonLines", "common_lines"),
Map.entry("separateLinesIfNotEmpty", "separate_lines_if_not_empty"),
Map.entry("separateLinesIfWrapped", "separate_lines_if_wrapped"),
Map.entry("separateLines", "separate_lines"),
Map.entry("preservePositions", "preserve_positions"),
Map.entry("never", "one_line_never"),
Map.entry("ifEmpty", "one_line_if_empty"),
Map.entry("ifSingleItem", "one_line_if_single_item"),
Map.entry("always", "one_line_always"),
Map.entry("preserve", "one_line_preserve"),
Map.entry("doNotInsert", "do not insert"),
Map.entry("endOfLine", "end_of_line"),
Map.entry("nextLine", "next_line"),
Map.entry("nextLineIndented", "next_line_indented"),
Map.entry("nextLineOnWrap", "next_line_on_wrap")
);
// @formatter:on

/**
* Convert known language server formatter options to eclipse formatter
* settings.
*
* @param lsOptions
* the given language server formatter options
* @return the converted eclipse formatter options
*/
public static Map<String, String> toEclipseOptions(Map<String, String> lsOptions) {
return lsOptions.entrySet().stream().filter(option -> eclipseOptions.containsKey(option.getKey())).collect(Collectors.toMap(option -> eclipseOptions.get(option.getKey()), option -> {
String value = option.getValue();
if (valueMap.containsKey(value)) {
return valueMap.get(value);
}
return value;
}));
}

/**
* Convert language server formatter alignment value to eclipse formatter
* alignment value.
*
* @param alignmentValue
* the given language server formatter alignment value
* @return the converted eclipse formatter alignment value
*/
public static String getEclipseAlignmentValue(Map<String, Object> alignmentValue) {
Object forceSplit = alignmentValue.getOrDefault("force.split", Boolean.FALSE);
Object indentationStyle = alignmentValue.getOrDefault("indentation.style", "indentDefault");
Object wrappingStyle = alignmentValue.getOrDefault("wrapping.style", "compact");
if (forceSplit instanceof Boolean forceSplitBoolean && indentationStyle instanceof String indentationStyleString && wrappingStyle instanceof String wrappingStyleString) {
int indentationStyleInt = 0;
switch (indentationStyleString) {
case "indentDefault":
indentationStyleInt = DefaultCodeFormatterConstants.INDENT_DEFAULT;
break;
case "indentOnColumn":
indentationStyleInt = DefaultCodeFormatterConstants.INDENT_ON_COLUMN;
break;
case "indentByOne":
indentationStyleInt = DefaultCodeFormatterConstants.INDENT_BY_ONE;
break;
default:
return null;
}
int wrappingStyleInt = 0;
switch (wrappingStyleString) {
case "noSplit":
wrappingStyleInt = DefaultCodeFormatterConstants.WRAP_NO_SPLIT;
break;
case "compact":
wrappingStyleInt = DefaultCodeFormatterConstants.WRAP_COMPACT;
break;
case "compactFirstBreak":
wrappingStyleInt = DefaultCodeFormatterConstants.WRAP_COMPACT_FIRST_BREAK;
break;
case "onePerLine":
wrappingStyleInt = DefaultCodeFormatterConstants.WRAP_ONE_PER_LINE;
break;
case "nextShifted":
wrappingStyleInt = DefaultCodeFormatterConstants.WRAP_NEXT_SHIFTED;
break;
case "nextPerLine":
wrappingStyleInt = DefaultCodeFormatterConstants.WRAP_NEXT_PER_LINE;
break;
default:
return null;
}
return DefaultCodeFormatterConstants.createAlignmentValue(forceSplitBoolean, wrappingStyleInt, indentationStyleInt);
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ public class Preferences {
*/
public static final String JAVA_CONFIGURATION_RUNTIMES = "java.configuration.runtimes";
public static final List<String> JAVA_CONFIGURATION_RUNTIMES_DEFAULT;
/**
* Specifies the java formatter scheme.
*/
public static final String JAVA_FORMATTER_SCHEME = "java.format.scheme";
/**
* Specifies the file path or url to the formatter xml url.
*/
Expand Down Expand Up @@ -619,6 +623,8 @@ public class Preferences {
private String formatterUrl;
private String settingsUrl;
private String formatterProfileName;
private Map<String, String> formatterSettings;
private FormatterScheme formatterScheme;
private Collection<IPath> rootPaths;
private Collection<IPath> triggerFiles;
private Collection<IPath> projectConfigurations;
Expand Down Expand Up @@ -722,6 +728,22 @@ static FeatureStatus fromString(String value, FeatureStatus defaultStatus) {
}
}

public static enum FormatterScheme {
eclipse;

static FormatterScheme fromString(String value, FormatterScheme defaultValue) {
if (value != null) {
String val = value.toLowerCase();
try {
return valueOf(val);
} catch (Exception e) {
//fall back to default severity
}
}
return defaultValue;
}
}

public static class ReferencedLibraries {
private Set<String> include;
private Set<String> exclude;
Expand Down Expand Up @@ -850,6 +872,8 @@ public Preferences() {
formatterUrl = null;
settingsUrl = null;
formatterProfileName = null;
formatterSettings = new HashMap<>();
formatterScheme = FormatterScheme.eclipse;
importOrder = JAVA_IMPORT_ORDER_DEFAULT;
filteredTypes = JAVA_COMPLETION_FILTERED_TYPES_DEFAULT;
parallelBuildsCount = PreferenceInitializer.PREF_MAX_CONCURRENT_BUILDS_DEFAULT;
Expand Down Expand Up @@ -1122,6 +1146,52 @@ public static Preferences createFrom(Map<String, Object> configuration) {
boolean javaFormatComments = getBoolean(configuration, JAVA_FORMAT_COMMENTS, true);
prefs.setJavaFormatComments(javaFormatComments);

String formatterSchemeString = getString(configuration, JAVA_FORMATTER_SCHEME);
if (formatterSchemeString != null) {
FormatterScheme formatterScheme = FormatterScheme.fromString(formatterSchemeString, FormatterScheme.eclipse);
if (formatterScheme != null) {
prefs.setFormatterScheme(formatterScheme);
}
} else {
Object formatterSchemeValue = getValue(configuration, JAVA_FORMATTER_SCHEME);
if (formatterSchemeValue instanceof Map) {
Map<String, Object> formatterSchemeValueMap = (Map<String, Object>) formatterSchemeValue;
Object style = formatterSchemeValueMap.getOrDefault("style", FormatterScheme.eclipse.toString());
if (style instanceof String schemeString) {
FormatterScheme formatterScheme = FormatterScheme.fromString(schemeString, FormatterScheme.eclipse);
if (formatterScheme != null) {
prefs.setFormatterScheme(formatterScheme);
}
}
Object path = formatterSchemeValueMap.getOrDefault("path", null);
if (path instanceof String pathString) {
prefs.setFormatterUrl(pathString);
}
Object profile = formatterSchemeValueMap.getOrDefault("profile", null);
if (profile instanceof String profileString) {
prefs.setFormatterProfileName(profileString);
}
Object configurations = formatterSchemeValueMap.getOrDefault("configurations", new HashMap<>());
if (configurations instanceof Map) {
Map<String, Object> configurationMap = (Map<String, Object>) configurations;
Map<String, String> formatterSettingsMap = new HashMap<>();
configurationMap.forEach((k, v) -> {
Object value = v;
if (value instanceof Double d) {
value = d.intValue();
} else if (value instanceof Map) {
Map<String, Object> valueMap = (Map<String, Object>) value;
value = FormatterPreferences.getEclipseAlignmentValue(valueMap);
}
if (value != null) {
formatterSettingsMap.put(String.valueOf(k), String.valueOf(value));
}
});
prefs.setFormatterSettings(formatterSettingsMap);
}
}
}

List<String> javaImportOrder = getList(configuration, JAVA_IMPORT_ORDER_KEY, JAVA_IMPORT_ORDER_DEFAULT);
prefs.setImportOrder(javaImportOrder);

Expand Down Expand Up @@ -1288,6 +1358,15 @@ public Preferences setSettingsUrl(String settingsUrl) {
return this;
}

public Preferences setFormatterSettings(Map<String, String> formatterSettings) {
this.formatterSettings = formatterSettings;
return this;
}

public void setFormatterScheme(FormatterScheme formatterScheme) {
this.formatterScheme = formatterScheme;
}

public Preferences setResourceFilters(List<String> resourceFilters) {
this.resourceFilters = resourceFilters == null ? new ArrayList<>() : resourceFilters;
return this;
Expand Down Expand Up @@ -1607,6 +1686,10 @@ public URI getFormatterAsURI() {
return asURI(formatterUrl);
}

public Map<String, String> getFormatterSettings() {
return this.formatterSettings;
}

public String getSettingsUrl() {
return settingsUrl;
}
Expand Down

0 comments on commit 934f22e

Please sign in to comment.