diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java
index 518fdbe2b5ae..d6472836103a 100644
--- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java
@@ -402,7 +402,7 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea
@NonNls public String HTML_INLINE_ELEMENTS =
"a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,span,strike,strong,sub,sup,textarea,tt,u,var";
@NonNls public String HTML_DONT_ADD_BREAKS_IF_INLINE_CONTENT = "title,h1,h2,h3,h4,h5,h6,p";
-
+ public QuoteStyle HTML_QUOTE_STYLE = QuoteStyle.Double;
// ---------------------------------------------------------------------------------------
@@ -1019,4 +1019,15 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea
return WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN;
}
+ public enum QuoteStyle {
+ Single("'"),
+ Double("\""),
+ None("");
+
+ public final String quote;
+
+ QuoteStyle(String quote) {
+ this.quote = quote;
+ }
+ }
}
diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties
index 3fec13c55433..0601f5484249 100644
--- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties
+++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties
@@ -89,6 +89,7 @@ checkbox.wrap.text=Wrap text
checkbox.parentheses.around.method.arguments=Add parentheses around method arguments
checkbox.rename.local.variables.inplace=Enable in-place mode
checkbox.rename.local.variables.preselect=Preselect old name
+generated.quote.marks=Generated quote marks:
editbox.keep.blank.lines=Keep blank lines:
checkbox.keep.white.spaces=Keep white spaces
checkbox.align.text=Align text
diff --git a/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.form b/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.form
index bf79ab8f021e..8c53c6bd7664 100644
--- a/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.form
+++ b/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.form
@@ -40,7 +40,7 @@
-
+
@@ -180,6 +180,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.java b/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.java
index 497305c5ed84..3b971b9cd921 100644
--- a/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.java
+++ b/xml/impl/src/com/intellij/application/options/CodeStyleHtmlPanel.java
@@ -28,6 +28,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
+import com.intellij.ui.EnumComboBoxModel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PlatformIcons;
@@ -66,6 +67,7 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
private TextFieldWithBrowseButton myDontBreakIfInlineContent;
private JBScrollPane myJBScrollPane;
private JPanel myRightMarginPanel;
+ private JComboBox myQuotesCombo;
private RightMarginForm myRightMarginForm;
public CodeStyleHtmlPanel(CodeStyleSettings settings) {
@@ -73,6 +75,7 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
installPreviewPanel(myPreviewPanel);
fillWrappingCombo(myWrapAttributes);
+ fillQuotesCombo(myQuotesCombo);
customizeField(ApplicationBundle.message("title.insert.new.line.before.tags"), myInsertNewLineTagNames);
customizeField(ApplicationBundle.message("title.remove.line.breaks.before.tags"), myRemoveNewLineTagNames);
@@ -162,9 +165,15 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
settings.HTML_KEEP_WHITESPACES_INSIDE = myKeepWhiteSpacesTagNames.getText();
settings.HTML_KEEP_LINE_BREAKS = myShouldKeepBlankLines.isSelected();
settings.HTML_KEEP_LINE_BREAKS_IN_TEXT = myShouldKeepLineBreaksInText.isSelected();
+ settings.HTML_QUOTE_STYLE = (CodeStyleSettings.QuoteStyle)myQuotesCombo.getSelectedItem();
myRightMarginForm.apply(settings);
}
+ @NotNull
+ protected String getQuotes() {
+ return ApplicationBundle.message("single.quotes").equals(myQuotesCombo.getSelectedItem()) ? "'" : "\"";
+ }
+
private static int getIntValue(JTextField keepBlankLines) {
try {
return Integer.parseInt(keepBlankLines.getText());
@@ -196,6 +205,7 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
myDontBreakIfInlineContent.setText(settings.HTML_DONT_ADD_BREAKS_IF_INLINE_CONTENT);
myKeepWhiteSpacesTagNames.setText(settings.HTML_KEEP_WHITESPACES_INSIDE);
myRightMarginForm.reset(settings);
+ myQuotesCombo.setSelectedItem(settings.HTML_QUOTE_STYLE);
}
@Override
@@ -266,6 +276,10 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
return true;
}
+ if (myQuotesCombo.getSelectedItem() != settings.HTML_QUOTE_STYLE) {
+ return true;
+ }
+
return myRightMarginForm.isModified(settings);
}
@@ -290,4 +304,8 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
protected void prepareForReformat(final PsiFile psiFile) {
//psiFile.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, LanguageLevel.HIGHEST);
}
+
+ private static void fillQuotesCombo(JComboBox combo) {
+ combo.setModel(new EnumComboBoxModel<>(CodeStyleSettings.QuoteStyle.class));
+ }
}
diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java
index 4249e2b271e9..38167f930812 100644
--- a/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java
+++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java
@@ -27,6 +27,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
@@ -34,6 +35,7 @@ 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;
@@ -66,14 +68,20 @@ public class XmlAttributeInsertHandler implements InsertHandler {
final PsiFile file = context.getFile();
final CharSequence chars = document.getCharsSequence();
- final boolean insertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue();
- final boolean hasQuotes = CharArrayUtil.regionMatches(chars, caretOffset, "=\"");
- if (!hasQuotes && !CharArrayUtil.regionMatches(chars, caretOffset, "='")) {
+ final String quote = getAttributeQuote(HtmlUtil.hasHtml(file) || HtmlUtil.supportsXmlTypedHandlers(file));
+ final boolean insertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue() && StringUtil.isNotEmpty(quote);
+ final boolean hasQuotes = CharArrayUtil.regionMatches(chars, caretOffset, "=\"") ||
+ CharArrayUtil.regionMatches(chars, caretOffset, "='");
+ if (!hasQuotes) {
PsiElement fileContext = file.getContext();
- String toInsert= "=\"\"";
+ String toInsert = null;
if(fileContext != null) {
if (fileContext.getText().startsWith("\"")) toInsert = "=''";
+ if (fileContext.getText().startsWith("\'")) toInsert = "=\"\"";
+ }
+ if (toInsert == null) {
+ toInsert = "=" + quote + quote;
}
if (!insertQuotes) toInsert = "=";
@@ -118,6 +126,10 @@ public class XmlAttributeInsertHandler implements InsertHandler {
}
}
+ public static String getAttributeQuote(boolean html) {
+ return html ? CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings().HTML_QUOTE_STYLE.quote : "\"";
+ }
+
private static void qualifyWithPrefix(@NotNull String namespacePrefix, @NotNull PsiElement context) {
final PsiElement parent = context.getParent();
diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java
index 9938e39ef720..0658f6e7d4c7 100644
--- a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java
+++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java
@@ -230,9 +230,9 @@ public class XmlTagInsertHandler implements InsertHandler {
if (shouldBeInserted && (tag == null || tag.getAttributeValue(attributeName) == null)) {
if (!notRequiredAttributes.contains(attributeName)) {
if (!extension.isIndirectSyntax(attributeDecl)) {
- template.addTextSegment(" " + attributeName + "=\"");
+ template.addTextSegment(" " + attributeName + "=" + XmlAttributeInsertHandler.getAttributeQuote(htmlCode));
template.addVariable(new MacroCallNode(new CompleteMacro()), true);
- template.addTextSegment("\"");
+ template.addTextSegment(XmlAttributeInsertHandler.getAttributeQuote(htmlCode));
}
else {
if (indirectRequiredAttrs == null) indirectRequiredAttrs = new StringBuilder();
@@ -241,7 +241,8 @@ public class XmlTagInsertHandler implements InsertHandler {
}
}
else if (shouldBeInserted && attributeDecl.isFixed() && attributeDecl.getDefaultValue() != null && !htmlCode) {
- template.addTextSegment(" " + attributeName + "=\"" + attributeDecl.getDefaultValue() + "\"");
+ template.addTextSegment(" " + attributeName + "=" + XmlAttributeInsertHandler.getAttributeQuote(false) +
+ attributeDecl.getDefaultValue() + XmlAttributeInsertHandler.getAttributeQuote(false));
}
}
}
@@ -254,6 +255,7 @@ public class XmlTagInsertHandler implements InsertHandler {
XmlTag tag,
Template template,
StringBuilder indirectRequiredAttrs) {
+ boolean htmlCode = HtmlUtil.hasHtml(tag.getContainingFile()) || HtmlUtil.supportsXmlTypedHandlers(tag.getContainingFile());
if (completionChar == '>' || (completionChar == '/' && indirectRequiredAttrs != null)) {
template.addTextSegment(">");
@@ -290,7 +292,7 @@ public class XmlTagInsertHandler implements InsertHandler {
else if (completionChar == ' ' && template.getSegmentsCount() == 0) {
if (WebEditorOptions.getInstance().isAutomaticallyStartAttribute() &&
(descriptor.getAttributesDescriptors(tag).length > 0 || isTagFromHtml(tag) && !HtmlUtil.isTagWithoutAttributes(tag.getName()))) {
- completeAttribute(template);
+ completeAttribute(template, htmlCode);
return true;
}
}
@@ -301,7 +303,7 @@ public class XmlTagInsertHandler implements InsertHandler {
else {
if (needAlLeastOneAttribute(tag) && WebEditorOptions.getInstance().isAutomaticallyStartAttribute() && tag.getAttributes().length == 0
&& template.getSegmentsCount() == 0) {
- completeAttribute(template);
+ completeAttribute(template, htmlCode);
return true;
}
else {
@@ -313,12 +315,12 @@ public class XmlTagInsertHandler implements InsertHandler {
return false;
}
- private static void completeAttribute(Template template) {
+ private static void completeAttribute(Template template, boolean htmlCode) {
template.addTextSegment(" ");
template.addVariable(new MacroCallNode(new CompleteMacro()), true);
- template.addTextSegment("=\"");
+ template.addTextSegment("=" + XmlAttributeInsertHandler.getAttributeQuote(htmlCode));
template.addEndVariable();
- template.addTextSegment("\"");
+ template.addTextSegment(XmlAttributeInsertHandler.getAttributeQuote(htmlCode));
}
private static boolean needAlLeastOneAttribute(XmlTag tag) {
diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java
index 6a5287b149c8..a2b988c5aa2a 100644
--- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java
+++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java
@@ -17,12 +17,14 @@ package com.intellij.codeInsight.editorActions;
import com.intellij.application.options.editor.WebEditorOptions;
import com.intellij.codeInsight.AutoPopupController;
+import com.intellij.codeInsight.completion.XmlAttributeInsertHandler;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlAttribute;
+import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.NotNull;
public class XmlEqTypedHandler extends TypedHandlerDelegate {
@@ -50,13 +52,18 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate {
if (needToInsertQuotes) {
int offset = editor.getCaretModel().getOffset();
PsiElement fileContext = file.getContext();
- String toInsert= "\"\"";
+ String toInsert = null;
if(fileContext != null) {
if (fileContext.getText().startsWith("\"")) toInsert = "''";
+ if (fileContext.getText().startsWith("\'")) toInsert = "\"\"";
+ }
+ if (toInsert == null) {
+ final String quote = XmlAttributeInsertHandler.getAttributeQuote(HtmlUtil.hasHtml(file) || HtmlUtil.supportsXmlTypedHandlers(file));
+ toInsert = quote + quote;
}
editor.getDocument().insertString(offset, toInsert);
- editor.getCaretModel().moveToOffset(offset + 1);
+ editor.getCaretModel().moveToOffset(offset + toInsert.length() / 2);
AutoPopupController.getInstance(project).scheduleAutoPopup(editor);
}
needToInsertQuotes = false;
diff --git a/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java b/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java
index 7fb0761a8019..40cb6c29d392 100644
--- a/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java
+++ b/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java
@@ -28,6 +28,8 @@ import com.intellij.javaee.ExternalResourceManagerEx;
import com.intellij.javaee.ExternalResourceManagerExImpl;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.psi.codeStyle.CodeStyleSchemes;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.psi.statistics.impl.StatisticsManagerImpl;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
@@ -342,6 +344,30 @@ public class XmlCompletionTest extends LightCodeInsightFixtureTestCase {
checkResultByFile("37_after.xml");
}
+ public void testInsertExtraRequiredAttributeSingleQuote() throws Exception {
+ final CodeStyleSettings settings = CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings();
+ final CodeStyleSettings.QuoteStyle quote = settings.HTML_QUOTE_STYLE;
+ try {
+ settings.HTML_QUOTE_STYLE = CodeStyleSettings.QuoteStyle.Single;
+ configureByFile(getTestName(true) + ".html");
+ checkResultByFile(getTestName(true) + "_after.html");
+ } finally {
+ CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings().HTML_QUOTE_STYLE = quote;
+ }
+ }
+
+ public void testInsertExtraRequiredAttributeNoneQuote() throws Exception {
+ final CodeStyleSettings settings = CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings();
+ final CodeStyleSettings.QuoteStyle quote = settings.HTML_QUOTE_STYLE;
+ try {
+ settings.HTML_QUOTE_STYLE = CodeStyleSettings.QuoteStyle.None;
+ configureByFile(getTestName(true) + ".html");
+ checkResultByFile(getTestName(true) + "_after.html");
+ } finally {
+ CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings().HTML_QUOTE_STYLE = quote;
+ }
+ }
+
public void testBeforeAttributeValue() throws Throwable {
configureByFile(getTestName(true) + ".xml");
assertEmpty(myFixture.getLookupElements());
diff --git a/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java b/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java
index 0db89fc934e3..57f4573a5ee0 100644
--- a/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java
+++ b/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java
@@ -16,7 +16,10 @@
package com.intellij.codeInsight.completion;
import com.intellij.application.options.editor.WebEditorOptions;
+import com.intellij.ide.highlighter.HtmlFileType;
import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.psi.codeStyle.CodeStyleSchemes;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
/**
@@ -95,6 +98,32 @@ public class XmlTypedHandlersTest extends LightPlatformCodeInsightFixtureTestCas
}
}
+ public void testSingleQuotes() {
+ final CodeStyleSettings settings = CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings();
+ final CodeStyleSettings.QuoteStyle quote = settings.HTML_QUOTE_STYLE;
+ try {
+ settings.HTML_QUOTE_STYLE = CodeStyleSettings.QuoteStyle.Single;
+ myFixture.configureByText(HtmlFileType.INSTANCE, "");
+ myFixture.type('=');
+ myFixture.checkResult(">text");
+ myFixture.type('=');
+ myFixture.checkResult(">text");
+ } finally {
+ CodeStyleSchemes.getInstance().getCurrentScheme().getCodeStyleSettings().HTML_QUOTE_STYLE = quote;
+ }
+ }
+
public void testFooBar() throws Exception {
doTest("\n" +
" \n" +
diff --git a/xml/tests/testData/completion/insertExtraRequiredAttributeNoneQuote.html b/xml/tests/testData/completion/insertExtraRequiredAttributeNoneQuote.html
new file mode 100644
index 000000000000..3fe294dcef59
--- /dev/null
+++ b/xml/tests/testData/completion/insertExtraRequiredAttributeNoneQuote.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/xml/tests/testData/completion/insertExtraRequiredAttributeNoneQuote_after.html b/xml/tests/testData/completion/insertExtraRequiredAttributeNoneQuote_after.html
new file mode 100644
index 000000000000..4fb461b54c73
--- /dev/null
+++ b/xml/tests/testData/completion/insertExtraRequiredAttributeNoneQuote_after.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/xml/tests/testData/completion/insertExtraRequiredAttributeSingleQuote.html b/xml/tests/testData/completion/insertExtraRequiredAttributeSingleQuote.html
new file mode 100644
index 000000000000..3fe294dcef59
--- /dev/null
+++ b/xml/tests/testData/completion/insertExtraRequiredAttributeSingleQuote.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/xml/tests/testData/completion/insertExtraRequiredAttributeSingleQuote_after.html b/xml/tests/testData/completion/insertExtraRequiredAttributeSingleQuote_after.html
new file mode 100644
index 000000000000..56810380770a
--- /dev/null
+++ b/xml/tests/testData/completion/insertExtraRequiredAttributeSingleQuote_after.html
@@ -0,0 +1 @@
+
\ No newline at end of file