diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java index 100914889c7b..21cdb6733f74 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java @@ -35,7 +35,6 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; import com.intellij.util.text.CharArrayUtil; import com.intellij.xml.XmlNamespaceHelper; -import com.intellij.xml.util.HtmlUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -68,7 +67,7 @@ public class XmlAttributeInsertHandler implements InsertHandler { final PsiFile file = context.getFile(); final CharSequence chars = document.getCharsSequence(); - final String quote = XmlEditUtil.getAttributeQuote(HtmlUtil.hasHtml(file) || HtmlUtil.supportsXmlTypedHandlers(file)); + final String quote = XmlEditUtil.getAttributeQuote(file); final boolean insertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue() && StringUtil.isNotEmpty(quote); final boolean hasQuotes = CharArrayUtil.regionMatches(chars, caretOffset, "=\"") || CharArrayUtil.regionMatches(chars, caretOffset, "='"); diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java index b51459284ba0..c2d6dd1b5010 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion; import com.intellij.application.options.editor.WebEditorOptions; import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.daemon.impl.quickfix.EmptyExpression; import com.intellij.codeInsight.editorActions.XmlEditUtil; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; @@ -238,7 +239,7 @@ public class XmlTagInsertHandler implements InsertHandler { if (!notRequiredAttributes.contains(attributeName)) { if (!extension.isIndirectSyntax(attributeDecl)) { template.addTextSegment(" " + attributeName + "=" + presenter.getPrefix()); - template.addVariable(new MacroCallNode(new CompleteMacro()), true); + template.addVariable(presenter.showAutoPopup() ? new MacroCallNode(new CompleteMacro()) : new EmptyExpression(), true); template.addTextSegment(presenter.getPostfix()); } else { diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/InsertRequiredAttributeFix.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/InsertRequiredAttributeFix.java index 208d828db595..9655f17df707 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/InsertRequiredAttributeFix.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/InsertRequiredAttributeFix.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.daemon.XmlErrorMessages; +import com.intellij.codeInsight.editorActions.XmlEditUtil; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; @@ -35,6 +36,7 @@ import com.intellij.psi.xml.XmlTag; 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.util.HtmlUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -96,11 +98,20 @@ public class InsertRequiredAttributeFix extends LocalQuickFixAndIntentionActionO if (anchor == null) return; final Template template = TemplateManager.getInstance(project).createTemplate("", ""); + String valuePostfix = "\""; if (indirectSyntax) { if (anchorIsEmptyTag) template.addTextSegment(">"); template.addTextSegment(""); - } else { - template.addTextSegment(" " + myAttrName + (!insertShorthand ? "=\"" : "")); + } + else { + template.addTextSegment(" " + myAttrName); + if (!insertShorthand) { + String quote = XmlEditUtil.getAttributeQuote(file); + AttributeValuePresentation presentation = XmlExtension.getExtension(file).getAttributeValuePresentation(attrDescriptor, quote); + + valuePostfix = presentation.getPostfix(); + template.addTextSegment("=" + presentation.getPrefix()); + } } Expression expression = new Expression() { @@ -133,7 +144,7 @@ public class InsertRequiredAttributeFix extends LocalQuickFixAndIntentionActionO template.addEndVariable(); if (anchorIsEmptyTag) template.addTextSegment(""); } else if (!insertShorthand) { - template.addTextSegment("\""); + template.addTextSegment(valuePostfix); } final PsiElement anchor1 = anchor; diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEditUtil.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEditUtil.java index face145d4dcd..d9b2a2947d69 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEditUtil.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEditUtil.java @@ -22,6 +22,9 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import org.jetbrains.annotations.NotNull; +import static com.intellij.xml.util.HtmlUtil.hasHtml; +import static com.intellij.xml.util.HtmlUtil.supportsXmlTypedHandlers; + public class XmlEditUtil { /** * Calculates quote style to use in a particular file depends on user's settings and injections @@ -39,4 +42,8 @@ public class XmlEditUtil { public static String getAttributeQuote(boolean html) { return html ? CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings().HTML_QUOTE_STYLE.quote : "\""; } + + public static String getAttributeQuote(@NotNull PsiFile file) { + return getAttributeQuote(hasHtml(file) || supportsXmlTypedHandlers(file)); + } } diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java index c93b0b943d30..58ad44b9b193 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java @@ -24,8 +24,11 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlAttribute; -import com.intellij.xml.util.HtmlUtil; +import com.intellij.xml.XmlAttributeDescriptor; +import com.intellij.xml.XmlExtension; +import com.intellij.xml.XmlExtension.AttributeValuePresentation; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class XmlEqTypedHandler extends TypedHandlerDelegate { private boolean needToInsertQuotes = false; @@ -35,10 +38,9 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate { if (c == '=' && WebEditorOptions.getInstance().isInsertQuotesForAttributeValue()) { if (XmlGtTypedHandler.fileContainsXmlLanguage(file)) { PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); - - PsiElement at = file.findElementAt(editor.getCaretModel().getOffset() - 1); - PsiElement atParent = at != null ? at.getParent() : null; - if(atParent instanceof XmlAttribute && ((XmlAttribute)atParent).getValueElement() == null) { + + PsiElement atParent = getAttributeCandidate(editor, file, false); + if (atParent instanceof XmlAttribute && ((XmlAttribute)atParent).getValueElement() == null) { needToInsertQuotes = ((XmlAttribute)atParent).getValueElement() == null; } } @@ -47,26 +49,57 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate { return super.beforeCharTyped(c, project, editor, file, fileType); } + @Nullable + private static PsiElement getAttributeCandidate(@NotNull Editor editor, @NotNull PsiFile file, boolean typed) { + int newOffset = editor.getCaretModel().getOffset() - (typed ? 2 : 1); + if (newOffset < 0) return null; + + PsiElement at = file.findElementAt(newOffset); + return at != null ? at.getParent() : null; + } + @Override public Result charTyped(char c, Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (needToInsertQuotes) { int offset = editor.getCaretModel().getOffset(); PsiElement fileContext = file.getContext(); - String toInsert = null; - - if(fileContext != null) { - if (fileContext.getText().startsWith("\"")) toInsert = "''"; - if (fileContext.getText().startsWith("\'")) toInsert = "\"\""; - } + String toInsert = tryCompleteQuotes(fileContext); + boolean showPopup = true; if (toInsert == null) { - final String quote = XmlEditUtil.getAttributeQuote(HtmlUtil.hasHtml(file) || HtmlUtil.supportsXmlTypedHandlers(file)); - toInsert = quote + quote; + final String quote = getDefaultQuote(file); + AttributeValuePresentation presentation = getValuePresentation(editor, file, quote); + toInsert = presentation.getPrefix() + presentation.getPostfix(); + showPopup = presentation.showAutoPopup(); } editor.getDocument().insertString(offset, toInsert); editor.getCaretModel().moveToOffset(offset + toInsert.length() / 2); - AutoPopupController.getInstance(project).scheduleAutoPopup(editor); + if (showPopup) { + AutoPopupController.getInstance(project).scheduleAutoPopup(editor); + } + needToInsertQuotes = false; } - needToInsertQuotes = false; + return super.charTyped(c, project, editor, file); } + + @Nullable + private static String tryCompleteQuotes(@Nullable PsiElement fileContext) { + if (fileContext != null) { + if (fileContext.getText().startsWith("\"")) return "''"; + if (fileContext.getText().startsWith("\'")) return "\"\""; + } + return null; + } + + @NotNull + private static String getDefaultQuote(@NotNull PsiFile file) { + return XmlEditUtil.getAttributeQuote(file); + } + + @NotNull + private static AttributeValuePresentation getValuePresentation(@NotNull Editor editor, @NotNull PsiFile file, @NotNull String quote) { + PsiElement atParent = getAttributeCandidate(editor, file, true); + XmlAttributeDescriptor descriptor = atParent instanceof XmlAttribute ? ((XmlAttribute)atParent).getDescriptor() : null; + return XmlExtension.getExtension(file).getAttributeValuePresentation(descriptor, quote); + } } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/XmlExtension.java b/xml/xml-psi-impl/src/com/intellij/xml/XmlExtension.java index 43aaddf4d859..3f01b12f7a80 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/XmlExtension.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/XmlExtension.java @@ -54,6 +54,10 @@ public abstract class XmlExtension { @NotNull String getPostfix(); + + default boolean showAutoPopup() { + return true; + } } private static XmlExtension calcExtension(PsiFile file) { @@ -168,7 +172,8 @@ public abstract class XmlExtension { return descriptor.isRequired(); } - public AttributeValuePresentation getAttributeValuePresentation(@NotNull XmlAttributeDescriptor descriptor, + @NotNull + public AttributeValuePresentation getAttributeValuePresentation(@Nullable XmlAttributeDescriptor descriptor, @NotNull String defaultAttributeQuote) { return new AttributeValuePresentation() { @NotNull diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java index efc78ba56bd5..407f935dd8d0 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java @@ -612,11 +612,11 @@ public class HtmlUtil { return tagName != null && "br".equalsIgnoreCase(tagName); } - public static boolean hasHtml(PsiFile file) { + public static boolean hasHtml(@NotNull PsiFile file) { return isHtmlFile(file) || file.getViewProvider() instanceof TemplateLanguageFileViewProvider; } - public static boolean supportsXmlTypedHandlers(PsiFile file) { + public static boolean supportsXmlTypedHandlers(@NotNull PsiFile file) { Language language = file.getLanguage(); while (language != null) { if ("JavaScript".equals(language.getID())) return true;