NodeIndentStrategy: J2K and cleanup

This commit is contained in:
Dmitry Jemerov
2017-06-12 17:07:41 +02:00
parent 14edd7e357
commit a4916a3c00
2 changed files with 92 additions and 114 deletions
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.idea.formatter package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.* import com.intellij.formatting.*
import com.intellij.formatting.ChildAttributes.DELEGATE_TO_NEXT_CHILD
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import com.intellij.psi.TokenType import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.codeStyle.CodeStyleSettings
@@ -26,7 +25,7 @@ import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.formatter.NodeIndentStrategy.strategy import org.jetbrains.kotlin.idea.formatter.NodeIndentStrategy.Companion.strategy
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -330,21 +329,21 @@ abstract class KotlinCommonBlock(
private val INDENT_RULES = arrayOf<NodeIndentStrategy>( private val INDENT_RULES = arrayOf<NodeIndentStrategy>(
strategy("No indent for braces in blocks") strategy("No indent for braces in blocks")
.`in`(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL) .within(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL)
.forType(RBRACE, LBRACE) .forType(RBRACE, LBRACE)
.set(Indent.getNoneIndent()), .set(Indent.getNoneIndent()),
strategy("Indent for block content") strategy("Indent for block content")
.`in`(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL) .within(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL)
.notForType(RBRACE, LBRACE, KtNodeTypes.BLOCK) .notForType(RBRACE, LBRACE, KtNodeTypes.BLOCK)
.set(Indent.getNormalIndent(false)), .set(Indent.getNormalIndent(false)),
strategy("Indent for property accessors") strategy("Indent for property accessors")
.`in`(KtNodeTypes.PROPERTY).forType(KtNodeTypes.PROPERTY_ACCESSOR) .within(KtNodeTypes.PROPERTY).forType(KtNodeTypes.PROPERTY_ACCESSOR)
.set(Indent.getNormalIndent()), .set(Indent.getNormalIndent()),
strategy("For a single statement in 'for'") strategy("For a single statement in 'for'")
.`in`(KtNodeTypes.BODY).notForType(KtNodeTypes.BLOCK) .within(KtNodeTypes.BODY).notForType(KtNodeTypes.BLOCK)
.set(Indent.getNormalIndent()), .set(Indent.getNormalIndent()),
strategy("For the entry in when") strategy("For the entry in when")
@@ -352,51 +351,51 @@ private val INDENT_RULES = arrayOf<NodeIndentStrategy>(
.set(Indent.getNormalIndent()), .set(Indent.getNormalIndent()),
strategy("For single statement in THEN and ELSE") strategy("For single statement in THEN and ELSE")
.`in`(KtNodeTypes.THEN, KtNodeTypes.ELSE).notForType(KtNodeTypes.BLOCK) .within(KtNodeTypes.THEN, KtNodeTypes.ELSE).notForType(KtNodeTypes.BLOCK)
.set(Indent.getNormalIndent()), .set(Indent.getNormalIndent()),
strategy("Indent for parts") strategy("Indent for parts")
.`in`(KtNodeTypes.PROPERTY, KtNodeTypes.FUN, KtNodeTypes.DESTRUCTURING_DECLARATION, KtNodeTypes.SECONDARY_CONSTRUCTOR) .within(KtNodeTypes.PROPERTY, KtNodeTypes.FUN, KtNodeTypes.DESTRUCTURING_DECLARATION, KtNodeTypes.SECONDARY_CONSTRUCTOR)
.notForType(KtNodeTypes.BLOCK, FUN_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, CONSTRUCTOR_KEYWORD) .notForType(KtNodeTypes.BLOCK, FUN_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, CONSTRUCTOR_KEYWORD)
.set(Indent.getContinuationWithoutFirstIndent()), .set(Indent.getContinuationWithoutFirstIndent()),
strategy("Chained calls") strategy("Chained calls")
.`in`(KtNodeTypes.DOT_QUALIFIED_EXPRESSION, KtNodeTypes.SAFE_ACCESS_EXPRESSION) .within(KtNodeTypes.DOT_QUALIFIED_EXPRESSION, KtNodeTypes.SAFE_ACCESS_EXPRESSION)
.set(Indent.getContinuationWithoutFirstIndent(false)), .set(Indent.getContinuationWithoutFirstIndent(false)),
strategy("Colon of delegation list") strategy("Colon of delegation list")
.`in`(KtNodeTypes.CLASS, KtNodeTypes.OBJECT_DECLARATION) .within(KtNodeTypes.CLASS, KtNodeTypes.OBJECT_DECLARATION)
.forType(KtTokens.COLON) .forType(KtTokens.COLON)
.set(Indent.getNormalIndent(false)), .set(Indent.getNormalIndent(false)),
strategy("Delegation list") strategy("Delegation list")
.`in`(KtNodeTypes.SUPER_TYPE_LIST, KtNodeTypes.INITIALIZER_LIST) .within(KtNodeTypes.SUPER_TYPE_LIST, KtNodeTypes.INITIALIZER_LIST)
.set(Indent.getContinuationIndent(false)), .set(Indent.getContinuationIndent(false)),
strategy("Indices") strategy("Indices")
.`in`(KtNodeTypes.INDICES) .within(KtNodeTypes.INDICES)
.set(Indent.getContinuationIndent(false)), .set(Indent.getContinuationIndent(false)),
strategy("Binary expressions") strategy("Binary expressions")
.`in`(BINARY_EXPRESSIONS) .within(BINARY_EXPRESSIONS)
.set(Indent.getContinuationWithoutFirstIndent(false)), .set(Indent.getContinuationWithoutFirstIndent(false)),
strategy("Parenthesized expression") strategy("Parenthesized expression")
.`in`(KtNodeTypes.PARENTHESIZED) .within(KtNodeTypes.PARENTHESIZED)
.set(Indent.getContinuationWithoutFirstIndent(false)), .set(Indent.getContinuationWithoutFirstIndent(false)),
strategy("Round Brackets around conditions") strategy("Round Brackets around conditions")
.forType(LPAR, RPAR) .forType(LPAR, RPAR)
.`in`(KtNodeTypes.IF, KtNodeTypes.WHEN_ENTRY, KtNodeTypes.WHILE, KtNodeTypes.DO_WHILE) .within(KtNodeTypes.IF, KtNodeTypes.WHEN_ENTRY, KtNodeTypes.WHILE, KtNodeTypes.DO_WHILE)
.set(Indent.getContinuationWithoutFirstIndent(true)), .set(Indent.getContinuationWithoutFirstIndent(true)),
strategy("KDoc comment indent") strategy("KDoc comment indent")
.`in`(KDOC_CONTENT) .within(KDOC_CONTENT)
.forType(KDocTokens.LEADING_ASTERISK, KDocTokens.END) .forType(KDocTokens.LEADING_ASTERISK, KDocTokens.END)
.set(Indent.getSpaceIndent(KDOC_COMMENT_INDENT)), .set(Indent.getSpaceIndent(KDOC_COMMENT_INDENT)),
strategy("Block in when entry") strategy("Block in when entry")
.`in`(KtNodeTypes.WHEN_ENTRY) .within(KtNodeTypes.WHEN_ENTRY)
.notForType(KtNodeTypes.BLOCK, KtNodeTypes.WHEN_CONDITION_EXPRESSION, KtNodeTypes.WHEN_CONDITION_IN_RANGE, KtNodeTypes.WHEN_CONDITION_IS_PATTERN, ELSE_KEYWORD, ARROW) .notForType(KtNodeTypes.BLOCK, KtNodeTypes.WHEN_CONDITION_EXPRESSION, KtNodeTypes.WHEN_CONDITION_IN_RANGE, KtNodeTypes.WHEN_CONDITION_IS_PATTERN, ELSE_KEYWORD, ARROW)
.set(Indent.getNormalIndent())) .set(Indent.getNormalIndent()))
@@ -14,151 +14,130 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.idea.formatter; package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.Indent; import com.intellij.formatting.Indent
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet
import org.jetbrains.annotations.NotNull; import java.util.*
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; abstract class NodeIndentStrategy {
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SuppressWarnings("UnusedDeclaration") abstract fun getIndent(node: ASTNode): Indent?
public abstract class NodeIndentStrategy {
public static NodeIndentStrategy constIndent(Indent indent) {
return new ConstIndentStrategy(indent);
}
public static PositionStrategy strategy(@Nullable String debugInfo) { class ConstIndentStrategy(private val indent: Indent) : NodeIndentStrategy() {
return new PositionStrategy(debugInfo);
}
@Nullable override fun getIndent(node: ASTNode): Indent? {
public abstract Indent getIndent(@NotNull ASTNode node); return indent
public static class ConstIndentStrategy extends NodeIndentStrategy {
private final Indent indent;
public ConstIndentStrategy(Indent indent) {
this.indent = indent;
}
@Nullable
@Override
public Indent getIndent(@NotNull ASTNode node) {
return indent;
} }
} }
public static class PositionStrategy extends NodeIndentStrategy { class PositionStrategy(private val debugInfo: String?) : NodeIndentStrategy() {
private Indent defaultIndent = Indent.getNoneIndent(); private var defaultIndent = Indent.getNoneIndent()
private final List<IElementType> in = new ArrayList<IElementType>(); private val within = ArrayList<IElementType>()
private final List<IElementType> notIn = new ArrayList<IElementType>(); private val notIn = ArrayList<IElementType>()
private final List<IElementType> forElement = new ArrayList<IElementType>(); private val forElement = ArrayList<IElementType>()
private final List<IElementType> notForElement = new ArrayList<IElementType>(); private val notForElement = ArrayList<IElementType>()
private final String debugInfo; override fun toString(): String {
return "PositionStrategy " + (debugInfo ?: "No debug info")
public PositionStrategy(@Nullable String debugInfo) {
this.debugInfo = debugInfo;
} }
@Override fun set(indent: Indent): PositionStrategy {
public String toString() { defaultIndent = indent
return "PositionStrategy " + (debugInfo != null ? debugInfo : "No debug info"); return this
} }
public PositionStrategy set(Indent indent) { fun within(parents: TokenSet): PositionStrategy {
defaultIndent = indent; val types = parents.types
return this; if (types.isEmpty()) {
} throw IllegalArgumentException("Empty token set is unexpected")
public PositionStrategy in(@NotNull TokenSet parents) {
IElementType[] types = parents.getTypes();
if (types.length == 0) {
throw new IllegalArgumentException("Empty token set is unexpected");
} }
fillTypes(in, types[0], Arrays.copyOfRange(types, 1, types.length)); fillTypes(within, types[0], Arrays.copyOfRange(types, 1, types.size))
return this; return this
} }
public PositionStrategy in(@NotNull IElementType parentType, @NotNull IElementType... orParentTypes) { fun within(parentType: IElementType, vararg orParentTypes: IElementType): PositionStrategy {
fillTypes(in, parentType, orParentTypes); fillTypes(within, parentType, orParentTypes)
return this; return this
} }
public PositionStrategy notIn(@NotNull IElementType parentType, @NotNull IElementType... orParentTypes) { fun notWithin(parentType: IElementType, vararg orParentTypes: IElementType): PositionStrategy {
fillTypes(notIn, parentType, orParentTypes); fillTypes(notIn, parentType, orParentTypes)
return this; return this
} }
public PositionStrategy inAny() { fun withinAny(): PositionStrategy {
in.clear(); within.clear()
notIn.clear(); notIn.clear()
return this; return this
} }
public PositionStrategy forType(@NotNull IElementType elementType, @NotNull IElementType... otherTypes) { fun forType(elementType: IElementType, vararg otherTypes: IElementType): PositionStrategy {
fillTypes(forElement, elementType, otherTypes); fillTypes(forElement, elementType, otherTypes)
return this; return this
} }
public PositionStrategy notForType(@NotNull IElementType elementType, @NotNull IElementType... otherTypes) { fun notForType(elementType: IElementType, vararg otherTypes: IElementType): PositionStrategy {
fillTypes(notForElement, elementType, otherTypes); fillTypes(notForElement, elementType, otherTypes)
return this; return this
} }
public PositionStrategy forAny() { fun forAny(): PositionStrategy {
forElement.clear(); forElement.clear()
notForElement.clear(); notForElement.clear()
return this; return this
} }
@Nullable override fun getIndent(node: ASTNode): Indent? {
@Override
public Indent getIndent(@NotNull ASTNode node) {
if (!forElement.isEmpty()) { if (!forElement.isEmpty()) {
if (!forElement.contains(node.getElementType())) { if (!forElement.contains(node.elementType)) {
return null; return null
} }
} }
if (notForElement.contains(node.getElementType())) { if (notForElement.contains(node.elementType)) {
return null; return null
} }
ASTNode parent = node.getTreeParent(); val parent = node.treeParent
if (parent != null) { if (parent != null) {
if (!in.isEmpty()) { if (!within.isEmpty()) {
if (!in.contains(parent.getElementType())) { if (!within.contains(parent.elementType)) {
return null; return null
} }
} }
if (notIn.contains(parent.getElementType())) { if (notIn.contains(parent.elementType)) {
return null; return null
} }
} }
else { else {
if (!in.isEmpty()) { if (!within.isEmpty()) {
return null; return null
} }
} }
return defaultIndent; return defaultIndent
} }
private static void fillTypes(List<IElementType> resultCollection, IElementType singleType, IElementType[] otherTypes) { private fun fillTypes(resultCollection: MutableList<IElementType>, singleType: IElementType, otherTypes: Array<out IElementType>) {
resultCollection.clear(); resultCollection.clear()
resultCollection.add(singleType); resultCollection.add(singleType)
Collections.addAll(resultCollection, otherTypes); Collections.addAll(resultCollection, *otherTypes)
}
}
companion object {
fun constIndent(indent: Indent): NodeIndentStrategy {
return ConstIndentStrategy(indent)
}
fun strategy(debugInfo: String?): PositionStrategy {
return PositionStrategy(debugInfo)
} }
} }
} }