package org.angularjs.codeInsight.tags;
import com.intellij.codeInsight.completion.XmlTagInsertHandler;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.lang.Language;
import com.intellij.lang.javascript.psi.stubs.JSImplicitElement;
import com.intellij.lang.javascript.psi.stubs.impl.JSImplicitElementImpl;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.impl.source.xml.XmlElementDescriptorProvider;
import com.intellij.psi.xml.XmlTag;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlNSDescriptor;
import com.intellij.xml.XmlTagNameProvider;
import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
import icons.AngularJSIcons;
import org.angularjs.codeInsight.DirectiveUtil;
import org.angularjs.index.AngularIndexUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author Dennis.Ushakov
*/
public class AngularJSTagDescriptorsProvider implements XmlElementDescriptorProvider, XmlTagNameProvider {
private static final String NG_CONTAINER = "ng-container";
private static final String NG_CONTENT = "ng-content";
private static final String NG_TEMPLATE = "ng-template";
@Override
public void addTagNameVariants(final List<LookupElement> elements, @NotNull XmlTag xmlTag, String prefix) {
if (!(xmlTag instanceof HtmlTag && AngularIndexUtil.hasAngularJS(xmlTag.getProject()))) return;
final Project project = xmlTag.getProject();
Language language = xmlTag.getContainingFile().getLanguage();
DirectiveUtil.processTagDirectives(project, directive -> {
addLookupItem(language, elements, directive);
return true;
});
if (AngularIndexUtil.hasAngularJS2(project)) {
addLookupItem(language, elements, createDirective(xmlTag, NG_CONTAINER));
addLookupItem(language, elements, createDirective(xmlTag, NG_CONTENT));
addLookupItem(language, elements, createDirective(xmlTag, NG_TEMPLATE));
}
}
private static void addLookupItem(Language language, List<LookupElement> elements, JSImplicitElement directive) {
LookupElementBuilder element = LookupElementBuilder.create(directive).
withIcon(AngularJSIcons.Angular2);
if (language.isKindOf(XMLLanguage.INSTANCE)) {
element = element.withInsertHandler(XmlTagInsertHandler.INSTANCE);
}
elements.add(element);
}
@Nullable
@Override
public XmlElementDescriptor getDescriptor(XmlTag xmlTag) {
final Project project = xmlTag.getProject();
if (!(xmlTag instanceof HtmlTag && AngularIndexUtil.hasAngularJS(project))) return null;
final String tagName = xmlTag.getName();
final String directiveName = DirectiveUtil.normalizeAttributeName(tagName);
final XmlNSDescriptor nsDescriptor = xmlTag.getNSDescriptor(xmlTag.getNamespace(), false);
final XmlElementDescriptor descriptor = nsDescriptor != null ? nsDescriptor.getElementDescriptor(xmlTag) : null;
if (descriptor != null && !(descriptor instanceof AnyXmlElementDescriptor)) {
return null;
}
if ((NG_CONTAINER.equals(directiveName) || NG_CONTENT.equals(directiveName) || NG_TEMPLATE.equals(directiveName)) &&
AngularIndexUtil.hasAngularJS2(project)) {
return new AngularJSTagDescriptor(directiveName, createDirective(xmlTag, directiveName));
}
JSImplicitElement directive = DirectiveUtil.getTagDirective(directiveName, project);
if (DirectiveUtil.isAngular2Directive(directive) && !directive.getName().equals(tagName)) {
// we've found directive via normalized name for Angular, it should not work
directive = null;
}
if (directive == null && !tagName.equals(directiveName) && AngularIndexUtil.hasAngularJS2(project)) {
directive = DirectiveUtil.getTagDirective(tagName, project);
if (!DirectiveUtil.isAngular2Directive(directive)) directive = null;
}
return directive != null ? new AngularJSTagDescriptor(directiveName, directive) : null;
}
@NotNull
private static JSImplicitElementImpl createDirective(XmlTag xmlTag, String name) {
return new JSImplicitElementImpl.Builder(name, xmlTag).setTypeString("E;;;").toImplicitElement();
}
}