Control serialize/deserialize of CommonCodeStyleSettings

This commit is contained in:
Nikolay Krasko
2018-02-04 01:08:14 +03:00
parent 9e22761262
commit 5d25b8b476
3 changed files with 356 additions and 121 deletions
@@ -0,0 +1,198 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter;
import com.intellij.lang.Language;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.DifferenceFilter;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.psi.codeStyle.arrangement.ArrangementSettings;
import com.intellij.psi.codeStyle.arrangement.ArrangementUtil;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.xmlb.XmlSerializer;
import kotlin.collections.ArraysKt;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter")
public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
public KotlinCommonCodeStyleSettings() {
super(KotlinLanguage.INSTANCE);
}
//<editor-fold desc="Copied and adapted from CommonCodeStyleSettings ">
@Override
public void readExternal(Element element) throws InvalidDataException {
super.readExternal(element);
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
CommonCodeStyleSettings defaultSettings = getDefaultSettings();
Set<String> supportedFields = getSupportedFields();
if (supportedFields != null) {
supportedFields.add("FORCE_REARRANGE_MODE");
}
//noinspection deprecation
DefaultJDOMExternalizer.writeExternal(this, element, new SupportedFieldsDiffFilter(this, supportedFields, defaultSettings));
List<Integer> softMargins = getSoftMargins();
serializeInto(softMargins, element);
IndentOptions myIndentOptions = getIndentOptions();
if (myIndentOptions != null) {
IndentOptions defaultIndentOptions = defaultSettings != null ? defaultSettings.getIndentOptions() : null;
Element indentOptionsElement = new Element(INDENT_OPTIONS_TAG);
myIndentOptions.serialize(indentOptionsElement, defaultIndentOptions);
if (!indentOptionsElement.getChildren().isEmpty()) {
element.addContent(indentOptionsElement);
}
}
ArrangementSettings myArrangementSettings = getArrangementSettings();
if (myArrangementSettings != null) {
Element container = new Element(ARRANGEMENT_ELEMENT_NAME);
ArrangementUtil.writeExternal(container, myArrangementSettings, myLanguage);
if (!container.getChildren().isEmpty()) {
element.addContent(container);
}
}
}
@Override
public CommonCodeStyleSettings clone(@NotNull CodeStyleSettings rootSettings) {
CommonCodeStyleSettings commonSettings = new KotlinCommonCodeStyleSettings();
copyPublicFieldsOwn(this, commonSettings);
try {
Method setRootSettingsMethod = CommonCodeStyleSettings.class.getDeclaredMethod("setRootSettings", CodeStyleSettings.class);
setRootSettingsMethod.setAccessible(true);
setRootSettingsMethod.invoke(commonSettings, rootSettings);
}
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
commonSettings.setForceArrangeMenuAvailable(isForceArrangeMenuAvailable());
IndentOptions indentOptions = getIndentOptions();
if (indentOptions != null) {
IndentOptions targetIndentOptions = commonSettings.initIndentOptions();
targetIndentOptions.copyFrom(indentOptions);
}
ArrangementSettings arrangementSettings = getArrangementSettings();
if (arrangementSettings != null) {
commonSettings.setArrangementSettings(arrangementSettings.clone());
}
try {
Method setRootSettingsMethod = ArraysKt.singleOrNull(
CommonCodeStyleSettings.class.getDeclaredMethods(),
method -> "setSoftMargins".equals(method.getName()));
if (setRootSettingsMethod != null) {
// Method was introduced in 173
setRootSettingsMethod.setAccessible(true);
setRootSettingsMethod.invoke(commonSettings, getSoftMargins());
}
}
catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
return commonSettings;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof KotlinCommonCodeStyleSettings)) {
return false;
}
if (!ReflectionUtil.comparePublicNonFinalFields(this, obj)) {
return false;
}
CommonCodeStyleSettings other = (CommonCodeStyleSettings) obj;
if (!getSoftMargins().equals(other.getSoftMargins())) {
return false;
}
IndentOptions options = getIndentOptions();
if ((options == null && other.getIndentOptions() != null) ||
(options != null && !options.equals(other.getIndentOptions()))) {
return false;
}
return arrangementSettingsEqual(other);
}
// SoftMargins.serializeInfo
private void serializeInto(@NotNull List<Integer> softMargins, @NotNull Element element) {
if (softMargins.size() > 0) {
XmlSerializer.serializeInto(this, element);
}
}
//</editor-fold>
//<editor-fold desc="Copied from CommonCodeStyleSettings">
private static final String INDENT_OPTIONS_TAG = "indentOptions";
private static final String ARRANGEMENT_ELEMENT_NAME = "arrangement";
private final Language myLanguage = KotlinLanguage.INSTANCE;
@Nullable
private CommonCodeStyleSettings getDefaultSettings() {
return LanguageCodeStyleSettingsProvider.getDefaultCommonSettings(myLanguage);
}
@Nullable
private Set<String> getSupportedFields() {
final LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(myLanguage);
return provider == null ? null : provider.getSupportedFields();
}
private static class SupportedFieldsDiffFilter extends DifferenceFilter<CommonCodeStyleSettings> {
private final Set<String> mySupportedFieldNames;
public SupportedFieldsDiffFilter(
final CommonCodeStyleSettings object,
Set<String> supportedFiledNames,
final CommonCodeStyleSettings parentObject
) {
super(object, parentObject);
mySupportedFieldNames = supportedFiledNames;
}
@Override
public boolean isAccept(@NotNull Field field) {
if (mySupportedFieldNames == null ||
mySupportedFieldNames.contains(field.getName())) {
return super.isAccept(field);
}
return false;
}
}
// Can't use super.copyPublicFields because the method is internal in 181
private static void copyPublicFieldsOwn(Object from, Object to) {
assert from != to;
com.intellij.util.ReflectionUtil.copyFields(to.getClass().getFields(), from, to);
}
//</editor-fold>
}
@@ -203,45 +203,65 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
"SPACE_BEFORE_CATCH_PARENTHESES" "SPACE_BEFORE_CATCH_PARENTHESES"
); );
showCustomOption(KotlinCodeStyleSettings::SPACE_AROUND_RANGE, showCustomOption(
KotlinCodeStyleSettings::SPACE_AROUND_RANGE,
"Range operator (..)", "Range operator (..)",
CodeStyleSettingsCustomizable.SPACES_AROUND_OPERATORS) CodeStyleSettingsCustomizable.SPACES_AROUND_OPERATORS
)
showCustomOption(KotlinCodeStyleSettings::SPACE_BEFORE_TYPE_COLON, showCustomOption(
KotlinCodeStyleSettings::SPACE_BEFORE_TYPE_COLON,
"Before colon, after declaration name", "Before colon, after declaration name",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_AFTER_TYPE_COLON, showCustomOption(
KotlinCodeStyleSettings::SPACE_AFTER_TYPE_COLON,
"After colon, before declaration type", "After colon, before declaration type",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_BEFORE_EXTEND_COLON, showCustomOption(
KotlinCodeStyleSettings::SPACE_BEFORE_EXTEND_COLON,
"Before colon in new type definition", "Before colon in new type definition",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_AFTER_EXTEND_COLON, showCustomOption(
KotlinCodeStyleSettings::SPACE_AFTER_EXTEND_COLON,
"After colon in new type definition", "After colon in new type definition",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD, showCustomOption(
KotlinCodeStyleSettings::INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD,
"In simple one line methods", "In simple one line methods",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_AROUND_FUNCTION_TYPE_ARROW, showCustomOption(
KotlinCodeStyleSettings::SPACE_AROUND_FUNCTION_TYPE_ARROW,
"Around arrow in function types", "Around arrow in function types",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_AROUND_WHEN_ARROW, showCustomOption(
KotlinCodeStyleSettings::SPACE_AROUND_WHEN_ARROW,
"Around arrow in \"when\" clause", "Around arrow in \"when\" clause",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_BEFORE_LAMBDA_ARROW, showCustomOption(
KotlinCodeStyleSettings::SPACE_BEFORE_LAMBDA_ARROW,
"Before lambda arrow", "Before lambda arrow",
CodeStyleSettingsCustomizable.SPACES_OTHER) CodeStyleSettingsCustomizable.SPACES_OTHER
)
showCustomOption(KotlinCodeStyleSettings::SPACE_BEFORE_WHEN_PARENTHESES, showCustomOption(
KotlinCodeStyleSettings::SPACE_BEFORE_WHEN_PARENTHESES,
"'when' parentheses", "'when' parentheses",
CodeStyleSettingsCustomizable.SPACES_BEFORE_PARENTHESES) CodeStyleSettingsCustomizable.SPACES_BEFORE_PARENTHESES
)
} }
LanguageCodeStyleSettingsProvider.SettingsType.WRAPPING_AND_BRACES_SETTINGS -> { LanguageCodeStyleSettingsProvider.SettingsType.WRAPPING_AND_BRACES_SETTINGS -> {
consumer.showStandardOptions( consumer.showStandardOptions(
@@ -276,35 +296,46 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
) )
consumer.renameStandardOption(CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT, "'when' statements") consumer.renameStandardOption(CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT, "'when' statements")
consumer.renameStandardOption("FIELD_ANNOTATION_WRAP", "Property annotations") consumer.renameStandardOption("FIELD_ANNOTATION_WRAP", "Property annotations")
showCustomOption(KotlinCodeStyleSettings::ALIGN_IN_COLUMNS_CASE_BRANCH, showCustomOption(
KotlinCodeStyleSettings::ALIGN_IN_COLUMNS_CASE_BRANCH,
"Align 'when' branches in columns", "Align 'when' branches in columns",
CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT) CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT
)
showCustomOption(KotlinCodeStyleSettings::LBRACE_ON_NEXT_LINE, showCustomOption(
KotlinCodeStyleSettings::LBRACE_ON_NEXT_LINE,
"Put left brace on new line", "Put left brace on new line",
CodeStyleSettingsCustomizable.WRAPPING_BRACES) CodeStyleSettingsCustomizable.WRAPPING_BRACES
)
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_PARAMETER_LISTS, KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_PARAMETER_LISTS,
"Use continuation indent", "Use continuation indent",
CodeStyleSettingsCustomizable.WRAPPING_METHOD_PARAMETERS) CodeStyleSettingsCustomizable.WRAPPING_METHOD_PARAMETERS
)
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_ARGUMENT_LISTS, KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_ARGUMENT_LISTS,
"Use continuation indent", "Use continuation indent",
CodeStyleSettingsCustomizable.WRAPPING_METHOD_ARGUMENTS_WRAPPING) CodeStyleSettingsCustomizable.WRAPPING_METHOD_ARGUMENTS_WRAPPING
)
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_CHAINED_CALLS, KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_CHAINED_CALLS,
"Use continuation indent", "Use continuation indent",
CodeStyleSettingsCustomizable.WRAPPING_CALL_CHAIN) CodeStyleSettingsCustomizable.WRAPPING_CALL_CHAIN
)
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_SUPERTYPE_LISTS, KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_SUPERTYPE_LISTS,
"Use continuation indent", "Use continuation indent",
CodeStyleSettingsCustomizable.WRAPPING_EXTENDS_LIST) CodeStyleSettingsCustomizable.WRAPPING_EXTENDS_LIST
)
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::WRAP_EXPRESSION_BODY_FUNCTIONS, KotlinCodeStyleSettings::WRAP_EXPRESSION_BODY_FUNCTIONS,
"Expression body functions", "Expression body functions",
options = *arrayOf(CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON, CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON) options = *arrayOf(
CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON,
CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON
)
) )
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_EXPRESSION_BODIES, KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_EXPRESSION_BODIES,
@@ -314,7 +345,10 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::WRAP_ELVIS_EXPRESSIONS, KotlinCodeStyleSettings::WRAP_ELVIS_EXPRESSIONS,
"Elvis expressions", "Elvis expressions",
options = *arrayOf(CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON, CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON) options = *arrayOf(
CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON,
CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON
)
) )
@Suppress("InvalidBundleOrProperty") @Suppress("InvalidBundleOrProperty")
showCustomOption( showCustomOption(
@@ -335,9 +369,11 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
"KEEP_BLANK_LINES_BEFORE_RBRACE", "KEEP_BLANK_LINES_BEFORE_RBRACE",
"BLANK_LINES_AFTER_CLASS_HEADER" "BLANK_LINES_AFTER_CLASS_HEADER"
) )
showCustomOption(KotlinCodeStyleSettings::BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES, showCustomOption(
KotlinCodeStyleSettings::BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES,
"Around 'when' branches with {}", "Around 'when' branches with {}",
CodeStyleSettingsCustomizable.BLANK_LINES) CodeStyleSettingsCustomizable.BLANK_LINES
)
} }
else -> consumer.showStandardOptions() else -> consumer.showStandardOptions()
} }
@@ -345,8 +381,9 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
override fun getIndentOptionsEditor(): IndentOptionsEditor = SmartIndentOptionsEditor() override fun getIndentOptionsEditor(): IndentOptionsEditor = SmartIndentOptionsEditor()
override fun getDefaultCommonSettings(): CommonCodeStyleSettings = override fun getDefaultCommonSettings(): CommonCodeStyleSettings {
CommonCodeStyleSettings(language).apply { return KotlinCommonCodeStyleSettings().apply {
initIndentOptions() initIndentOptions()
} }
}
} }
@@ -103,7 +103,7 @@ public class SettingsConfigurator {
private static boolean setSettingWithField(String settingName, Object object, Object value) { private static boolean setSettingWithField(String settingName, Object object, Object value) {
try { try {
Field field = object.getClass().getDeclaredField(settingName); Field field = object.getClass().getField(settingName);
field.set(object, value); field.set(object, value);
return true; return true;
} }