ffadaea460cf0ef6f010c9e3cb17ce88bcdace12
[idea/community.git] / platform / analysis-impl / src / com / intellij / codeHighlighting / RainbowHighlighter.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeHighlighting;
17
18 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
19 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
20 import com.intellij.lang.annotation.HighlightSeverity;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
23 import com.intellij.openapi.editor.colors.EditorColorsManager;
24 import com.intellij.openapi.editor.colors.TextAttributesKey;
25 import com.intellij.openapi.editor.colors.TextAttributesScheme;
26 import com.intellij.openapi.editor.markup.TextAttributes;
27 import com.intellij.openapi.util.registry.Registry;
28 import com.intellij.openapi.util.text.StringUtil;
29 import com.intellij.psi.PsiElement;
30 import com.intellij.ui.ColorUtil;
31 import com.intellij.ui.JBColor;
32 import com.intellij.util.containers.ContainerUtil;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
35
36 import java.awt.*;
37 import java.util.List;
38
39 public class RainbowHighlighter {
40   private static final JBColor[] RAINBOW_JB_COLORS_DEFAULT = {
41     new JBColor(0x9b3b6a, 0x529d52),
42     new JBColor(0x114d77, 0xbe7070),
43     new JBColor(0xbc8650, 0x3d7676),
44     new JBColor(0x005910, 0xbe9970),
45     new JBColor(0xbc5150, 0x9d527c),
46   };
47   private static final TextAttributesKey[] RAINBOW_COLOR_KEYS = new TextAttributesKey[RAINBOW_JB_COLORS_DEFAULT.length];
48   private static final int RAINBOW_COLORS_BETWEEN = 4;
49   private static final String UNIT_TEST_COLORS = "#000001,#000002,#000003,#000004"; // Do not modify!
50   static {
51     for (int i = 0; i < RAINBOW_JB_COLORS_DEFAULT.length; ++i) {
52       JBColor jbColor = RAINBOW_JB_COLORS_DEFAULT[i];
53       TextAttributes textAttributes = new TextAttributes(jbColor, null, null, null, Font.PLAIN);
54       RAINBOW_COLOR_KEYS[i] = TextAttributesKey.createTextAttributesKey("RAINBOW_COLOR" + i, textAttributes);
55     }
56   }
57
58   @NotNull private final TextAttributesScheme myColorsScheme;
59   @NotNull private final Color[] myRainbowColors;
60
61   public RainbowHighlighter(@Nullable TextAttributesScheme colorsScheme) {
62     myColorsScheme = colorsScheme != null ? colorsScheme : EditorColorsManager.getInstance().getGlobalScheme();
63     myRainbowColors = generateColorSequence(myColorsScheme);
64   }
65
66   public static final HighlightInfoType RAINBOW_ELEMENT = new HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, DefaultLanguageHighlighterColors.CONSTANT);
67
68   public static boolean isRainbowEnabled() {
69     return Registry.is("editor.rainbow.identifiers", false);
70   }
71
72   public static void setRainbowEnabled(boolean enabled) {
73     Registry.get("editor.rainbow.identifiers").setValue(enabled);
74   }
75
76   @NotNull
77   private Color calculateForeground(int colorIndex) {
78     return myRainbowColors[colorIndex];
79   }
80
81   public int getColorsCount() {
82     return myRainbowColors.length;
83   }
84
85   @NotNull
86   private static Color[] generateColorSequence(@NotNull TextAttributesScheme colorsScheme) {
87     String colorDump = ApplicationManager.getApplication().isUnitTestMode()
88                        ? UNIT_TEST_COLORS
89                        : Registry.get("rainbow.highlighter.colors").asString();
90
91     final List<String> registryColors = StringUtil.split(colorDump, ",");
92     if (!registryColors.isEmpty()) {
93       return registryColors.stream().map(s -> ColorUtil.fromHex(s.trim())).toArray(Color[]::new);
94     }
95
96     List<Color> foregroundColors = ContainerUtil.map(RAINBOW_COLOR_KEYS, key -> colorsScheme.getAttributes(key).getForegroundColor());
97     List<Color> colors = ColorGenerator.generateLinearColorSequence(foregroundColors, RAINBOW_COLORS_BETWEEN);
98     return colors.toArray(new Color[colors.size()]);
99   }
100
101   public HighlightInfo getInfo(int colorIndex, @Nullable PsiElement id, @Nullable TextAttributesKey colorKey) {
102     return id == null ? null : getInfoBuilder(colorIndex, colorKey).range(id).create();
103   }
104
105   public HighlightInfo getInfo(int colorIndex, int start, int end, @Nullable TextAttributesKey colorKey) {
106     return getInfoBuilder(colorIndex, colorKey).range(start, end).create();
107   }
108
109   @NotNull
110   protected HighlightInfo.Builder getInfoBuilder(int colorIndex, @Nullable TextAttributesKey colorKey) {
111     if (colorKey == null) {
112       colorKey = DefaultLanguageHighlighterColors.LOCAL_VARIABLE;
113     }
114     return HighlightInfo
115       .newHighlightInfo(RAINBOW_ELEMENT)
116       .textAttributes(TextAttributes
117                         .fromFlyweight(myColorsScheme
118                                          .getAttributes(colorKey)
119                                          .getFlyweight()
120                                          .withForeground(calculateForeground(colorIndex))));
121   }
122 }