From b4f73fb1ee28cb5cbb008f5b89ed61a6403464fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=91=E5=AE=87?= <738576547@qq.com>
Date: Fri, 9 Aug 2024 07:40:07 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E6=81=A2=E5=A4=8Dsymbol-search?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/main/resources/META-INF/plugin.xml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 9f35223f0..86e967f2a 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -878,6 +878,9 @@
+
+
+
Date: Fri, 9 Aug 2024 07:43:06 +0800
Subject: [PATCH 2/2] symbol-search restore
---
.../action/SymfonySymbolSearchAction.java | 285 ++++++++++++++++++
1 file changed, 285 insertions(+)
create mode 100644 src/main/java/fr/adrienbrault/idea/symfony2plugin/action/SymfonySymbolSearchAction.java
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/action/SymfonySymbolSearchAction.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/action/SymfonySymbolSearchAction.java
new file mode 100644
index 000000000..6294379bd
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/action/SymfonySymbolSearchAction.java
@@ -0,0 +1,285 @@
+package fr.adrienbrault.idea.symfony2plugin.action;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.featureStatistics.FeatureUsageTracker;
+import com.intellij.ide.actions.GotoActionBase;
+import com.intellij.ide.util.gotoByName.ChooseByNamePopup;
+import com.intellij.navigation.ChooseByNameContributor;
+import com.intellij.navigation.ChooseByNameContributorEx;
+import com.intellij.navigation.NavigationItem;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.Processor;
+import com.intellij.util.indexing.FindSymbolParameters;
+import com.intellij.util.indexing.IdFilter;
+import com.jetbrains.php.lang.psi.elements.PhpClass;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
+import fr.adrienbrault.idea.symfony2plugin.action.model.SymfonySymbolSearchModel;
+import fr.adrienbrault.idea.symfony2plugin.dic.ContainerService;
+import fr.adrienbrault.idea.symfony2plugin.doctrine.EntityHelper;
+import fr.adrienbrault.idea.symfony2plugin.doctrine.EntityReference;
+import fr.adrienbrault.idea.symfony2plugin.navigation.NavigationItemEx;
+import fr.adrienbrault.idea.symfony2plugin.routing.Route;
+import fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper;
+import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
+import fr.adrienbrault.idea.symfony2plugin.templating.dict.TwigExtension;
+import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigExtensionParser;
+import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
+import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
+import fr.adrienbrault.idea.symfony2plugin.util.SymfonyCommandUtil;
+import fr.adrienbrault.idea.symfony2plugin.util.dict.SymfonyCommand;
+import icons.TwigIcons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * @author Daniel Espendiller
+ */
+public class SymfonySymbolSearchAction extends GotoActionBase {
+
+ @Override
+ protected void gotoActionPerformed(AnActionEvent paramAnActionEvent) {
+ FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.file");
+ Project localProject = paramAnActionEvent.getData(CommonDataKeys.PROJECT);
+ if (localProject != null) {
+ SymfonySymbolSearchModel searchModel = new SymfonySymbolSearchModel(localProject, new ChooseByNameContributor[] { new Symfony2NavigationContributor(localProject) });
+ showNavigationPopup(paramAnActionEvent, searchModel, new MyGotoCallback(), null, true);
+ }
+ }
+
+ @Override
+ public void update(AnActionEvent event) {
+ super.update(event);
+
+ Project project = event.getData(CommonDataKeys.PROJECT);
+
+ boolean enabled = Symfony2ProjectComponent.isEnabled(project);
+
+ event.getPresentation().setVisible(enabled);
+ event.getPresentation().setEnabled(enabled);
+
+ }
+
+ private static class Symfony2NavigationContributor implements ChooseByNameContributorEx, DumbAware {
+ @NotNull
+ final private Project project;
+
+ private ContainerCollectionResolver.ServiceCollector serviceCollector;
+ private Map> templateMap;
+ private Map routes;
+ private Set twigMacroSet;
+ private Map lookupElements;
+
+ private Symfony2NavigationContributor(@NotNull Project project) {
+ this.project = project;
+ }
+
+ private ContainerCollectionResolver.ServiceCollector getServiceCollector() {
+ if(this.serviceCollector == null) {
+ this.serviceCollector = ContainerCollectionResolver.ServiceCollector.create(this.project);
+ }
+
+ return this.serviceCollector;
+ }
+
+ private Map> getTemplateMap() {
+ if(this.templateMap == null) {
+ this.templateMap = TwigUtil.getTemplateMap(this.project, true);
+ }
+
+ return this.templateMap;
+ }
+
+ private Map getRoutes() {
+ if(this.routes == null) {
+ this.routes = RouteHelper.getAllRoutes(project);
+ }
+
+ return this.routes;
+ }
+
+ private Set getTwigMacroSet() {
+ if(this.twigMacroSet == null) {
+ this.twigMacroSet = TwigUtil.getTwigMacroSet(this.project);
+ }
+
+ return this.twigMacroSet;
+ }
+
+ private Map getModelLookupElements() {
+
+ if(this.lookupElements == null) {
+ List modelLookupElements = EntityReference.getModelLookupElements(this.project);
+
+ this.lookupElements = new HashMap<>();
+ for(LookupElement lookupElement: modelLookupElements) {
+ this.lookupElements.put(lookupElement.getLookupString(), lookupElement);
+ }
+
+ }
+
+ return this.lookupElements;
+ }
+
+ @Override
+ public void processNames(@NotNull Processor super String> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter) {
+ for(String name: getServiceCollector().getServices().keySet()) {
+ processor.process(name);
+ }
+
+ for(String templateName: getTemplateMap().keySet()) {
+ processor.process(templateName);
+ }
+
+ for(String name: getRoutes().keySet()) {
+ processor.process(name);
+ }
+
+ for(Map.Entry entry: getRoutes().entrySet()) {
+ processor.process(entry.getKey());
+ String path = entry.getValue().getPath();
+ if(path != null) {
+ processor.process(path);
+ }
+ }
+
+ for(String name: getTwigMacroSet()) {
+ processor.process(name);
+ }
+
+ for(String name: getModelLookupElements().keySet()) {
+ processor.process(name);
+ }
+
+ for(SymfonyCommand command: SymfonyCommandUtil.getCommands(project)) {
+ processor.process(command.getName());
+ }
+
+ // Twig Extensions
+ for (Map extensionMap : Arrays.asList(TwigExtensionParser.getFilters(project), TwigExtensionParser.getFunctions(project))) {
+ for(String twigFilter: extensionMap.keySet()) {
+ processor.process(twigFilter);
+ }
+ }
+ }
+
+ @Override
+ public void processElementsWithName(@NotNull String name, @NotNull Processor super NavigationItem> processor, @NotNull FindSymbolParameters parameters) {
+
+ for(ContainerService containerService: getServiceCollector().collect()) {
+ if(containerService.getName().equals(name)) {
+
+ String serviceClass = getServiceCollector().resolve(name);
+ if (serviceClass != null) {
+ PhpClass phpClass = PhpElementsUtil.getClassInterface(this.project, serviceClass);
+ if(phpClass != null) {
+ processor.process(new NavigationItemEx(phpClass, containerService.getName(), containerService.isWeak() ? Symfony2Icons.SERVICE_PRIVATE_OPACITY : Symfony2Icons.SERVICE, "Service"));
+ }
+ }
+
+ }
+ }
+
+ // @TODO name filter
+ if(getTemplateMap().containsKey(name)) {
+ for (PsiFile psiFile : TwigUtil.getTemplatePsiElements(project, name)) {
+ processor.process(new NavigationItemEx(psiFile, name, psiFile.getFileType().getIcon(), "Template"));
+ }
+ }
+
+ Set controllers = new HashSet<>();
+ if(getRoutes().containsKey(name)) {
+ String controllerName = getRoutes().get(name).getController();
+ if(controllerName != null) {
+ controllers.add(controllerName);
+ }
+ }
+
+ // route path: /foo/bar
+ for (Route route : getRoutes().values()) {
+ if(!name.equals(route.getPath())) {
+ continue;
+ }
+
+ String controller = route.getController();
+ if(controller != null) {
+ controllers.add(controller);
+ }
+ }
+
+ if(!controllers.isEmpty()) {
+ for (String controller : controllers) {
+ for(PsiElement psiElement: RouteHelper.getMethodsOnControllerShortcut(this.project, controller)) {
+ processor.process(new NavigationItemEx(psiElement, name, Symfony2Icons.ROUTE, "Route"));
+ }
+ }
+ }
+
+ if(getTwigMacroSet().contains(name)) {
+ for(PsiElement macroTarget: TwigUtil.getTwigMacroTargets(project, name)) {
+ processor.process(new NavigationItemEx(macroTarget, name, TwigIcons.TwigFileIcon, "Macro"));
+ }
+ }
+
+ if(getModelLookupElements().containsKey(name)) {
+ PsiElement[] psiElements = EntityHelper.getModelPsiTargets(this.project, name);
+
+ getModelLookupElements().get(name).getLookupString();
+ for(PsiElement target: psiElements) {
+ processor.process(new NavigationItemEx(target, name, target.getIcon(0), "Entity"));
+ }
+ }
+
+ for (SymfonyCommand symfonyCommand : SymfonyCommandUtil.getCommands(project)) {
+ if(symfonyCommand.getName().equals(name)) {
+ processor.process(new NavigationItemEx(symfonyCommand.getPhpClass(), name, Symfony2Icons.SYMFONY, "Command"));
+ }
+ }
+
+ // Twig Extensions
+ for (Map extensionMap : Arrays.asList(TwigExtensionParser.getFilters(project), TwigExtensionParser.getFunctions(project))) {
+ for(Map.Entry twigFunc: extensionMap.entrySet()) {
+ if(twigFunc.getKey().equals(name)) {
+ TwigExtension twigExtension = twigFunc.getValue();
+ PsiElement extensionTarget = TwigExtensionParser.getExtensionTarget(project, twigExtension);
+ if(extensionTarget != null) {
+ processor.process(new NavigationItemEx(extensionTarget, name, TwigExtensionParser.getIcon(twigExtension.getTwigExtensionType()), twigExtension.getTwigExtensionType().toString()));
+ }
+ }
+ }
+ }
+ }
+
+ @NotNull
+ @Override
+ public String @NotNull [] getNames(Project project, boolean includeNonProjectItems) {
+ return new String[0];
+ }
+
+ @NotNull
+ @Override
+ public NavigationItem @NotNull [] getItemsByName(String name, String pattern, Project project, boolean includeNonProjectItems) {
+ return new NavigationItem[0];
+ }
+ }
+
+ static class MyGotoCallback extends GotoActionCallback {
+ @Override
+ public void elementChosen(ChooseByNamePopup popup, Object element) {
+ if(element instanceof NavigationItem) {
+ ((NavigationItem) element).navigate(true);
+ }
+ }
+ }
+}
+