Skip to content

Commit

Permalink
Added index, completion and references for table names, column names …
Browse files Browse the repository at this point in the history
…in db_schema.xml file
  • Loading branch information
bohdan-harniuk committed Oct 24, 2020
1 parent 2e1a9f5 commit df995c8
Show file tree
Hide file tree
Showing 23 changed files with 964 additions and 7 deletions.
1 change: 1 addition & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex" />
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex" />
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.MenuIndex" />
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.TableAndColumnNameIndex" />

<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.linemarker.php.PluginLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.linemarker.php.PluginTargetLineMarkerProvider"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* 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.impl.source.xml.XmlAttributeImpl;
import com.intellij.psi.impl.source.xml.XmlTagImpl;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ProcessingContext;
import com.intellij.util.indexing.FileBasedIndex;
import com.magento.idea.magento2plugin.magento.files.ModuleDbSchemaXml;
import com.magento.idea.magento2plugin.stubs.indexes.xml.TableAndColumnNameIndex;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;

/**
* Provides column names for completion.
*/
public class ColumnNameCompletionProvider extends CompletionProvider<CompletionParameters> {
@Override
protected void addCompletions(
final @NotNull CompletionParameters parameters,
final @NotNull ProcessingContext context,
final @NotNull CompletionResultSet result
) {
final PsiElement position = parameters.getPosition().getOriginalElement();
final String currentAttrName = getCurrentAttributeName(position);
if (position == null || currentAttrName == null) {
return;
}
String targetTableAttrName;

switch (currentAttrName) {
case ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_COLUMN_NAME:
targetTableAttrName = ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_TABLE_NAME;
break;
case ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_REFERENCE_COLUMN_NAME:
targetTableAttrName = ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_REFERENCE_TABLE_NAME;
break;
default:
return;
}
final String targetTableName = getTargetTableFromPositionAndAttrName(
position,
targetTableAttrName
);

if (targetTableName == null) {
return;
}
final Collection<String> tableAndColumnNames = FileBasedIndex.getInstance().getAllKeys(
TableAndColumnNameIndex.KEY, position.getProject()
);
final List<String> filteredColumnNames = tableAndColumnNames.stream()
.filter(name -> name.contains(targetTableName + ".")).collect(Collectors.toList())
.stream().map(name -> name.substring(name.indexOf(".") + 1))
.collect(Collectors.toList());

for (final String columnName: filteredColumnNames) {
result.addElement(LookupElementBuilder.create(columnName));
}
}

/**
* Get attribute name from position.
*
* @param position PsiElement
*
* @return String
*/
private String getCurrentAttributeName(final PsiElement position) {
if (position instanceof XmlAttributeImpl) {
return ((XmlAttributeImpl) position).getName();
} else {
return getCurrentAttributeName(position.getParent());
}
}

/**
* Get reference table name from current position.
*
* @param position PsiElement
* @param targetTableAttrName String
*
* @return String
*/
private String getTargetTableFromPositionAndAttrName(
final PsiElement position,
final String targetTableAttrName
) {
if (targetTableAttrName == null) {
return null;
}

if (position instanceof XmlTagImpl
&& ((XmlTag) position).getName().equals(ModuleDbSchemaXml.XML_TAG_CONSTRAINT)) {
return ((XmlTag) position)
.getAttributeValue(targetTableAttrName);
} else {
return getTargetTableFromPositionAndAttrName(
position.getParent(),
targetTableAttrName
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.util.ProcessingContext;
import com.intellij.util.indexing.FileBasedIndex;
import com.magento.idea.magento2plugin.stubs.indexes.xml.TableAndColumnNameIndex;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;

/**
* Provides table names for completion.
*/
public class TableNameCompletionProvider extends CompletionProvider<CompletionParameters> {
@Override
protected void addCompletions(
final @NotNull CompletionParameters parameters,
final @NotNull ProcessingContext context,
final @NotNull CompletionResultSet result
) {
final PsiElement position = parameters.getPosition().getOriginalElement();
if (position == null) {
return;
}

final Collection<String> tableNames = FileBasedIndex.getInstance().getAllKeys(
TableAndColumnNameIndex.KEY, position.getProject()
);
final List<String> filteredTableNames = tableNames.stream()
.filter(name -> !name.contains(".")).collect(Collectors.toList());

for (final String tableName: filteredTableNames) {
result.addElement(LookupElementBuilder.create(tableName));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,64 @@ public XmlCompletionContributor() {
new MenuCompletionProvider()
);

// <table name="completion" /> in db_schema.xml
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
.inside(XmlPatterns.xmlAttribute().withName(ModuleDbSchemaXml.XML_ATTR_TABLE_NAME)
.withParent(XmlPatterns.xmlTag().withName(ModuleDbSchemaXml.XML_TAG_TABLE)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_SCHEMA))))
.inFile(xmlFile().withName(string().matches(ModuleDbSchemaXml.FILE_NAME))),
new TableNameCompletionProvider()
);

// <constraint table="completion" /> in db_schema.xml
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
.inside(XmlPatterns.xmlAttribute()
.withName(ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_TABLE_NAME)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_CONSTRAINT)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_TABLE))))
.inFile(xmlFile().withName(string().matches(ModuleDbSchemaXml.FILE_NAME))),
new TableNameCompletionProvider()
);

// <constraint referenceTable="completion" /> in db_schema.xml
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
.inside(XmlPatterns.xmlAttribute()
.withName(ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_REFERENCE_TABLE_NAME)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_CONSTRAINT)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_TABLE))))
.inFile(xmlFile().withName(string().matches(ModuleDbSchemaXml.FILE_NAME))),
new TableNameCompletionProvider()
);

// <constraint column="completion" /> in db_schema.xml
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
.inside(XmlPatterns.xmlAttribute()
.withName(ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_COLUMN_NAME)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_CONSTRAINT)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_TABLE))))
.inFile(xmlFile().withName(string().matches(ModuleDbSchemaXml.FILE_NAME))),
new ColumnNameCompletionProvider()
);

// <constraint referenceColumn="completion" /> in db_schema.xml
extend(CompletionType.BASIC, psiElement(XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN)
.inside(XmlPatterns.xmlAttribute()
.withName(ModuleDbSchemaXml.XML_ATTR_CONSTRAINT_REFERENCE_COLUMN_NAME)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_CONSTRAINT)
.withParent(XmlPatterns.xmlTag()
.withName(ModuleDbSchemaXml.XML_TAG_TABLE))))
.inFile(xmlFile().withName(string().matches(ModuleDbSchemaXml.FILE_NAME))),
new ColumnNameCompletionProvider()
);

registerCompletionsForDifferentNesting();
}

Expand Down
2 changes: 2 additions & 0 deletions src/com/magento/idea/magento2plugin/indexes/IndexManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex;
import com.magento.idea.magento2plugin.stubs.indexes.xml.MenuIndex;
import com.magento.idea.magento2plugin.stubs.indexes.xml.PhpClassNameIndex;
import com.magento.idea.magento2plugin.stubs.indexes.xml.TableAndColumnNameIndex;

@SuppressWarnings({"PMD.ClassNamingConventions", "PMD.UseUtilityClass"})
public class IndexManager {
Expand All @@ -41,6 +42,7 @@ public static void manualReindex() {
// xml|di configuration
PluginIndex.KEY,
VirtualTypeIndex.KEY,
TableAndColumnNameIndex.KEY,
// layouts
BlockNameIndex.KEY,
ContainerNameIndex.KEY,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.magento.files;

import com.intellij.lang.Language;
import com.intellij.lang.xml.XMLLanguage;

public class ModuleDbSchemaXml implements ModuleFileInterface {
private static final ModuleDbSchemaXml INSTANCE = new ModuleDbSchemaXml();
public static final String FILE_NAME = "db_schema.xml";
public static final String TEMPLATE = "Magento Module Declarative Schema XML";

//attributes
public static final String XML_ATTR_TABLE_NAME = "name";
public static final String XML_ATTR_COLUMN_NAME = "name";
public static final String XML_ATTR_CONSTRAINT_TABLE_NAME = "table";
public static final String XML_ATTR_CONSTRAINT_REFERENCE_TABLE_NAME = "referenceTable";
public static final String XML_ATTR_CONSTRAINT_COLUMN_NAME = "column";
public static final String XML_ATTR_CONSTRAINT_REFERENCE_COLUMN_NAME = "referenceColumn";
//tags
public static final String XML_TAG_SCHEMA = "schema";
public static final String XML_TAG_TABLE = "table";
public static final String XML_TAG_COLUMN = "column";
public static final String XML_TAG_CONSTRAINT = "constraint";

public static ModuleDbSchemaXml getInstance() {
return INSTANCE;
}

@Override
public String getFileName() {
return FILE_NAME;
}

@Override
public String getTemplate() {
return TEMPLATE;
}

@Override
public Language getLanguage() {
return XMLLanguage.INSTANCE;
}
}
Loading

0 comments on commit df995c8

Please sign in to comment.