Skip to content

Commit 388182e

Browse files
committed
#305_Add reference navigation and autocomplete for UI component
1 parent 184a422 commit 388182e

File tree

5 files changed

+210
-7
lines changed

5 files changed

+210
-7
lines changed

resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex" />
126126
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex" />
127127
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.MenuIndex" />
128+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.UiComponentIndex" />
128129

129130
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.linemarker.php.PluginLineMarkerProvider"/>
130131
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.linemarker.php.PluginTargetLineMarkerProvider"/>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.completion.provider;
7+
8+
import com.intellij.codeInsight.completion.CompletionParameters;
9+
import com.intellij.codeInsight.completion.CompletionProvider;
10+
import com.intellij.codeInsight.completion.CompletionResultSet;
11+
import com.intellij.codeInsight.lookup.LookupElementBuilder;
12+
import com.intellij.psi.PsiElement;
13+
import com.intellij.psi.xml.XmlFile;
14+
import com.intellij.util.ProcessingContext;
15+
import com.jetbrains.php.PhpIcons;
16+
import com.magento.idea.magento2plugin.indexes.UiComponentIndex;
17+
import java.util.List;
18+
import org.jetbrains.annotations.NotNull;
19+
20+
21+
public class UiComponentCompletionProvider extends CompletionProvider<CompletionParameters> {
22+
23+
@Override
24+
protected void addCompletions(@NotNull CompletionParameters parameters,
25+
ProcessingContext context,
26+
@NotNull CompletionResultSet result) {
27+
PsiElement position = parameters.getPosition().getOriginalElement();
28+
if (position == null) {
29+
return;
30+
}
31+
32+
List<XmlFile> targets = UiComponentIndex.getUiComponentFiles(position.getProject());
33+
if (targets.size() > 0) {
34+
for (XmlFile file : targets) {
35+
result.addElement(LookupElementBuilder
36+
.create(file.getVirtualFile().getNameWithoutExtension())
37+
.withIcon(PhpIcons.XML_TAG_ICON)
38+
);
39+
}
40+
}
41+
}
42+
}

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ public XmlCompletionContributor() {
8888
new FilePathCompletionProvider()
8989
);
9090

91+
// <uiComponent name="completion"/>
92+
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
93+
.inside(XmlPatterns.xmlAttribute().withName(LayoutXml.NAME_ATTRIBUTE)
94+
.withParent(XmlPatterns.xmlTag().withName(LayoutXml.UI_COMPONENT_TAG_NAME))),
95+
new UiComponentCompletionProvider()
96+
);
97+
9198
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_DATA_CHARACTERS)
9299
.withParent(XmlPatterns.xmlText().withParent(
93100
XmlPatterns.xmlTag().withName(UiComponentXml.XML_TAG_ITEM).withChild(
@@ -126,19 +133,17 @@ public XmlCompletionContributor() {
126133

127134
// <observer instance="Class">
128135
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
129-
.inside(XmlPatterns.xmlAttribute().withName(ModuleEventsXml.INSTANCE_ATTRIBUTE)
130-
.withParent(XmlPatterns.xmlTag().withName(ModuleEventsXml.OBSERVER_TAG)
131-
)
132-
).inFile(xmlFile().withName(string().matches(ModuleEventsXml.FILE_NAME))),
136+
.inside(XmlPatterns.xmlAttribute().withName(ModuleEventsXml.INSTANCE_ATTRIBUTE)
137+
.withParent(XmlPatterns.xmlTag().withName(ModuleEventsXml.OBSERVER_TAG)))
138+
.inFile(xmlFile().withName(string().matches(ModuleEventsXml.FILE_NAME))),
133139
new PhpClassCompletionProvider()
134140
);
135141

136142
// <job instance="class">
137143
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
138144
.inside(XmlPatterns.xmlAttribute().withName(CommonXml.ATTR_INSTANCE)
139-
.withParent(XmlPatterns.xmlTag().withName(CrontabXmlTemplate.CRON_JOB_TAG)
140-
)
141-
).inFile(xmlFile().withName(string().matches(CrontabXmlTemplate.FILE_NAME))),
145+
.withParent(XmlPatterns.xmlTag().withName(CrontabXmlTemplate.CRON_JOB_TAG)))
146+
.inFile(xmlFile().withName(string().matches(CrontabXmlTemplate.FILE_NAME))),
142147
new PhpClassCompletionProvider()
143148
);
144149

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.indexes;
7+
8+
import com.intellij.ide.highlighter.XmlFileType;
9+
import com.intellij.openapi.project.Project;
10+
import com.intellij.openapi.vfs.VirtualFile;
11+
import com.intellij.psi.PsiFile;
12+
import com.intellij.psi.PsiManager;
13+
import com.intellij.psi.search.FilenameIndex;
14+
import com.intellij.psi.xml.XmlFile;
15+
import com.intellij.util.indexing.FileBasedIndex;
16+
import com.intellij.util.indexing.ID;
17+
import java.util.ArrayList;
18+
import java.util.Collection;
19+
import java.util.List;
20+
import org.jetbrains.annotations.Nullable;
21+
22+
23+
public class UiComponentIndex {
24+
25+
/**
26+
* Available ui component file.
27+
*
28+
* @param virtualFile VirtualFile
29+
* @return boolean
30+
*/
31+
public static boolean isUiComponentFile(final VirtualFile virtualFile) {
32+
final VirtualFile parent = virtualFile.getParent();
33+
return virtualFile.getFileType() == XmlFileType.INSTANCE && parent.isDirectory()
34+
&& parent.getName().endsWith("ui_component");
35+
}
36+
37+
/**
38+
* Get ui component files.
39+
*
40+
* @param project Project
41+
* @param fileName String
42+
* @return List
43+
*/
44+
public static List<XmlFile> getUiComponentFiles(final Project project, final @Nullable String fileName) {
45+
final List<XmlFile> results = new ArrayList<XmlFile>();//NOPMD
46+
final Collection<VirtualFile> xmlFiles = FilenameIndex.getAllFilesByExt(project, "xml");
47+
48+
final PsiManager psiManager = PsiManager.getInstance(project);
49+
for (final VirtualFile xmlFile: xmlFiles) {
50+
if (isUiComponentFile(xmlFile)) {
51+
if (fileName != null && !xmlFile.getNameWithoutExtension().equals(fileName)) {
52+
continue;
53+
}
54+
55+
final PsiFile file = psiManager.findFile(xmlFile);
56+
if (file != null) {
57+
results.add((XmlFile)file);
58+
}
59+
}
60+
}
61+
62+
return results;
63+
}
64+
65+
public static List<XmlFile> getUiComponentFiles(final Project project) {
66+
return getUiComponentFiles(project, null);
67+
}
68+
69+
public static Collection<String> getAllKeys(final ID<String, Void> id, final Project project) {
70+
return FileBasedIndex.getInstance().getAllKeys(id, project);
71+
}
72+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.stubs.indexes.xml;
7+
8+
import com.intellij.ide.highlighter.XmlFileType;
9+
import com.intellij.openapi.vfs.VirtualFile;
10+
import com.intellij.psi.PsiFile;
11+
import com.intellij.util.indexing.*;
12+
import com.intellij.util.io.EnumeratorStringDescriptor;
13+
import com.intellij.util.io.KeyDescriptor;
14+
import com.intellij.util.xml.impl.DomApplicationComponent;
15+
import com.magento.idea.magento2plugin.project.Settings;
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import org.jetbrains.annotations.NotNull;
19+
20+
21+
public class UiComponentIndex extends ScalarIndexExtension<String> {
22+
23+
public static final ID<String, Void> KEY =
24+
ID.create("com.magento.idea.magento2plugin.stubs.indexes.ui_component");
25+
26+
@NotNull
27+
@Override
28+
public ID<String, Void> getName() {
29+
return KEY;
30+
}
31+
32+
/**
33+
* Indexer for `ui_component` files.
34+
*
35+
* @return this
36+
*/
37+
@NotNull
38+
@Override
39+
public DataIndexer<String, Void, FileContent> getIndexer() {
40+
return inputData -> {
41+
final Map<String, Void> map = new HashMap<>();//NOPMD
42+
43+
final PsiFile psiFile = inputData.getPsiFile();
44+
if (!Settings.isEnabled(psiFile.getProject())) {
45+
return map;
46+
}
47+
48+
final VirtualFile file = inputData.getFile();
49+
if (!file.getPath().matches("uiComponent")) {
50+
return map;
51+
}
52+
53+
final String key = file.getName();
54+
if (!key.isEmpty()) {
55+
map.put(key, null);
56+
}
57+
58+
return map;
59+
};
60+
}
61+
62+
@NotNull
63+
@Override
64+
public KeyDescriptor<String> getKeyDescriptor() {
65+
return new EnumeratorStringDescriptor();
66+
}
67+
68+
@NotNull
69+
@Override
70+
public FileBasedIndex.InputFilter getInputFilter() {
71+
return file -> file.getFileType() == XmlFileType.INSTANCE;
72+
}
73+
74+
@Override
75+
public boolean dependsOnFileContent() {
76+
return true;
77+
}
78+
79+
@Override
80+
public int getVersion() {
81+
return DomApplicationComponent.getInstance().getCumulativeVersion(false);
82+
}
83+
}

0 commit comments

Comments
 (0)