FIXED IDEA-52549 Reformat Code misbehaviour in a XML file

This commit is contained in:
Rustam Vishnyakov
2016-06-09 16:02:10 +03:00
parent 65d58e239c
commit 85f8adf90f
3 changed files with 75 additions and 0 deletions
@@ -19,13 +19,16 @@ import com.intellij.formatting.*;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.formatter.common.AbstractBlock;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlElementType;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -103,6 +106,11 @@ public class SyntheticBlock extends AbstractSyntheticBlock implements Block, Rea
boolean firstIsEntityRef = isEntityRef(node1);
boolean secondIsEntityRef = isEntityRef(node2);
if ((secondIsText && isInlineTag(node1) || firstIsText && isInlineTag(node2)) &&
myXmlFormattingPolicy.isKeepSpacesAroundInlineTags()) {
return Spacing.getReadOnlySpacing();
}
if (isSpaceInText(firstIsTag, secondIsTag, firstIsText, secondIsText) && keepWhiteSpaces()) {
return Spacing.getReadOnlySpacing();
}
@@ -264,4 +272,48 @@ public class SyntheticBlock extends AbstractSyntheticBlock implements Block, Rea
public Indent getChildIndent() {
return myChildIndent;
}
private static boolean isInlineTag(@NotNull ASTNode astNode) {
return astNode.getElementType() == XmlElementType.XML_TAG && isTextOnlyTag(astNode) &&
isTextNotEndingWithLineBreaks(astNode.getTreePrev()) && isTextNotStartingWithLineBreaks(astNode.getTreeNext());
}
private static boolean isTextNotEndingWithLineBreaks(@Nullable ASTNode astNode) {
if (astNode != null && astNode.getElementType() == XmlElementType.XML_TEXT) {
ASTNode lastChild = astNode.getLastChildNode();
if (lastChild != null) {
return !(lastChild.getPsi() instanceof PsiWhiteSpace) || !CharArrayUtil.containLineBreaks(lastChild.getChars());
}
}
return false;
}
private static boolean isTextNotStartingWithLineBreaks(@Nullable ASTNode astNode) {
if (astNode != null && astNode.getElementType() == XmlElementType.XML_TEXT) {
ASTNode firstChild = astNode.getFirstChildNode();
if (firstChild != null) {
return !(firstChild.getPsi() instanceof PsiWhiteSpace) || !CharArrayUtil.containLineBreaks(firstChild.getChars());
}
}
return false;
}
private static boolean isTextOnlyTag(@NotNull ASTNode tagNode) {
ASTNode child = tagNode.getFirstChildNode();
boolean checkContent = false;
while (child != null) {
IElementType childType = child.getElementType();
if (checkContent) {
if (childType == XmlTokenType.XML_END_TAG_START) return true;
else if (childType != XmlElementType.XML_TEXT) return false;
}
else {
if (childType == XmlTokenType.XML_TAG_END) {
checkContent = true;
}
}
child = child.getTreeNext();
}
return false;
}
}
@@ -161,4 +161,23 @@ public abstract class XmlFormattingPolicy {
public void dontProcessJavaTree() {
myProcessJavaTree = false;
}
/**
* Inline tags are the ones which:
* <ul>
* <li>Have no line breaks around them,</li>
* <li>Do not contain any another nested tags.</li>
* </ul> F
* or example:
* <pre>
* &lt;para&gt;
* Some &lt;em&gt;emphasized&lt;/em&gt; text.
* &lt;/para&gt;
* </pre>
* If true, spaces around such tags will be preserved, no line breaks inserted.
* @return <code>false</code> by default.
*/
public boolean isKeepSpacesAroundInlineTags() {
return false;
}
}
@@ -162,4 +162,8 @@ public class XmlPolicy extends XmlFormattingPolicy{
return false;
}
@Override
public boolean isKeepSpacesAroundInlineTags() {
return true;
}
}