From e81fc858bcf33fcc2e9e7277e4766e32da720222 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 29 Sep 2016 07:54:43 +0200 Subject: [PATCH] do not write unmodified user copy of editor color scheme --- .../src/DirectoryBasedStorage.kt | 2 +- .../src/SchemeManagerImpl.kt | 92 +++++++-------- .../src/schemeLoader.kt | 40 +++++++ .../colors/impl/AbstractColorsScheme.java | 108 ++++++++++++------ .../colors/impl/DefaultColorsScheme.java | 8 +- .../colors/impl/EditorColorsSchemeImpl.java | 60 +++++----- .../options/colors/ColorAndFontOptions.java | 39 +++---- .../options/colors/SchemesPanel.java | 12 +- .../application/options/SaveSchemeDialog.java | 3 +- .../colors/impl/EditorColorsManagerImpl.java | 28 ++++- .../src/com/intellij/util/containers/util.kt | 11 +- .../configurationStore/scheme-impl.kt | 7 +- .../openapi/options/SchemeManager.java | 2 + 13 files changed, 258 insertions(+), 154 deletions(-) diff --git a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt index cc28a60b6b18..4b2a1519627e 100644 --- a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt +++ b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt @@ -204,7 +204,7 @@ open class DirectoryBasedStorage(private val dir: Path, storeElement.setAttribute(FileStorageCoreUtil.NAME, storage.componentName!!) storeElement.addContent(element) - val file = getFile(fileName, dir, this) + val file = dir.getOrCreateChild(fileName, this) // we don't write xml prolog due to historical reasons (and should not in any case) writeFile(null, this, file, storeElement, LineSeparator.fromString(if (file.exists()) loadFile(file).second else SystemProperties.getLineSeparator()), false) } diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index 9aaa33d6c372..eb9b341f4316 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -25,26 +25,25 @@ import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil.DEFAULT_E import com.intellij.openapi.diagnostic.catchAndLog import com.intellij.openapi.extensions.AbstractExtensionPointBean import com.intellij.openapi.options.* -import com.intellij.openapi.project.ProjectBundle import com.intellij.openapi.util.Condition -import com.intellij.openapi.util.JDOMUtil import com.intellij.openapi.util.WriteExternalException import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtilRt -import com.intellij.openapi.vfs.* +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.SafeWriteRequestor +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.NewVirtualFile import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent import com.intellij.openapi.vfs.newvfs.events.VFileEvent -import com.intellij.util.PathUtil -import com.intellij.util.PathUtilRt -import com.intellij.util.SmartList +import com.intellij.util.* import com.intellij.util.containers.ConcurrentList import com.intellij.util.containers.ContainerUtil +import com.intellij.util.containers.catch import com.intellij.util.io.* -import com.intellij.util.loadElement import com.intellij.util.messages.MessageBus import com.intellij.util.text.UniqueNameGenerator import gnu.trove.THashSet @@ -575,7 +574,7 @@ class SchemeManagerImpl(val fileSpec: String, val currentFileNameWithoutExtension = externalInfo?.fileNameWithoutExtension val parent = processor.writeScheme(scheme) val element = if (parent is Element) parent else (parent as Document).detachRootElement() - if (JDOMUtil.isEmpty(element)) { + if (element.isEmpty()) { externalInfo?.scheduleDelete() return } @@ -591,9 +590,7 @@ class SchemeManagerImpl(val fileSpec: String, } // save only if scheme differs from bundled - val bundledScheme = readOnlyExternalizableSchemes.get(scheme.name) - if (bundledScheme != null && schemeToInfo.get(bundledScheme)?.isDigestEquals(newDigest) ?: false) { - externalInfo?.scheduleDelete() + if (isEqualToBundledScheme(externalInfo, newDigest, scheme)) { return } @@ -642,7 +639,7 @@ class SchemeManagerImpl(val fileSpec: String, } if (file == null) { - file = getFile(fileName, dir, this) + file = dir.getOrCreateChild(fileName, this) } runWriteAction { @@ -676,6 +673,38 @@ class SchemeManagerImpl(val fileSpec: String, externalInfo.schemeName = scheme.name } + private fun isEqualToBundledScheme(externalInfo: ExternalInfo?, newDigest: ByteArray, scheme: MUTABLE_SCHEME): Boolean { + fun serializeIfPossible(scheme: T): Element? { + LOG.catchAndLog { + @Suppress("UNCHECKED_CAST") + val bundledAsMutable = scheme as? MUTABLE_SCHEME ?: return null + return processor.writeScheme(bundledAsMutable) as Element + } + return null + } + + val bundledScheme = readOnlyExternalizableSchemes.get(scheme.name) + if (bundledScheme == null) { + if ((processor as? LazySchemeProcessor)?.let { it.isSchemeEqualToBundled(scheme) } ?: false) { + externalInfo?.scheduleDelete() + return true + } + return false + } + + val bundledExternalInfo = schemeToInfo.get(bundledScheme) ?: return false + if (bundledExternalInfo.digest == null) { + serializeIfPossible(bundledScheme)?.let { + bundledExternalInfo.digest = it.digest() + } ?: return false + } + if (bundledExternalInfo.isDigestEquals(newDigest)) { + externalInfo?.scheduleDelete() + return true + } + return false + } + private fun ExternalInfo.scheduleDelete() { filesToDelete.add(fileName) } @@ -930,25 +959,6 @@ class SchemeManagerImpl(val fileSpec: String, override fun isMetadataEditable(scheme: T) = !readOnlyExternalizableSchemes.containsKey(scheme.name) - private class ExternalInfo(var fileNameWithoutExtension: String, var fileExtension: String?) { - // we keep it to detect rename - var schemeName: String? = null - - var digest: ByteArray? = null - - val fileName: String - get() = "$fileNameWithoutExtension$fileExtension" - - fun setFileNameWithoutExtension(nameWithoutExtension: String, extension: String) { - fileNameWithoutExtension = nameWithoutExtension - fileExtension = extension - } - - fun isDigestEquals(newDigest: ByteArray) = Arrays.equals(digest, newDigest) - - override fun toString() = fileName - } - override fun toString() = fileSpec } @@ -959,26 +969,6 @@ private fun ExternalizableScheme.renameScheme(newName: String) { } } -private inline fun MutableList.catch(runnable: () -> Unit) { - try { - runnable() - } - catch (e: Throwable) { - add(e) - } -} - -fun createDir(ioDir: Path, requestor: Any): VirtualFile { - ioDir.createDirectories() - val parentFile = ioDir.parent - val parentVirtualFile = (if (parentFile == null) null else VfsUtil.createDirectoryIfMissing(parentFile.systemIndependentPath)) ?: throw IOException(ProjectBundle.message("project.configuration.save.file.not.found", parentFile)) - return getFile(ioDir.fileName.toString(), parentVirtualFile, requestor) -} - -fun getFile(fileName: String, parent: VirtualFile, requestor: Any): VirtualFile { - return parent.findChild(fileName) ?: runWriteAction { parent.createChildData(requestor, fileName) } -} - private inline fun catchAndLog(fileName: String, runnable: (fileName: String) -> Unit) { try { runnable(fileName) diff --git a/platform/configuration-store-impl/src/schemeLoader.kt b/platform/configuration-store-impl/src/schemeLoader.kt index 4a69c29009ec..ee780abac95c 100644 --- a/platform/configuration-store-impl/src/schemeLoader.kt +++ b/platform/configuration-store-impl/src/schemeLoader.kt @@ -1,7 +1,16 @@ package com.intellij.configurationStore +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.project.ProjectBundle +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.io.createDirectories +import com.intellij.util.io.systemIndependentPath import org.xmlpull.mxp1.MXParser import org.xmlpull.v1.XmlPullParser +import java.io.IOException +import java.nio.file.Path +import java.util.* internal inline fun lazyPreloadScheme(bytes: ByteArray, isUseOldFileNameSanitize: Boolean, consumer: (name: String?, parser: XmlPullParser) -> Unit) { val parser = MXParser() @@ -49,4 +58,35 @@ private fun preload(isUseOldFileNameSanitize: Boolean, parser: MXParser): String } while (eventType != XmlPullParser.END_DOCUMENT) return null +} + +internal class ExternalInfo(var fileNameWithoutExtension: String, var fileExtension: String?) { + // we keep it to detect rename + var schemeName: String? = null + + var digest: ByteArray? = null + + val fileName: String + get() = "$fileNameWithoutExtension$fileExtension" + + fun setFileNameWithoutExtension(nameWithoutExtension: String, extension: String) { + fileNameWithoutExtension = nameWithoutExtension + fileExtension = extension + } + + fun isDigestEquals(newDigest: ByteArray) = Arrays.equals(digest, newDigest) + + override fun toString() = fileName +} + +internal fun VirtualFile.getOrCreateChild(fileName: String, requestor: Any): VirtualFile { + return findChild(fileName) ?: runWriteAction { createChildData(requestor, fileName) } +} + +internal fun createDir(ioDir: Path, requestor: Any): VirtualFile { + ioDir.createDirectories() + val parentFile = ioDir.parent + val parentVirtualFile = (if (parentFile == null) null else VfsUtil.createDirectoryIfMissing(parentFile.systemIndependentPath)) + ?: throw IOException(ProjectBundle.message("project.configuration.save.file.not.found", parentFile)) + return parentVirtualFile.getOrCreateChild(ioDir.fileName.toString(), requestor) } \ No newline at end of file diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java index 5def887f1990..12420c103d9c 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java @@ -17,6 +17,7 @@ package com.intellij.openapi.editor.colors.impl; import com.intellij.application.options.EditorFontsConstants; +import com.intellij.configurationStore.SerializableScheme; import com.intellij.ide.ui.ColorBlindness; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.application.ex.ApplicationInfoEx; @@ -26,6 +27,7 @@ import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager; import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.options.FontSize; +import com.intellij.openapi.options.SchemeManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.WriteExternalException; @@ -49,7 +51,7 @@ import static com.intellij.openapi.editor.colors.EditorColors.*; import static com.intellij.openapi.util.Couple.of; import static com.intellij.ui.ColorUtil.fromHex; -public abstract class AbstractColorsScheme implements EditorColorsScheme { +public abstract class AbstractColorsScheme implements EditorColorsScheme, SerializableScheme { private static final int CURR_VERSION = 142; private static final FontSize DEFAULT_FONT_SIZE = FontSize.SMALL; @@ -340,28 +342,28 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { } myMetaInfo.clear(); - for (final Object o : node.getChildren()) { - Element childNode = (Element)o; + for (Element childNode : node.getChildren()) { String childName = childNode.getName(); - if (OPTION_ELEMENT.equals(childName)) { - readSettings(childNode, isDefault); + switch (childName) { + case OPTION_ELEMENT: + readSettings(childNode, isDefault); + break; + case EDITOR_FONT: + readFontSettings(childNode, myFontPreferences, isDefault); + break; + case CONSOLE_FONT: + readFontSettings(childNode, myConsoleFontPreferences, isDefault); + break; + case COLORS_ELEMENT: + readColors(childNode); + break; + case ATTRIBUTES_ELEMENT: + readAttributes(childNode); + break; + case META_INFO_ELEMENT: + readMetaInfo(childNode); + break; } - else if (EDITOR_FONT.equals(childName)) { - readFontSettings(childNode, myFontPreferences, isDefault); - } - else if (CONSOLE_FONT.equals(childName)) { - readFontSettings(childNode, myConsoleFontPreferences, isDefault); - } - else if (COLORS_ELEMENT.equals(childName)) { - readColors(childNode); - } - else if (ATTRIBUTES_ELEMENT.equals(childName)) { - readAttributes(childNode); - } - else if(META_INFO_ELEMENT.equals(childName)) { - readMetaInfo(childNode); - } - } if (myDeprecatedBackgroundColor != null) { @@ -526,8 +528,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { } } - public void - writeExternal(Element parentNode) throws WriteExternalException { + public void writeExternal(Element parentNode) { parentNode.setAttribute(NAME_ATTR, getName()); parentNode.setAttribute(VERSION_ATTR, Integer.toString(myVersion)); @@ -606,10 +607,10 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { writeColors(colorElements); writeAttributes(attrElements); - if (colorElements.getChildren().size() > 0) { + if (!colorElements.getChildren().isEmpty()) { parentNode.addContent(colorElements); } - if (attrElements.getChildren().size() > 0) { + if (!attrElements.getChildren().isEmpty()) { parentNode.addContent(attrElements); } @@ -676,9 +677,8 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { private Element metaInfoToElement() { Element metaInfoElement = new Element(META_INFO_ELEMENT); myMetaInfo.setProperty(META_INFO_MODIFIED_TIME, META_INFO_DATE_FORMAT.format(new Date())); - ArrayList sortedPropertyNames = new ArrayList<>(myMetaInfo.size()); - sortedPropertyNames.addAll(myMetaInfo.stringPropertyNames()); - Collections.sort(sortedPropertyNames); + List sortedPropertyNames = new ArrayList<>(myMetaInfo.stringPropertyNames()); + sortedPropertyNames.sort(null); for (String propertyName : sortedPropertyNames) { String value = myMetaInfo.getProperty(propertyName); Element propertyInfo = new Element(PROPERTY_ELEMENT); @@ -704,8 +704,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { private void writeColors(Element colorElements) { List list = new ArrayList<>(myColorsMap.keySet()); - Collections.sort(list); - + list.sort(null); for (ColorKey key : list) { if (haveToWrite(key)) { Color value = myColorsMap.get(key); @@ -857,12 +856,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { public static String getDisplayName(@NotNull EditorColorsScheme scheme) { String schemeName = scheme.getName(); return - schemeName.startsWith(DefaultColorsScheme.EDITABLE_COPY_PREFIX) ? - schemeName.substring(DefaultColorsScheme.EDITABLE_COPY_PREFIX.length()) : + schemeName.startsWith(SchemeManager.EDITABLE_COPY_PREFIX) ? + schemeName.substring(SchemeManager.EDITABLE_COPY_PREFIX.length()) : schemeName; } - - + @Nullable public AbstractColorsScheme getOriginal() { String originalSchemeName = getMetaProperties().getProperty(META_INFO_ORIGINAL); @@ -872,4 +870,46 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { } return null; } + + @NotNull + @Override + public Element writeScheme() { + Element root = new Element("scheme"); + writeExternal(root); + return root; + } + + public boolean isEqualToBundled(AbstractColorsScheme bundledScheme) { + // parent is used only for default schemes (e.g. Darcula — bundled in all ide (opposite to IDE-specific, like Cobalt)) + if (myParentScheme != bundledScheme.myParentScheme && myParentScheme != bundledScheme) { + return false; + } + + for (String propertyName : myMetaInfo.stringPropertyNames()) { + if (propertyName.equals(META_INFO_CREATION_TIME) || + propertyName.equals(META_INFO_MODIFIED_TIME) || + propertyName.equals(META_INFO_IDE) || + propertyName.equals(META_INFO_IDE_VERSION) || + propertyName.equals(META_INFO_ORIGINAL) + ) { + continue; + } + + if (!Comparing.equal(myMetaInfo.getProperty(propertyName), bundledScheme.myMetaInfo.getProperty(propertyName))) { + return false; + } + } + + return getLineSpacing() == bundledScheme.getLineSpacing() && + getConsoleLineSpacing() == bundledScheme.getConsoleLineSpacing() && + getQuickDocFontSize() == bundledScheme.getQuickDocFontSize() && + myFontPreferences.getRealFontFamilies().equals(bundledScheme.myFontPreferences.getRealFontFamilies()) && + myFontPreferences.useLigatures() == bundledScheme.myFontPreferences.useLigatures() && + myConsoleFontPreferences.useLigatures() == bundledScheme.myConsoleFontPreferences.useLigatures() && + myConsoleFontPreferences.getRealFontFamilies().equals(bundledScheme.myConsoleFontPreferences.getRealFontFamilies()) && + myColorsMap.equals(bundledScheme.myColorsMap) && + myAttributesMap.equals(bundledScheme.myAttributesMap) && + myFontPreferences.equals(bundledScheme.myFontPreferences) && + myConsoleFontPreferences.equals(bundledScheme.myConsoleFontPreferences); + } } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/DefaultColorsScheme.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/DefaultColorsScheme.java index ab7e65b39641..c3254814cf81 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/DefaultColorsScheme.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/DefaultColorsScheme.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.SchemeManager; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,9 +28,6 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; public class DefaultColorsScheme extends AbstractColorsScheme implements ReadOnlyColorsScheme { - - public final static String EDITABLE_COPY_PREFIX = "_@user_"; - private String myName; public DefaultColorsScheme() { @@ -77,7 +75,7 @@ public class DefaultColorsScheme extends AbstractColorsScheme implements ReadOnl } @Override - public void setAttributes(TextAttributesKey key, TextAttributes attributes) { + public void setAttributes(@NotNull TextAttributesKey key, TextAttributes attributes) { } @Override @@ -107,7 +105,7 @@ public class DefaultColorsScheme extends AbstractColorsScheme implements ReadOnl } public String getEditableCopyName() { - return EDITABLE_COPY_PREFIX + myName; + return SchemeManager.EDITABLE_COPY_PREFIX + myName; } @Override diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EditorColorsSchemeImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EditorColorsSchemeImpl.java index 17ecad114fd0..e6d171104484 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EditorColorsSchemeImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EditorColorsSchemeImpl.java @@ -15,14 +15,12 @@ */ package com.intellij.openapi.editor.colors.impl; -import com.intellij.configurationStore.SerializableScheme; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.options.ExternalizableScheme; import com.intellij.openapi.util.Comparing; -import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,16 +29,24 @@ import java.awt.*; /** * @author Yura Cangea */ -public class EditorColorsSchemeImpl extends AbstractColorsScheme implements ExternalizableScheme, SerializableScheme { +public class EditorColorsSchemeImpl extends AbstractColorsScheme implements ExternalizableScheme { public EditorColorsSchemeImpl(EditorColorsScheme parentScheme) { super(parentScheme); } @Override - public void setAttributes(TextAttributesKey key, TextAttributes attributes) { - if (attributes != getAttributes(key)) { - myAttributesMap.put(key, attributes); + public void setAttributes(@NotNull TextAttributesKey key, TextAttributes attributes) { + TextAttributes ownAttributes = getOwnAttributes(key); + if (ownAttributes != null && ownAttributes.equals(attributes)) { + return; } + TextAttributes parentAttributes = myParentScheme.getAttributes(key); + if (parentAttributes != null && parentAttributes.equals(attributes)) { + myAttributesMap.remove(key); + return; + } + + myAttributesMap.put(key, attributes); } @Override @@ -51,20 +57,30 @@ public class EditorColorsSchemeImpl extends AbstractColorsScheme implements Exte } @Override - public TextAttributes getAttributes(TextAttributesKey key) { - if (key != null) { - TextAttributesKey fallbackKey = key.getFallbackAttributeKey(); - TextAttributes attributes = getDirectlyDefinedAttributes(key); - if (fallbackKey == null) { - if (containsValue(attributes)) return attributes; - } - else { - if (containsValue(attributes) && !attributes.isFallbackEnabled()) return attributes; - attributes = getFallbackAttributes(fallbackKey); - if (containsValue(attributes)) return attributes; + public TextAttributes getAttributes(@Nullable TextAttributesKey key) { + TextAttributes attributes = key == null ? null : getOwnAttributes(key); + return attributes == null ? myParentScheme.getAttributes(key) : attributes; + } + + @Nullable + private TextAttributes getOwnAttributes(@NotNull TextAttributesKey key) { + TextAttributesKey fallbackKey = key.getFallbackAttributeKey(); + TextAttributes attributes = getDirectlyDefinedAttributes(key); + if (fallbackKey == null) { + if (containsValue(attributes)) { + return attributes; } } - return myParentScheme.getAttributes(key); + else { + if (containsValue(attributes) && !attributes.isFallbackEnabled()) { + return attributes; + } + attributes = getFallbackAttributes(fallbackKey); + if (containsValue(attributes)) { + return attributes; + } + } + return null; } @Nullable @@ -86,12 +102,4 @@ public class EditorColorsSchemeImpl extends AbstractColorsScheme implements Exte newScheme.setDefaultMetaInfo(this); return newScheme; } - - @NotNull - @Override - public Element writeScheme() { - Element root = new Element("scheme"); - writeExternal(root); - return root; - } } diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index 0c76b11de507..e3fc61515212 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -27,7 +27,6 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.*; import com.intellij.openapi.editor.colors.impl.*; import com.intellij.openapi.editor.markup.EffectType; @@ -74,8 +73,6 @@ import java.util.List; public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider { public static final String ID = "reference.settingsdialog.IDE.editor.colors"; - private static Logger LOG = Logger.getInstance("#" + ColorAndFontOptions.class.getName()); - private Map mySchemes; private MyColorScheme mySelectedScheme; @@ -208,7 +205,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract EditorColorsScheme clone = (EditorColorsScheme)scheme.getOriginalScheme().clone(); - scheme.apply(clone); + scheme.apply(clone, false); clone.setName(name); MyColorScheme newScheme = new MyColorScheme(clone); @@ -279,12 +276,9 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract boolean activeSchemeModified = false; EditorColorsScheme activeOriginalScheme = mySelectedScheme.getOriginalScheme(); for (MyColorScheme scheme : mySchemes.values()) { - if (!activeSchemeModified && activeOriginalScheme == scheme.getOriginalScheme()) { - activeSchemeModified = scheme.isModified(); - } - - if (!scheme.isDefault()) { - scheme.apply(); + boolean isModified = scheme.apply(); + if (isModified && !activeSchemeModified && activeOriginalScheme == scheme.getOriginalScheme()) { + activeSchemeModified = true; } result.add(scheme.getOriginalScheme()); } @@ -842,7 +836,9 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract @Override public void apply(EditorColorsScheme scheme) { - if (scheme == null) scheme = getScheme(); + if (scheme == null) { + scheme = getScheme(); + } scheme.setAttributes(key, isInherited() ? new TextAttributes() : getTextAttributes()); } @@ -1086,10 +1082,6 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract return myDescriptors; } - public boolean isDefault() { - return myParentScheme instanceof DefaultColorsScheme; - } - @Override public boolean isReadOnly() { return myParentScheme instanceof ReadOnlyColorsScheme; @@ -1123,13 +1115,16 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract return getConsoleLineSpacing() != myParentScheme.getConsoleLineSpacing(); } - public void apply() { + private boolean apply() { if (!(myParentScheme instanceof ReadOnlyColorsScheme)) { - apply(myParentScheme); + return apply(myParentScheme, true); } + return false; } - public void apply(@NotNull EditorColorsScheme scheme) { + private boolean apply(@NotNull EditorColorsScheme scheme, boolean onlyIfModified) { + boolean isModified = isFontModified() || isConsoleFontModified(); + scheme.setFontPreferences(getFontPreferences()); scheme.setLineSpacing(myLineSpacing); scheme.setQuickDocFontSize(getQuickDocFontSize()); @@ -1137,12 +1132,16 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract scheme.setConsoleLineSpacing(getConsoleLineSpacing()); for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) { - descriptor.apply(scheme); + if (!onlyIfModified || descriptor.isModified()) { + isModified = true; + descriptor.apply(scheme); + } } - if (scheme instanceof AbstractColorsScheme) { + if (isModified && scheme instanceof AbstractColorsScheme) { ((AbstractColorsScheme)scheme).setSaveNeeded(true); } + return isModified; } @Override diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java index 547e7af7897c..ea5812a23553 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java @@ -21,12 +21,12 @@ import com.intellij.application.options.SaveSchemeDialog; import com.intellij.application.options.SkipSelfSearchComponent; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.colors.impl.*; +import com.intellij.openapi.editor.colors.impl.AbstractColorsScheme; +import com.intellij.openapi.editor.colors.impl.EditorColorsSchemeImpl; +import com.intellij.openapi.editor.colors.impl.EmptyColorScheme; +import com.intellij.openapi.editor.colors.impl.ReadOnlyColorsScheme; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.options.SchemeImportException; -import com.intellij.openapi.options.SchemeImportUtil; -import com.intellij.openapi.options.SchemeImporter; -import com.intellij.openapi.options.SchemeImporterEP; +import com.intellij.openapi.options.*; import com.intellij.openapi.project.DefaultProjectFactory; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.MessageType; @@ -83,7 +83,7 @@ public class SchemesPanel extends JPanel implements SkipSelfSearchComponent { selected instanceof AbstractColorsScheme ? ((AbstractColorsScheme)selected).getOriginal() : null; myResetButton.setEnabled( !readOnly && - selectedName.startsWith(DefaultColorsScheme.EDITABLE_COPY_PREFIX) && + selectedName.startsWith(SchemeManager.EDITABLE_COPY_PREFIX) && originalScheme instanceof ReadOnlyColorsScheme); } } diff --git a/platform/platform-impl/src/com/intellij/application/options/SaveSchemeDialog.java b/platform/platform-impl/src/com/intellij/application/options/SaveSchemeDialog.java index 4ad5df4f2a05..9a30a3ff26f1 100644 --- a/platform/platform-impl/src/com/intellij/application/options/SaveSchemeDialog.java +++ b/platform/platform-impl/src/com/intellij/application/options/SaveSchemeDialog.java @@ -20,6 +20,7 @@ import com.intellij.CommonBundle; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager; import com.intellij.openapi.editor.colors.impl.DefaultColorsScheme; +import com.intellij.openapi.options.SchemeManager; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.util.text.UniqueNameGenerator; @@ -79,7 +80,7 @@ public class SaveSchemeDialog extends DialogWrapper { } else if ( isDefaultSchemeName(schemeName) || - schemeName.startsWith(DefaultColorsScheme.EDITABLE_COPY_PREFIX)) { + schemeName.startsWith(SchemeManager.EDITABLE_COPY_PREFIX)) { Messages.showMessageDialog(getContentPane(), ApplicationBundle.message("error.illegal.scheme.name"), CommonBundle.getErrorTitle(), Messages.getErrorIcon()); return; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java index 1adb34edb1ac..50e3306a3124 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java @@ -88,8 +88,12 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Pers EditorColorsSchemeImpl scheme = isBundled ? new BundledScheme() : new EditorColorsSchemeImpl(null); // todo be lazy scheme.readExternal(dataHolder.read()); - // https://gist.github.com/develar/6efc34c5f11ad50346e8eaef020b0ee4 - //dataHolder.updateDigest(scheme); + // we don't need to update digest for bundled scheme because + // 1) it can be computed on demand later (because bundled scheme is not mutable) + // 2) in the future user copy of bundled scheme will use bundled scheme as parent (not as full copy) + if (!isBundled) { + //dataHolder.updateDigest(scheme); + } return scheme; } @@ -116,6 +120,21 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Pers public String getSchemeExtension() { return ".icls"; } + + @Override + public boolean isSchemeEqualToBundled(@NotNull EditorColorsSchemeImpl scheme) { + if (!scheme.getName().startsWith(SchemeManager.EDITABLE_COPY_PREFIX)) { + return false; + } + + AbstractColorsScheme bundledScheme = + (AbstractColorsScheme)mySchemeManager.findSchemeByName(scheme.getName().substring(SchemeManager.EDITABLE_COPY_PREFIX.length())); + if (bundledScheme == null) { + return false; + } + + return scheme.isEqualToBundled(bundledScheme); + } } mySchemeManager = schemeManagerFactory.create(FILE_SPEC, new EditorColorSchemeProcessor()); @@ -142,7 +161,6 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Pers loadAdditionalTextAttributes(); } - private void initEditableDefaultSchemesCopies() { for (DefaultColorsScheme defaultScheme : myDefaultColorSchemeManager.getAllSchemes()) { if (defaultScheme.hasEditableCopy()) { @@ -172,7 +190,7 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Pers if (editableCopy == null) { editableCopy = (AbstractColorsScheme)initialScheme.clone(); editableCopy.setName(editableCopyName); - addColorsScheme(editableCopy); + mySchemeManager.addScheme(editableCopy); } editableCopy.setCanBeDeleted(false); } @@ -205,7 +223,7 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Pers } public String getEditableCopyName() { - return DefaultColorsScheme.EDITABLE_COPY_PREFIX + getName(); + return SchemeManager.EDITABLE_COPY_PREFIX + getName(); } } diff --git a/platform/platform-impl/src/com/intellij/util/containers/util.kt b/platform/platform-impl/src/com/intellij/util/containers/util.kt index 0c45fa1e55d5..535b1a47ee41 100644 --- a/platform/platform-impl/src/com/intellij/util/containers/util.kt +++ b/platform/platform-impl/src/com/intellij/util/containers/util.kt @@ -121,4 +121,13 @@ fun Stream?.getIfSingle(): T? = * * Also see [Stream.concat] documentation for other possible issues of concatenating large number of streams. */ -fun concat(vararg streams: Stream): Stream = Stream.of(*streams).reduce(Stream.empty()) { a, b -> Stream.concat(a, b) } \ No newline at end of file +fun concat(vararg streams: Stream): Stream = Stream.of(*streams).reduce(Stream.empty()) { a, b -> Stream.concat(a, b) } + +inline fun MutableList.catch(runnable: () -> Unit) { + try { + runnable() + } + catch (e: Throwable) { + add(e) + } +} \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt index a4d4a7721e16..cc6b497a61ce 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt @@ -62,12 +62,13 @@ abstract class LazySchemeProcessor(pri name: String, attributeProvider: Function, isBundled: Boolean = false): MUTABLE_SCHEME - override final fun writeScheme(scheme: MUTABLE_SCHEME) = (scheme as SerializableScheme).writeScheme() open fun isSchemeFile(name: CharSequence) = true open fun isSchemeDefault(scheme: MUTABLE_SCHEME, digest: ByteArray) = false + + open fun isSchemeEqualToBundled(scheme: MUTABLE_SCHEME) = false } class DigestOutputStream(val digest: MessageDigest) : OutputStream() { @@ -79,9 +80,7 @@ class DigestOutputStream(val digest: MessageDigest) : OutputStream() { digest.update(b, off, len) } - override fun toString(): String { - return "[Digest Output Stream] " + digest.toString() - } + override fun toString() = "[Digest Output Stream] $digest" } fun Element.digest(): ByteArray { diff --git a/platform/projectModel-impl/src/com/intellij/openapi/options/SchemeManager.java b/platform/projectModel-impl/src/com/intellij/openapi/options/SchemeManager.java index 8521c86e4136..66db8f9024a6 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/options/SchemeManager.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/options/SchemeManager.java @@ -25,6 +25,8 @@ import java.util.List; @SuppressWarnings("UnusedParameters") public abstract class SchemeManager { + public final static String EDITABLE_COPY_PREFIX = "_@user_"; + @NotNull public abstract Collection loadSchemes();