From 485dc5269122ff989471d37b7f3826cb5f34bb49 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 14 Mar 2016 17:41:47 +0100 Subject: [PATCH] IDEA-131690 Settings repository plugin: when I merged settings from PyCharm java-related setting was deleted --- .../psi/codeStyle/JavaCodeStyleSettings.java | 8 +- .../testSrc/CodeStyleTest.kt | 45 ++++++++++ platform/lang-api/lang-api.iml | 1 + .../UnknownElementManager.kt | 85 +++++++++++++++++++ .../psi/codeStyle/CodeStyleSettings.java | 20 +++-- .../CommonCodeStyleSettingsManager.java | 2 +- .../codeStyle/CustomCodeStyleSettings.java | 11 ++- .../openapi/util/WriteExternalException.java | 4 +- .../formatter/xml/XmlCodeStyleSettings.java | 4 +- 9 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 platform/configuration-store-impl/testSrc/CodeStyleTest.kt create mode 100644 platform/lang-api/src/com/intellij/configurationStore/UnknownElementManager.kt diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java index fbf3b77ddf20..9a7268339b7e 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,11 +48,7 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings { } @Override - public void importLegacySettings() { - importLegacyUseFqClassNamesInJavadocSetting(); - } - - private void importLegacyUseFqClassNamesInJavadocSetting() { + protected void importLegacySettings() { CodeStyleSettings settings = getContainer(); boolean isDefaultValue = settings.USE_FQ_CLASS_NAMES_IN_JAVADOC; if (!isDefaultValue) { diff --git a/platform/configuration-store-impl/testSrc/CodeStyleTest.kt b/platform/configuration-store-impl/testSrc/CodeStyleTest.kt new file mode 100644 index 000000000000..014e10432220 --- /dev/null +++ b/platform/configuration-store-impl/testSrc/CodeStyleTest.kt @@ -0,0 +1,45 @@ +package com.intellij.configurationStore + +import com.intellij.openapi.util.JDOMUtil +import com.intellij.psi.codeStyle.CodeStyleSettings +import com.intellij.testFramework.ProjectRule +import com.intellij.util.loadElement +import org.assertj.core.api.Assertions.assertThat +import org.jdom.Element +import org.junit.ClassRule +import org.junit.Test + +class CodeStyleTest { + companion object { + @JvmField + @ClassRule + val projectRule = ProjectRule() + } + + @Test fun `do not remove unknown`() { + val settings = CodeStyleSettings() + val loaded = """ + + + + + + + + + + + + """.trimIndent() + settings.readExternal(loadElement(loaded)) + + val serialized = Element("code_scheme").setAttribute("name", "testSchemeName") + settings.writeExternal(serialized) + assertThat(JDOMUtil.writeElement(serialized)).isEqualTo(loaded) + } +} \ No newline at end of file diff --git a/platform/lang-api/lang-api.iml b/platform/lang-api/lang-api.iml index c6851ed56112..f854eaacf13a 100644 --- a/platform/lang-api/lang-api.iml +++ b/platform/lang-api/lang-api.iml @@ -16,5 +16,6 @@ + \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/configurationStore/UnknownElementManager.kt b/platform/lang-api/src/com/intellij/configurationStore/UnknownElementManager.kt new file mode 100644 index 000000000000..0f68e88d8918 --- /dev/null +++ b/platform/lang-api/src/com/intellij/configurationStore/UnknownElementManager.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.configurationStore + +import gnu.trove.THashMap +import gnu.trove.THashSet +import org.jdom.Element +import java.util.function.Consumer +import java.util.function.Function + +// Empty unknown tags supported to simplify client write code (with and without unknown elements) +class UnknownElementWriter internal constructor(private val unknownElements: Map = emptyMap()) { + companion object { + @JvmField + val EMPTY = UnknownElementWriter() + } + + fun write(outElement: Element, items: Collection, itemToTagName: Function, writer: Consumer) { + val knownNameToWriter = THashMap(items.size) + for (item in items) { + knownNameToWriter.put(itemToTagName.apply(item), item) + } + write(outElement, knownNameToWriter, writer) + } + + fun write(outElement: Element, knownNameToWriter: Map, writer: Consumer) { + val names: Set + if (unknownElements.isEmpty()) { + names = knownNameToWriter.keys + } + else { + names = THashSet(unknownElements.keys) + names.addAll(knownNameToWriter.keys) + } + + val sortedNames = names.toTypedArray() + sortedNames.sort() + for (name in sortedNames) { + val known = knownNameToWriter.get(name) + if (known == null) { + outElement.addContent(unknownElements.get(name)!!.clone()) + } + else { + writer.accept(known) + } + } + } +} + +class UnknownElementCollector { + private val knownTagNames = THashSet() + + fun addKnownName(name: String) { + knownTagNames.add(name) + } + + fun createWriter(element: Element): UnknownElementWriter? { + var unknownElements: MutableMap? = null + val iterator = element.children.iterator() + for (child in iterator) { + if (child.name != "option" && !knownTagNames.contains(child.name)) { + if (unknownElements == null) { + unknownElements = THashMap() + } + unknownElements.put(child.name, child) + iterator.remove() + } + } + + return unknownElements?.let { UnknownElementWriter(it) } ?: UnknownElementWriter.EMPTY + } +} \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java index fcff0cbbef86..518fdbe2b5ae 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java @@ -15,6 +15,8 @@ */ package com.intellij.psi.codeStyle; +import com.intellij.configurationStore.UnknownElementCollector; +import com.intellij.configurationStore.UnknownElementWriter; import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -57,6 +59,8 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea @NonNls private static final String FILETYPE = "fileType"; private CommonCodeStyleSettingsManager myCommonSettingsManager = new CommonCodeStyleSettingsManager(this); + private UnknownElementWriter myUnknownElementWriter = UnknownElementWriter.EMPTY; + public CodeStyleSettings() { this(true); } @@ -490,11 +494,14 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY); } } + + UnknownElementCollector unknownElementCollector = new UnknownElementCollector(); for (CustomCodeStyleSettings settings : getCustomSettingsValues()) { + unknownElementCollector.addKnownName(settings.getTagName()); settings.readExternal(element); - settings.importLegacySettings(); } + unknownElementCollector.addKnownName(ADDITIONAL_INDENT_OPTIONS); List list = element.getChildren(ADDITIONAL_INDENT_OPTIONS); if (list != null) { for (Element additionalIndentElement : list) { @@ -512,8 +519,11 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea } } + unknownElementCollector.addKnownName(CommonCodeStyleSettingsManager.COMMON_SETTINGS_TAG); myCommonSettingsManager.readExternal(element); + myUnknownElementWriter = unknownElementCollector.createWriter(element); + if (USE_SAME_INDENTS) { IGNORE_SAME_INDENTS_FOR_LANGUAGES = true; } @@ -523,16 +533,14 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea public void writeExternal(Element element) throws WriteExternalException { final CodeStyleSettings parentSettings = new CodeStyleSettings(); DefaultJDOMExternalizer.writeExternal(this, element, new DifferenceFilter(this, parentSettings)); - List customSettings = new ArrayList(getCustomSettingsValues()); - customSettings.sort((o1, o2) -> o1.getTagName().compareTo(o2.getTagName())); - for (final CustomCodeStyleSettings settings : customSettings) { - final CustomCodeStyleSettings parentCustomSettings = parentSettings.getCustomSettings(settings.getClass()); + myUnknownElementWriter.write(element, getCustomSettingsValues(), CustomCodeStyleSettings::getTagName, settings -> { + CustomCodeStyleSettings parentCustomSettings = parentSettings.getCustomSettings(settings.getClass()); if (parentCustomSettings == null) { throw new WriteExternalException("Custom settings are null for " + settings.getClass()); } settings.writeExternal(element, parentCustomSettings); - } + }); final FileType[] fileTypes = myAdditionalIndentOptions.keySet().toArray(new FileType[myAdditionalIndentOptions.keySet().size()]); Arrays.sort(fileTypes, (o1, o2) -> o1.getDefaultExtension().compareTo(o2.getDefaultExtension())); diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java index be7167d389ef..bc280db0fe54 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java @@ -45,7 +45,7 @@ public class CommonCodeStyleSettingsManager { @NotNull private final CodeStyleSettings myParentSettings; - @NonNls private static final String COMMON_SETTINGS_TAG = "codeStyleSettings"; + @NonNls static final String COMMON_SETTINGS_TAG = "codeStyleSettings"; private static final String LANGUAGE_ATTR = "language"; CommonCodeStyleSettingsManager(@NotNull CodeStyleSettings parentSettings) { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CustomCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CustomCodeStyleSettings.java index 3ccfa1ca4e8c..967cb4d65e82 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CustomCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CustomCodeStyleSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,11 @@ public abstract class CustomCodeStyleSettings implements Cloneable { } public void readExternal(Element parentElement) throws InvalidDataException { - DefaultJDOMExternalizer.readExternal(this, parentElement.getChild(myTagName)); + Element child = parentElement.getChild(myTagName); + if (child != null) { + DefaultJDOMExternalizer.readExternal(this, child); + importLegacySettings(); + } } public void writeExternal(Element parentElement, @NotNull final CustomCodeStyleSettings parentSettings) throws WriteExternalException { @@ -69,7 +73,6 @@ public abstract class CustomCodeStyleSettings implements Cloneable { /** * For compatibility with old code style settings stored in CodeStyleSettings. */ - public void importLegacySettings() { + protected void importLegacySettings() { } - } diff --git a/platform/util/src/com/intellij/openapi/util/WriteExternalException.java b/platform/util/src/com/intellij/openapi/util/WriteExternalException.java index 76714142f974..586a2b520337 100644 --- a/platform/util/src/com/intellij/openapi/util/WriteExternalException.java +++ b/platform/util/src/com/intellij/openapi/util/WriteExternalException.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ package com.intellij.openapi.util; * Throw this exception from {@link JDOMExternalizable#writeExternal(org.jdom.Element)} method if you don't want to store any settings. * If you simply return from the method empty '' tag will be written leading to unneeded modification of configuration files. */ -public class WriteExternalException extends Exception { +public class WriteExternalException extends RuntimeException { public WriteExternalException() { super(); } diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/XmlCodeStyleSettings.java b/xml/impl/src/com/intellij/psi/formatter/xml/XmlCodeStyleSettings.java index 5489e3f75b05..aa52d88f058d 100644 --- a/xml/impl/src/com/intellij/psi/formatter/xml/XmlCodeStyleSettings.java +++ b/xml/impl/src/com/intellij/psi/formatter/xml/XmlCodeStyleSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ public class XmlCodeStyleSettings extends CustomCodeStyleSettings { } @Override - public void importLegacySettings() { + protected void importLegacySettings() { if (!XML_LEGACY_SETTINGS_IMPORTED) { CodeStyleSettings container = getContainer(); CodeStyleSettings defaults = new CodeStyleSettings();