Skip to content

Commit 1ce0ccb

Browse files
author
Vitaliy
authored
Merge pull request #99 from rogyar/61-plugin-target-class
Line markers support for target plugin class and methods
2 parents 1b1d03e + 389cb13 commit 1ce0ccb

File tree

4 files changed

+203
-4
lines changed

4 files changed

+203
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
* Create a Plugin class for a class public method action
1414
* Code Inspection: Warning regarding Cacheable false attribute in default XML
1515
* Create a Preference for a class action
16+
* Create a Block action
17+
* Line markers for navigation from a plugin class to a target class
1618

1719
0.3.0
1820
=============

resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex" />
110110

111111
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginLineMarkerProvider"/>
112+
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginTargetLineMarkerProvider"/>
112113
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.ClassConfigurationLineMarkerProvider"/>
113114
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.WebApiLineMarkerProvider"/>
114115

src/com/magento/idea/magento2plugin/php/linemarker/PluginLineMarkerProvider.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Copyright © Magento, Inc. All rights reserved.
33
* See COPYING.txt for license details.
44
*/
@@ -22,9 +22,6 @@
2222

2323
import java.util.*;
2424

25-
/**
26-
* Created by dkvashnin on 11/12/15.
27-
*/
2825
public class PluginLineMarkerProvider implements LineMarkerProvider {
2926
@Nullable
3027
@Override
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.php.linemarker;
6+
7+
import com.intellij.codeInsight.daemon.LineMarkerInfo;
8+
import com.intellij.codeInsight.daemon.LineMarkerProvider;
9+
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
10+
import com.intellij.icons.AllIcons;
11+
import com.intellij.psi.PsiElement;
12+
import com.jetbrains.php.PhpIndex;
13+
import com.jetbrains.php.lang.psi.elements.Method;
14+
import com.jetbrains.php.lang.psi.elements.PhpClass;
15+
import com.magento.idea.magento2plugin.magento.files.Plugin;
16+
import com.magento.idea.magento2plugin.project.Settings;
17+
import org.jetbrains.annotations.NotNull;
18+
import org.jetbrains.annotations.Nullable;
19+
import com.magento.idea.magento2plugin.util.magento.plugin.GetTargetClassNamesByPluginClassName;
20+
import com.intellij.psi.util.PsiTreeUtil;
21+
22+
import java.util.*;
23+
24+
public class PluginTargetLineMarkerProvider implements LineMarkerProvider {
25+
@Nullable
26+
@Override
27+
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement psiElement) {
28+
return null;
29+
}
30+
31+
@Override
32+
public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNull Collection<LineMarkerInfo> collection) {
33+
if (psiElements.size() > 0) {
34+
if (!Settings.isEnabled(psiElements.get(0).getProject())) {
35+
return;
36+
}
37+
}
38+
PluginClassCache pluginClassCache = new PluginClassCache();
39+
TargetClassesCollector TargetClassesCollector = new TargetClassesCollector(pluginClassCache);
40+
TargetMethodsCollector TargetMethodsCollector = new TargetMethodsCollector(pluginClassCache);
41+
42+
for (PsiElement psiElement : psiElements) {
43+
if (psiElement instanceof PhpClass || psiElement instanceof Method) {
44+
List<? extends PsiElement> results;
45+
46+
if (psiElement instanceof PhpClass) {
47+
results = TargetClassesCollector.collect((PhpClass) psiElement);
48+
if (results.size() > 0 ) {
49+
collection.add(NavigationGutterIconBuilder
50+
.create(AllIcons.Nodes.Class)
51+
.setTargets(results)
52+
.setTooltipText("Navigate to target class")
53+
.createLineMarkerInfo(PsiTreeUtil.getDeepestFirst(psiElement))
54+
);
55+
}
56+
} else {
57+
results = TargetMethodsCollector.collect((Method) psiElement);
58+
if (results.size() > 0 ) {
59+
collection.add(NavigationGutterIconBuilder
60+
.create(AllIcons.Nodes.Method)
61+
.setTargets(results)
62+
.setTooltipText("Navigate to target method")
63+
.createLineMarkerInfo(PsiTreeUtil.getDeepestFirst(psiElement))
64+
);
65+
}
66+
}
67+
68+
}
69+
}
70+
}
71+
72+
private static class PluginClassCache {
73+
private HashMap<String, List<PhpClass>> pluginClassesMap = new HashMap<String, List<PhpClass>>();
74+
75+
List<PhpClass> getTargetClassesForPlugin(@NotNull PhpClass phpClass, @NotNull String classFQN) {
76+
List<PhpClass> results = new ArrayList<>();
77+
78+
if (pluginClassesMap.containsKey(classFQN)) {
79+
return pluginClassesMap.get(classFQN);
80+
}
81+
82+
GetTargetClassNamesByPluginClassName targetClassesService = GetTargetClassNamesByPluginClassName.getInstance(phpClass.getProject());
83+
ArrayList<String> targetClassNames = targetClassesService.execute(classFQN);
84+
85+
if (targetClassNames.size() == 0) {
86+
pluginClassesMap.put(classFQN, results);
87+
return results;
88+
}
89+
90+
PhpIndex phpIndex = PhpIndex.getInstance(phpClass.getProject());
91+
92+
for (String targetClassName : targetClassNames) {
93+
Collection<PhpClass> targets = phpIndex.getClassesByFQN(targetClassName);
94+
95+
results.addAll(targets);
96+
}
97+
98+
return results;
99+
}
100+
101+
List<PhpClass> getTargetClassesForPlugin(@NotNull PhpClass phpClass) {
102+
List<PhpClass> classesForPlugin = getTargetClassesForPlugin(phpClass, phpClass.getPresentableFQN());
103+
for (PhpClass parent: phpClass.getSupers()) {
104+
classesForPlugin.addAll(getTargetClassesForPlugin(parent));
105+
}
106+
107+
return classesForPlugin;
108+
}
109+
}
110+
111+
private static class TargetClassesCollector implements Collector<PhpClass, PhpClass> {
112+
private PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache;
113+
114+
TargetClassesCollector(PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache) {
115+
this.pluginClassCache = pluginClassCache;
116+
}
117+
118+
@Override
119+
public List<PhpClass> collect(@NotNull PhpClass psiElement) {
120+
return pluginClassCache.getTargetClassesForPlugin(psiElement);
121+
}
122+
}
123+
124+
private static class TargetMethodsCollector implements Collector<Method, Method> {
125+
private PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache;
126+
127+
TargetMethodsCollector(PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache) {
128+
this.pluginClassCache = pluginClassCache;
129+
}
130+
131+
@Override
132+
public List<Method> collect(@NotNull Method pluginMethod) {
133+
List<Method> results = new ArrayList<>();
134+
135+
/* Check if the method is a plugin */
136+
if (null == getPluginPrefix(pluginMethod)) {
137+
return results;
138+
}
139+
140+
PhpClass pluginClass = pluginMethod.getContainingClass();
141+
if (pluginClass == null) {
142+
return results;
143+
}
144+
145+
List<PhpClass> targetClasses = pluginClassCache.getTargetClassesForPlugin(pluginClass);
146+
if (targetClasses.size() == 0) {
147+
return results;
148+
}
149+
150+
for (PhpClass targetClass: targetClasses) {
151+
String pluginPrefix = getPluginPrefix(pluginMethod);
152+
String targetClassMethodName = getTargetMethodName(pluginMethod, pluginPrefix);
153+
if (targetClassMethodName == null) {
154+
continue;
155+
}
156+
157+
Method targetMethod = targetClass.findMethodByName(targetClassMethodName);
158+
if (targetMethod == null) {
159+
continue;
160+
}
161+
162+
results.add(targetMethod);
163+
}
164+
165+
return results;
166+
}
167+
168+
private String getTargetMethodName(Method pluginMethod, String pluginPrefix) {
169+
String pluginMethodName = pluginMethod.getName();
170+
String targetClassMethodName = pluginMethodName.
171+
replace(pluginPrefix, "");
172+
char firstCharOfTargetName = targetClassMethodName.charAt(0);
173+
int charType = Character.getType(firstCharOfTargetName);
174+
if (charType == Character.LOWERCASE_LETTER) {
175+
return null;
176+
}
177+
return Character.toLowerCase(firstCharOfTargetName) + targetClassMethodName.substring(1);
178+
}
179+
180+
private String getPluginPrefix(Method pluginMethod) {
181+
String pluginMethodName = pluginMethod.getName();
182+
if (pluginMethodName.startsWith(Plugin.PluginType.around.toString())) {
183+
return Plugin.PluginType.around.toString();
184+
}
185+
if (pluginMethodName.startsWith(Plugin.PluginType.before.toString())) {
186+
return Plugin.PluginType.before.toString();
187+
}
188+
if (pluginMethodName.startsWith(Plugin.PluginType.after.toString())) {
189+
return Plugin.PluginType.after.toString();
190+
}
191+
192+
return null;
193+
}
194+
}
195+
196+
private interface Collector<T extends PsiElement, K> {
197+
List<K> collect(@NotNull T psiElement);
198+
}
199+
}

0 commit comments

Comments
 (0)