From afce3735a48373fa3d7f4df4f312809edd4cdfca Mon Sep 17 00:00:00 2001 From: Alexey Utkin Date: Wed, 29 Jun 2016 15:29:02 +0300 Subject: [PATCH] CPP-778 Support for semantic per-variable highlighting (fix Darcula background, before code inspection pass, EP approach) --- .../codeHighlighting/RainbowHighlighter.java | 49 +++++++++++++-- .../codeInsight/daemon/RainbowProvider.java | 49 +++++++++++++++ .../daemon/impl/HighlightInfo.java | 2 +- .../RainbowIdentifierHighlighterPass.java | 63 +++++-------------- ...inbowIdentifierHighlighterPassFactory.java | 32 ++-------- .../src/META-INF/LangExtensionPoints.xml | 3 + .../src/componentSets/Lang.xml | 4 ++ 7 files changed, 123 insertions(+), 79 deletions(-) create mode 100644 platform/analysis-impl/src/com/intellij/codeInsight/daemon/RainbowProvider.java diff --git a/platform/analysis-impl/src/com/intellij/codeHighlighting/RainbowHighlighter.java b/platform/analysis-impl/src/com/intellij/codeHighlighting/RainbowHighlighter.java index 16eb577f0924..30718ede0a2c 100644 --- a/platform/analysis-impl/src/com/intellij/codeHighlighting/RainbowHighlighter.java +++ b/platform/analysis-impl/src/com/intellij/codeHighlighting/RainbowHighlighter.java @@ -15,27 +15,41 @@ */ package com.intellij.codeHighlighting; +import com.intellij.codeInsight.daemon.RainbowProvider; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.lang.Language; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; -import com.intellij.openapi.editor.colors.TextAttributesScheme; +import com.intellij.openapi.editor.HighlighterColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringHash; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.awt.*; public class RainbowHighlighter { private final float[] myFloats; - private static final HashSet BY_PASS_LANGUAGES = new HashSet(); + @NotNull private final EditorColorsScheme myColorsScheme; + @NotNull private final Color myDefaultBackground; - public RainbowHighlighter(@NotNull TextAttributesScheme colorsScheme) { - float[] components = colorsScheme.getAttributes(DefaultLanguageHighlighterColors.CONSTANT).getForegroundColor().getRGBColorComponents(null); + private static final HashSet BY_PASS_LANGUAGES = new HashSet(); + static { + RainbowProvider.initRainbow(); + } + + public RainbowHighlighter(@Nullable EditorColorsScheme colorsScheme, @Nullable Color background) { + myColorsScheme = colorsScheme != null ? colorsScheme : EditorColorsManager.getInstance().getGlobalScheme(); + myDefaultBackground = background != null ? background : myColorsScheme.getDefaultBackground(); + float[] components = myColorsScheme.getAttributes(DefaultLanguageHighlighterColors.CONSTANT).getForegroundColor().getRGBColorComponents(null); myFloats = Color.RGBtoHSB((int)(255 * components[0]), (int)(255 * components[0]), (int)(255 * components[0]), null); } @@ -62,11 +76,34 @@ public class RainbowHighlighter { //System.out.println("name = " + name + " \tv=" + v); final Color color = Color.getHSBColor(v, 0.7f, myFloats[2] + .3f); + Color bkColor = origin.getBackgroundColor(); + if (bkColor == null) { + bkColor = myColorsScheme.getAttributes(HighlighterColors.TEXT).getBackgroundColor(); + } + if (bkColor == null) { + bkColor = myDefaultBackground; + } return TextAttributes.fromFlyweight(origin .getFlyweight() .withForeground(color) //fixme: uta: foreground color is not activated for local variables without background color reset - .withBackground(UIManager.getColor("EditorPane.background")) + .withBackground(bkColor) ); } + + public HighlightInfo getInfo( + @Nullable String nameKey, + @Nullable PsiElement id, + @Nullable TextAttributesKey colorKey) { + + if (id == null || nameKey == null || StringUtil.isEmpty(nameKey)) return null; + if (colorKey == null) colorKey = DefaultLanguageHighlighterColors.LOCAL_VARIABLE; + final TextAttributes attributes = getAttributes(nameKey, myColorsScheme.getAttributes(colorKey)); + return HighlightInfo + .newHighlightInfo(RAINBOW_ELEMENT) + .textAttributes(attributes) + .range(id) + .create(); + } + } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/RainbowProvider.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/RainbowProvider.java new file mode 100644 index 000000000000..0939626683d3 --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/RainbowProvider.java @@ -0,0 +1,49 @@ +/* + * 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; + +import com.intellij.codeHighlighting.RainbowHighlighter; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public abstract class RainbowProvider { + static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.rainbowProvider"); + + @NotNull + public static RainbowProvider[] getRainbowFileProcessors() { + return Extensions.getExtensions(EP_NAME); + } + + public static void initRainbow() { + for (RainbowProvider processor : getRainbowFileProcessors()) { + processor.init(); + } + } + + public abstract void init(); + + public abstract boolean isValidContext(@NotNull final PsiFile file); + + public abstract List getHighlights(@NotNull PsiFile file, + @NotNull RainbowHighlighter highlighter, + @NotNull ProgressIndicator progress); +} diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java index fcee18707296..2fc95e221254 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java @@ -185,7 +185,7 @@ public class HighlightInfo implements Segment { isLikeVariable(type.getAttributesKey())) { String text = element.getContainingFile().getText(); String name = text.substring(startOffset, endOffset); - attributes = new RainbowHighlighter(colorsScheme).getAttributes(name, attributes); + attributes = new RainbowHighlighter(colorsScheme, null).getAttributes(name, attributes); } 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 index d4f5f6b0a968..4ebf316ff175 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPass.java @@ -18,75 +18,46 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.RainbowHighlighter; import com.intellij.codeHighlighting.TextEditorHighlightingPass; -import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.codeInsight.daemon.RainbowProvider; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import java.awt.*; import java.util.ArrayList; import java.util.List; public class RainbowIdentifierHighlighterPass extends TextEditorHighlightingPass { protected final PsiFile myFile; - protected final RainbowHighlighter myRainbowHighlighter; - protected List toHighlight; - protected final EditorColorsScheme myEditorColorsScheme; + protected List myHighlight; + protected final Color myBackgroundColor; protected RainbowIdentifierHighlighterPass(@NotNull PsiFile file, @NotNull Editor editor) { super(file.getProject(), editor.getDocument(), false); + myBackgroundColor = (editor instanceof EditorImpl) ? ((EditorImpl)editor).getBackgroundColor() : null; myFile = file; - myEditorColorsScheme = editor.getColorsScheme(); - myRainbowHighlighter = new RainbowHighlighter(myEditorColorsScheme); } @Override public void doCollectInformation(@NotNull final ProgressIndicator progress) { - // reference implementation! final List 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, null); - } - else if (e instanceof PsiNameIdentifierOwner) { - PsiNameIdentifierOwner identifierOwner = (PsiNameIdentifierOwner)e; - attrs = getInfo(identifierOwner.getName(), identifierOwner.getNameIdentifier(), null); - } - else { - attrs = null; - } - if (attrs != null) { - infos.add(attrs); - } - super.visitElement(e); + + // myBackgroundColor takes into account "read only" editors + final RainbowHighlighter rainbowHighlighter = new RainbowHighlighter(getColorsScheme(), myBackgroundColor); + for (RainbowProvider processor : RainbowProvider.getRainbowFileProcessors()) { + if (processor.isValidContext(myFile)) { + infos.addAll(processor.getHighlights(myFile, rainbowHighlighter, progress)); } - }); - toHighlight = infos; + } + myHighlight = 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 nameKey, @Nullable PsiElement id, @Nullable TextAttributesKey colorKey) { - if (id == null || nameKey == null || StringUtil.isEmpty(nameKey)) return null; - if (colorKey == null) colorKey = DefaultLanguageHighlighterColors.LOCAL_VARIABLE; - final TextAttributes attributes = myRainbowHighlighter.getAttributes(nameKey, - myEditorColorsScheme.getAttributes(colorKey)); - return HighlightInfo - .newHighlightInfo(RainbowHighlighter.RAINBOW_ELEMENT) - .textAttributes(attributes) - .range(id) - .create(); + if (myHighlight == null || myDocument == null) return; + UpdateHighlightersUtil + .setHighlightersToEditor(myProject, myDocument, 0, myFile.getTextLength(), myHighlight, getColorsScheme(), getId()); } } 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 index 42c0a2813285..6fa898260b89 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/RainbowIdentifierHighlighterPassFactory.java @@ -23,13 +23,13 @@ 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); + highlightingPassRegistrar.registerTextEditorHighlightingPass(this, + TextEditorHighlightingPassRegistrar.Anchor.BEFORE, + Pass.UPDATE_FOLDING, + false, false); } @Override @@ -41,29 +41,9 @@ public class RainbowIdentifierHighlighterPassFactory extends AbstractProjectComp @Override public TextEditorHighlightingPass createHighlightingPass(@NotNull final PsiFile file, @NotNull final Editor editor) { - if (RainbowHighlighter.isRainbowEnabled() && isValidContext(file, editor)) { - return getRainbowPass(file, editor); + if (RainbowHighlighter.isRainbowEnabled()) { + return new RainbowIdentifierHighlighterPass(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; - } } diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 2b0d6129d33b..80ca56326205 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -95,6 +95,9 @@ + + diff --git a/platform/platform-resources/src/componentSets/Lang.xml b/platform/platform-resources/src/componentSets/Lang.xml index 9fb161e81b10..720d67480145 100644 --- a/platform/platform-resources/src/componentSets/Lang.xml +++ b/platform/platform-resources/src/componentSets/Lang.xml @@ -154,6 +154,10 @@ com.intellij.codeInsight.daemon.impl.CodeFoldingPassFactory + + com.intellij.codeInsight.daemon.impl.RainbowIdentifierHighlighterPassFactory + + com.intellij.codeInsight.daemon.impl.IndentsPassFactory