do not write unmodified user copy of editor color scheme

This commit is contained in:
Vladimir Krivosheev
2016-09-29 07:54:43 +02:00
parent bcd7029777
commit e81fc858bc
13 changed files with 258 additions and 154 deletions
@@ -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)
}
@@ -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<T : Scheme, MUTABLE_SCHEME : T>(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<T : Scheme, MUTABLE_SCHEME : T>(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<T : Scheme, MUTABLE_SCHEME : T>(val fileSpec: String,
}
if (file == null) {
file = getFile(fileName, dir, this)
file = dir.getOrCreateChild(fileName, this)
}
runWriteAction {
@@ -676,6 +673,38 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(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<T : Scheme, MUTABLE_SCHEME : T>(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<Throwable>.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)
@@ -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)
}
@@ -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<String> sortedPropertyNames = new ArrayList<>(myMetaInfo.size());
sortedPropertyNames.addAll(myMetaInfo.stringPropertyNames());
Collections.sort(sortedPropertyNames);
List<String> 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<ColorKey> 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);
}
}
@@ -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
@@ -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;
}
}
@@ -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<String, MyColorScheme> 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
@@ -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);
}
}
@@ -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;
@@ -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();
}
}
@@ -121,4 +121,13 @@ fun <T> Stream<T>?.getIfSingle(): T? =
*
* Also see [Stream.concat] documentation for other possible issues of concatenating large number of streams.
*/
fun <T> concat(vararg streams: Stream<T>): Stream<T> = Stream.of(*streams).reduce(Stream.empty()) { a, b -> Stream.concat(a, b) }
fun <T> concat(vararg streams: Stream<T>): Stream<T> = Stream.of(*streams).reduce(Stream.empty()) { a, b -> Stream.concat(a, b) }
inline fun MutableList<Throwable>.catch(runnable: () -> Unit) {
try {
runnable()
}
catch (e: Throwable) {
add(e)
}
}
@@ -62,12 +62,13 @@ abstract class LazySchemeProcessor<SCHEME : Scheme, MUTABLE_SCHEME : SCHEME>(pri
name: String,
attributeProvider: Function<String, String?>,
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 {
@@ -25,6 +25,8 @@ import java.util.List;
@SuppressWarnings("UnusedParameters")
public abstract class SchemeManager<T extends Scheme> {
public final static String EDITABLE_COPY_PREFIX = "_@user_";
@NotNull
public abstract Collection<T> loadSchemes();