diff --git a/platform/platform-api/intellij.platform.ide.iml b/platform/platform-api/intellij.platform.ide.iml index ae734b9f1638..79f3ea6c7b12 100644 --- a/platform/platform-api/intellij.platform.ide.iml +++ b/platform/platform-api/intellij.platform.ide.iml @@ -32,7 +32,6 @@ - \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/ide/ui/UITheme.java b/platform/platform-api/src/com/intellij/ide/ui/UITheme.java index 046c4da5f0af..0d8944ae703c 100644 --- a/platform/platform-api/src/com/intellij/ide/ui/UITheme.java +++ b/platform/platform-api/src/com/intellij/ide/ui/UITheme.java @@ -1,14 +1,13 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.ui; -import com.fasterxml.jackson.jr.ob.JSON; +import com.fasterxml.jackson.core.JsonFactory; import com.intellij.AbstractBundle; import com.intellij.DynamicBundle; import com.intellij.ide.plugins.cl.PluginAwareClassLoader; import com.intellij.ide.ui.laf.UIThemeLookAndFeelInfo; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.IconPathPatcher; -import com.intellij.openapi.util.SystemInfoRt; import com.intellij.ui.ColorHexUtil; import com.intellij.ui.Gray; import com.intellij.ui.icons.ImageDataByPathLoader; @@ -31,6 +30,7 @@ import java.awt.*; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; +import java.util.List; import java.util.*; import java.util.function.Function; @@ -44,11 +44,6 @@ public final class UITheme { private final UIThemeBean bean; - private static final String OS_MACOS_KEY = "os.mac"; - private static final String OS_WINDOWS_KEY = "os.windows"; - private static final String OS_LINUX_KEY = "os.linux"; - private static final String OS_DEFAULT_KEY = "os.default"; - private UITheme(@NotNull UIThemeBean bean) { this.bean = bean; } @@ -73,18 +68,9 @@ public final class UITheme { return bean.author; } - // it caches classes - must be not extracted to util class - // .disable(JSON.Feature.PRESERVE_FIELD_ORDERING) - cannot be disabled, for unknown reason order is important, - // for example, button label font color for light theme is not white, but black - private static final JSON JSON_READER = JSON.builder() - .enable(JSON.Feature.READ_ONLY) - .disable(JSON.Feature.USE_DEFERRED_MAPS) - .disable(JSON.Feature.HANDLE_JAVA_BEANS) - .build(); - @ApiStatus.Internal public static @NotNull UITheme loadFromJson(@NotNull InputStream stream, @NotNull @NonNls String themeId) throws IOException { - UIThemeBean theme = JSON_READER.beanFrom(UIThemeBean.class, stream); + UIThemeBean theme = UIThemeBean.Companion.readTheme(new JsonFactory().createParser(stream)); theme.id = themeId; return postProcessTheme(theme, findParentTheme(theme), null, Function.identity()); } @@ -93,7 +79,7 @@ public final class UITheme { @NotNull @NonNls String themeId, @Nullable ClassLoader provider, @NotNull Function iconsMapper) throws IOException { - UIThemeBean theme = JSON_READER.beanFrom(UIThemeBean.class, data); + UIThemeBean theme = UIThemeBean.Companion.readTheme(new JsonFactory().createParser(data)); theme.id = themeId; return postProcessTheme(theme, findParentTheme(theme), provider, iconsMapper); } @@ -105,7 +91,7 @@ public final class UITheme { @NotNull Function iconsMapper, @Nullable UITheme defaultDarkParent, @Nullable UITheme defaultLightParent) throws IOException { - UIThemeBean theme = JSON_READER.beanFrom(UIThemeBean.class, data); + UIThemeBean theme = UIThemeBean.Companion.readTheme(new JsonFactory().createParser(data)); theme.id = themeId; if (theme.dark && parentTheme == null) { return postProcessTheme(theme, defaultDarkParent, provider, iconsMapper); @@ -120,11 +106,9 @@ public final class UITheme { @Nullable UITheme parentTheme, @Nullable ClassLoader provider, @NotNull Function iconsMapper) throws IllegalStateException { - normalizeKeyPaths(theme); if (parentTheme != null) { UIThemeBean.Companion.importFromParentTheme(theme, parentTheme.bean); } - UIThemeBean.Companion.putDefaultsIfAbsent(theme); return new UITheme(loadFromJson(theme, provider, iconsMapper)); } @@ -143,60 +127,6 @@ public final class UITheme { return null; } - /** - * Flatten - *
{@code "Editor": { "SearchField" : { "borderInsets" : "7,10,7,8" } }}
- * to - *
{@code "Editor.SearchField.borderInsets" : "7,10,7,8"}
- * in internal representation. - *

- * We also resolve per-OS keys here: - *

 {@code
-   *  "Menu.borderColor": {
-   *      "os.default": "Grey12",
-   *      "os.windows": "Blue12"
-   *  }
-   * }
- *

- * This is helpful when we need to check if some key was already set in {@link UIThemeBean.Companion#putDefaultsIfAbsent}, - * and to make overriding parentTheme keys independent of used form. - *

- * NB: we intentionally do not expand "*" patterns here. - */ - private static void normalizeKeyPaths(@NotNull UIThemeBean theme) { - if (theme.ui == null) { - return; - } - - Map result = new LinkedHashMap<>(); - for (Map.Entry entry : theme.ui.entrySet()) { - normalizeKeyValue(entry.getKey(), entry.getValue(), result); - } - theme.ui = result; - } - - private static void normalizeKeyValue(@NotNull String keyPrefix, - @NotNull Object value, - @NotNull Map result) { - if (value instanceof Map) { - @SuppressWarnings("unchecked") Map valueMap = (Map)value; - - Object osValue = getOSCustomization(valueMap); - if (osValue == null) { - for (Map.Entry entry : valueMap.entrySet()) { - String uiKey = createUIKey(keyPrefix, entry.getKey()); - normalizeKeyValue(uiKey, entry.getValue(), result); - } - } - else { - normalizeKeyValue(keyPrefix, osValue, result); - } - } - else { - result.put(keyPrefix, value); - } - } - private static @NotNull UIThemeBean loadFromJson(@NotNull UIThemeBean theme, @Nullable ClassLoader provider, @NotNull Function iconsMapper) throws IllegalStateException { @@ -422,7 +352,7 @@ public final class UITheme { return bean.editorScheme; } - public String @Nullable [] getAdditionalEditorSchemes() { + public @Nullable List getAdditionalEditorSchemes() { return bean.additionalEditorSchemes; } @@ -530,18 +460,6 @@ public final class UITheme { } } - private static @Nullable Object getOSCustomization(@NotNull Map map) { - String osKey = SystemInfoRt.isWindows ? OS_WINDOWS_KEY : - SystemInfoRt.isMac ? OS_MACOS_KEY : - SystemInfoRt.isLinux ? OS_LINUX_KEY : null; - if (osKey != null && map.containsKey(osKey)) { - return map.get(osKey); - } - else { - return map.get(OS_DEFAULT_KEY); - } - } - @SuppressWarnings("unchecked") private static void addPattern(String key, Object value, UIDefaults defaults) { Object o = defaults.get("*"); diff --git a/platform/platform-api/src/com/intellij/ide/ui/UIThemeBean.kt b/platform/platform-api/src/com/intellij/ide/ui/UIThemeBean.kt index b2855f7ce032..4a5b4ce85e1c 100644 --- a/platform/platform-api/src/com/intellij/ide/ui/UIThemeBean.kt +++ b/platform/platform-api/src/com/intellij/ide/ui/UIThemeBean.kt @@ -1,35 +1,20 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -@file:Suppress("ReplacePutWithAssignment") +@file:Suppress("ReplacePutWithAssignment", "ReplaceGetOrSet") package com.intellij.ide.ui +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.JsonToken +import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.util.IconPathPatcher -import com.intellij.ui.ExperimentalUI.Companion.isNewUI +import com.intellij.openapi.util.SystemInfoRt +import com.intellij.ui.ExperimentalUI import com.intellij.util.SVGLoader.SvgElementColorPatcherProvider +import java.util.* +import java.util.function.BiFunction internal class UIThemeBean { companion object { - /** - * Ensure that the old themes are not missing some vital keys. - * - * We are patching them here instead of using [com.intellij.ui.JBColor.namedColor] fallback - * to make sure [javax.swing.UIManager.getColor] works properly. - */ - fun putDefaultsIfAbsent(theme: UIThemeBean) { - var ui = theme.ui - if (ui == null) { - ui = LinkedHashMap() - theme.ui = ui - } - if (isNewUI()) { - ui.putIfAbsent("EditorTabs.underlineArc", "4") - - // require theme to specify ToolWindow stripe button colors explicitly, without "*" - ui.putIfAbsent("ToolWindow.Button.selectedBackground", "#3573F0") - ui.putIfAbsent("ToolWindow.Button.selectedForeground", "#FFFFFF") - } - } - fun importFromParentTheme(theme: UIThemeBean, parentTheme: UIThemeBean) { theme.ui = importMapFromParentTheme(theme.ui, parentTheme.ui) theme.icons = importMapFromParentTheme(theme.icons, parentTheme.icons) @@ -39,7 +24,8 @@ internal class UIThemeBean { theme.iconColorsOnSelection = importMapFromParentTheme(theme.iconColorsOnSelection, parentTheme.iconColorsOnSelection) } - private fun importMapFromParentTheme(themeMap: MutableMap?, parentThemeMap: Map?): MutableMap? { + private fun importMapFromParentTheme(themeMap: MutableMap?, + parentThemeMap: Map?): MutableMap? { if (parentThemeMap == null) { return themeMap } @@ -53,56 +39,338 @@ internal class UIThemeBean { } return result } + + fun readTheme(parser: JsonParser): UIThemeBean { + check(parser.nextToken() == JsonToken.START_OBJECT) + val bean = UIThemeBean() + while (true) { + when (parser.nextToken()) { + JsonToken.START_OBJECT -> { + val fieldName = parser.currentName() + // ordered map is required (not clear why) + val map = LinkedHashMap() + readFlatMapFromJson(parser, map) + when (fieldName) { + "icons" -> bean.icons = map + "background" -> bean.background = map + "emptyFrameBackground" -> bean.emptyFrameBackground = map + "colors" -> bean.colors = map + "iconColorsOnSelection" -> bean.iconColorsOnSelection = map + "ui" -> { + putDefaultsIfAbsent(map) + bean.ui = map + } + "UIDesigner" -> { + parser.skipChildren() + } + else -> { + logger().warn("Unknown field: $fieldName") + } + } + } + JsonToken.END_OBJECT -> { + } + JsonToken.START_ARRAY -> { + val fieldName = parser.currentName() + val list = ArrayList() + while (parser.nextToken() != JsonToken.END_ARRAY) { + when (parser.currentToken()) { + JsonToken.VALUE_STRING -> { + list.add(parser.valueAsString) + } + else -> {} + } + } + + when (fieldName) { + "additionalEditorSchemes" -> { + bean.additionalEditorSchemes = list + } + else -> { + logger().warn("Unknown field: ${parser.currentName()}") + } + } + } + JsonToken.VALUE_STRING -> { + when (parser.currentName()) { + "id" -> bean.id = parser.valueAsString + "name" -> bean.name = parser.valueAsString + "nameKey" -> bean.nameKey = parser.valueAsString + "parentTheme" -> bean.parentTheme = parser.valueAsString + "resourceBundle" -> bean.resourceBundle = parser.valueAsString + "author" -> bean.author = parser.valueAsString + + "editorScheme" -> bean.editorScheme = parser.valueAsString + "editorSchemeName" -> bean.editorSchemeName = parser.valueAsString + } + } + JsonToken.VALUE_TRUE -> readTopLevelBoolean(parser, bean, value = true) + JsonToken.VALUE_FALSE -> readTopLevelBoolean(parser, bean, value = false) + JsonToken.FIELD_NAME -> { + } + null -> break + else -> { + logger().warn("Unknown field: ${parser.currentName()}") + } + } + } + + putDefaultsIfAbsent(bean) + return bean + } + + private fun readTopLevelBoolean(parser: JsonParser, bean: UIThemeBean, value: Boolean) { + when (parser.currentName()) { + "dark" -> bean.dark = value + } + } } @Transient @JvmField var providerClassLoader: ClassLoader? = null - @JvmField - var name: String? = null - @JvmField - var dark = false - @JvmField - var author: String? = null @JvmField var id: String? = null + @JvmField - var editorScheme: String? = null + var name: String? = null + + @JvmField + var nameKey: String? = null + @JvmField var parentTheme: String? = null + @JvmField - var additionalEditorSchemes: Array? = null + var resourceBundle: String? = "messages.IdeBundle" + + @JvmField + var author: String? = null + + @JvmField + var editorScheme: String? = null + + @JvmField + var editorSchemeName: String? = null + + @JvmField + var dark: Boolean = false + + @JvmField + var additionalEditorSchemes: List? = null + @JvmField var ui: MutableMap? = null + @JvmField var icons: MutableMap? = null + @JvmField + var background: MutableMap? = null + + @JvmField + var emptyFrameBackground: MutableMap? = null + + @JvmField + var colors: MutableMap? = null + + @JvmField + var iconColorsOnSelection: MutableMap? = null + @JvmField @Transient var patcher: IconPathPatcher? = null - @JvmField - var background: MutableMap? = null - @JvmField - var emptyFrameBackground: MutableMap? = null - @JvmField - var colors: MutableMap? = null - @JvmField - var iconColorsOnSelection: MutableMap? = null - - @JvmField - var editorSchemeName: String? = null - @JvmField @Transient var colorPatcher: SvgElementColorPatcherProvider? = null + @JvmField @Transient var selectionColorPatcher: SvgElementColorPatcherProvider? = null +} - @JvmField - var resourceBundle: String? = "messages.IdeBundle" - @JvmField - var nameKey: String? = null -} \ No newline at end of file +/** + * Flatten example: `"Editor": { "SearchField": { "borderInsets": "7,10,7,8" } }` is flattened to + * `"Editor.SearchField.borderInsets": "7,10,7,8` in internal representation. + * + * Per-OS keys are also resolved as shown below: + * ```json + * "Menu.borderColor": { + * "os.default": "Grey12", + * "os.windows": "Blue12" + * } + * ``` + * + * This is useful when we need to validate if a certain key was already set in [putDefaultsIfAbsent], + * and to uniformly override parentTheme keys regardless of used format. + * + * Note: we intentionally do not expand "*" patterns here. + */ +private fun readFlatMapFromJson(parser: JsonParser, result: MutableMap) { + check(parser.currentToken() == JsonToken.START_OBJECT) + + val prefix = ArrayDeque() + val path = StringBuilder() + var currentFieldName: String? = null + var level = 1 + while (true) { + when (parser.nextToken()) { + JsonToken.START_OBJECT -> { + level++ + prefix.addLast(currentFieldName!!) + currentFieldName = null + } + JsonToken.END_OBJECT -> { + level-- + prefix.pollLast() + currentFieldName = null + + if (level == 0) { + assert(prefix.isEmpty()) + break + } + } + JsonToken.START_ARRAY -> { + val fieldName = parser.currentName() + while (true) { + when (parser.nextToken()) { + JsonToken.END_ARRAY -> break + JsonToken.VALUE_STRING -> { + if (!prefix.isEmpty()) { + prefix.joinTo(buffer = path, separator = "/") + path.append('.') + } + path.append(fieldName) + result.put(path.toString(), parser.text) + path.setLength(0) + } + else -> { + logError(parser) + } + } + } + } + JsonToken.VALUE_STRING -> { + putEntry(prefix, result, parser, path) { parser.text } + } + JsonToken.VALUE_NUMBER_INT -> { + putEntry(prefix, result, parser, path) { parser.intValue } + } + JsonToken.VALUE_NUMBER_FLOAT -> { + putEntry(prefix, result, parser, path) { parser.doubleValue } + } + JsonToken.VALUE_FALSE -> { + putEntry(prefix, result, parser, path) { false } + } + JsonToken.VALUE_TRUE -> { + putEntry(prefix, result, parser, path) { true } + } + JsonToken.VALUE_NULL -> { + } + JsonToken.FIELD_NAME -> { + currentFieldName = parser.currentName() + } + null -> { + break + } + else -> { + logError(parser) + } + } + } + + result.replaceAll(BiFunction { _, u -> if (u is OsDefaultValue) u.v else u }) +} + +private const val OS_MACOS_KEY = "os.mac" +private const val OS_WINDOWS_KEY = "os.windows" +private const val OS_LINUX_KEY = "os.linux" +private const val OS_DEFAULT_KEY = "os.default" + +private val osKey = when { + SystemInfoRt.isWindows -> OS_WINDOWS_KEY + SystemInfoRt.isMac -> OS_MACOS_KEY + else -> OS_LINUX_KEY +} + +private fun putEntry(prefix: Deque, + result: MutableMap, + parser: JsonParser, + path: StringBuilder, + getter: () -> Any?) { + if (!prefix.isEmpty()) { + prefix.joinTo(buffer = path, separator = ".") + } + + val key = parser.currentName() + val value = getter() + when (key) { + osKey -> { + } + OS_WINDOWS_KEY, OS_MACOS_KEY, OS_LINUX_KEY -> { + path.setLength(0) + return + } + OS_DEFAULT_KEY -> { + val compositeKey = path.toString() + path.setLength(0) + + val oldValue = result.putIfAbsent(compositeKey, OsDefaultValue(value)) + if (oldValue is OsDefaultValue) { + logger().error("Duplicated value: (value=$value, compositeKey=$compositeKey)") + } + return + } + "UI" -> { + path.append(key) + } + else -> { + if (path.isNotEmpty()) { + path.append('.') + } + path.append(key) + } + } + + result.put(path.toString(), value) + path.setLength(0) +} + +private class OsDefaultValue(@JvmField val v: Any?) + +private fun logError(parser: JsonParser) { + logger().warn("JSON contains data in unsupported format (token=${parser.currentToken}): ${parser.currentValue()}") +} + +/** + * Ensure that the old themes are not missing some vital keys. + * + * We are patching them here instead of using [com.intellij.ui.JBColor.namedColor] fallback + * to make sure [javax.swing.UIManager.getColor] works properly. + */ +private fun putDefaultsIfAbsent(theme: UIThemeBean) { + if (!ExperimentalUI.isNewUI()) { + return + } + + var ui = theme.ui + if (ui == null) { + ui = LinkedHashMap() + theme.ui = ui + putDefaultsIfAbsent(ui) + } +} + +private fun putDefaultsIfAbsent(ui: MutableMap) { + if (!ExperimentalUI.isNewUI()) { + return + } + + ui.putIfAbsent("EditorTabs.underlineArc", "4") + + // require theme to specify ToolWindow stripe button colors explicitly, without "*" + ui.putIfAbsent("ToolWindow.Button.selectedBackground", "#3573F0") + ui.putIfAbsent("ToolWindow.Button.selectedForeground", "#FFFFFF") +} diff --git a/platform/platform-impl/intellij.platform.ide.impl.iml b/platform/platform-impl/intellij.platform.ide.impl.iml index eea239789ecb..fc8806c84cb7 100644 --- a/platform/platform-impl/intellij.platform.ide.impl.iml +++ b/platform/platform-impl/intellij.platform.ide.impl.iml @@ -119,7 +119,6 @@ - diff --git a/platform/platform-impl/src/com/intellij/ide/bootstrap/ApplicationLoader.kt b/platform/platform-impl/src/com/intellij/ide/bootstrap/ApplicationLoader.kt index ea2922e96509..68195018ad33 100644 --- a/platform/platform-impl/src/com/intellij/ide/bootstrap/ApplicationLoader.kt +++ b/platform/platform-impl/src/com/intellij/ide/bootstrap/ApplicationLoader.kt @@ -233,9 +233,11 @@ private suspend fun preInitApp(app: ApplicationImpl, euaTaskDeferred?.await()?.invoke() - val installIconPatcherJob = if (loadIconMapping == null) null else launch { - loadIconMapping.join() - ExperimentalUI.getInstance().installIconPatcher() + if (loadIconMapping != null) { + launch { + loadIconMapping.join() + ExperimentalUI.getInstance().installIconPatcher() + } } coroutineScope { diff --git a/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentAttributes.kt b/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentAttributes.kt index de9300276b0a..890fb6d6a5ee 100644 --- a/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentAttributes.kt +++ b/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentAttributes.kt @@ -1,15 +1,55 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.gdpr; +package com.intellij.ide.gdpr + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json /** * Data structure describing all possible Consent JSON attributes */ -final class ConsentAttributes { - public String consentId; - public String version; - public String text; - public String printableName; - public boolean accepted; - public boolean deleted; - public long acceptanceTime; +@Serializable +internal class ConsentAttributes { + companion object { + @OptIn(ExperimentalSerializationApi::class) + private val jsonConfig by lazy { + Json { + ignoreUnknownKeys = true + isLenient = true + encodeDefaults = false + prettyPrint = true + prettyPrintIndent = " " + } + } + + fun readListFromJson(json: String): List { + return jsonConfig.decodeFromString>(json) + } + + fun writeListToJson(list: List): String { + return jsonConfig.encodeToString>(list) + } + } + + @JvmField + var consentId: String? = null + + @JvmField + var version: String? = null + + @JvmField + var text: String? = null + + @JvmField + var printableName: String? = null + + @JvmField + var accepted: Boolean = false + + @JvmField + var deleted: Boolean = false + + @JvmField + var acceptanceTime: Long = 0 } diff --git a/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentOptions.java b/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentOptions.java index 6b8c0d744944..6963386aacec 100644 --- a/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentOptions.java +++ b/platform/platform-impl/src/com/intellij/ide/gdpr/ConsentOptions.java @@ -1,9 +1,6 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.gdpr; -import com.fasterxml.jackson.jr.ob.JSON; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.intellij.diagnostic.LoadingState; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; @@ -424,14 +421,16 @@ public final class ConsentOptions { } private @NotNull Collection fromJson(@Nullable String json) { + if (json == null || json.isEmpty()) { + return Collections.emptyList(); + } + try { - List data = json == null || json.isEmpty() ? null : JSON.std.listOfFrom(ConsentAttributes.class, json); - if (data != null) { - for (ConsentAttributes attributes : data) { - attributes.consentId = lookupConsentID(attributes.consentId); - } - return data; + List data = ConsentAttributes.Companion.readListFromJson(json); + for (ConsentAttributes attributes : data) { + attributes.consentId = lookupConsentID(attributes.consentId); } + return data; } catch (Throwable e) { LOG.info(e); @@ -440,15 +439,14 @@ public final class ConsentOptions { } private @NotNull String consentsToJson(@NotNull Stream consents) { - Gson gson = new GsonBuilder().disableHtmlEscaping().create(); - return gson.toJson(consents.map(consent -> { + return ConsentAttributes.Companion.writeListToJson(consents.map(consent -> { final ConsentAttributes attribs = consent.toConsentAttributes(); final String prefix = getProductConsentKind(myProductCode, attribs.consentId); if (prefix != null) { attribs.consentId = prefix; } return attribs; - }).toArray()); + }).toList()); } private static @NotNull String confirmedConsentToExternalString(@NotNull Stream consents) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/IconMapLoader.kt b/platform/platform-impl/src/com/intellij/ide/ui/IconMapLoader.kt index 8a6cc958841d..0294854c3df0 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/IconMapLoader.kt +++ b/platform/platform-impl/src/com/intellij/ide/ui/IconMapLoader.kt @@ -138,11 +138,12 @@ private fun readDataFromJson(parser: JsonParser, result: MutableMap, parser: JsonParser, path: StringBuilder) { - val oldValue = result.get(parser.text) - if (oldValue != null && oldValue != path.toString()) { - logger().error("Double icon mapping: ${parser.text} -> $oldValue or $path") + val key = parser.text + val p = path.toString() + val oldValue = result.put(key, p) + if (oldValue != null && oldValue != p) { + logger().error("Double icon mapping: $key -> $oldValue or $path") } - result.put(parser.text, path.toString()) } private fun logError(parser: JsonParser) { 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 275607945a50..e1126459b568 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 @@ -319,7 +319,7 @@ public final class EditorColorsManagerImpl extends EditorColorsManager implement for (UIThemeLookAndFeelInfo laf : UiThemeProviderListManager.Companion.getInstance().getLaFs()) { UITheme theme = laf.getTheme(); - String[] schemes = theme.getAdditionalEditorSchemes(); + List schemes = theme.getAdditionalEditorSchemes(); PluginDescriptor pluginDescriptor = getPluginDescriptor(theme); if (schemes != null) { for (String scheme : schemes) {