2828import fr .adrienbrault .idea .symfony2plugin .dic .RelatedPopupGotoLineMarker ;
2929import fr .adrienbrault .idea .symfony2plugin .stubs .indexes .TwigIncludeStubIndex ;
3030import 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 ;
3134import icons .TwigIcons ;
3235import org .apache .commons .lang .StringUtils ;
3336import org .jetbrains .annotations .NotNull ;
4245public class TwigLineMarkerProvider implements LineMarkerProvider {
4346 @ Override
4447 public void collectSlowLineMarkers (@ NotNull List <PsiElement > psiElements , @ NotNull Collection <LineMarkerInfo > results ) {
45-
4648 if (psiElements .size () == 0 || !Symfony2ProjectComponent .isEnabled (psiElements .get (0 ))) {
4749 return ;
4850 }
4951
52+ Map <VirtualFile , FileImplementsLazyLoader > implementsMap = new HashMap <>();
53+ FileOverwritesLazyLoader fileOverwritesLazyLoader = null ;
54+
5055 for (PsiElement psiElement : psiElements ) {
5156 // controller
5257 if (psiElement instanceof TwigFile ) {
@@ -67,12 +72,21 @@ public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNu
6772 } else if (TwigPattern .getBlockTagPattern ().accepts (psiElement ) || TwigPattern .getPrintBlockFunctionPattern ("block" ).accepts (psiElement )) {
6873 // blocks: {% block 'foobar' %}, {{ block('foobar') }}
6974
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 ));
7181 if (lineImpl != null ) {
7282 results .add (lineImpl );
7383 }
7484
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 );
7690 if (lineOverwrites != null ) {
7791 results .add (lineOverwrites );
7892 }
@@ -179,52 +193,64 @@ private LineMarkerInfo getRelatedPopover(String singleItemTitle, String singleIt
179193 }
180194
181195 @ 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 )) {
185198 return null ;
186199 }
187200
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 ;
191215 }
192216
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+ }
194222 }
195223
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 ;
201233 }
202234
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 );
209239 }
240+ }
210241
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 ;
218246 }
219247
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 );
228254 }
229255
230256 @ Nullable
@@ -323,4 +349,29 @@ protected Collection<? extends PsiElement> compute() {
323349 return targets ;
324350 }
325351 }
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+ }
326377}
0 commit comments