[lang] HierarchyNodeDescriptor: avoid computing tag icon/text in EDT

Fixes IDEA-326861 Type Hierarchy: slow operations on paint HierarchyNodeRenderer

GitOrigin-RevId: dba132544c8118dadf8487948b0b5e9b93f605c0
This commit is contained in:
Tagir Valeev
2023-08-14 11:58:23 +02:00
committed by intellij-monorepo-bot
parent 0d9c9c392f
commit fdb37661df
5 changed files with 25 additions and 9 deletions

View File

@@ -33,8 +33,12 @@ public abstract class TagManager {
public static boolean isEnabled() {
return Registry.is("ide.element.tags.enabled");
}
public record TagIconAndText(@Nullable Icon icon, @NotNull ColoredText coloredText) {
public static final TagIconAndText EMPTY = new TagIconAndText(null, ColoredText.empty());
}
public static Pair<@Nullable Icon, @NotNull ColoredText> getTagIconAndText(@Nullable PsiElement element) {
public static @NotNull TagIconAndText getTagIconAndText(@Nullable PsiElement element) {
Collection<TagManager.Tag> tags = getElementTags(element);
ColoredText.Builder ct = ColoredText.builder();
Icon tagIcon = null;
@@ -46,7 +50,7 @@ public abstract class TagManager {
SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES.derive(SimpleTextAttributes.STYLE_BOLD, tag.color, null, null)
);
}
return Pair.create(tagIcon, ct.build());
return new TagIconAndText(tagIcon, ct.build());
}
public static @NotNull Collection<Tag> getElementTags(@Nullable PsiElement element) {

View File

@@ -5,6 +5,8 @@ package com.intellij.ide.hierarchy;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.projectView.impl.ProjectViewTree;
import com.intellij.ide.tags.TagManager;
import com.intellij.ide.tags.TagManager.TagIconAndText;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.ide.util.treeView.SmartElementDescriptor;
import com.intellij.openapi.editor.markup.TextAttributes;
@@ -27,6 +29,7 @@ public abstract class HierarchyNodeDescriptor extends SmartElementDescriptor {
private Object[] myCachedChildren;
protected final boolean myIsBase;
private Color myBackgroundColor;
private @NotNull TagIconAndText myTagIconAndText = TagIconAndText.EMPTY;
protected HierarchyNodeDescriptor(@NotNull Project project,
@Nullable NodeDescriptor parentDescriptor,
@@ -66,9 +69,18 @@ public abstract class HierarchyNodeDescriptor extends SmartElementDescriptor {
return myBackgroundColor;
}
public @NotNull TagIconAndText getTagIconAndTextCached() {
return myTagIconAndText;
}
@Override
public boolean update() {
boolean changed = super.update();
TagIconAndText newTagIconAndText = TagManager.isEnabled() ? TagManager.getTagIconAndText(getPsiElement()) : TagIconAndText.EMPTY;
if (!newTagIconAndText.equals(myTagIconAndText)) {
myTagIconAndText = newTagIconAndText;
changed = true;
}
myBackgroundColor = ProjectViewTree.getColorForElement(getContainingFile());
return changed;
}

View File

@@ -34,10 +34,10 @@ public final class HierarchyNodeRenderer extends NodeRenderer {
int row, boolean hasFocus) {
Object userObject = TreeUtil.getUserObject(value);
if (userObject instanceof HierarchyNodeDescriptor descriptor) {
var tagIconAndText = TagManager.getTagIconAndText(descriptor.getPsiElement());
var tagIconAndText = descriptor.getTagIconAndTextCached();
descriptor.getHighlightedText().customize(this);
setIcon(IconUtil.rowIcon(tagIconAndText.first, fixIconIfNeeded(descriptor.getIcon(), selected, hasFocus)));
append(tagIconAndText.second);
setIcon(IconUtil.rowIcon(tagIconAndText.icon(), fixIconIfNeeded(descriptor.getIcon(), selected, hasFocus)));
append(tagIconAndText.coloredText());
}
else {
super.customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus);

View File

@@ -187,8 +187,8 @@ public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value>
}
else {
var tagIconAndText = TagManager.getTagIconAndText(value);
tagIcon = tagIconAndText.first;
tagText = tagIconAndText.second;
tagIcon = tagIconAndText.icon();
tagText = tagIconAndText.coloredText();
}
data.setIcon(withIconMarker(icon, tagIcon));
data.setPresentableText(myName);

View File

@@ -412,9 +412,9 @@ public class GroupNode extends Node implements Navigatable, Comparable<GroupNode
FileStatus fileStatus = group.getFileStatus();
Color foregroundColor = fileStatus != null ? fileStatus.getColor() : null;
var tagIconAndText = TagManager.getTagIconAndText(element);
Icon icon = IconUtil.rowIcon(tagIconAndText.first, group.getIcon());
Icon icon = IconUtil.rowIcon(tagIconAndText.icon(), group.getIcon());
List<TextChunk> chunks = new ArrayList<>();
for (ColoredText.Fragment fragment : tagIconAndText.second.fragments()) {
for (ColoredText.Fragment fragment : tagIconAndText.coloredText().fragments()) {
chunks.add(new TextChunk(fragment.fragmentAttributes().toTextAttributes(), fragment.fragmentText()));
}
TextAttributes attributes = SimpleTextAttributes.REGULAR_ATTRIBUTES.toTextAttributes();