mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
WEB-20321 HTML code style — attribute value quotation
This commit is contained in:
@@ -403,6 +403,7 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea
|
||||
"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;
|
||||
public boolean HTML_ENFORCE_QUOTES = false;
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ checkbox.parentheses.around.method.arguments=Add parentheses around method argum
|
||||
checkbox.rename.local.variables.inplace=Enable in-place mode
|
||||
checkbox.rename.local.variables.preselect=Preselect old name
|
||||
generated.quote.marks=Generated quote marks:
|
||||
generated.quote.enforce.format=Enforce on format
|
||||
editbox.keep.blank.lines=Keep blank lines:
|
||||
checkbox.keep.white.spaces=Keep white spaces
|
||||
checkbox.align.text=Align text
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
<lang.whiteSpaceFormattingStrategy language="XML"
|
||||
implementationClass="com.intellij.lang.xml.XmlWhiteSpaceFormattingStrategy"/>
|
||||
<lang.formatter language="HTML" implementationClass="com.intellij.lang.html.HtmlFormattingModelBuilder"/>
|
||||
<preFormatProcessor implementation="com.intellij.lang.html.HtmlQuotesFormatPreprocessor"/>
|
||||
<lang.formatter language="XHTML" implementationClass="com.intellij.lang.xhtml.XhtmlFormattingModelBuilder"/>
|
||||
<lang.lineWrapStrategy language="XML" implementationClass="com.intellij.psi.formatter.MarkupLineWrapPositionStrategy"/>
|
||||
<lang.lineWrapStrategy language="HTML" implementationClass="com.intellij.psi.formatter.MarkupLineWrapPositionStrategy"/>
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
</head>
|
||||
|
||||
<body class="resharperbg">
|
||||
<div id="container">
|
||||
<div id=container>
|
||||
|
||||
<div id="top">
|
||||
<div id="logo"><a href="../index.html"><img src="../img/logo_bw.gif" width="124" height="44" alt="JetBrains home"/></a></div>
|
||||
<div id='top'>
|
||||
<div id='logo'><a href="../index.html"><img src="../img/logo_bw.gif" width="124" height="44" alt="JetBrains home"/></a></div>
|
||||
|
||||
<div id="nav">
|
||||
<div id=nav>
|
||||
<ul id="topnav">
|
||||
<li class="home"><a href="../index.html">Home</a></li>
|
||||
<li class="act"><a href="../products.html">Products</a></li>
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
<div id="quote">
|
||||
<p class="text">"If you are a C# developer you simply owe it to yourself to get this tool. It has
|
||||
dramatically made my life better (SERIOUSLY!). I put it up there with amazing tools<6C>"</p>
|
||||
dramatically made my life better (SERIOUSLY!). I put it up there with amazing tools<6C>"</p>
|
||||
<p class="author"><a target="" href="http://agiledamon.blogspot.com/2004/09/my-latest-net-developers-best-friend.html">Damon Wilder Carr</a>, <br/>Chief Technologist and CEO,<br/> Agilerfactor</p>
|
||||
</div>
|
||||
<p class="spacer"></p>
|
||||
@@ -121,7 +121,7 @@
|
||||
<p>Refactoring can significantly improve your code design and efficiency. ReSharper's automated refactoring
|
||||
support takes care of code consistency and compilability after even the most dramatic modifications.</p>
|
||||
<p>ReSharper supports the following types of refactoring:</p>
|
||||
<p><a href="features/refactoring.html">More about this feature<72></a></p>
|
||||
<p><a href="features/refactoring.html">More about this feature<72></a></p>
|
||||
</div>
|
||||
|
||||
<p>To get the full story on ReSharper’s feature set, please visit the <a href="features/index.html">Features</a> page.</p>
|
||||
@@ -131,7 +131,7 @@
|
||||
handwork, giving you more time to focus on the task at hand. Its robust set of features for automatic error-checking
|
||||
and code correction cuts development time and increases your efficiency. You'll find that ReSharper quickly
|
||||
pays back it's cost in increased developer productivity and improved code quality.</p>
|
||||
<p>The wait is over<65> ReSharper is here and now C# developers can experience what we mean when we say
|
||||
<p>The wait is over<65> ReSharper is here and now C# developers can experience what we mean when we say
|
||||
"Develop with pleasure!" <a href="download">Download a copy today</a>!</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<grid id="97358" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="4" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="4" y="8" width="828" height="588"/>
|
||||
<xy x="4" y="8" width="828" height="803"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@@ -40,7 +40,7 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="ca5bb" layout-manager="GridLayoutManager" row-count="8" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="ca5bb" layout-manager="GridLayoutManager" row-count="9" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
@@ -194,6 +194,14 @@
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="bd61d" class="com.intellij.ui.components.JBCheckBox" binding="myEnforceQuotesBox">
|
||||
<constraints>
|
||||
<grid row="8" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/ApplicationBundle" key="generated.quote.enforce.format"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="b8acc" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
|
||||
@@ -29,6 +29,7 @@ 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.JBCheckBox;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
@@ -68,6 +69,7 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
|
||||
private JBScrollPane myJBScrollPane;
|
||||
private JPanel myRightMarginPanel;
|
||||
private JComboBox myQuotesCombo;
|
||||
private JBCheckBox myEnforceQuotesBox;
|
||||
private RightMarginForm myRightMarginForm;
|
||||
|
||||
public CodeStyleHtmlPanel(CodeStyleSettings settings) {
|
||||
@@ -91,7 +93,14 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
|
||||
myInlineElementsTagNames.getTextField().setColumns(5);
|
||||
myDontBreakIfInlineContent.getTextField().setColumns(5);
|
||||
|
||||
|
||||
myQuotesCombo.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
boolean quotesRequired = !CodeStyleSettings.QuoteStyle.None.equals(myQuotesCombo.getSelectedItem());
|
||||
myEnforceQuotesBox.setEnabled(quotesRequired);
|
||||
if (!quotesRequired) myEnforceQuotesBox.setSelected(false);
|
||||
}
|
||||
});
|
||||
addPanelToWatch(myPanel);
|
||||
}
|
||||
|
||||
@@ -166,6 +175,7 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
|
||||
settings.HTML_KEEP_LINE_BREAKS = myShouldKeepBlankLines.isSelected();
|
||||
settings.HTML_KEEP_LINE_BREAKS_IN_TEXT = myShouldKeepLineBreaksInText.isSelected();
|
||||
settings.HTML_QUOTE_STYLE = (CodeStyleSettings.QuoteStyle)myQuotesCombo.getSelectedItem();
|
||||
settings.HTML_ENFORCE_QUOTES = myEnforceQuotesBox.isSelected();
|
||||
myRightMarginForm.apply(settings);
|
||||
}
|
||||
|
||||
@@ -206,6 +216,7 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
|
||||
myKeepWhiteSpacesTagNames.setText(settings.HTML_KEEP_WHITESPACES_INSIDE);
|
||||
myRightMarginForm.reset(settings);
|
||||
myQuotesCombo.setSelectedItem(settings.HTML_QUOTE_STYLE);
|
||||
myEnforceQuotesBox.setSelected(settings.HTML_ENFORCE_QUOTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -280,7 +291,8 @@ public class CodeStyleHtmlPanel extends CodeStyleAbstractPanel {
|
||||
return true;
|
||||
}
|
||||
|
||||
return myRightMarginForm.isModified(settings);
|
||||
return myRightMarginForm.isModified(settings) ||
|
||||
myEnforceQuotesBox.isSelected() != settings.HTML_ENFORCE_QUOTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.lang.html;
|
||||
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.XmlRecursiveElementVisitor;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.impl.source.codeStyle.PreFormatProcessor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.psi.xml.XmlTokenType;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class HtmlQuotesFormatPreprocessor implements PreFormatProcessor {
|
||||
@NotNull
|
||||
@Override
|
||||
public TextRange process(@NotNull ASTNode node, @NotNull TextRange range) {
|
||||
PsiElement psiElement = node.getPsi();
|
||||
if (psiElement != null &&
|
||||
psiElement.isValid() &&
|
||||
psiElement.getLanguage().is(HTMLLanguage.INSTANCE)) {
|
||||
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(psiElement.getProject());
|
||||
CodeStyleSettings.QuoteStyle quoteStyle = settings.HTML_QUOTE_STYLE;
|
||||
if (quoteStyle != CodeStyleSettings.QuoteStyle.None && settings.HTML_ENFORCE_QUOTES) {
|
||||
HtmlQuotesConverter converter = new HtmlQuotesConverter(quoteStyle, psiElement, range);
|
||||
Document document = converter.getDocument();
|
||||
if (document != null) {
|
||||
DocumentUtil.executeInBulk(document, true, converter);
|
||||
}
|
||||
return converter.getTextRange();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
private static class HtmlQuotesConverter extends XmlRecursiveElementVisitor implements Runnable {
|
||||
private TextRange myTextRange;
|
||||
private final Document myDocument;
|
||||
private final PsiDocumentManager myDocumentManager;
|
||||
private final PsiElement myElement;
|
||||
private int myDelta = 0;
|
||||
private final char myQuoteChar;
|
||||
|
||||
private HtmlQuotesConverter(CodeStyleSettings.QuoteStyle style,
|
||||
@NotNull PsiElement element,
|
||||
@NotNull TextRange textRange) {
|
||||
Project project = element.getProject();
|
||||
PsiFile file = element.getContainingFile();
|
||||
myElement = element;
|
||||
myTextRange = new TextRange(textRange.getStartOffset(), textRange.getEndOffset());
|
||||
myDocumentManager = PsiDocumentManager.getInstance(project);
|
||||
myDocument = myDocumentManager.getDocument(file);
|
||||
switch (style) {
|
||||
case Single:
|
||||
myQuoteChar = '\'';
|
||||
break;
|
||||
case Double:
|
||||
myQuoteChar = '"';
|
||||
break;
|
||||
default:
|
||||
myQuoteChar = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public TextRange getTextRange() {
|
||||
return myTextRange.grown(myDelta);
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return myDocument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlAttributeValue(XmlAttributeValue value) {
|
||||
if (myTextRange.contains(value.getTextRange())) {
|
||||
PsiElement child = value.getFirstChild();
|
||||
if (child != null &&
|
||||
!containsQuoteChars(value) // For now we skip values containing quotes to be inserted/replaced
|
||||
) {
|
||||
String newValue = null;
|
||||
if (child.getNode().getElementType() == XmlTokenType.XML_ATTRIBUTE_VALUE_START_DELIMITER) {
|
||||
PsiElement lastChild = value.getLastChild();
|
||||
if (lastChild != null && lastChild.getNode().getElementType() == XmlTokenType.XML_ATTRIBUTE_VALUE_END_DELIMITER) {
|
||||
CharSequence delimiterChars = child.getNode().getChars();
|
||||
if (delimiterChars.length() == 1) {
|
||||
char existingQuote = delimiterChars.charAt(0);
|
||||
if (existingQuote != myQuoteChar) {
|
||||
newValue = convertQuotes(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (child.getNode().getElementType() == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN
|
||||
&& child == value.getLastChild()) {
|
||||
newValue = surroundWithQuotes(value);
|
||||
}
|
||||
if (newValue != null) {
|
||||
int startOffset = value.getTextRange().getStartOffset() + myDelta;
|
||||
int endOffset = value.getTextRange().getEndOffset() + myDelta;
|
||||
myDocument.replaceString(startOffset, endOffset, newValue);
|
||||
myDelta += newValue.length() - value.getTextLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String convertQuotes(@NotNull XmlAttributeValue value) {
|
||||
String currValue = value.getNode().getChars().toString();
|
||||
if (currValue.length() >= 2) {
|
||||
return myQuoteChar + currValue.substring(1, currValue.length() - 1) + myQuoteChar;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String surroundWithQuotes(@NotNull XmlAttributeValue value) {
|
||||
String currValue = value.getNode().getChars().toString();
|
||||
return myQuoteChar + currValue + myQuoteChar;
|
||||
}
|
||||
|
||||
private boolean containsQuoteChars(@NotNull XmlAttributeValue value) {
|
||||
for (PsiElement child = value.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (!isDelimiter(child.getNode().getElementType())) {
|
||||
CharSequence valueChars = child.getNode().getChars();
|
||||
for (int i = 0; i < valueChars.length(); i ++) {
|
||||
if (valueChars.charAt(i) == myQuoteChar) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isDelimiter(@NotNull IElementType elementType) {
|
||||
return elementType == XmlTokenType.XML_ATTRIBUTE_VALUE_START_DELIMITER ||
|
||||
elementType == XmlTokenType.XML_ATTRIBUTE_VALUE_END_DELIMITER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (myDocument != null) {
|
||||
myDocumentManager.doPostponedOperationsAndUnblockDocument(myDocument);
|
||||
myElement.accept(this);
|
||||
myDocumentManager.commitDocument(myDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user