CPP-778 Support for semantic per-variable highlighting idea/162.832
authorAlexey Utkin <alexey.utkin@jetbrains.com>
Mon, 6 Jun 2016 12:30:04 +0000 (15:30 +0300)
committerAlexey Utkin <alexey.utkin@jetbrains.com>
Mon, 6 Jun 2016 13:25:53 +0000 (16:25 +0300)
platform/analysis-impl/src/com/intellij/codeHighlighting/RainbowHighlighter.java
platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPass.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPassFactory.java [new file with mode: 0644]

index b86c8cbc2b3506c003cc05b0a0d32a1a4465a35a..aec8793a65d35acb46128ed8d3f4bbbc48fb8238 100644 (file)
@@ -18,25 +18,27 @@ package com.intellij.codeHighlighting;
 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
 import com.intellij.lang.annotation.HighlightSeverity;
 import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
 import com.intellij.openapi.editor.colors.TextAttributesScheme;
 import com.intellij.openapi.editor.markup.TextAttributes;
 import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.util.text.StringHash;
 import org.jetbrains.annotations.NotNull;
 
+import javax.swing.*;
 import java.awt.*;
 
 public class RainbowHighlighter {
   private final float[] myFloats;
+  private TextAttributes myColorsSchemeAttributes;
+
   public RainbowHighlighter(@NotNull TextAttributesScheme colorsScheme) {
-    float[] components = colorsScheme.getAttributes(DefaultLanguageHighlighterColors.CONSTANT).getForegroundColor().getRGBColorComponents(null);
+    myColorsSchemeAttributes = colorsScheme.getAttributes(DefaultLanguageHighlighterColors.CONSTANT);
+    float[] components = myColorsSchemeAttributes.getForegroundColor().getRGBColorComponents(null);
     myFloats = Color.RGBtoHSB((int)(255 * components[0]), (int)(255 * components[0]), (int)(255 * components[0]), null);
   }
 
-  private static final HighlightSeverity RAINBOW_ELEMENT_SEV = new HighlightSeverity("RAINBOW_ELEMENT", HighlightSeverity.ERROR.myVal + 10);
-  public static final HighlightInfoType RAINBOW_ELEMENT = new HighlightInfoType.HighlightInfoTypeImpl(RAINBOW_ELEMENT_SEV, TextAttributesKey
-    .createTextAttributesKey("RAINBOW_ELEMENT"));
+  public static final HighlightInfoType RAINBOW_ELEMENT = new HighlightInfoType
+    .HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, DefaultLanguageHighlighterColors.CONSTANT);
 
   public static boolean isRainbowEnabled() {
     return Registry.is("editor.rainbow.identifiers", false);
@@ -48,10 +50,14 @@ public class RainbowHighlighter {
     final float colors = 36.0f;
     final float v = Math.round(Math.abs(colors * hash) / Integer.MAX_VALUE) / colors;
     //System.out.println("name = " + name + " \tv=" + v);
-    final Color color =  Color.getHSBColor(v, 0.7f, myFloats[2] + .3f);
+    final Color color = Color.getHSBColor(v, 0.7f, myFloats[2] + .3f);
+
+    final TextAttributes attributes = TextAttributes.fromFlyweight(myColorsSchemeAttributes
+                                                                     .getFlyweight()
+                                                                     .withForeground(color)
+    //fixme: uta: foreground color is not activated for local variables without background color reset
+                                                                     .withBackground(UIManager.getColor("EditorPane.background")));
 
-    final TextAttributes attributes = new TextAttributes();
-    attributes.setForegroundColor(color);
     return attributes;
   }
 }
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPass.java
new file mode 100644 (file)
index 0000000..91debbc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intellij.codeInsight.daemon.impl;
+
+import com.intellij.codeHighlighting.RainbowHighlighter;
+import com.intellij.codeHighlighting.TextEditorHighlightingPass;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.ui.JBColor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RainbowIdentifierHighlighterPass extends TextEditorHighlightingPass {
+  protected final PsiFile myFile;
+  protected final RainbowHighlighter myRainbowHighlighter;
+  protected List<HighlightInfo> toHighlight;
+
+  protected RainbowIdentifierHighlighterPass(@NotNull PsiFile file, @NotNull Editor editor) {
+    super(file.getProject(), editor.getDocument(), false);
+    myFile = file;
+    myRainbowHighlighter = new RainbowHighlighter(editor.getColorsScheme());
+  }
+
+  @Override
+  public void doCollectInformation(@NotNull final ProgressIndicator progress) {
+    // reference implementation!
+    final List<HighlightInfo> infos = new ArrayList<>();
+    myFile.accept(new PsiRecursiveElementWalkingVisitor() {
+      @Override
+      public void visitElement(PsiElement e) {
+        final HighlightInfo attrs;
+        if (e instanceof PsiReference) {
+          attrs = getInfo(e.getText(), e);
+        }
+        else if (e instanceof PsiNameIdentifierOwner) {
+          PsiNameIdentifierOwner identifierOwner = (PsiNameIdentifierOwner)e;
+          attrs = getInfo(identifierOwner.getName(), identifierOwner.getNameIdentifier());
+        }
+        else {
+          attrs = null;
+        }
+        if (attrs != null) {
+          infos.add(attrs);
+        }
+        super.visitElement(e);
+      }
+    });
+    toHighlight = infos;
+  }
+
+  @Override
+  public void doApplyInformationToEditor() {
+    if (toHighlight == null || myDocument == null) return;
+    UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, 0, myFile.getTextLength(), toHighlight, getColorsScheme(), getId());
+  }
+
+  protected HighlightInfo getInfo(@Nullable String colorKey, @Nullable PsiElement id) {
+    if (id == null || colorKey == null || StringUtil.isEmpty(colorKey)) return null;
+    final TextAttributes attributes = myRainbowHighlighter.getAttributes(colorKey);
+    return HighlightInfo
+      .newHighlightInfo(RainbowHighlighter.RAINBOW_ELEMENT)
+      .textAttributes(attributes)
+      .range(id)
+      .create();
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPassFactory.java
new file mode 100644 (file)
index 0000000..42c0a28
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.impl;
+
+import com.intellij.codeHighlighting.*;
+import com.intellij.openapi.components.AbstractProjectComponent;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Language-dependent implementation need to be inherited from this class and
+ */
+public class RainbowIdentifierHighlighterPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory {
+  public RainbowIdentifierHighlighterPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) {
+    super(project);
+    highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.UPDATE_ALL}, null, false, -1);
+  }
+
+  @Override
+  @NonNls
+  @NotNull
+  public String getComponentName() {
+    return "RainbowIdentifierPassFactory";
+  }
+
+  @Override
+  public TextEditorHighlightingPass createHighlightingPass(@NotNull final PsiFile file, @NotNull final Editor editor) {
+    if (RainbowHighlighter.isRainbowEnabled() && isValidContext(file, editor)) {
+      return getRainbowPass(file, editor);
+    }
+
+    return null;
+  }
+
+  /**
+   * Need to be rewritten in language-dependent implementation.
+   * Default implementation colors all identifiers in [PsiReference] and [PsiNameIdentifierOwner] elements.
+   */
+  @NotNull
+  protected RainbowIdentifierHighlighterPass getRainbowPass(@NotNull PsiFile file, @NotNull Editor editor) {
+    return new RainbowIdentifierHighlighterPass(file, editor);
+  }
+
+  /**
+   * Need to be rewritten in language-dependent implementation.
+   * For example:
+   *    return file instanceof JavaFile;
+   * Default implementation works for any language.
+   */
+  protected boolean isValidContext(@NotNull final PsiFile file, @NotNull Editor editor) {
+    return true;
+  }
+}