WEB-44210 Update behavior of tag completion in HTML, JSX, and XML

GitOrigin-RevId: 721caf7344143b6a6254fb0b87d3a7e98d7ab939
This commit is contained in:
Piotr Tomiak
2020-03-21 17:10:40 +00:00
committed by intellij-monorepo-bot
parent f652c91582
commit ac163e1235
3 changed files with 29 additions and 9 deletions
@@ -36,12 +36,17 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.xml.HtmlCodeStyleSettings;
import com.intellij.psi.formatter.xml.XmlCodeStyleSettings;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.impl.source.html.dtd.HtmlAttributeDescriptorImpl;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.xml.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlExtension;
import com.intellij.xml.XmlExtension.AttributeValuePresentation;
import com.intellij.xml.XmlTagRuleProvider;
import com.intellij.xml.actions.GenerateXmlTagAction;
import com.intellij.xml.impl.schema.XmlElementDescriptorImpl;
import com.intellij.xml.util.HtmlUtil;
@@ -274,10 +279,13 @@ public class XmlTagInsertHandler implements InsertHandler<LookupElement> {
}
else if (completionChar == Lookup.AUTO_INSERT_SELECT_CHAR || completionChar == Lookup.NORMAL_SELECT_CHAR || completionChar == Lookup.REPLACE_SELECT_CHAR) {
if (WebEditorOptions.getInstance().isAutomaticallyInsertClosingTag() && isHtmlCode && HtmlUtil.isSingleHtmlTag(tag, true)) {
if (hasOwnAttributes(descriptor, tag)) {
template.addEndVariable();
}
template.addTextSegment(HtmlUtil.isHtmlTag(tag) ? ">" : closeTag(tag));
}
else {
if (needAlLeastOneAttribute(tag) && WebEditorOptions.getInstance().isAutomaticallyStartAttribute() && tag.getAttributes().length == 0
if (needAtLeastOneAttribute(tag) && WebEditorOptions.getInstance().isAutomaticallyStartAttribute() && tag.getAttributes().length == 0
&& template.getSegmentsCount() == 0) {
completeAttribute(tag.getContainingFile(), template);
return true;
@@ -308,7 +316,7 @@ public class XmlTagInsertHandler implements InsertHandler<LookupElement> {
template.addTextSegment(XmlEditUtil.getAttributeQuote(file));
}
private static boolean needAlLeastOneAttribute(XmlTag tag) {
private static boolean needAtLeastOneAttribute(XmlTag tag) {
for (XmlTagRuleProvider ruleProvider : XmlTagRuleProvider.EP_NAME.getExtensionList()) {
for (XmlTagRuleProvider.Rule rule : ruleProvider.getTagRule(tag)) {
if (rule.needAtLeastOneAttribute(tag)) {
@@ -352,7 +360,8 @@ public class XmlTagInsertHandler implements InsertHandler<LookupElement> {
}
private static void completeTagTail(Template template, XmlElementDescriptor descriptor, PsiFile file, XmlTag context, boolean firstLevel) {
boolean completeIt = !firstLevel || !canHaveAttributes(descriptor, context);
boolean completeIt = (!firstLevel || !canHaveAttributes(descriptor, context))
&& (file == null || XmlExtension.getExtension(file).shouldCompleteTag(context));
switch (descriptor.getContentType()) {
case XmlElementDescriptor.CONTENT_TYPE_UNKNOWN:
return;
@@ -385,6 +394,11 @@ public class XmlTagInsertHandler implements InsertHandler<LookupElement> {
}
}
private static boolean hasOwnAttributes(XmlElementDescriptor descriptor, XmlTag tag) {
return ContainerUtil.find(descriptor.getAttributesDescriptors(tag),
attr -> attr instanceof HtmlAttributeDescriptorImpl && HtmlUtil.isOwnHtmlAttribute(attr)) != null;
}
private static boolean canHaveAttributes(XmlElementDescriptor descriptor, XmlTag context) {
XmlAttributeDescriptor[] attributes = descriptor.getAttributesDescriptors(context);
int required = WebEditorOptions.getInstance().isAutomaticallyInsertRequiredAttributes() ?
@@ -170,6 +170,10 @@ public abstract class XmlExtension {
public boolean shouldBeInserted(final XmlAttributeDescriptor descriptor) {
return descriptor.isRequired();
}
public boolean shouldCompleteTag(XmlTag context) {
return true;
}
@NotNull
public AttributeValuePresentation getAttributeValuePresentation(@Nullable XmlTag tag,
@@ -466,7 +466,9 @@ public class HtmlUtil {
final PsiElement declaration = descriptor.getDeclaration();
final PsiFile file = declaration != null ? declaration.getContainingFile() : null;
final String name = file != null ? file.getName() : null;
return "meta.rnc".equals(name);
return "meta.rnc".equals(name) || "web-forms.rnc".equals(name)
|| "embed.rnc".equals(name) || "tables.rnc".equals(name)
|| "media.rnc".equals(name);
}
private static class TerminateException extends RuntimeException {
@@ -491,7 +493,7 @@ public class HtmlUtil {
new HtmlBuilderDriver(content).build(new XmlBuilder() {
@NonNls final Set<String> inTag = new THashSet<>();
boolean metHttpEquiv;
boolean metHttml5Charset;
boolean metHtml5Charset;
@Override
public void doctype(@Nullable final CharSequence publicId,
@@ -516,7 +518,7 @@ public class HtmlUtil {
@Override
public void endTag(final CharSequence localName, final String namespace, final int startoffset, final int endoffset) {
@NonNls final String name = StringUtil.toLowerCase(localName.toString());
if ("meta".equals(name) && (metHttpEquiv || metHttml5Charset) && contentAttributeValue != null) {
if ("meta".equals(name) && (metHttpEquiv || metHtml5Charset) && contentAttributeValue != null) {
String charsetName;
if (metHttpEquiv) {
int start = contentAttributeValue.indexOf(CHARSET_PREFIX);
@@ -537,7 +539,7 @@ public class HtmlUtil {
}
inTag.remove(name);
metHttpEquiv = false;
metHttml5Charset = false;
metHtml5Charset = false;
contentAttributeValue = null;
}
@@ -552,7 +554,7 @@ public class HtmlUtil {
metHttpEquiv |= value.equals("content-type");
}
else if (name.equals(CHARSET)) {
metHttml5Charset = true;
metHtml5Charset = true;
contentAttributeValue = value;
}
if (name.equals("content")) {