diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml
index 11e9c1026..8af540006 100644
--- a/resources/META-INF/plugin.xml
+++ b/resources/META-INF/plugin.xml
@@ -125,6 +125,7 @@
+
diff --git a/src/com/magento/idea/magento2plugin/completion/provider/UiComponentCompletionProvider.java b/src/com/magento/idea/magento2plugin/completion/provider/UiComponentCompletionProvider.java
new file mode 100644
index 000000000..0091aae2b
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/completion/provider/UiComponentCompletionProvider.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.completion.provider;
+
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.util.ProcessingContext;
+import com.jetbrains.php.PhpIcons;
+import com.magento.idea.magento2plugin.indexes.UIComponentIndex;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+
+public class UiComponentCompletionProvider extends CompletionProvider {
+
+ @Override
+ protected void addCompletions(@NotNull final CompletionParameters parameters,
+ final ProcessingContext context,
+ @NotNull final CompletionResultSet result) {
+ final PsiElement position = parameters.getPosition().getOriginalElement();
+ if (position == null) {
+ return;
+ }
+
+ final List targets = UIComponentIndex.getUiComponentFiles(position.getProject());
+ if (!targets.isEmpty()) {
+ for (final XmlFile file : targets) {
+ result.addElement(LookupElementBuilder
+ .create(file.getVirtualFile().getNameWithoutExtension())
+ .withIcon(PhpIcons.XML_TAG_ICON)
+ );
+ }
+ }
+ }
+}
diff --git a/src/com/magento/idea/magento2plugin/completion/xml/XmlCompletionContributor.java b/src/com/magento/idea/magento2plugin/completion/xml/XmlCompletionContributor.java
index 9e4b53b8c..cc2e5e651 100644
--- a/src/com/magento/idea/magento2plugin/completion/xml/XmlCompletionContributor.java
+++ b/src/com/magento/idea/magento2plugin/completion/xml/XmlCompletionContributor.java
@@ -88,6 +88,13 @@ public XmlCompletionContributor() {
new FilePathCompletionProvider()
);
+ //
+ extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
+ .inside(XmlPatterns.xmlAttribute().withName(LayoutXml.NAME_ATTRIBUTE)
+ .withParent(XmlPatterns.xmlTag().withName(LayoutXml.UI_COMPONENT_TAG_NAME))),
+ new UiComponentCompletionProvider()
+ );
+
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_DATA_CHARACTERS)
.withParent(XmlPatterns.xmlText().withParent(
XmlPatterns.xmlTag().withName(UiComponentXml.XML_TAG_ITEM).withChild(
@@ -126,20 +133,20 @@ public XmlCompletionContributor() {
//
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
- .inside(XmlPatterns.xmlAttribute().withName(ModuleEventsXml.INSTANCE_ATTRIBUTE)
- .withParent(XmlPatterns.xmlTag().withName(ModuleEventsXml.OBSERVER_TAG)
- )
- ).inFile(xmlFile().withName(string().matches(ModuleEventsXml.FILE_NAME))),
- new PhpClassCompletionProvider()
+ .inside(XmlPatterns.xmlAttribute().withName(ModuleEventsXml.INSTANCE_ATTRIBUTE)
+ .withParent(XmlPatterns.xmlTag().withName(ModuleEventsXml.OBSERVER_TAG)
+ )
+ ).inFile(xmlFile().withName(string().matches(ModuleEventsXml.FILE_NAME))),
+ new PhpClassCompletionProvider()
);
//
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
- .inside(XmlPatterns.xmlAttribute().withName(CommonXml.ATTR_INSTANCE)
- .withParent(XmlPatterns.xmlTag().withName(CrontabXmlTemplate.CRON_JOB_TAG)
- )
- ).inFile(xmlFile().withName(string().matches(CrontabXmlTemplate.FILE_NAME))),
- new PhpClassCompletionProvider()
+ .inside(XmlPatterns.xmlAttribute().withName(CommonXml.ATTR_INSTANCE)
+ .withParent(XmlPatterns.xmlTag().withName(CrontabXmlTemplate.CRON_JOB_TAG)
+ )
+ ).inFile(xmlFile().withName(string().matches(CrontabXmlTemplate.FILE_NAME))),
+ new PhpClassCompletionProvider()
);
// php class completion in system.xml files.
diff --git a/src/com/magento/idea/magento2plugin/indexes/UIComponentIndex.java b/src/com/magento/idea/magento2plugin/indexes/UIComponentIndex.java
new file mode 100644
index 000000000..9f5f80ccf
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/indexes/UIComponentIndex.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.indexes;
+
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.search.FilenameIndex;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.util.indexing.FileBasedIndex;
+import com.intellij.util.indexing.ID;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("PMD")
+public final class UIComponentIndex {
+
+ private UIComponentIndex() {
+ throw new AssertionError("Instantiating utility class...");
+ }
+
+ /**
+ * Available ui component file.
+ *
+ * @param virtualFile VirtualFile
+ * @return boolean
+ */
+ public static boolean isUiComponentFile(final VirtualFile virtualFile) {
+ final VirtualFile parent = virtualFile.getParent();
+ return virtualFile.getFileType() == XmlFileType.INSTANCE && parent.isDirectory()
+ && parent.getName().endsWith("ui_component");
+ }
+
+ /**
+ * Get ui component files.
+ *
+ * @param project Project
+ * @param fileName String
+ * @return List
+ */
+ public static List getUiComponentFiles(
+ final Project project,
+ final @Nullable String fileName
+ ) {
+ final List results = new ArrayList();//NOPMD
+ final Collection xmlFiles = FilenameIndex.getAllFilesByExt(project, "xml");
+
+ final PsiManager psiManager = PsiManager.getInstance(project);
+ for (final VirtualFile xmlFile: xmlFiles) {
+ if (isUiComponentFile(xmlFile)) {
+ if (fileName != null && !xmlFile.getNameWithoutExtension().equals(fileName)) {
+ continue;
+ }
+
+ final PsiFile file = psiManager.findFile(xmlFile);
+ if (file != null) {
+ results.add((XmlFile)file);
+ }
+ }
+ }
+
+ return results;
+ }
+
+ /**
+ * Get ui component files.
+ *
+ * @param project Project
+ * @return List
+ */
+ public static List getUiComponentFiles(final Project project) {
+ return getUiComponentFiles(project, null);
+ }
+
+ /**
+ * Get All Keys.
+ *
+ * @param identifier ID
+ * @param project Project
+ * @return Collection
+ */
+ public static Collection getAllKeys(
+ final ID identifier,
+ final Project project
+ ) {
+ return FileBasedIndex.getInstance().getAllKeys(identifier, project);
+ }
+
+ /**
+ * Get ui component files.
+ *
+ * @param project Project
+ * @param fileName String
+ * @return List
+ */
+ public static List getUIComponentFiles(Project project, @Nullable String fileName) {
+ List results = new ArrayList();
+ Collection xmlFiles = FilenameIndex.getAllFilesByExt(project, "xml");
+
+ PsiManager psiManager = PsiManager.getInstance(project);
+ for (VirtualFile xmlFile: xmlFiles) {
+ if (isUIComponentFile(xmlFile)) {
+ if (fileName != null && !xmlFile.getNameWithoutExtension().equals(fileName)) {
+ continue;
+ }
+
+ PsiFile file = psiManager.findFile(xmlFile);
+ if (file != null) {
+ results.add((XmlFile)file);
+ }
+ }
+ }
+
+ return results;
+ }
+
+ /**
+ * Available ui component file.
+ *
+ * @param virtualFile VirtualFile
+ * @return boolean
+ */
+ public static boolean isUIComponentFile(VirtualFile virtualFile) {
+ VirtualFile parent = virtualFile.getParent();
+ return virtualFile.getFileType() == XmlFileType.INSTANCE && parent.isDirectory()
+ && parent.getName().endsWith("ui_component");
+ }
+
+}
diff --git a/src/com/magento/idea/magento2plugin/reference/provider/UIComponentReferenceProvider.java b/src/com/magento/idea/magento2plugin/reference/provider/UIComponentReferenceProvider.java
new file mode 100644
index 000000000..9e9a95b9d
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/reference/provider/UIComponentReferenceProvider.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.reference.provider;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceProvider;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.util.ProcessingContext;
+import com.magento.idea.magento2plugin.indexes.UIComponentIndex;
+import com.magento.idea.magento2plugin.reference.xml.PolyVariantReferenceBase;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+
+public class UIComponentReferenceProvider extends PsiReferenceProvider {
+
+ @NotNull
+ @Override
+ public PsiReference[] getReferencesByElement(
+ @NotNull final PsiElement element,
+ @NotNull final ProcessingContext context
+ ) {
+ final String value = StringUtil.unquoteString(element.getText());
+ final List targets = UIComponentIndex.getUIComponentFiles(
+ element.getProject(),
+ value
+ );
+ if (!targets.isEmpty()) {
+ return new PsiReference[] {new PolyVariantReferenceBase(element, targets)};
+ }
+ return PsiReference.EMPTY_ARRAY;
+ }
+}
diff --git a/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java b/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java
index c4bde6ca0..c29142ca4 100644
--- a/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java
+++ b/src/com/magento/idea/magento2plugin/reference/xml/XmlReferenceContributor.java
@@ -132,6 +132,16 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
new LayoutUpdateReferenceProvider()
);
+ //
+ registrar.registerReferenceProvider(
+ XmlPatterns.xmlAttributeValue().withParent(
+ XmlPatterns.xmlAttribute().withName("name").withParent(
+ XmlPatterns.xmlTag().withName("uiComponent")
+ )
+ ),
+ new UIComponentReferenceProvider()
+ );
+
//
registrar.registerReferenceProvider(
XmlPatterns.xmlAttributeValue().withParent(
diff --git a/src/com/magento/idea/magento2plugin/stubs/indexes/xml/UIComponentIndex.java b/src/com/magento/idea/magento2plugin/stubs/indexes/xml/UIComponentIndex.java
new file mode 100644
index 000000000..f08623465
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/stubs/indexes/xml/UIComponentIndex.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.stubs.indexes.xml;
+
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.indexing.DataIndexer;
+import com.intellij.util.indexing.FileBasedIndex;
+import com.intellij.util.indexing.FileContent;
+import com.intellij.util.indexing.ID;
+import com.intellij.util.indexing.ScalarIndexExtension;
+import com.intellij.util.io.EnumeratorStringDescriptor;
+import com.intellij.util.io.KeyDescriptor;
+import com.intellij.util.xml.impl.DomApplicationComponent;
+import com.magento.idea.magento2plugin.project.Settings;
+import java.util.HashMap;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+
+
+public class UIComponentIndex extends ScalarIndexExtension {
+
+ public static final ID KEY =
+ ID.create("com.magento.idea.magento2plugin.stubs.indexes.ui_component");
+
+ @NotNull
+ @Override
+ public ID getName() {
+ return KEY;
+ }
+
+ /**
+ * Indexer for `ui_component` files.
+ *
+ * @return this
+ */
+ @NotNull
+ @Override
+ public DataIndexer getIndexer() {
+ return inputData -> {
+ final Map map = new HashMap<>();//NOPMD
+
+ final PsiFile psiFile = inputData.getPsiFile();
+ if (!Settings.isEnabled(psiFile.getProject())) {
+ return map;
+ }
+
+ final VirtualFile file = inputData.getFile();
+ if (!file.getPath().matches("uiComponent")) {
+ return map;
+ }
+
+ final String key = file.getName();
+ if (!key.isEmpty()) {
+ map.put(key, null);
+ }
+
+ return map;
+ };
+ }
+
+ @NotNull
+ @Override
+ public KeyDescriptor getKeyDescriptor() {
+ return new EnumeratorStringDescriptor();
+ }
+
+ @NotNull
+ @Override
+ public FileBasedIndex.InputFilter getInputFilter() {
+ return file -> file.getFileType() == XmlFileType.INSTANCE;
+ }
+
+ @Override
+ public boolean dependsOnFileContent() {
+ return true;
+ }
+
+ @Override
+ public int getVersion() {
+ return DomApplicationComponent.getInstance().getCumulativeVersion(false);
+ }
+}