diff --git a/launch/jdt.ls.remote.server.launch b/launch/jdt.ls.remote.server.launch index 1d8e1a2fcf..dcc44cfdee 100644 --- a/launch/jdt.ls.remote.server.launch +++ b/launch/jdt.ls.remote.server.launch @@ -36,7 +36,7 @@ - + diff --git a/launch/jdt.ls.socket-stream.launch b/launch/jdt.ls.socket-stream.launch index 9dbec2e0b6..88b4236284 100644 --- a/launch/jdt.ls.socket-stream.launch +++ b/launch/jdt.ls.socket-stream.launch @@ -37,7 +37,7 @@ - + diff --git a/org.eclipse.jdt.ls.core/.classpath b/org.eclipse.jdt.ls.core/.classpath index 5e3f97eca3..f16168535a 100644 --- a/org.eclipse.jdt.ls.core/.classpath +++ b/org.eclipse.jdt.ls.core/.classpath @@ -4,6 +4,7 @@ + diff --git a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF index ff4cf7875e..87d440ef96 100644 --- a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF @@ -62,6 +62,7 @@ Export-Package: org.eclipse.jdt.ls.core.contentassist;x-friends:="org.eclipse.jd org.eclipse.lsp4j.legacy.typeHierarchy;x-friends:="org.eclipse.jdt.ls.tests" Bundle-ClassPath: lib/jsoup-1.14.2.jar, lib/remark-1.2.0.jar, + lib/google-java-format-1.13.0.jar, . Bundle-Vendor: %Bundle-Vendor Automatic-Module-Name: org.eclipse.jdt.ls.core diff --git a/org.eclipse.jdt.ls.core/build.properties b/org.eclipse.jdt.ls.core/build.properties index 26d037ace9..a0e3793b69 100644 --- a/org.eclipse.jdt.ls.core/build.properties +++ b/org.eclipse.jdt.ls.core/build.properties @@ -5,6 +5,7 @@ bin.includes = META-INF/,\ plugin.xml,\ lib/jsoup-1.14.2.jar,\ lib/remark-1.2.0.jar,\ + lib/google-java-format-1.13.0.jar,\ lifecycle-mapping-metadata.xml,\ plugin.properties,\ gradle/checksums/checksums.json,\ diff --git a/org.eclipse.jdt.ls.core/pom.xml b/org.eclipse.jdt.ls.core/pom.xml index 3dc4a33950..fdbb99786a 100644 --- a/org.eclipse.jdt.ls.core/pom.xml +++ b/org.eclipse.jdt.ls.core/pom.xml @@ -27,6 +27,11 @@ jsoup 1.14.2 + + com.google.googlejavaformat + google-java-format + 1.13.0 + diff --git a/org.eclipse.jdt.ls.core/src/com/google/googlejavaformat/java/GoogleJavaFormatter.java b/org.eclipse.jdt.ls.core/src/com/google/googlejavaformat/java/GoogleJavaFormatter.java new file mode 100644 index 0000000000..ab59910a18 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/com/google/googlejavaformat/java/GoogleJavaFormatter.java @@ -0,0 +1,130 @@ +package com.google.googlejavaformat.java; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Range; +import com.google.googlejavaformat.java.SnippetFormatter.SnippetKind; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.formatter.CodeFormatter; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.text.edits.TextEdit; + +/** Runs the Google Java formatter on the given code. */ +public class GoogleJavaFormatter extends CodeFormatter { + + private static final int INDENTATION_SIZE = 2; + + @Override + public TextEdit format( + int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) { + IRegion[] regions = new IRegion[] {new Region(offset, length)}; + return formatInternal(kind, source, regions, indentationLevel); + } + + @Override + public TextEdit format( + int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) { + return formatInternal(kind, source, regions, indentationLevel); + } + + @Override + public String createIndentationString(int indentationLevel) { + Preconditions.checkArgument( + indentationLevel >= 0, + "Indentation level cannot be less than zero. Given: %s", + indentationLevel); + int spaces = indentationLevel * INDENTATION_SIZE; + StringBuilder buf = new StringBuilder(spaces); + for (int i = 0; i < spaces; i++) { + buf.append(' '); + } + return buf.toString(); + } + + /** Runs the Google Java formatter on the given source, with only the given ranges specified. */ + private TextEdit formatInternal(int kind, String source, IRegion[] regions, int initialIndent) { + try { + boolean includeComments = + (kind & CodeFormatter.F_INCLUDE_COMMENTS) == CodeFormatter.F_INCLUDE_COMMENTS; + kind &= ~CodeFormatter.F_INCLUDE_COMMENTS; + SnippetKind snippetKind; + switch (kind) { + case ASTParser.K_EXPRESSION: + snippetKind = SnippetKind.EXPRESSION; + break; + case ASTParser.K_STATEMENTS: + snippetKind = SnippetKind.STATEMENTS; + break; + case ASTParser.K_CLASS_BODY_DECLARATIONS: + snippetKind = SnippetKind.CLASS_BODY_DECLARATIONS; + break; + case ASTParser.K_COMPILATION_UNIT: + snippetKind = SnippetKind.COMPILATION_UNIT; + break; + default: + throw new IllegalArgumentException(String.format("Unknown snippet kind: %d", kind)); + } + List replacements = + new SnippetFormatter() + .format( + snippetKind, source, rangesFromRegions(regions), initialIndent, includeComments); + if (idempotent(source, regions, replacements)) { + // Do not create edits if there's no diff. + return null; + } + // Convert replacements to text edits. + return editFromReplacements(replacements); + } catch (IllegalArgumentException | FormatterException exception) { + // Do not format on errors. + return null; + } + } + + private List> rangesFromRegions(IRegion[] regions) { + List> ranges = new ArrayList<>(); + for (IRegion region : regions) { + ranges.add(Range.closedOpen(region.getOffset(), region.getOffset() + region.getLength())); + } + return ranges; + } + + /** @return {@code true} if input and output texts are equal, else {@code false}. */ + private boolean idempotent(String source, IRegion[] regions, List replacements) { + // This implementation only checks for single replacement. + if (replacements.size() == 1) { + Replacement replacement = replacements.get(0); + String output = replacement.getReplacementString(); + // Entire source case: input = output, nothing changed. + if (output.equals(source)) { + return true; + } + // Single region and single replacement case: if they are equal, nothing changed. + if (regions.length == 1) { + Range range = replacement.getReplaceRange(); + String snippet = source.substring(range.lowerEndpoint(), range.upperEndpoint()); + if (output.equals(snippet)) { + return true; + } + } + } + return false; + } + + private TextEdit editFromReplacements(List replacements) { + // Split the replacements that cross line boundaries. + TextEdit edit = new MultiTextEdit(); + for (Replacement replacement : replacements) { + Range replaceRange = replacement.getReplaceRange(); + edit.addChild( + new ReplaceEdit( + replaceRange.lowerEndpoint(), + replaceRange.upperEndpoint() - replaceRange.lowerEndpoint(), + replacement.getReplacementString())); + } + return edit; + } +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java index 2b44431a97..e5922de679 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java @@ -38,7 +38,9 @@ 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.jdt.ls.core.internal.preferences.Preferences.FormatterScheme; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; @@ -56,6 +58,8 @@ import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; +import com.google.googlejavaformat.java.GoogleJavaFormatter; + /** * @author IBM Corporation (Markus Keller) */ @@ -108,18 +112,29 @@ private List format(ICompilationUnit cu, IDocument d return Collections.emptyList(); } - CodeFormatter formatter = ToolFactory.createCodeFormatter(getOptions(options, cu)); + CodeFormatter formatter; + if (this.preferenceManager.getPreferences().getFormatterScheme().equals(FormatterScheme.google)) { + formatter = new GoogleJavaFormatter(); + } else { + formatter = ToolFactory.createCodeFormatter(getOptions(options, cu)); + } String lineDelimiter = TextUtilities.getDefaultLineDelimiter(document); String sourceToFormat = document.get(); int kind = getFormattingKind(cu, includeComments); - TextEdit format = formatter.format(kind, sourceToFormat, region.getOffset(), region.getLength(), 0, lineDelimiter); - if (format == null || format.getChildren().length == 0 || monitor.isCanceled()) { - // nothing to return - return Collections.emptyList(); + + try { + TextEdit format = formatter.format(kind, sourceToFormat, region.getOffset(), region.getLength(), 0, lineDelimiter); + if (format == null || format.getChildren().length == 0 || monitor.isCanceled()) { + // nothing to return + return Collections.emptyList(); + } + MultiTextEdit flatEdit = TextEditUtil.flatten(format); + return convertEdits(flatEdit.getChildren(), document); + } catch (Throwable e) { + JavaLanguageServerPlugin.logException(e); } - MultiTextEdit flatEdit = TextEditUtil.flatten(format); - return convertEdits(flatEdit.getChildren(), document); + return Collections.emptyList(); } private int getFormattingKind(ICompilationUnit cu, boolean includeComments) { @@ -150,6 +165,7 @@ public static Map getOptions(FormattingOptions options, ICompila Map 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) { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/FormatterPreferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/FormatterPreferences.java new file mode 100644 index 0000000000..e548341e50 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/FormatterPreferences.java @@ -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 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 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 toEclipseOptions(Map 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 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; + } +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java index 1a54866d94..c73cbc3f51 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java @@ -114,6 +114,10 @@ public class Preferences { */ public static final String JAVA_CONFIGURATION_RUNTIMES = "java.configuration.runtimes"; public static final List 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. */ @@ -619,6 +623,8 @@ public class Preferences { private String formatterUrl; private String settingsUrl; private String formatterProfileName; + private Map formatterSettings; + private FormatterScheme formatterScheme; private Collection rootPaths; private Collection triggerFiles; private Collection projectConfigurations; @@ -722,6 +728,22 @@ static FeatureStatus fromString(String value, FeatureStatus defaultStatus) { } } + public static enum FormatterScheme { + eclipse, google; + + 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 include; private Set exclude; @@ -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; @@ -1122,6 +1146,52 @@ public static Preferences createFrom(Map 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 formatterSchemeValueMap = (Map) 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 configurationMap = (Map) configurations; + Map formatterSettingsMap = new HashMap<>(); + configurationMap.forEach((k, v) -> { + Object value = v; + if (value instanceof Double d) { + value = d.intValue(); + } else if (value instanceof Map) { + Map valueMap = (Map) value; + value = FormatterPreferences.getEclipseAlignmentValue(valueMap); + } + if (value != null) { + formatterSettingsMap.put(String.valueOf(k), String.valueOf(value)); + } + }); + prefs.setFormatterSettings(formatterSettingsMap); + } + } + } + List javaImportOrder = getList(configuration, JAVA_IMPORT_ORDER_KEY, JAVA_IMPORT_ORDER_DEFAULT); prefs.setImportOrder(javaImportOrder); @@ -1288,6 +1358,15 @@ public Preferences setSettingsUrl(String settingsUrl) { return this; } + public Preferences setFormatterSettings(Map formatterSettings) { + this.formatterSettings = formatterSettings; + return this; + } + + public void setFormatterScheme(FormatterScheme formatterScheme) { + this.formatterScheme = formatterScheme; + } + public Preferences setResourceFilters(List resourceFilters) { this.resourceFilters = resourceFilters == null ? new ArrayList<>() : resourceFilters; return this; @@ -1607,6 +1686,14 @@ public URI getFormatterAsURI() { return asURI(formatterUrl); } + public Map getFormatterSettings() { + return this.formatterSettings; + } + + public FormatterScheme getFormatterScheme() { + return this.formatterScheme; + } + public String getSettingsUrl() { return settingsUrl; }