Add utility methods for unified comparison of element/node with element type

This commit is contained in:
Mikhail Golubev
2014-10-22 16:32:46 +04:00
parent 9ec8fbb7d8
commit a2b4b60088
2 changed files with 54 additions and 28 deletions
@@ -1,7 +1,6 @@
package com.intellij.json.formatter;
import com.intellij.formatting.*;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.JsonLanguage;
import com.intellij.json.psi.JsonArray;
import com.intellij.json.psi.JsonObject;
@@ -22,17 +21,19 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.intellij.json.JsonElementTypes.*;
import static com.intellij.json.JsonParserDefinition.*;
import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_COLON;
import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_VALUE;
import static com.intellij.json.psi.JsonPsiUtil.hasElementType;
/**
* @author Mikhail Golubev
*/
public class JsonBlock implements ASTBlock {
private static final TokenSet OPEN_BRACES = TokenSet.create(JsonElementTypes.L_BRACKET, JsonElementTypes.L_CURLY);
private static final TokenSet CLOSE_BRACES = TokenSet.create(JsonElementTypes.R_BRACKET, JsonElementTypes.R_CURLY);
private static final TokenSet BRACES = TokenSet.orSet(OPEN_BRACES, CLOSE_BRACES);
private static final TokenSet JSON_OPEN_BRACES = TokenSet.create(L_BRACKET, L_CURLY);
private static final TokenSet JSON_CLOSE_BRACES = TokenSet.create(R_BRACKET, R_CURLY);
private static final TokenSet JSON_ALL_BRACES = TokenSet.orSet(JSON_OPEN_BRACES, JSON_CLOSE_BRACES);
private final JsonBlock myParent;
@@ -107,20 +108,18 @@ public class JsonBlock implements ASTBlock {
}
private Block makeSubBlock(@NotNull ASTNode childNode) {
final IElementType childNodeType = childNode.getElementType();
Indent indent = Indent.getNoneIndent();
Alignment alignment = null;
Wrap wrap = null;
final JsonCodeStyleSettings customSettings = getCustomSettings();
if (isContainer()) {
if (childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) {
if (hasElementType(myNode, JSON_CONTAINERS)) {
if (!hasElementType(childNode, COMMA) && !hasElementType(childNode, JSON_ALL_BRACES)) {
assert myChildWrap != null;
wrap = myChildWrap;
indent = Indent.getNormalIndent();
}
else if (OPEN_BRACES.contains(childNodeType)) {
else if (hasElementType(childNode, JSON_OPEN_BRACES)) {
if (JsonPsiUtil.isPropertyValue(myPsiElement) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) {
// WEB-13587 Align compound values on opening brace/bracket, not the whole block
assert myParent != null && myParent.myParent != null && myParent.myParent.myPropertyValueAlignment != null;
@@ -129,13 +128,13 @@ public class JsonBlock implements ASTBlock {
}
}
// Handle properties alignment
else if (myNode.getElementType() == JsonElementTypes.PROPERTY) {
else if (hasElementType(myNode, PROPERTY) ) {
assert myParent != null && myParent.myPropertyValueAlignment != null;
if (childNode.getElementType() == JsonElementTypes.COLON && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) {
if (hasElementType(childNode, COLON) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) {
alignment = myParent.myPropertyValueAlignment;
}
else if (JsonPsiUtil.isPropertyValue(childNode.getPsi()) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) {
if (!JSON_CONTAINERS.contains(childNodeType)) {
if (!hasElementType(childNode, JSON_CONTAINERS)) {
alignment = myParent.myPropertyValueAlignment;
}
}
@@ -165,17 +164,17 @@ public class JsonBlock implements ASTBlock {
@Override
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
final CommonCodeStyleSettings commonSettings = getCommonSettings();
final IElementType leftChildType = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode.getElementType() : null;
final IElementType rightChildType = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode.getElementType() : null;
final ASTNode leftChild = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode : null;
final ASTNode rightChild = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode : null;
// This causes braces/brackets to be on their own lines if whole object/array spans several lines.
if (leftChildType != null && rightChildType != null) {
if (JSON_BRACES.contains(leftChildType) ^ JSON_BRACES.contains(rightChildType)) {
if (leftChild != null && rightChild != null) {
if (hasElementType(leftChild, JSON_BRACES) ^ hasElementType(rightChild, JSON_BRACES)) {
final int numSpaces = commonSettings.SPACE_WITHIN_BRACES ? 1 : 0;
return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(),
commonSettings.KEEP_LINE_BREAKS,
commonSettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (JSON_BRACKETS.contains(leftChildType) ^ JSON_BRACKETS.contains(rightChildType)) {
else if (hasElementType(leftChild, JSON_BRACKETS) ^ hasElementType(rightChild, JSON_BRACKETS)) {
final int numSpaces = commonSettings.SPACE_WITHIN_BRACKETS ? 1 : 0;
return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(),
commonSettings.KEEP_LINE_BREAKS,
@@ -188,7 +187,7 @@ public class JsonBlock implements ASTBlock {
@NotNull
@Override
public ChildAttributes getChildAttributes(int newChildIndex) {
if (isContainer()) {
if (hasElementType(myNode, JSON_CONTAINERS)) {
// WEB-13675: For some reason including alignment in child attributes causes
// indents to consist solely of spaces when both USE_TABS and SMART_TAB
// options are enabled.
@@ -200,15 +199,14 @@ public class JsonBlock implements ASTBlock {
@Override
public boolean isIncomplete() {
final IElementType nodeType = myNode.getElementType();
final ASTNode lastChildNode = myNode.getLastChildNode();
if (nodeType == JsonElementTypes.OBJECT) {
return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_CURLY;
if (hasElementType(myNode, OBJECT)) {
return lastChildNode != null && lastChildNode.getElementType() != R_CURLY;
}
else if (nodeType == JsonElementTypes.ARRAY) {
return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_BRACKET;
else if (hasElementType(myNode, ARRAY)) {
return lastChildNode != null && lastChildNode.getElementType() != R_BRACKET;
}
else if (myPsiElement instanceof JsonProperty) {
else if (hasElementType(myNode, PROPERTY)) {
return ((JsonProperty)myPsiElement).getValue() == null;
}
return false;
@@ -223,10 +221,6 @@ public class JsonBlock implements ASTBlock {
return node.getElementType() == TokenType.WHITE_SPACE || node.getTextLength() == 0;
}
private boolean isContainer() {
return JSON_CONTAINERS.contains(myNode.getElementType());
}
private JsonCodeStyleSettings getCustomSettings() {
return mySettings.getCustomSettings(JsonCodeStyleSettings.class);
}
@@ -5,6 +5,7 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import static com.intellij.json.JsonParserDefinition.JSON_COMMENTARIES;
@@ -86,4 +87,35 @@ public class JsonPsiUtil {
}
return lastSeen.getPsi();
}
/**
* Check that element type of the given AST node belongs to the token set.
* <p/>
* It slightly less verbose than {@code set.contains(node.getElementType())} and overloaded methods with the same name
* allow check ASTNode/PsiElement against both concrete element types and token sets in uniform way.
*/
public static boolean hasElementType(@NotNull ASTNode node, @NotNull TokenSet set) {
return set.contains(node.getElementType());
}
/**
* @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.TokenSet)
*/
public static boolean hasElementType(@NotNull ASTNode node, IElementType... types) {
return hasElementType(node, TokenSet.create(types));
}
/**
* @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.TokenSet)
*/
public static boolean hasElementType(@NotNull PsiElement element, @NotNull TokenSet set) {
return element.getNode() != null && hasElementType(element.getNode(), set);
}
/**
* @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.IElementType...)
*/
public static boolean hasElementType(@NotNull PsiElement element, IElementType... types) {
return element.getNode() != null && hasElementType(element.getNode(), types);
}
}