28
28
import fr .adrienbrault .idea .symfony2plugin .dic .RelatedPopupGotoLineMarker ;
29
29
import fr .adrienbrault .idea .symfony2plugin .stubs .indexes .TwigIncludeStubIndex ;
30
30
import fr .adrienbrault .idea .symfony2plugin .templating .util .TwigUtil ;
31
+ import fr .adrienbrault .idea .symfony2plugin .twig .loader .FileImplementsLazyLoader ;
32
+ import fr .adrienbrault .idea .symfony2plugin .twig .loader .FileOverwritesLazyLoader ;
33
+ import fr .adrienbrault .idea .symfony2plugin .twig .utils .TwigBlockUtil ;
31
34
import icons .TwigIcons ;
32
35
import org .apache .commons .lang .StringUtils ;
33
36
import org .jetbrains .annotations .NotNull ;
42
45
public class TwigLineMarkerProvider implements LineMarkerProvider {
43
46
@ Override
44
47
public void collectSlowLineMarkers (@ NotNull List <PsiElement > psiElements , @ NotNull Collection <LineMarkerInfo > results ) {
45
-
46
48
if (psiElements .size () == 0 || !Symfony2ProjectComponent .isEnabled (psiElements .get (0 ))) {
47
49
return ;
48
50
}
49
51
52
+ Map <VirtualFile , FileImplementsLazyLoader > implementsMap = new HashMap <>();
53
+ FileOverwritesLazyLoader fileOverwritesLazyLoader = null ;
54
+
50
55
for (PsiElement psiElement : psiElements ) {
51
56
// controller
52
57
if (psiElement instanceof TwigFile ) {
@@ -67,12 +72,21 @@ public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNu
67
72
} else if (TwigPattern .getBlockTagPattern ().accepts (psiElement ) || TwigPattern .getPrintBlockFunctionPattern ("block" ).accepts (psiElement )) {
68
73
// blocks: {% block 'foobar' %}, {{ block('foobar') }}
69
74
70
- LineMarkerInfo lineImpl = this .attachBlockImplements (psiElement );
75
+ VirtualFile virtualFile = psiElement .getContainingFile ().getVirtualFile ();
76
+ if (!implementsMap .containsKey (virtualFile )) {
77
+ implementsMap .put (virtualFile , new FileImplementsLazyLoader (psiElement .getProject (), virtualFile ));
78
+ }
79
+
80
+ LineMarkerInfo lineImpl = attachBlockImplements (psiElement , implementsMap .get (virtualFile ));
71
81
if (lineImpl != null ) {
72
82
results .add (lineImpl );
73
83
}
74
84
75
- LineMarkerInfo lineOverwrites = this .attachBlockOverwrites (psiElement );
85
+ if (fileOverwritesLazyLoader == null ) {
86
+ fileOverwritesLazyLoader = new FileOverwritesLazyLoader (psiElements .get (0 ).getProject ());
87
+ }
88
+
89
+ LineMarkerInfo lineOverwrites = attachBlockOverwrites (psiElement , fileOverwritesLazyLoader );
76
90
if (lineOverwrites != null ) {
77
91
results .add (lineOverwrites );
78
92
}
@@ -179,52 +193,64 @@ private LineMarkerInfo getRelatedPopover(String singleItemTitle, String singleIt
179
193
}
180
194
181
195
@ Nullable
182
- private LineMarkerInfo attachBlockImplements (@ NotNull PsiElement psiElement ) {
183
- Collection <PsiElement > blockTargets = TwigUtil .getBlocksByImplementations (psiElement );
184
- if (blockTargets .size () == 0 ) {
196
+ private LineMarkerInfo attachBlockImplements (@ NotNull PsiElement psiElement , @ NotNull FileImplementsLazyLoader implementsLazyLoader ) {
197
+ if (!TwigBlockUtil .hasBlockImplementations (psiElement , implementsLazyLoader )) {
185
198
return null ;
186
199
}
187
200
188
- List <GotoRelatedItem > gotoRelatedItems = new ArrayList <>();
189
- for (PsiElement blockTag : blockTargets ) {
190
- gotoRelatedItems .add (new RelatedPopupGotoLineMarker .PopupGotoRelatedItem (blockTag , TwigUtil .getPresentableTemplateName (blockTag , true )).withIcon (TwigIcons .TwigFileIcon , Symfony2Icons .TWIG_LINE_MARKER ));
201
+ NavigationGutterIconBuilder <PsiElement > builder = NavigationGutterIconBuilder .create (PhpIcons .IMPLEMENTED )
202
+ .setTargets (new BlockImplementationLazyValue (psiElement ))
203
+ .setTooltipText ("Implementations" )
204
+ .setCellRenderer (new MyBlockListCellRenderer ());
205
+
206
+ return builder .createLineMarkerInfo (psiElement );
207
+ }
208
+
209
+ private static class BlockImplementationLazyValue extends NotNullLazyValue <Collection <? extends PsiElement >> {
210
+ @ NotNull
211
+ private final PsiElement psiElement ;
212
+
213
+ BlockImplementationLazyValue (@ NotNull PsiElement psiElement ) {
214
+ this .psiElement = psiElement ;
191
215
}
192
216
193
- return getRelatedPopover ("Implementations" , "Impl: " , psiElement , gotoRelatedItems , PhpIcons .IMPLEMENTED );
217
+ @ NotNull
218
+ @ Override
219
+ protected Collection <? extends PsiElement > compute () {
220
+ return TwigBlockUtil .getBlockImplementationTargets (psiElement );
221
+ }
194
222
}
195
223
196
- @ Nullable
197
- private LineMarkerInfo attachBlockOverwrites (PsiElement psiElement ) {
198
- Collection <PsiElement > blocks = TwigTemplateGoToDeclarationHandler .getBlockGoTo (psiElement );
199
- if (blocks .size () == 0 ) {
200
- return null ;
224
+ /**
225
+ * Provides lazy targets for given template scope
226
+ */
227
+ private static class BlockOverwriteLazyValue extends NotNullLazyValue <Collection <? extends PsiElement >> {
228
+ @ NotNull
229
+ private final PsiElement psiElement ;
230
+
231
+ BlockOverwriteLazyValue (@ NotNull PsiElement psiElement ) {
232
+ this .psiElement = psiElement ;
201
233
}
202
234
203
- List <GotoRelatedItem > gotoRelatedItems = new ArrayList <>();
204
- for (PsiElement blockTag : blocks ) {
205
- gotoRelatedItems .add (new RelatedPopupGotoLineMarker .PopupGotoRelatedItem (
206
- blockTag ,
207
- TwigUtil .getPresentableTemplateName (blockTag , true )
208
- ).withIcon (TwigIcons .TwigFileIcon , Symfony2Icons .TWIG_LINE_MARKER ));
235
+ @ NotNull
236
+ @ Override
237
+ protected Collection <? extends PsiElement > compute () {
238
+ return TwigBlockUtil .getBlockOverwriteTargets (psiElement );
209
239
}
240
+ }
210
241
211
- // single item has no popup
212
- String title = "Overwrites" ;
213
- if (gotoRelatedItems .size () == 1 ) {
214
- String customName = gotoRelatedItems .get (0 ).getCustomName ();
215
- if (customName != null ) {
216
- title = title .concat (": " ).concat (customName );
217
- }
242
+ @ Nullable
243
+ private LineMarkerInfo attachBlockOverwrites (PsiElement psiElement , @ NotNull FileOverwritesLazyLoader loader ) {
244
+ if (!TwigBlockUtil .hasBlockOverwrites (psiElement , loader )) {
245
+ return null ;
218
246
}
219
247
220
- return new LineMarkerInfo <>(
221
- psiElement ,
222
- psiElement .getTextRange (),
223
- PhpIcons .OVERRIDES , 6 ,
224
- new ConstantFunction <>(title ),
225
- new RelatedPopupGotoLineMarker .NavigationHandler (gotoRelatedItems ),
226
- GutterIconRenderer .Alignment .RIGHT
227
- );
248
+ NavigationGutterIconBuilder <PsiElement > builder = NavigationGutterIconBuilder .create (PhpIcons .OVERRIDES )
249
+ .setTargets (new BlockOverwriteLazyValue (psiElement ))
250
+ .setTooltipText ("Overwrites" )
251
+ .setCellRenderer (new MyBlockListCellRenderer ());
252
+
253
+ return builder .createLineMarkerInfo (psiElement );
228
254
}
229
255
230
256
@ Nullable
@@ -323,4 +349,29 @@ protected Collection<? extends PsiElement> compute() {
323
349
return targets ;
324
350
}
325
351
}
352
+
353
+ private static class MyBlockListCellRenderer extends PsiElementListCellRenderer {
354
+ @ Override
355
+ public String getElementText (PsiElement psiElement ) {
356
+ return StringUtils .abbreviate (
357
+ SymbolPresentationUtil .getSymbolPresentableText (psiElement ),
358
+ 50
359
+ );
360
+ }
361
+
362
+ @ Override
363
+ protected String getContainerText (PsiElement psiElement , String s ) {
364
+ return TwigUtil .getPresentableTemplateName (psiElement , true );
365
+ }
366
+
367
+ @ Override
368
+ protected int getIconFlags () {
369
+ return 1 ;
370
+ }
371
+
372
+ @ Override
373
+ protected Icon getIcon (PsiElement psiElement ) {
374
+ return TwigIcons .TwigFileIcon ;
375
+ }
376
+ }
326
377
}
0 commit comments