theme.json: preview named colors (IDEA-214797)

GitOrigin-RevId: a946d69951e99762e94934be0d48920df3ecfbee
This commit is contained in:
Yann Cébron
2019-05-29 20:09:14 +03:00
committed by intellij-monorepo-bot
parent 73f5f4a202
commit 7e629ae86b
3 changed files with 75 additions and 35 deletions
@@ -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<JsonProperty> 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);
}
}
}
@@ -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<JsonLitera
@Nullable
@Override
public PsiElement resolveInner() {
PsiFile file = getElement().getContainingFile();
if (file instanceof JsonFile) {
PsiElement object = file.getFirstChild();
if (object instanceof JsonObject) {
PsiElement[] children = object.getChildren();
for (PsiElement child : children) {
if (child instanceof JsonProperty && ((JsonProperty)child).getName().equals("colors")) {
JsonValue colors = ((JsonProperty)child).getValue();
if (colors != null) {
for (PsiElement namedColor : colors.getChildren()) {
if (namedColor instanceof JsonProperty && ((JsonProperty)namedColor).getName().equals(myName)) {
return ((JsonProperty)namedColor).getNameElement();
}
}
}
}
}
}
}
final PsiFile containingFile = getElement().getContainingFile();
if (!(containingFile instanceof JsonFile)) return null;
return null;
final List<JsonProperty> namedColors = ThemeJsonUtil.getNamedColors((JsonFile)containingFile);
return ContainerUtil.find(namedColors, property -> property.getName().equals(myName));
}
@NotNull
@@ -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<JsonProperty> 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<UIThemeMetadata, UIThemeMetadata.UIKeyMetadata> findMetadata(@NotNull JsonProperty property) {
final String key = property.getName();