diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/linemarker/XmlLineMarkerProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/linemarker/XmlLineMarkerProvider.java index 9572d8076..e7be54f00 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/linemarker/XmlLineMarkerProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/linemarker/XmlLineMarkerProvider.java @@ -48,10 +48,6 @@ public void collectSlowLineMarkers(@NotNull List psiElemen continue; } - if(!XmlHelper.getXmlTagNameLeafStartPattern().accepts(psiElement)) { - continue; - } - PsiElement xmlTag = psiElement.getParent(); if(!(xmlTag instanceof XmlTag)) { continue; diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/XmlLineMarkerProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/XmlLineMarkerProvider.java index 53d1f5a3d..e242b103b 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/XmlLineMarkerProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/XmlLineMarkerProvider.java @@ -4,6 +4,8 @@ import com.intellij.codeInsight.daemon.LineMarkerProvider; import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo; import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.patterns.XmlPatterns; import com.intellij.patterns.XmlTagPattern; import com.intellij.psi.PsiElement; @@ -12,13 +14,20 @@ import com.intellij.psi.xml.XmlTag; import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons; import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; +import fr.adrienbrault.idea.symfony2plugin.config.ServiceLineMarkerProvider; import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper; +import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil; +import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils; import fr.adrienbrault.idea.symfony2plugin.util.resource.FileResourceUtil; +import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.function.Supplier; /** * @author Daniel Espendiller @@ -39,6 +48,10 @@ public void collectSlowLineMarkers(@NotNull List psiElemen for(PsiElement psiElement: psiElements) { if(XmlHelper.getXmlTagNameLeafStartPattern().accepts(psiElement)) { attachRouteActions(psiElement, lineMarkerInfos); + attachRouteImport(psiElement, lineMarkerInfos); + + + } else if(psiElement instanceof XmlFile) { RelatedItemLineMarkerInfo lineMarker = FileResourceUtil.getFileImplementsLineMarker((PsiFile) psiElement); if(lineMarker != null) { @@ -68,6 +81,30 @@ private void attachRouteActions(@NotNull PsiElement psiElement, @NotNull Collect } } + private void attachRouteImport(@NotNull PsiElement psiElement, @NotNull Collection> lineMarkerInfos) { + PsiElement xmlTag = psiElement.getParent(); + if(!(xmlTag instanceof XmlTag) || !Pattern.getRouteImport().accepts(xmlTag)) { + return; + } + + if (!"annotation".equals(((XmlTag) xmlTag).getAttributeValue("type"))) { + return; + } + + String resource = ((XmlTag) xmlTag).getAttributeValue("resource"); + if (StringUtils.isBlank(resource)) { + return; + } + + lineMarkerInfos.add( + FileResourceUtil.getNavigationGutterForRouteAnnotationResources( + psiElement.getProject(), + psiElement.getContainingFile().getVirtualFile(), + resource + ).createLineMarkerInfo(psiElement) + ); + } + @Nullable @Override public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement psiElement) { @@ -82,6 +119,11 @@ public static XmlTagPattern.Capture getRouteTag() { ).inFile(XmlHelper.getXmlFilePattern()); } + public static XmlTagPattern.Capture getRouteImport() { + return XmlPatterns.xmlTag().withName("import").withParent( + XmlPatterns.xmlTag().withName("routes") + ).inFile(XmlHelper.getXmlFilePattern()); + } } } diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/YamlLineMarkerProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/YamlLineMarkerProvider.java index 3d2bef5c9..6b8133633 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/YamlLineMarkerProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/YamlLineMarkerProvider.java @@ -13,6 +13,7 @@ import fr.adrienbrault.idea.symfony2plugin.doctrine.metadata.util.DoctrineMetadataUtil; import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil; import fr.adrienbrault.idea.symfony2plugin.util.resource.FileResourceUtil; +import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +38,7 @@ public void collectSlowLineMarkers(@NotNull List psiElemen attachRouteActions(lineMarkerInfos, psiElement); attachEntityClass(lineMarkerInfos, psiElement); attachRelationClass(lineMarkerInfos, psiElement); + attachRoutingForResources(lineMarkerInfos, psiElement); if(psiElement instanceof YAMLFile) { RelatedItemLineMarkerInfo lineMarker = FileResourceUtil.getFileImplementsLineMarker((PsiFile) psiElement); @@ -47,6 +49,39 @@ public void collectSlowLineMarkers(@NotNull List psiElemen } } + /** + * controllers: + * resource: '../../src/Controller/' + * type: annotation + */ + private void attachRoutingForResources(@NotNull Collection> result, @NotNull PsiElement leafTarget) { + if (leafTarget.getNode().getElementType() != YAMLTokenTypes.SCALAR_KEY) { + return; + } + + PsiElement yamlKeyValue = leafTarget.getParent(); + if (!(yamlKeyValue instanceof YAMLKeyValue)) { + return; + } + + String resource = YamlHelper.getYamlKeyValueAsString((YAMLKeyValue) yamlKeyValue, "resource"); + if (resource == null) { + return; + } + + if (!"annotation".equals(YamlHelper.getYamlKeyValueAsString((YAMLKeyValue) yamlKeyValue, "type"))) { + return; + } + + result.add( + FileResourceUtil.getNavigationGutterForRouteAnnotationResources( + leafTarget.getProject(), + leafTarget.getContainingFile().getVirtualFile(), + resource + ).createLineMarkerInfo(leafTarget) + ); + } + private void attachEntityClass(@NotNull Collection> lineMarkerInfos, @NotNull PsiElement psiElement) { if(psiElement.getNode().getElementType() != YAMLTokenTypes.SCALAR_KEY) { return; diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/resource/FileResourceUtil.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/resource/FileResourceUtil.java index 0cecb13a6..235072034 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/resource/FileResourceUtil.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/resource/FileResourceUtil.java @@ -2,6 +2,7 @@ import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo; import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder; +import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.Pair; @@ -47,7 +48,7 @@ public class FileResourceUtil { * chars that trigger a glob resolving on symfony * extracted from: \Symfony\Component\Config\Loader\FileLoader::import */ - private static final String[] GLOB_DETECTION_CHARS = {"*", "?", "{", "["}; + public static final String[] GLOB_DETECTION_CHARS = {"*", "?", "{", "["}; /** * Search for files refers to given file @@ -395,6 +396,30 @@ public static Pair getGlobalPatternDirectory(@NotNull String res return new Pair<>(join, null); } + public static @NotNull NavigationGutterIconBuilder getNavigationGutterForRouteAnnotationResources(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull String resource) { + return NavigationGutterIconBuilder.create(AllIcons.Modules.SourceRoot) + .setTargets(NotNullLazyValue.lazy(() -> { + String r = resource; + + // try to resolve the following pattern; all are recursive search for php + // ../../Core/**/**/Controller/*Controller.php + // ../src/Controller/ + // ../src/Kernel.php + if (resource.endsWith("/") || resource.endsWith("\\")) { + r += "**.php"; + } else if (Arrays.stream(FileResourceUtil.GLOB_DETECTION_CHARS).noneMatch(r::contains) && !resource.toLowerCase().endsWith(".php")) { + r += "**.php"; + } + + Collection filesForResources = FileResourceUtil.getFilesForResources(project, virtualFile, r) + .stream() + .filter(virtualFile1 -> "php".equalsIgnoreCase(virtualFile1.getExtension())).collect(Collectors.toSet()); + + return PsiElementUtils.convertVirtualFilesToPsiFiles(project, filesForResources); + })) + .setTooltipText("Navigate to matching files"); + } + /** * Find a file based on "glob" and its content path. *