Skip to content

Commit cf52b1b

Browse files
author
Vitaliy
authored
Merge pull request #22 from danmooney2/MFTF-support-squashed
Add partial MFTF support (autocomplete/navigation)
2 parents f26fb17 + d5d8b18 commit cf52b1b

16 files changed

+1211
-0
lines changed

META-INF/plugin.xml

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.ModulePackageIndex" />
6363
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.ModuleNameIndex" />
6464
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.PhpClassNameIndex" />
65+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.SectionIndex" />
66+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.ActionGroupIndex" />
67+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex" />
68+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.PageIndex" />
69+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.StepKeyIndex" />
6570

6671
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginLineMarkerProvider"/>
6772
<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
@@ -9,6 +9,7 @@
99
import com.intellij.patterns.XmlPatterns;
1010
import com.intellij.psi.xml.XmlTokenType;
1111
import com.magento.idea.magento2plugin.completion.provider.*;
12+
import com.magento.idea.magento2plugin.completion.provider.mftf.*;
1213

1314
import static com.intellij.patterns.PlatformPatterns.psiElement;
1415
import static com.intellij.patterns.StandardPatterns.string;
@@ -105,5 +106,46 @@ public XmlCompletionContributor() {
105106
).inFile(xmlFile().withName(string().endsWith("events.xml"))),
106107
new EventNameCompletionContributor()
107108
);
109+
110+
// mftf selector completion contributor
111+
extend(CompletionType.BASIC,
112+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
113+
.inside(XmlPatterns.xmlAttribute())
114+
.inFile(xmlFile().withName(string().endsWith("Test.xml"))),
115+
new SelectorCompletionProvider()
116+
);
117+
118+
// mftf action group completion contributor
119+
extend(
120+
CompletionType.BASIC,
121+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
122+
.inside(
123+
XmlPatterns.xmlAttribute().withName(string().oneOf("ref", "extends"))
124+
.withParent(XmlPatterns.xmlTag().withName("actionGroup")
125+
)
126+
),
127+
new ActionGroupCompletionProvider()
128+
);
129+
130+
// mftf data entity completion contributor
131+
extend(
132+
CompletionType.BASIC,
133+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
134+
.inside(XmlPatterns.xmlAttribute().withName(string().oneOf("entity", "value", "userInput", "url"))
135+
),
136+
new DataCompletionProvider()
137+
);
138+
139+
// Data entity/extends completion contributor
140+
extend(
141+
CompletionType.BASIC,
142+
psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
143+
.inside(
144+
XmlPatterns.xmlAttribute().withName("extends")
145+
.withParent(XmlPatterns.xmlTag().withName("entity")
146+
)
147+
),
148+
new DataCompletionProvider()
149+
);
108150
}
109151
}
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)