Skip to content

Commit 9132df1

Browse files
committed
Use resolved Twig template icons in Symfony Profiler actions
1 parent 01d79d6 commit 9132df1

2 files changed

Lines changed: 65 additions & 2 deletions

File tree

src/main/java/fr/adrienbrault/idea/symfony2plugin/profiler/widget/action/SymfonyProfilerWidgetActions.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import com.intellij.openapi.actionSystem.AnAction;
44
import com.intellij.openapi.actionSystem.AnActionEvent;
55
import com.intellij.openapi.actionSystem.Presentation;
6+
import com.intellij.openapi.application.ApplicationManager;
67
import com.intellij.openapi.project.Project;
8+
import com.intellij.openapi.util.Computable;
79
import com.intellij.psi.PsiElement;
810
import com.intellij.psi.PsiFile;
11+
import com.intellij.ui.IconManager;
12+
import com.intellij.util.PsiIconUtil;
913
import com.jetbrains.php.lang.psi.elements.PhpClass;
1014
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
1115
import fr.adrienbrault.idea.symfony2plugin.form.util.FormUtil;
@@ -35,8 +39,8 @@ public static class TemplateAction extends AnAction {
3539
private final String templateName;
3640
private final Project project;
3741

38-
public TemplateAction(Project project, @NotNull String templateName) {
39-
super(templateName, "Open Template", TwigIcons.TwigFileIcon);
42+
public TemplateAction(@NotNull Project project, @NotNull String templateName) {
43+
super(templateName, "Open Template", createDeferredTemplateIcon(project, templateName));
4044
this.templateName = templateName;
4145
this.project = project;
4246
}
@@ -50,6 +54,32 @@ public void actionPerformed(@NotNull AnActionEvent e) {
5054
IdeHelper.navigateToPsiElement(psiFiles.iterator().next());
5155
}
5256
}
57+
58+
@NotNull
59+
private static Icon createDeferredTemplateIcon(@NotNull Project project, @NotNull String templateName) {
60+
return IconManager.getInstance().createDeferredIcon(
61+
TwigIcons.TwigFileIcon,
62+
new TemplateIconRequest(project, templateName),
63+
request -> {
64+
Icon icon = ApplicationManager.getApplication().runReadAction((Computable<Icon>) () ->
65+
getTemplateFileIcon(request.project(), request.templateName())
66+
);
67+
return icon != null ? icon : TwigIcons.TwigFileIcon;
68+
}
69+
);
70+
}
71+
72+
@Nullable
73+
public static Icon getTemplateFileIcon(@NotNull Project project, @NotNull String templateName) {
74+
for (PsiFile psiFile : TwigUtil.getTemplatePsiElements(project, templateName)) {
75+
return PsiIconUtil.getIconFromProviders(psiFile, 0);
76+
}
77+
78+
return null;
79+
}
80+
81+
private record TemplateIconRequest(@NotNull Project project, @NotNull String templateName) {
82+
}
5383
}
5484

5585
public static class FormTypeAction extends AnAction {

src/test/java/fr/adrienbrault/idea/symfony2plugin/profiler/widget/SymfonyProfilerWidgetTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,26 @@
33
import com.intellij.openapi.actionSystem.AnAction;
44
import com.intellij.openapi.actionSystem.DefaultActionGroup;
55
import com.intellij.openapi.actionSystem.Separator;
6+
import com.intellij.openapi.application.ApplicationManager;
7+
import com.intellij.openapi.util.Computable;
8+
import com.intellij.ui.LayeredIcon;
9+
import fr.adrienbrault.idea.symfony2plugin.Settings;
610
import fr.adrienbrault.idea.symfony2plugin.profiler.ProfilerIndexInterface;
711
import fr.adrienbrault.idea.symfony2plugin.profiler.collector.DefaultDataCollectorInterface;
812
import fr.adrienbrault.idea.symfony2plugin.profiler.collector.MailCollectorInterface;
913
import fr.adrienbrault.idea.symfony2plugin.profiler.collector.TwigComponentDataCollectorInterface;
1014
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.MailMessage;
1115
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequestInterface;
1216
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerTwigComponent;
17+
import fr.adrienbrault.idea.symfony2plugin.profiler.widget.action.SymfonyProfilerWidgetActions;
18+
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigIncludeStubIndex;
19+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigNamespaceSetting;
20+
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
1321
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
1422
import org.jetbrains.annotations.NotNull;
1523
import org.jetbrains.annotations.Nullable;
1624

25+
import javax.swing.Icon;
1726
import java.util.ArrayList;
1827
import java.util.Collection;
1928
import java.util.Collections;
@@ -80,6 +89,30 @@ public String getUrlForRequest(@NotNull ProfilerRequestInterface request) {
8089
assertTrue(actionTexts.indexOf("HighTraffic") < actionTexts.indexOf("LowTraffic"));
8190
}
8291

92+
public void testTemplateActionUsesResolvedTemplateFileIcon() {
93+
Settings.getInstance(getProject()).twigNamespaces.clear();
94+
Settings.getInstance(getProject()).twigNamespaces.add(
95+
new TwigNamespaceSetting(TwigUtil.MAIN, "templates", true, TwigUtil.NamespaceType.ADD_PATH, true)
96+
);
97+
98+
myFixture.addFileToProject(
99+
"templates/page.html.twig",
100+
"{% include 'partial.html.twig' %}"
101+
);
102+
myFixture.addFileToProject(
103+
"templates/partial.html.twig",
104+
"<div>Partial</div>"
105+
);
106+
107+
assertIndexContains(TwigIncludeStubIndex.KEY, "partial.html.twig");
108+
109+
Icon icon = ApplicationManager.getApplication().runReadAction((Computable<Icon>) () ->
110+
SymfonyProfilerWidgetActions.TemplateAction.getTemplateFileIcon(getProject(), "partial.html.twig")
111+
);
112+
113+
assertTrue("Profiler template action should use the decorated Twig file icon", icon instanceof LayeredIcon);
114+
}
115+
83116
private static class TestProfilerRequest implements ProfilerRequestInterface {
84117
private final String hash;
85118
private final String url;

0 commit comments

Comments
 (0)