Skip to content

Commit 9a70056

Browse files
committed
refactoring for template resolving, one file can have more then one template name now. So provide a overwrite template linemarker #437
1 parent 8069ee9 commit 9a70056

File tree

9 files changed

+185
-48
lines changed

9 files changed

+185
-48
lines changed

src/fr/adrienbrault/idea/symfony2plugin/Symfony2Icons.java

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class Symfony2Icons {
4545
public static final Icon TWIG_CONTROLLER_LINE_MARKER = IconLoader.getIcon("icons/twig_controller_line_marker.png");
4646
public static final Icon SYMFONY_LINE_MARKER = IconLoader.getIcon("icons/symfony_line_marker.png");
4747
public static final Icon TWIG_LINE_MARKER = IconLoader.getIcon("icons/twig_line_marker.png");
48+
public static final Icon TWIG_LINE_OVERWRITE = IconLoader.getIcon("icons/overwrite.png");
4849

4950
public static final Icon PARAMETER_OPACITY = IconLoader.getIcon("icons/parameter_opacity.png");
5051

src/fr/adrienbrault/idea/symfony2plugin/TwigHelper.java

+41-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigMacroFunctionStubIndex;
3030
import fr.adrienbrault.idea.symfony2plugin.templating.TemplateLookupElement;
3131
import fr.adrienbrault.idea.symfony2plugin.templating.assets.TwigNamedAssetsServiceParser;
32+
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TemplateFileMap;
3233
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TwigBlock;
3334
import fr.adrienbrault.idea.symfony2plugin.templating.path.*;
3435
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigTypeResolveUtil;
@@ -58,17 +59,52 @@ public class TwigHelper {
5859

5960
public static String TEMPLATE_ANNOTATION_CLASS = "\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Template";
6061

61-
public static Map<String, VirtualFile> getTemplateFilesByName(Project project, boolean useTwig, boolean usePhp) {
62+
@Deprecated
63+
public static Map<String, VirtualFile> getTemplateFilesByName(@NotNull Project project, boolean useTwig, boolean usePhp) {
64+
return getTemplateMap(project, useTwig, usePhp).getTemplates();
65+
}
6266

63-
Map<String, VirtualFile> results = new HashMap<String, VirtualFile>();
67+
@NotNull
68+
public static TemplateFileMap getTemplateMap(@NotNull Project project, boolean useTwig, boolean usePhp) {
6469

6570
List<TwigPath> twigPaths = new ArrayList<TwigPath>();
6671
twigPaths.addAll(getTwigNamespaces(project));
6772

6873
if(twigPaths.size() == 0) {
69-
return results;
74+
return new TemplateFileMap();
75+
}
76+
77+
// app/Resources/ParentBundle/Resources/views
78+
Map<String, SymfonyBundle> parentBundles = new SymfonyBundleUtil(project).getParentBundles();
79+
if(parentBundles.size() > 0) {
80+
for (Map.Entry<String, SymfonyBundle> entry : parentBundles.entrySet()) {
81+
VirtualFile views = entry.getValue().getRelative("Resources/views");
82+
if(views != null) {
83+
twigPaths.add(new TwigPath(views.getPath(), entry.getKey(), TwigPathIndex.NamespaceType.BUNDLE));
84+
}
85+
}
86+
}
87+
88+
// app/Resources/FooBundle/views
89+
VirtualFile relativeFile = VfsUtil.findRelativeFile(project.getBaseDir(), "app", "Resources");
90+
if(relativeFile != null) {
91+
for (VirtualFile virtualFile : relativeFile.getChildren()) {
92+
93+
if(!virtualFile.isDirectory() || !virtualFile.getName().endsWith("Bundle")) {
94+
continue;
95+
}
96+
97+
VirtualFile views = virtualFile.findChild("views");
98+
if(views == null) {
99+
continue;
100+
}
101+
102+
twigPaths.add(new TwigPath(views.getPath(), virtualFile.getName(), TwigPathIndex.NamespaceType.BUNDLE));
103+
}
70104
}
71105

106+
TemplateFileMap container = new TemplateFileMap();
107+
72108
for (TwigPath twigPath : twigPaths) {
73109
if(twigPath.isEnabled()) {
74110
VirtualFile virtualDirectoryFile = twigPath.getDirectory(project);
@@ -83,13 +119,13 @@ public boolean visitFile(@NotNull VirtualFile virtualFile) {
83119
}
84120
});
85121

86-
results.putAll(twigPathContentIterator.getResults());
122+
container.putAll(twigPathContentIterator.getResults());
87123
}
88124
}
89125

90126
}
91127

92-
return results;
128+
return container;
93129
}
94130

95131
public static Map<String, VirtualFile> getTwigFilesByName(Project project) {
Loading
Loading

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigControllerLineMarkerProvider.java

+60-20
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,19 @@
2727
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigExtendsStubIndex;
2828
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigIncludeStubIndex;
2929
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigMacroFromStubIndex;
30+
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TemplateFileMap;
3031
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
3132
import icons.TwigIcons;
3233
import org.jetbrains.annotations.NotNull;
3334
import org.jetbrains.annotations.Nullable;
3435

36+
import javax.swing.*;
3537
import java.util.*;
3638

3739
public class TwigControllerLineMarkerProvider implements LineMarkerProvider {
3840

3941

40-
private Map<String, VirtualFile> templateMapCache = null;
42+
private TemplateFileMap templateMapCache = null;
4143

4244
@Override
4345
public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNull Collection<LineMarkerInfo> results) {
@@ -78,6 +80,12 @@ public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNu
7880
if(lineFromInclude != null) {
7981
results.add(lineFromInclude);
8082
}
83+
84+
// attach parent includes goto
85+
LineMarkerInfo overwrites = attachOverwrites((TwigFile) psiElement);
86+
if(overwrites != null) {
87+
results.add(overwrites);
88+
}
8189
}
8290

8391
}
@@ -110,12 +118,13 @@ private void attachController(@NotNull TwigFile twigFile, @NotNull Collection<?
110118

111119
private LineMarkerInfo attachIncludes(TwigFile twigFile) {
112120

121+
TemplateFileMap files = getTemplateFilesByName(twigFile.getProject());
113122

114123
final Collection<PsiFile> targets = new ArrayList<PsiFile>();
115-
for(Map.Entry<String, VirtualFile> entry: TwigUtil.getTemplateName(twigFile).entrySet()) {
124+
for(String templateName: TwigUtil.getTemplateName(twigFile.getVirtualFile(), files)) {
116125

117126
final Project project = twigFile.getProject();
118-
FileBasedIndexImpl.getInstance().getFilesWithKey(TwigIncludeStubIndex.KEY, new HashSet<String>(Arrays.asList(entry.getKey())), new Processor<VirtualFile>() {
127+
FileBasedIndexImpl.getInstance().getFilesWithKey(TwigIncludeStubIndex.KEY, new HashSet<String>(Arrays.asList(templateName)), new Processor<VirtualFile>() {
119128
@Override
120129
public boolean process(VirtualFile virtualFile) {
121130
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
@@ -134,29 +143,60 @@ public boolean process(VirtualFile virtualFile) {
134143
return null;
135144
}
136145

137-
Map<String, VirtualFile> files = getTemplateFilesByName(twigFile.getProject());
138146

139147
List<GotoRelatedItem> gotoRelatedItems = new ArrayList<GotoRelatedItem>();
140148
for(PsiElement blockTag: targets) {
141-
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files, blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
149+
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files.getTemplates(), blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
142150
}
143151

144152
return getRelatedPopover("Implementations", "Impl: " ,twigFile, gotoRelatedItems);
145153

146154
}
147155

148-
private Map<String, VirtualFile> getTemplateFilesByName(Project project) {
149-
return this.templateMapCache == null ? this.templateMapCache = TwigHelper.getTemplateFilesByName(project, true, false) : this.templateMapCache;
156+
@Nullable
157+
private LineMarkerInfo attachOverwrites(@NotNull TwigFile twigFile) {
158+
159+
Collection<PsiFile> targets = new ArrayList<PsiFile>();
160+
161+
TemplateFileMap files = getTemplateFilesByName(twigFile.getProject());
162+
163+
for (String templateName: TwigUtil.getTemplateName(twigFile.getVirtualFile(), files)) {
164+
for (PsiFile psiFile : TwigHelper.getTemplatePsiElements(twigFile.getProject(), templateName)) {
165+
if(!psiFile.getVirtualFile().equals(twigFile.getVirtualFile()) && !targets.contains(psiFile)) {
166+
targets.add(psiFile);
167+
}
168+
}
169+
}
170+
171+
if(targets.size() == 0) {
172+
return null;
173+
}
174+
175+
List<GotoRelatedItem> gotoRelatedItems = new ArrayList<GotoRelatedItem>();
176+
for(PsiElement blockTag: targets) {
177+
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(
178+
blockTag,
179+
TwigUtil.getPresentableTemplateName(files.getTemplates(), blockTag, true)
180+
).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_OVERWRITE));
181+
}
182+
183+
return getRelatedPopover("Overwrites", "Overwrite", twigFile, gotoRelatedItems, Symfony2Icons.TWIG_LINE_OVERWRITE);
184+
}
185+
186+
private TemplateFileMap getTemplateFilesByName(Project project) {
187+
return this.templateMapCache == null ? this.templateMapCache = TwigHelper.getTemplateMap(project, true, false) : this.templateMapCache;
150188
}
151189

152190
@Nullable
153191
private LineMarkerInfo attachFromIncludes(TwigFile twigFile) {
154192

193+
TemplateFileMap files = getTemplateFilesByName(twigFile.getProject());
194+
155195
final Collection<PsiFile> targets = new ArrayList<PsiFile>();
156-
for(Map.Entry<String, VirtualFile> entry: TwigUtil.getTemplateName(twigFile).entrySet()) {
196+
for(String templateName: files.getNames(twigFile.getVirtualFile())) {
157197

158198
final Project project = twigFile.getProject();
159-
FileBasedIndexImpl.getInstance().getFilesWithKey(TwigMacroFromStubIndex.KEY, new HashSet<String>(Arrays.asList(entry.getKey())), new Processor<VirtualFile>() {
199+
FileBasedIndexImpl.getInstance().getFilesWithKey(TwigMacroFromStubIndex.KEY, new HashSet<String>(Arrays.asList(templateName)), new Processor<VirtualFile>() {
160200
@Override
161201
public boolean process(VirtualFile virtualFile) {
162202
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
@@ -175,17 +215,19 @@ public boolean process(VirtualFile virtualFile) {
175215
return null;
176216
}
177217

178-
Map<String, VirtualFile> files = getTemplateFilesByName(twigFile.getProject());
179-
180218
List<GotoRelatedItem> gotoRelatedItems = new ArrayList<GotoRelatedItem>();
181219
for(PsiElement blockTag: targets) {
182-
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files, blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
220+
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files.getTemplates(), blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
183221
}
184222

185-
return getRelatedPopover("Implementations", "Impl: " ,twigFile, gotoRelatedItems);
223+
return getRelatedPopover("Implementations", "Impl: ", twigFile, gotoRelatedItems);
186224
}
187225

188226
private LineMarkerInfo getRelatedPopover(String singleItemTitle, String singleItemTooltipPrefix, PsiElement lineMarkerTarget, List<GotoRelatedItem> gotoRelatedItems) {
227+
return getRelatedPopover(singleItemTitle, singleItemTooltipPrefix, lineMarkerTarget, gotoRelatedItems, PhpIcons.IMPLEMENTED);
228+
}
229+
230+
private LineMarkerInfo getRelatedPopover(String singleItemTitle, String singleItemTooltipPrefix, PsiElement lineMarkerTarget, List<GotoRelatedItem> gotoRelatedItems, Icon icon) {
189231

190232
// single item has no popup
191233
String title = singleItemTitle;
@@ -196,7 +238,7 @@ private LineMarkerInfo getRelatedPopover(String singleItemTitle, String singleIt
196238
}
197239
}
198240

199-
return new LineMarkerInfo<PsiElement>(lineMarkerTarget, lineMarkerTarget.getTextOffset(), PhpIcons.IMPLEMENTED, 6, new ConstantFunction<PsiElement, String>(title), new RelatedPopupGotoLineMarker.NavigationHandler(gotoRelatedItems));
241+
return new LineMarkerInfo<PsiElement>(lineMarkerTarget, lineMarkerTarget.getTextOffset(), icon, 6, new ConstantFunction<PsiElement, String>(title), new RelatedPopupGotoLineMarker.NavigationHandler(gotoRelatedItems));
200242
}
201243

202244
@Nullable
@@ -207,10 +249,10 @@ private LineMarkerInfo attachBlockImplements(final PsiElement psiElement) {
207249
return null;
208250
}
209251

210-
Map<String, VirtualFile> files = getTemplateFilesByName(psiElement.getProject());
252+
TemplateFileMap files = getTemplateFilesByName(psiElement.getProject());
211253

212254
List<PsiFile> twigChild = new ArrayList<PsiFile>();
213-
getTwigChildList(files, psiFile, twigChild, 8);
255+
getTwigChildList(files.getTemplates(), psiFile, twigChild, 8);
214256

215257
if(twigChild.size() == 0) {
216258
return null;
@@ -236,7 +278,7 @@ public boolean isAccepted(PsiElement psiElement) {
236278

237279
List<GotoRelatedItem> gotoRelatedItems = new ArrayList<GotoRelatedItem>();
238280
for(PsiElement blockTag: blockTargets) {
239-
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files, blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
281+
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files.getTemplates(), blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
240282
}
241283

242284
return getRelatedPopover("Implementations", "Impl: ", psiElement, gotoRelatedItems);
@@ -251,11 +293,9 @@ private LineMarkerInfo attachBlockOverwrites(PsiElement psiElement) {
251293
return null;
252294
}
253295

254-
Map<String, VirtualFile> files = getTemplateFilesByName(psiElement.getProject());
255-
256296
List<GotoRelatedItem> gotoRelatedItems = new ArrayList<GotoRelatedItem>();
257297
for(PsiElement blockTag: blocks) {
258-
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(files, blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
298+
gotoRelatedItems.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(blockTag, TwigUtil.getPresentableTemplateName(getTemplateFilesByName(psiElement.getProject()).getTemplates(), blockTag, true)).withIcon(TwigIcons.TwigFileIcon, Symfony2Icons.TWIG_LINE_MARKER));
259299
}
260300

261301
// single item has no popup
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package fr.adrienbrault.idea.symfony2plugin.templating.dict;
2+
3+
import com.intellij.openapi.vfs.VirtualFile;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
import java.util.HashMap;
7+
import java.util.HashSet;
8+
import java.util.Map;
9+
import java.util.Set;
10+
11+
/**
12+
* @author Daniel Espendiller <daniel@espendiller.net>
13+
*/
14+
public class TemplateFileMap {
15+
16+
private final Map<String, Set<VirtualFile>> templateNames = new HashMap<String, Set<VirtualFile>>();
17+
18+
public Map<String, Set<VirtualFile>> getTemplateNames() {
19+
return templateNames;
20+
}
21+
22+
public Set<String> getNames(@NotNull VirtualFile virtualFile) {
23+
Set<String> fileNames = new HashSet<String>();
24+
25+
for (Map.Entry<String, Set<VirtualFile>> entry : templateNames.entrySet()) {
26+
if(entry.getValue().contains(virtualFile)) {
27+
fileNames.add(entry.getKey());
28+
}
29+
}
30+
31+
return fileNames;
32+
}
33+
34+
@Deprecated
35+
public Map<String, VirtualFile> getTemplates() {
36+
37+
Map<String, VirtualFile> templates = new HashMap<String, VirtualFile>();
38+
39+
for (Map.Entry<String, Set<VirtualFile>> entry : templateNames.entrySet()) {
40+
templates.put(entry.getKey(), entry.getValue().iterator().next());
41+
}
42+
43+
return templates;
44+
}
45+
46+
public void put(@NotNull String namespace, @NotNull VirtualFile virtualFile) {
47+
if(!templateNames.containsKey(namespace)) {
48+
templateNames.put(namespace, new HashSet<VirtualFile>());
49+
}
50+
51+
templateNames.get(namespace).add(virtualFile);
52+
}
53+
54+
public void putAll(@NotNull Map<String, VirtualFile> files) {
55+
for (Map.Entry<String, VirtualFile> entry : files.entrySet()) {
56+
put(entry.getKey(), entry.getValue());
57+
}
58+
}
59+
}

src/fr/adrienbrault/idea/symfony2plugin/templating/util/TwigUtil.java

+8-21
Original file line numberDiff line numberDiff line change
@@ -353,26 +353,14 @@ public static Method findTwigFileController(TwigFile twigFile) {
353353

354354
}
355355

356-
public static Map<String, VirtualFile> getTemplateName(TwigFile twigFile, Map<String, VirtualFile> templateMap) {
357-
358-
Map<String, VirtualFile> map = new HashMap<String, VirtualFile>();
359-
360-
for(Map.Entry<String, VirtualFile> entry: templateMap.entrySet()) {
361-
if(twigFile.getVirtualFile().equals(entry.getValue())) {
362-
map.put(entry.getKey(), twigFile.getVirtualFile());
363-
}
364-
}
365-
366-
String templateNameByOverwrite = getTemplateNameByOverwrite(twigFile.getProject(), twigFile.getVirtualFile());
367-
if(templateNameByOverwrite != null) {
368-
map.put(templateNameByOverwrite, twigFile.getVirtualFile());
369-
}
370-
371-
return map;
356+
@NotNull
357+
public static Set<String> getTemplateName(@NotNull VirtualFile virtualFile, @NotNull TemplateFileMap map) {
358+
return map.getNames(virtualFile);
372359
}
373360

374-
public static Map<String, VirtualFile> getTemplateName(TwigFile twigFile) {
375-
return getTemplateName(twigFile, TwigHelper.getTemplateFilesByName(twigFile.getProject(), true, false));
361+
@NotNull
362+
public static Set<String> getTemplateName(@NotNull TwigFile twigFile) {
363+
return getTemplateName(twigFile.getVirtualFile(), TwigHelper.getTemplateMap(twigFile.getProject(), true, false));
376364
}
377365

378366
public static Map<String, PsiVariable> collectControllerTemplateVariables(PsiElement psiElement) {
@@ -403,12 +391,11 @@ public static Map<String, PsiVariable> collectControllerTemplateVariables(PsiEle
403391
@NotNull
404392
public static Set<Method> getTwigFileMethodUsageOnIndex(@NotNull TwigFile psiFile) {
405393

406-
Map<String, VirtualFile> templateName = TwigUtil.getTemplateName(psiFile);
407-
if(templateName.size() == 0) {
394+
final Set<String> keys = TwigUtil.getTemplateName(psiFile);
395+
if(keys.size() == 0) {
408396
return Collections.emptySet();
409397
}
410398

411-
final Set<String> keys = templateName.keySet();
412399
final Set<VirtualFile> virtualFiles = new HashSet<VirtualFile>();
413400

414401
// find virtual files

src/fr/adrienbrault/idea/symfony2plugin/templating/variable/collector/IncludeVariableCollector.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ private Collection<VirtualFile> getImplements(TwigFile twigFile) {
173173

174174
final Set<VirtualFile> targets = new HashSet<VirtualFile>();
175175

176-
for(Map.Entry<String, VirtualFile> entry: TwigUtil.getTemplateName(twigFile).entrySet()) {
176+
for(String templateName: TwigUtil.getTemplateName(twigFile)) {
177177

178178
final Project project = twigFile.getProject();
179-
FileBasedIndexImpl.getInstance().getFilesWithKey(TwigIncludeStubIndex.KEY, new HashSet<String>(Arrays.asList(entry.getKey())), new Processor<VirtualFile>() {
179+
FileBasedIndexImpl.getInstance().getFilesWithKey(TwigIncludeStubIndex.KEY, new HashSet<String>(Arrays.asList(templateName)), new Processor<VirtualFile>() {
180180
@Override
181181
public boolean process(VirtualFile virtualFile) {
182182
targets.add(virtualFile);

0 commit comments

Comments
 (0)