Skip to content

Commit d5d8b18

Browse files
committed
Add partial MFTF support (autocomplete/navigation)
1 parent 80760d5 commit d5d8b18

16 files changed

+1211
-0
lines changed

META-INF/plugin.xml

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@
5656
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.ModulePackageIndex" />
5757
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.ModuleNameIndex" />
5858
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.PhpClassNameIndex" />
59+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.SectionIndex" />
60+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.ActionGroupIndex" />
61+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex" />
62+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.PageIndex" />
63+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.StepKeyIndex" />
5964

6065
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginLineMarkerProvider"/>
6166
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.ClassConfigurationLineMarkerProvider"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.magento.idea.magento2plugin.completion.provider.mftf;
2+
3+
import com.intellij.codeInsight.completion.CompletionParameters;
4+
import com.intellij.codeInsight.completion.CompletionProvider;
5+
import com.intellij.codeInsight.completion.CompletionResultSet;
6+
import com.intellij.codeInsight.lookup.LookupElementBuilder;
7+
import com.intellij.psi.PsiElement;
8+
import com.intellij.util.ProcessingContext;
9+
import com.intellij.util.indexing.FileBasedIndex;
10+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.ActionGroupIndex;
11+
import org.jetbrains.annotations.NotNull;
12+
13+
import java.util.Collection;
14+
15+
public class ActionGroupCompletionProvider extends CompletionProvider<CompletionParameters> {
16+
17+
@Override
18+
protected void addCompletions(@NotNull CompletionParameters parameters,
19+
ProcessingContext context,
20+
@NotNull CompletionResultSet result)
21+
{
22+
PsiElement position = parameters.getPosition().getOriginalElement();
23+
24+
if (position == null) {
25+
return;
26+
}
27+
28+
Collection<String> selectorNames
29+
= FileBasedIndex.getInstance().getAllKeys(ActionGroupIndex.KEY, position.getProject());
30+
31+
for (String selectorName: selectorNames) {
32+
result.addElement(LookupElementBuilder.create(selectorName));
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.magento.idea.magento2plugin.completion.provider.mftf;
2+
3+
import com.intellij.codeInsight.completion.CompletionParameters;
4+
import com.intellij.codeInsight.completion.CompletionProvider;
5+
import com.intellij.codeInsight.completion.CompletionResultSet;
6+
import com.intellij.codeInsight.lookup.LookupElementBuilder;
7+
import com.intellij.psi.PsiElement;
8+
import com.intellij.util.ProcessingContext;
9+
import com.intellij.util.indexing.FileBasedIndex;
10+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex;
11+
import org.jetbrains.annotations.NotNull;
12+
13+
import java.util.Collection;
14+
15+
public class DataCompletionProvider extends CompletionProvider<CompletionParameters> {
16+
17+
@Override
18+
protected void addCompletions(@NotNull CompletionParameters parameters,
19+
ProcessingContext context,
20+
@NotNull CompletionResultSet result)
21+
{
22+
PsiElement position = parameters.getPosition().getOriginalElement();
23+
24+
if (position == null) {
25+
return;
26+
}
27+
28+
Collection<String> selectorNames
29+
= FileBasedIndex.getInstance().getAllKeys(DataIndex.KEY, position.getProject());
30+
31+
for (String selectorName: selectorNames) {
32+
result.addElement(LookupElementBuilder.create(selectorName));
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.magento.idea.magento2plugin.completion.provider.mftf;
2+
3+
import com.intellij.codeInsight.completion.CompletionParameters;
4+
import com.intellij.codeInsight.completion.CompletionProvider;
5+
import com.intellij.codeInsight.completion.CompletionResultSet;
6+
import com.intellij.codeInsight.lookup.LookupElementBuilder;
7+
import com.intellij.psi.PsiElement;
8+
import com.intellij.util.ProcessingContext;
9+
import com.intellij.util.indexing.FileBasedIndex;
10+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.SectionIndex;
11+
import org.jetbrains.annotations.NotNull;
12+
13+
import java.util.Collection;
14+
15+
public class SelectorCompletionProvider extends CompletionProvider<CompletionParameters> {
16+
17+
@Override
18+
protected void addCompletions(@NotNull CompletionParameters parameters,
19+
ProcessingContext context,
20+
@NotNull CompletionResultSet result)
21+
{
22+
PsiElement position = parameters.getPosition().getOriginalElement();
23+
24+
if (position == null) {
25+
return;
26+
}
27+
28+
Collection<String> selectorNames
29+
= FileBasedIndex.getInstance().getAllKeys(SectionIndex.KEY, position.getProject());
30+
31+
for (String selectorName: selectorNames) {
32+
result.addElement(LookupElementBuilder.create(selectorName));
33+
}
34+
}
35+
}

src/com/magento/idea/magento2plugin/completion/xml/XmlCompletionContributor.java

+42
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.intellij.patterns.XmlPatterns;
66
import com.intellij.psi.xml.XmlTokenType;
77
import com.magento.idea.magento2plugin.completion.provider.*;
8+
import com.magento.idea.magento2plugin.completion.provider.mftf.*;
89

910
import static com.intellij.patterns.PlatformPatterns.psiElement;
1011
import static com.intellij.patterns.StandardPatterns.string;
@@ -101,5 +102,46 @@ public XmlCompletionContributor() {
101102
).inFile(xmlFile().withName(string().endsWith("events.xml"))),
102103
new EventNameCompletionContributor()
103104
);
105+
106+
// mftf selector completion contributor
107+
extend(CompletionType.BASIC,
108+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
109+
.inside(XmlPatterns.xmlAttribute())
110+
.inFile(xmlFile().withName(string().endsWith("Test.xml"))),
111+
new SelectorCompletionProvider()
112+
);
113+
114+
// mftf action group completion contributor
115+
extend(
116+
CompletionType.BASIC,
117+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
118+
.inside(
119+
XmlPatterns.xmlAttribute().withName(string().oneOf("ref", "extends"))
120+
.withParent(XmlPatterns.xmlTag().withName("actionGroup")
121+
)
122+
),
123+
new ActionGroupCompletionProvider()
124+
);
125+
126+
// mftf data entity completion contributor
127+
extend(
128+
CompletionType.BASIC,
129+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
130+
.inside(XmlPatterns.xmlAttribute().withName(string().oneOf("entity", "value", "userInput", "url"))
131+
),
132+
new DataCompletionProvider()
133+
);
134+
135+
// Data entity/extends completion contributor
136+
extend(
137+
CompletionType.BASIC,
138+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
139+
.inside(
140+
XmlPatterns.xmlAttribute().withName("extends")
141+
.withParent(XmlPatterns.xmlTag().withName("entity")
142+
)
143+
),
144+
new DataCompletionProvider()
145+
);
104146
}
105147
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.magento.idea.magento2plugin.reference.provider.mftf;
2+
3+
import com.intellij.ide.highlighter.XmlFileType;
4+
import com.intellij.openapi.util.TextRange;
5+
import com.intellij.openapi.util.text.StringUtil;
6+
import com.intellij.openapi.vfs.VfsUtilCore;
7+
import com.intellij.openapi.vfs.VirtualFile;
8+
import com.intellij.openapi.vfs.VirtualFileManager;
9+
import com.intellij.openapi.vfs.VirtualFileVisitor;
10+
import com.intellij.psi.*;
11+
import com.intellij.psi.search.FilenameIndex;
12+
import com.intellij.psi.search.GlobalSearchScope;
13+
import com.intellij.psi.util.PsiTreeUtil;
14+
import com.intellij.psi.xml.*;
15+
import com.intellij.util.ProcessingContext;
16+
import com.intellij.util.indexing.FileBasedIndex;
17+
import com.jetbrains.php.lang.PhpFileType;
18+
import com.jetbrains.php.lang.psi.PhpFile;
19+
import com.magento.idea.magento2plugin.reference.xml.PolyVariantReferenceBase;
20+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.ActionGroupIndex;
21+
import com.magento.idea.magento2plugin.xml.XmlPsiTreeUtil;
22+
import gnu.trove.THashMap;
23+
import org.jetbrains.annotations.NotNull;
24+
25+
import java.util.ArrayList;
26+
import java.util.Collection;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.regex.Matcher;
30+
import java.util.regex.Pattern;
31+
32+
public class ActionGroupReferenceProvider extends PsiReferenceProvider {
33+
34+
@NotNull
35+
@Override
36+
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
37+
List<PsiReference> psiReferences = new ArrayList<>();
38+
39+
String origValue = StringUtil.unquoteString(element.getText());
40+
41+
Collection<VirtualFile> containingFiles = FileBasedIndex.getInstance()
42+
.getContainingFiles(
43+
ActionGroupIndex.KEY,
44+
origValue,
45+
GlobalSearchScope.getScopeRestrictedByFileTypes(
46+
GlobalSearchScope.allScope(element.getProject()),
47+
XmlFileType.INSTANCE
48+
)
49+
);
50+
51+
PsiManager psiManager = PsiManager.getInstance(element.getProject());
52+
53+
List<PsiElement> psiElements = new ArrayList<>();
54+
55+
for (VirtualFile virtualFile: containingFiles) {
56+
XmlFile xmlFile = (XmlFile) psiManager.findFile(virtualFile);
57+
58+
if (xmlFile == null) {
59+
continue;
60+
}
61+
62+
Collection<XmlAttributeValue> valueElements = XmlPsiTreeUtil
63+
.findAttributeValueElements(xmlFile, "actionGroup", "name", origValue);
64+
65+
psiElements.addAll(valueElements);
66+
}
67+
68+
if (psiElements.size() > 0) {
69+
psiReferences.add(new PolyVariantReferenceBase(element, psiElements));
70+
}
71+
72+
return psiReferences.toArray(new PsiReference[psiReferences.size()]);
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.magento.idea.magento2plugin.reference.provider.mftf;
2+
3+
import com.intellij.ide.highlighter.XmlFileType;
4+
import com.intellij.openapi.util.text.StringUtil;
5+
import com.intellij.openapi.vfs.VirtualFile;
6+
import com.intellij.psi.PsiElement;
7+
import com.intellij.psi.PsiManager;
8+
import com.intellij.psi.PsiReference;
9+
import com.intellij.psi.PsiReferenceProvider;
10+
import com.intellij.psi.search.GlobalSearchScope;
11+
import com.intellij.psi.xml.XmlAttribute;
12+
import com.intellij.psi.xml.XmlAttributeValue;
13+
import com.intellij.psi.xml.XmlFile;
14+
import com.intellij.psi.xml.XmlTag;
15+
import com.intellij.util.ProcessingContext;
16+
import com.intellij.util.indexing.FileBasedIndex;
17+
import com.magento.idea.magento2plugin.reference.xml.PolyVariantReferenceBase;
18+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex;
19+
import com.magento.idea.magento2plugin.xml.XmlPsiTreeUtil;
20+
import org.jetbrains.annotations.NotNull;
21+
22+
import java.util.ArrayList;
23+
import java.util.Collection;
24+
import java.util.List;
25+
26+
27+
public class DataReferenceProvider extends PsiReferenceProvider {
28+
29+
@NotNull
30+
@Override
31+
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
32+
List<PsiReference> psiReferences = new ArrayList<>();
33+
34+
String origValue = StringUtil.unquoteString(element.getText());
35+
String modifiedValue = origValue.replaceAll("\\{{2}([_A-Za-z0-9.]+)(\\([^}]+\\))?\\}{2}", "$1").toString();
36+
37+
Collection<VirtualFile> containingFiles = FileBasedIndex.getInstance()
38+
.getContainingFiles(
39+
DataIndex.KEY,
40+
modifiedValue,
41+
GlobalSearchScope.getScopeRestrictedByFileTypes(
42+
GlobalSearchScope.allScope(element.getProject()),
43+
XmlFileType.INSTANCE
44+
)
45+
);
46+
47+
PsiManager psiManager = PsiManager.getInstance(element.getProject());
48+
49+
List<PsiElement> psiElements = new ArrayList<>();
50+
51+
for (VirtualFile virtualFile: containingFiles) {
52+
XmlFile xmlFile = (XmlFile) psiManager.findFile(virtualFile);
53+
54+
if (xmlFile == null) {
55+
continue;
56+
}
57+
58+
if (!modifiedValue.contains(".")) {
59+
Collection<XmlAttributeValue> valueElements = XmlPsiTreeUtil
60+
.findAttributeValueElements(xmlFile, "entity", "name", modifiedValue);
61+
62+
psiElements.addAll(valueElements);
63+
continue;
64+
}
65+
66+
67+
String[] parts = modifiedValue.split("\\.");
68+
String entityName = parts[0];
69+
String dataName = parts[1];
70+
71+
XmlTag rootTag = xmlFile.getRootTag();
72+
73+
for (XmlTag entityTag: rootTag.findSubTags("entity")) {
74+
if (entityTag == null) {
75+
continue;
76+
}
77+
78+
XmlAttribute entityNameAttribute = entityTag.getAttribute("name");
79+
80+
if (entityNameAttribute == null ||
81+
entityNameAttribute.getValueElement() == null ||
82+
!entityNameAttribute.getValueElement().getValue().equals(entityName)
83+
) {
84+
continue;
85+
}
86+
87+
for (XmlTag dataTag: entityTag.findSubTags("data")) {
88+
XmlAttribute keyNameAttribute = dataTag.getAttribute("key");
89+
90+
if (keyNameAttribute != null &&
91+
keyNameAttribute.getValueElement() != null &&
92+
keyNameAttribute.getValueElement().getValue().equals(dataName)
93+
) {
94+
psiElements.add(keyNameAttribute.getValueElement());
95+
}
96+
}
97+
}
98+
}
99+
100+
if (psiElements.size() > 0) {
101+
psiReferences.add(new PolyVariantReferenceBase(element, psiElements));
102+
}
103+
104+
return psiReferences.toArray(new PsiReference[psiReferences.size()]);
105+
}
106+
}

0 commit comments

Comments
 (0)