From 7e629ae86b906560729df00f1bba6438ddcefc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Wed, 29 May 2019 18:32:16 +0200 Subject: [PATCH] theme.json: preview named colors (IDEA-214797) GitOrigin-RevId: a946d69951e99762e94934be0d48920df3ecfbee --- .../src/themes/ThemeColorAnnotator.java | 63 ++++++++++++++----- .../ThemeJsonNamedColorPsiReference.java | 30 +++------ .../devkit-core/src/themes/ThemeJsonUtil.java | 17 +++++ 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/plugins/devkit/devkit-core/src/themes/ThemeColorAnnotator.java b/plugins/devkit/devkit-core/src/themes/ThemeColorAnnotator.java index 8e9bcbcbef2d..09987dcd56af 100644 --- a/plugins/devkit/devkit-core/src/themes/ThemeColorAnnotator.java +++ b/plugins/devkit/devkit-core/src/themes/ThemeColorAnnotator.java @@ -2,8 +2,8 @@ package org.jetbrains.idea.devkit.themes; import com.intellij.codeInsight.daemon.LineMarkerSettings; -import com.intellij.json.psi.JsonElementGenerator; -import com.intellij.json.psi.JsonStringLiteral; +import com.intellij.json.psi.*; +import com.intellij.json.psi.impl.JsonPsiImplUtils; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; @@ -20,6 +20,7 @@ import com.intellij.psi.PsiFile; import com.intellij.ui.ColorChooser; import com.intellij.ui.ColorLineMarkerProvider; import com.intellij.ui.ColorUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColorIcon; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.JBUI; @@ -29,6 +30,7 @@ import org.jetbrains.idea.devkit.DevKitBundle; import javax.swing.*; import java.awt.*; +import java.util.List; import java.util.Objects; import java.util.regex.Pattern; @@ -60,8 +62,13 @@ public class ThemeColorAnnotator implements Annotator { if (!(element instanceof JsonStringLiteral)) return false; if (!ThemeJsonUtil.isThemeFilename(containingFile.getName())) return false; + if (JsonPsiImplUtils.isPropertyName((JsonStringLiteral)element)) return false; String text = ((JsonStringLiteral)element).getValue(); - return isColorCode(text); + return isColorCode(text) || isNamedColor(text); + } + + private static boolean isNamedColor(String text) { + return StringUtil.isLatinAlphanumeric(text); } private static boolean isColorCode(@Nullable String text) { @@ -75,19 +82,19 @@ public class ThemeColorAnnotator implements Annotator { private static class MyRenderer extends GutterIconRenderer { private static final int ICON_SIZE = 12; - private final String myColorHex; + private final String myColorText; private final JsonStringLiteral myLiteral; - private MyRenderer(@NotNull String colorHex, @NotNull JsonStringLiteral literal) { - myColorHex = colorHex; + private MyRenderer(@NotNull String colorText, @NotNull JsonStringLiteral literal) { + myColorText = colorText; myLiteral = literal; } @NotNull @Override public Icon getIcon() { - Color color = getColor(myColorHex); + Color color = getColor(myColorText); if (color != null) { return JBUI.scale(new ColorIcon(ICON_SIZE, color)); } @@ -96,28 +103,30 @@ public class ThemeColorAnnotator implements Annotator { @Override public boolean isNavigateAction() { - return true; + return canChooseColor(); } @Nullable @Override public String getTooltipText() { - return "Choose Color"; + return canChooseColor() ? "Choose Color" : null; } @Nullable @Override public AnAction getClickAction() { + if (!canChooseColor()) return null; + return new AnAction("Choose Color...") { @Override public void actionPerformed(@NotNull AnActionEvent e) { Editor editor = e.getData(CommonDataKeys.EDITOR); if (editor == null) return; - Color currentColor = getColor(myColorHex); + Color currentColor = getColor(myColorText); if (currentColor == null) return; - boolean withAlpha = isRgbaColorHex(myColorHex); + boolean withAlpha = isRgbaColorHex(myColorText); Color newColor = ColorChooser.chooseColor(editor.getProject(), editor.getComponent(), DevKitBundle.message("theme.choose.color.dialog.title"), @@ -134,8 +143,21 @@ public class ThemeColorAnnotator implements Annotator { }; } + private boolean canChooseColor() { + return isColorCode(myColorText); + } + @Nullable - private static Color getColor(@NotNull String colorHex) { + private Color getColor(@NotNull String colorText) { + if (!isColorCode(colorText)) { + return findNamedColor(colorText); + } + + return parseColor(colorText); + } + + @Nullable + private static Color parseColor(@NotNull String colorHex) { boolean isRgba = isRgbaColorHex(colorHex); if (!isRgba && !isRgbColorHex(colorHex)) return null; @@ -154,6 +176,19 @@ public class ThemeColorAnnotator implements Annotator { } } + @Nullable + private Color findNamedColor(String colorText) { + final PsiFile file = myLiteral.getContainingFile(); + if (!(file instanceof JsonFile)) return null; + final List colors = ThemeJsonUtil.getNamedColors((JsonFile)file); + final JsonProperty namedColor = ContainerUtil.find(colors, property -> property.getName().equals(colorText)); + if (namedColor == null) return null; + + final JsonValue value = namedColor.getValue(); + if (!(value instanceof JsonStringLiteral)) return null; + return parseColor(((JsonStringLiteral)value).getValue()); + } + private static boolean isRgbaColorHex(@NotNull String colorHex) { return colorHex.length() == HEX_COLOR_LENGTH_RGBA; } @@ -167,13 +202,13 @@ public class ThemeColorAnnotator implements Annotator { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyRenderer renderer = (MyRenderer)o; - return myColorHex.equals(renderer.myColorHex) && + return myColorText.equals(renderer.myColorText) && myLiteral.equals(renderer.myLiteral); } @Override public int hashCode() { - return Objects.hash(myColorHex, myLiteral); + return Objects.hash(myColorText, myLiteral); } } } diff --git a/plugins/devkit/devkit-core/src/themes/ThemeJsonNamedColorPsiReference.java b/plugins/devkit/devkit-core/src/themes/ThemeJsonNamedColorPsiReference.java index 0174855b5d43..e5c38309c014 100644 --- a/plugins/devkit/devkit-core/src/themes/ThemeJsonNamedColorPsiReference.java +++ b/plugins/devkit/devkit-core/src/themes/ThemeJsonNamedColorPsiReference.java @@ -1,18 +1,22 @@ // Copyright 2000-2019 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 org.jetbrains.idea.devkit.themes; -import com.intellij.json.psi.*; +import com.intellij.json.psi.JsonFile; +import com.intellij.json.psi.JsonLiteral; +import com.intellij.json.psi.JsonProperty; import com.intellij.model.SymbolResolveResult; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.jsonSchema.impl.JsonSchemaBaseReference; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * @author Konstantin Bulenkov @@ -28,27 +32,11 @@ class ThemeJsonNamedColorPsiReference extends JsonSchemaBaseReference namedColors = ThemeJsonUtil.getNamedColors((JsonFile)containingFile); + return ContainerUtil.find(namedColors, property -> property.getName().equals(myName)); } @NotNull diff --git a/plugins/devkit/devkit-core/src/themes/ThemeJsonUtil.java b/plugins/devkit/devkit-core/src/themes/ThemeJsonUtil.java index 4a984dd6af4e..2a4afa9ff6d3 100644 --- a/plugins/devkit/devkit-core/src/themes/ThemeJsonUtil.java +++ b/plugins/devkit/devkit-core/src/themes/ThemeJsonUtil.java @@ -3,7 +3,10 @@ package org.jetbrains.idea.devkit.themes; import com.google.common.collect.Lists; import com.intellij.ide.ui.UIThemeMetadata; +import com.intellij.json.psi.JsonFile; +import com.intellij.json.psi.JsonObject; import com.intellij.json.psi.JsonProperty; +import com.intellij.json.psi.JsonValue; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; @@ -13,6 +16,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.themes.metadata.UIThemeMetadataService; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -21,6 +25,9 @@ class ThemeJsonUtil { @NonNls private static final String UI_PROPERTY_NAME = "ui"; + @NonNls + private static final String COLORS_PROPERTY_NAME = "colors"; + static boolean isInsideUiProperty(@NotNull JsonProperty property) { PsiElement parent = property; while ((parent = parent.getParent()) != null) { @@ -45,6 +52,16 @@ class ThemeJsonUtil { return StringUtil.endsWithIgnoreCase(fileName, ".theme.json"); } + static List getNamedColors(@NotNull JsonFile themeFile) { + JsonValue topLevelValue = themeFile.getTopLevelValue(); + if (!(topLevelValue instanceof JsonObject)) return Collections.emptyList(); + JsonProperty colorsProperty = ((JsonObject)topLevelValue).findProperty(COLORS_PROPERTY_NAME); + if (colorsProperty == null) return Collections.emptyList(); + final JsonValue colorsValue = colorsProperty.getValue(); + if (!(colorsValue instanceof JsonObject)) return Collections.emptyList(); + return ((JsonObject)colorsValue).getPropertyList(); + } + @Nullable static Pair findMetadata(@NotNull JsonProperty property) { final String key = property.getName();