package de.espend.idea.shopware.navigation; import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.xml.XmlFile; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.php.PhpIndex; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; import de.espend.idea.shopware.ShopwareProjectComponent; import de.espend.idea.shopware.completion.ShopwarePhpCompletion; import de.espend.idea.shopware.util.ConfigUtil; import de.espend.idea.shopware.util.ShopwareUtil; import de.espend.idea.shopware.util.ThemeUtil; import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; /** * @author Daniel Espendiller <[email protected]> */ public class PhpGoToHandler implements GotoDeclarationHandler { @Nullable @Override public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Editor editor) { if(!ShopwareProjectComponent.isValidForProject(psiElement)) { return new PsiElement[0]; } List<PsiElement> psiElements = new ArrayList<>(); if(ShopwareUtil.getBootstrapPathPattern().accepts(psiElement)) { attachBootstrapFiles(psiElement, psiElements); } if(ThemeUtil.getJavascriptClassFieldPattern().accepts(psiElement)){ attachThemeJsFieldReferences(psiElement, psiElements); } if(ThemeUtil.getThemeExtendsPattern().accepts(psiElement)){ attachThemeExtend(psiElement, psiElements); } if(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)).accepts(psiElement)) { attachNamespaceNavigation(psiElement, psiElements); } if(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)).accepts(psiElement)) { attachNamespaceValueNavigation(psiElement, psiElements); } return psiElements.toArray(new PsiElement[0]); } private void attachNamespaceNavigation(@NotNull PsiElement psiElement, @NotNull List<PsiElement> psiElements) { PsiElement parent = psiElement.getParent(); if(!(parent instanceof StringLiteralExpression)) { return; } String contents = ((StringLiteralExpression) parent).getContents(); if(StringUtils.isBlank(contents)) { return; } MethodMatcher.MethodMatchParameter match = MethodMatcher.getMatchedSignatureWithDepth(parent, ShopwarePhpCompletion.CONFIG_NAMESPACE); if(match == null) { return; } ConfigUtil.visitNamespace(psiElement.getProject(), pair -> { if(contents.equalsIgnoreCase(pair.getFirst())) { PhpClass phpClass = pair.getSecond(); PsiElement target = phpClass; // PhpClass or "Resources/config.xml" as target PsiDirectory pluginDir = phpClass.getContainingFile().getParent(); if(pluginDir != null) { VirtualFile resources = VfsUtil.findRelativeFile(pluginDir.getVirtualFile(), "Resources", "config.xml"); if(resources != null) { PsiFile file = PsiManager.getInstance(phpClass.getProject()).findFile(resources); if(file instanceof XmlFile) { target = file; } } } psiElements.add(target); } }); } private void attachNamespaceValueNavigation(@NotNull PsiElement psiElement, @NotNull List<PsiElement> psiElements) { PsiElement parent = psiElement.getParent(); if(!(parent instanceof StringLiteralExpression)) { return; } String contents = ((StringLiteralExpression) parent).getContents(); if(StringUtils.isBlank(contents)) { return; } String namespace = ConfigUtil.getNamespaceFromConfigValueParameter((StringLiteralExpression) parent); if (namespace == null) { return; } ConfigUtil.visitNamespaceConfigurations(psiElement.getProject(), namespace, pair -> { if(contents.equalsIgnoreCase(pair.getFirst())) { psiElements.add(pair.getSecond()); } }); } private void attachThemeJsFieldReferences(final PsiElement psiElement, final List<PsiElement> psiElements) { final PsiElement parent = psiElement.getParent(); if(!(parent instanceof StringLiteralExpression)) { return; } final String contents = ((StringLiteralExpression) parent).getContents(); if(StringUtils.isBlank(contents)) { return; } ThemeUtil.collectThemeJsFieldReferences((StringLiteralExpression) parent, (virtualFile, path) -> { if(path.equals(contents)) { PsiFile psiFile = PsiManager.getInstance(psiElement.getProject()).findFile(virtualFile); if(psiFile != null) { psiElements.add(psiFile); } return false; } return true; }); } private void attachThemeExtend(PsiElement psiElement, List<PsiElement> psiElements) { final PsiElement parent = psiElement.getParent(); if(!(parent instanceof StringLiteralExpression)) { return; } final String contents = ((StringLiteralExpression) parent).getContents(); if(StringUtils.isBlank(contents)) { return; } for(PhpClass phpClass: PhpIndex.getInstance(parent.getProject()).getAllSubclasses("\\Shopware\\Components\\Theme")) { String name = phpClass.getContainingFile().getContainingDirectory().getName(); if(contents.equals(name)) { psiElements.add(phpClass.getContainingFile().getContainingDirectory()); } } } private void attachBootstrapFiles(final PsiElement psiElement, final List<PsiElement> psiElements) { final PsiElement parent = psiElement.getParent(); if(!(parent instanceof StringLiteralExpression)) { return; } ShopwareUtil.collectBootstrapFiles((StringLiteralExpression) parent, (virtualFile, relativePath) -> { String contents = ((StringLiteralExpression) parent).getContents(); if(contents.endsWith("\\") || contents.endsWith("/")) { contents = contents.substring(0, contents.length() - 1); } if(!StringUtils.stripStart(contents, "/\\").equalsIgnoreCase(relativePath)) { return; } ContainerUtil.addIfNotNull(psiElements, PsiManager.getInstance(psiElement.getProject()).findFile(virtualFile)); ContainerUtil.addIfNotNull(psiElements, PsiManager.getInstance(psiElement.getProject()).findDirectory(virtualFile)); }); } @Nullable @Override public String getActionText(DataContext dataContext) { return null; } }