Formatter refactoring: Rewrite spacing rules to kotlin, place all rules in one place
This commit is contained in:
@@ -0,0 +1,111 @@
|
|||||||
|
<root>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder append(com.intellij.formatting.SpacingBuilder)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder after(com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder afterInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder afterInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.TokenSet)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder afterInside(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder around(com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder around(com.intellij.psi.tree.TokenSet)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder aroundInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder aroundInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.TokenSet)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder aroundInside(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder aroundInside(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.TokenSet)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder before(com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder beforeInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder beforeInside(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder between(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder between(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.TokenSet)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder between(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder between(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.TokenSet)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder betweenInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder betweenInside(com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.TokenSet, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder withinPair(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder com.intellij.formatting.SpacingBuilder.RuleBuilder withinPairInside(com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType, com.intellij.psi.tree.IElementType)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder blankLines(int)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder lineBreakInCode()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder lineBreakInCodeIf(boolean)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder none()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder spaceIf(boolean)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder spaces(int)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.formatting.SpacingBuilder.RuleBuilder com.intellij.formatting.SpacingBuilder spacing(int, int, int, boolean, int)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
</root>
|
||||||
@@ -47,7 +47,7 @@ public class JetBlock extends AbstractBlock {
|
|||||||
private final ASTAlignmentStrategy myAlignmentStrategy;
|
private final ASTAlignmentStrategy myAlignmentStrategy;
|
||||||
private final Indent myIndent;
|
private final Indent myIndent;
|
||||||
private final CodeStyleSettings mySettings;
|
private final CodeStyleSettings mySettings;
|
||||||
private final SpacingBuilder mySpacingBuilder;
|
private final KotlinSpacingBuilder mySpacingBuilder;
|
||||||
|
|
||||||
private List<Block> mySubBlocks;
|
private List<Block> mySubBlocks;
|
||||||
|
|
||||||
@@ -63,7 +63,8 @@ public class JetBlock extends AbstractBlock {
|
|||||||
Indent indent,
|
Indent indent,
|
||||||
Wrap wrap,
|
Wrap wrap,
|
||||||
CodeStyleSettings settings,
|
CodeStyleSettings settings,
|
||||||
SpacingBuilder spacingBuilder) {
|
KotlinSpacingBuilder spacingBuilder
|
||||||
|
) {
|
||||||
|
|
||||||
super(node, wrap, alignmentStrategy.getAlignment(node));
|
super(node, wrap, alignmentStrategy.getAlignment(node));
|
||||||
myAlignmentStrategy = alignmentStrategy;
|
myAlignmentStrategy = alignmentStrategy;
|
||||||
@@ -136,73 +137,9 @@ public class JetBlock extends AbstractBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
|
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
|
||||||
Spacing customSpacing = getCustomSpacing(child1, child2);
|
|
||||||
if (customSpacing != null) {
|
|
||||||
return customSpacing;
|
|
||||||
}
|
|
||||||
return mySpacingBuilder.getSpacing(this, child1, child2);
|
return mySpacingBuilder.getSpacing(this, child1, child2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Spacing getCustomSpacing(@Nullable Block child1, @NotNull Block child2) {
|
|
||||||
// TODO: extend SpacingBuilder API - afterInside(RBRACE, FUNCTION_LITERAL).spacing(...), beforeInside(RBRACE, FUNCTION_LITERAL).spacing(...)
|
|
||||||
if (!(child1 instanceof ASTBlock && child2 instanceof ASTBlock)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IElementType parentType = this.getNode().getElementType();
|
|
||||||
IElementType child1Type = ((ASTBlock) child1).getNode().getElementType();
|
|
||||||
IElementType child2Type = ((ASTBlock) child2).getNode().getElementType();
|
|
||||||
|
|
||||||
JetCodeStyleSettings jetSettings = mySettings.getCustomSettings(JetCodeStyleSettings.class);
|
|
||||||
int spacesInSimpleMethod = jetSettings.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD ? 1 : 0;
|
|
||||||
|
|
||||||
if (parentType == FUNCTION_LITERAL && child1Type == LBRACE && child2Type == BLOCK) {
|
|
||||||
return Spacing.createDependentLFSpacing(
|
|
||||||
spacesInSimpleMethod, spacesInSimpleMethod, this.getTextRange(),
|
|
||||||
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentType == FUNCTION_LITERAL && child1Type == ARROW && child2Type == BLOCK) {
|
|
||||||
return Spacing.createDependentLFSpacing(1, 1, this.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentType == FUNCTION_LITERAL && child2Type == RBRACE) {
|
|
||||||
return Spacing.createDependentLFSpacing(
|
|
||||||
spacesInSimpleMethod, spacesInSimpleMethod, this.getTextRange(),
|
|
||||||
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentType == FUNCTION_LITERAL && child1Type == LBRACE) {
|
|
||||||
if (child2Type == VALUE_PARAMETER_LIST) {
|
|
||||||
ASTNode firstParamListNode = ((ASTBlock) child2).getNode().getFirstChildNode();
|
|
||||||
if (firstParamListNode != null && firstParamListNode.getElementType() == LPAR) {
|
|
||||||
// Don't put space for situation {<here>(a: Int) -> a }
|
|
||||||
return Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Spacing.createSpacing(spacesInSimpleMethod, spacesInSimpleMethod, 0,
|
|
||||||
mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentType == IF && (child2Type == THEN || child2Type == ELSE)) {
|
|
||||||
ASTNode blockOrExpression = ((ASTBlock) child2).getNode().getFirstChildNode();
|
|
||||||
if (blockOrExpression != null && blockOrExpression.getElementType() == BLOCK) {
|
|
||||||
ASTNode leftBrace = blockOrExpression.getFirstChildNode();
|
|
||||||
if (leftBrace != null && leftBrace.getElementType() == LBRACE) {
|
|
||||||
ASTNode previousLeaf = FormatterUtil.getPreviousNonWhitespaceLeaf(leftBrace);
|
|
||||||
boolean isAfterEolComment = previousLeaf != null && (previousLeaf.getElementType() == EOL_COMMENT);
|
|
||||||
boolean keepLineBreaks = jetSettings.LBRACE_ON_NEXT_LINE || isAfterEolComment;
|
|
||||||
int minimumLF = jetSettings.LBRACE_ON_NEXT_LINE ? 1 : 0;
|
|
||||||
return Spacing.createSpacing(1, 1, minimumLF, keepLineBreaks, /*don't keep blank lines*/ 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public ChildAttributes getChildAttributes(int newChildIndex) {
|
public ChildAttributes getChildAttributes(int newChildIndex) {
|
||||||
|
|||||||
@@ -16,20 +16,18 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.formatter;
|
package org.jetbrains.jet.plugin.formatter;
|
||||||
|
|
||||||
import com.intellij.formatting.*;
|
import com.intellij.formatting.FormattingModel;
|
||||||
|
import com.intellij.formatting.FormattingModelBuilder;
|
||||||
|
import com.intellij.formatting.FormattingModelProvider;
|
||||||
|
import com.intellij.formatting.Indent;
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
|
||||||
import com.intellij.psi.tree.TokenSet;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.plugin.JetLanguage;
|
import org.jetbrains.jet.plugin.JetLanguage;
|
||||||
|
|
||||||
import static org.jetbrains.jet.JetNodeTypes.*;
|
|
||||||
import static org.jetbrains.jet.lexer.JetTokens.*;
|
|
||||||
|
|
||||||
public class JetFormattingModelBuilder implements FormattingModelBuilder {
|
public class JetFormattingModelBuilder implements FormattingModelBuilder {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
@@ -37,102 +35,12 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder {
|
|||||||
PsiFile containingFile = element.getContainingFile().getViewProvider().getPsi(JetLanguage.INSTANCE);
|
PsiFile containingFile = element.getContainingFile().getViewProvider().getPsi(JetLanguage.INSTANCE);
|
||||||
JetBlock block = new JetBlock(
|
JetBlock block = new JetBlock(
|
||||||
containingFile.getNode(), ASTAlignmentStrategy.getNullStrategy(), Indent.getNoneIndent(), null, settings,
|
containingFile.getNode(), ASTAlignmentStrategy.getNullStrategy(), Indent.getNoneIndent(), null, settings,
|
||||||
createSpacingBuilder(settings));
|
FormatterPackage.createSpacingBuilder(settings));
|
||||||
|
|
||||||
return FormattingModelProvider.createFormattingModelForPsiFile(
|
return FormattingModelProvider.createFormattingModelForPsiFile(
|
||||||
element.getContainingFile(), block, settings);
|
element.getContainingFile(), block, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) {
|
|
||||||
JetCodeStyleSettings jetSettings = settings.getCustomSettings(JetCodeStyleSettings.class);
|
|
||||||
CommonCodeStyleSettings jetCommonSettings = settings.getCommonSettings(JetLanguage.INSTANCE);
|
|
||||||
|
|
||||||
return new SpacingBuilder(settings, JetLanguage.INSTANCE)
|
|
||||||
// ============ Line breaks ==============
|
|
||||||
.after(PACKAGE_DIRECTIVE).blankLines(1)
|
|
||||||
|
|
||||||
.between(IMPORT_DIRECTIVE, IMPORT_DIRECTIVE).lineBreakInCode()
|
|
||||||
.after(IMPORT_LIST).blankLines(1)
|
|
||||||
|
|
||||||
.before(DOC_COMMENT).lineBreakInCode()
|
|
||||||
.before(FUN).lineBreakInCode()
|
|
||||||
.before(PROPERTY).lineBreakInCode()
|
|
||||||
.between(FUN, FUN).blankLines(1)
|
|
||||||
.between(FUN, PROPERTY).blankLines(1)
|
|
||||||
|
|
||||||
.afterInside(LBRACE, BLOCK).lineBreakInCode()
|
|
||||||
.beforeInside(RBRACE, CLASS_BODY).lineBreakInCode()
|
|
||||||
.beforeInside(RBRACE, BLOCK).lineBreakInCode()
|
|
||||||
|
|
||||||
// =============== Spacing ================
|
|
||||||
.before(COMMA).spaceIf(jetCommonSettings.SPACE_BEFORE_COMMA)
|
|
||||||
.after(COMMA).spaceIf(jetCommonSettings.SPACE_AFTER_COMMA)
|
|
||||||
|
|
||||||
.around(TokenSet.create(EQ, MULTEQ, DIVEQ, PLUSEQ, MINUSEQ, PERCEQ)).spaceIf(jetCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
|
|
||||||
.around(TokenSet.create(ANDAND, OROR)).spaceIf(jetCommonSettings.SPACE_AROUND_LOGICAL_OPERATORS)
|
|
||||||
.around(TokenSet.create(EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ)).spaceIf(jetCommonSettings.SPACE_AROUND_EQUALITY_OPERATORS)
|
|
||||||
.aroundInside(TokenSet.create(LT, GT, LTEQ, GTEQ), BINARY_EXPRESSION).spaceIf(jetCommonSettings.SPACE_AROUND_RELATIONAL_OPERATORS)
|
|
||||||
.aroundInside(TokenSet.create(PLUS, MINUS), BINARY_EXPRESSION).spaceIf(jetCommonSettings.SPACE_AROUND_ADDITIVE_OPERATORS)
|
|
||||||
.aroundInside(TokenSet.create(MUL, DIV, PERC), BINARY_EXPRESSION).spaceIf(
|
|
||||||
jetCommonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS)
|
|
||||||
.around(TokenSet.create(PLUSPLUS, MINUSMINUS, EXCLEXCL, MINUS, PLUS, EXCL)).spaceIf(
|
|
||||||
jetCommonSettings.SPACE_AROUND_UNARY_OPERATOR)
|
|
||||||
.around(RANGE).spaceIf(jetSettings.SPACE_AROUND_RANGE)
|
|
||||||
|
|
||||||
.beforeInside(BLOCK, FUN).spaceIf(jetCommonSettings.SPACE_BEFORE_METHOD_LBRACE)
|
|
||||||
|
|
||||||
.afterInside(LPAR, VALUE_PARAMETER_LIST).spaces(0)
|
|
||||||
.beforeInside(RPAR, VALUE_PARAMETER_LIST).spaces(0)
|
|
||||||
.afterInside(LT, TYPE_PARAMETER_LIST).spaces(0)
|
|
||||||
.beforeInside(GT, TYPE_PARAMETER_LIST).spaces(0)
|
|
||||||
.afterInside(LPAR, VALUE_ARGUMENT_LIST).spaces(0)
|
|
||||||
.beforeInside(RPAR, VALUE_ARGUMENT_LIST).spaces(0)
|
|
||||||
.afterInside(LT, TYPE_ARGUMENT_LIST).spaces(0)
|
|
||||||
.beforeInside(GT, TYPE_ARGUMENT_LIST).spaces(0)
|
|
||||||
|
|
||||||
.betweenInside(FOR_KEYWORD, LPAR, FOR).spacing(1, 1, 0, false, 0)
|
|
||||||
.betweenInside(IF_KEYWORD, LPAR, IF).spacing(1, 1, 0, false, 0)
|
|
||||||
.betweenInside(WHILE_KEYWORD, LPAR, WHILE).spacing(1, 1, 0, false, 0)
|
|
||||||
.betweenInside(WHILE_KEYWORD, LPAR, DO_WHILE).spacing(1, 1, 0, false, 0)
|
|
||||||
|
|
||||||
.aroundInside(WHILE_KEYWORD, DO_WHILE).spaces(1)
|
|
||||||
.afterInside(DO_KEYWORD, DO_WHILE).spaces(1)
|
|
||||||
|
|
||||||
// TODO: Ask for better API
|
|
||||||
// Type of the declaration colon
|
|
||||||
.beforeInside(COLON, PROPERTY).spaceIf(jetSettings.SPACE_BEFORE_TYPE_COLON)
|
|
||||||
.afterInside(COLON, PROPERTY).spaceIf(jetSettings.SPACE_AFTER_TYPE_COLON)
|
|
||||||
.beforeInside(COLON, FUN).spaceIf(jetSettings.SPACE_BEFORE_TYPE_COLON)
|
|
||||||
.afterInside(COLON, FUN).spaceIf(jetSettings.SPACE_AFTER_TYPE_COLON)
|
|
||||||
.beforeInside(COLON, VALUE_PARAMETER).spaceIf(jetSettings.SPACE_BEFORE_TYPE_COLON)
|
|
||||||
.afterInside(COLON, VALUE_PARAMETER).spaceIf(jetSettings.SPACE_AFTER_TYPE_COLON)
|
|
||||||
|
|
||||||
// Extends or constraint colon
|
|
||||||
.beforeInside(COLON, TYPE_CONSTRAINT).spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON)
|
|
||||||
.afterInside(COLON, TYPE_CONSTRAINT).spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON)
|
|
||||||
.beforeInside(COLON, CLASS).spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON)
|
|
||||||
.afterInside(COLON, CLASS).spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON)
|
|
||||||
.beforeInside(COLON, TYPE_PARAMETER).spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON)
|
|
||||||
.afterInside(COLON, TYPE_PARAMETER).spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON)
|
|
||||||
|
|
||||||
.between(VALUE_ARGUMENT_LIST, FUNCTION_LITERAL_EXPRESSION).spaces(1)
|
|
||||||
.beforeInside(ARROW, FUNCTION_LITERAL).spaceIf(jetSettings.SPACE_BEFORE_LAMBDA_ARROW)
|
|
||||||
|
|
||||||
//when
|
|
||||||
.aroundInside(ARROW, WHEN_ENTRY).spaceIf(jetSettings.SPACE_AROUND_WHEN_ARROW)
|
|
||||||
.beforeInside(LBRACE, WHEN).spacing(1, 1, 0, true, 0) //omit blank lines before '{' in 'when' statement
|
|
||||||
|
|
||||||
.aroundInside(ARROW, FUNCTION_TYPE).spaceIf(jetSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW)
|
|
||||||
|
|
||||||
.betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_EXPRESSION, CALL_EXPRESSION).spaces(1)
|
|
||||||
|
|
||||||
.aroundInside(ELSE_KEYWORD, IF).spaces(1)
|
|
||||||
.betweenInside(RPAR, THEN, IF).spaces(1)
|
|
||||||
|
|
||||||
.between(RPAR, BODY).spaces(1)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TextRange getRangeAffectingIndent(PsiFile psiFile, int i, ASTNode astNode) {
|
public TextRange getRangeAffectingIndent(PsiFile psiFile, int i, ASTNode astNode) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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 org.jetbrains.jet.plugin.formatter
|
||||||
|
|
||||||
|
import com.intellij.formatting.*
|
||||||
|
|
||||||
|
import org.jetbrains.jet.plugin.JetLanguage
|
||||||
|
import com.intellij.psi.codeStyle.CodeStyleSettings
|
||||||
|
import java.util.ArrayList
|
||||||
|
import org.jetbrains.jet.JetNodeTypes.*
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens.*
|
||||||
|
import com.intellij.psi.tree.TokenSet
|
||||||
|
import com.intellij.psi.tree.IElementType
|
||||||
|
import com.intellij.psi.formatter.FormatterUtil
|
||||||
|
|
||||||
|
class KotlinSpacingBuilder(val codeStyleSettings: CodeStyleSettings) {
|
||||||
|
|
||||||
|
private val builders = ArrayList<Builder>()
|
||||||
|
|
||||||
|
private trait Builder {
|
||||||
|
fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing?
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class BasicSpacingBuilder() : SpacingBuilder(codeStyleSettings, JetLanguage.INSTANCE), Builder {
|
||||||
|
override fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing? {
|
||||||
|
return super<SpacingBuilder>.getSpacing(parent, left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CustomSpacingBuilder() : Builder {
|
||||||
|
private val rules = ArrayList<(ASTBlock, ASTBlock, ASTBlock) -> Spacing?>()
|
||||||
|
private var conditions = ArrayList<(ASTBlock, ASTBlock, ASTBlock) -> Boolean>()
|
||||||
|
|
||||||
|
override fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing? {
|
||||||
|
for (rule in rules) {
|
||||||
|
val spacing = rule(parent, left, right)
|
||||||
|
if (spacing != null) {
|
||||||
|
return spacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun inPosition(parent: IElementType? = null, left: IElementType? = null, right: IElementType? = null): CustomSpacingBuilder {
|
||||||
|
conditions.add {
|
||||||
|
p, l, r ->
|
||||||
|
(parent == null || p.getNode()!!.getElementType() == parent) &&
|
||||||
|
(left == null || l.getNode()!!.getElementType() == left) &&
|
||||||
|
(right == null || r.getNode()!!.getElementType() == right)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lineBreakIfLineBreakInParent(numSpacesOtherwise: Int) {
|
||||||
|
newRule {
|
||||||
|
p, l, r ->
|
||||||
|
Spacing.createDependentLFSpacing(numSpacesOtherwise, numSpacesOtherwise, p.getTextRange(),
|
||||||
|
codeStyleSettings.KEEP_LINE_BREAKS, codeStyleSettings.KEEP_BLANK_LINES_IN_CODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun customRule(block: (ASTBlock, ASTBlock, ASTBlock) -> Spacing?) {
|
||||||
|
newRule(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newRule(rule: (ASTBlock, ASTBlock, ASTBlock) -> Spacing?) {
|
||||||
|
val savedConditions = ArrayList(conditions)
|
||||||
|
rules.add { p, l, r -> if (savedConditions.all { it(p, l, r) }) rule(p, l, r) else null }
|
||||||
|
conditions.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSpacing(parent: Block, child1: Block?, child2: Block): Spacing? {
|
||||||
|
if (parent !is ASTBlock || child1 !is ASTBlock || child2 !is ASTBlock) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
for (builder in builders) {
|
||||||
|
val spacing = builder.getSpacing(parent, child1, child2)
|
||||||
|
if (spacing != null) {
|
||||||
|
return spacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun simple(init: BasicSpacingBuilder.() -> Unit) {
|
||||||
|
val builder = BasicSpacingBuilder()
|
||||||
|
builder.init()
|
||||||
|
builders.add(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun custom(init: CustomSpacingBuilder.() -> Unit) {
|
||||||
|
val builder = CustomSpacingBuilder()
|
||||||
|
builder.init()
|
||||||
|
builders.add(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rules(codeStyleSettings: CodeStyleSettings, init: KotlinSpacingBuilder.() -> Unit): KotlinSpacingBuilder {
|
||||||
|
val builder = KotlinSpacingBuilder(codeStyleSettings)
|
||||||
|
builder.init()
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createSpacingBuilder(settings: CodeStyleSettings): KotlinSpacingBuilder {
|
||||||
|
val jetSettings = settings.getCustomSettings(javaClass<JetCodeStyleSettings>())!!
|
||||||
|
val jetCommonSettings = settings.getCommonSettings(JetLanguage.INSTANCE)!!
|
||||||
|
return rules(settings) {
|
||||||
|
custom {
|
||||||
|
val lbraceRuleForControlStructure: (ASTBlock, ASTBlock, ASTBlock) -> Spacing? = {
|
||||||
|
parent, left, right ->
|
||||||
|
val blockOrExpression = right.getNode()!!.getFirstChildNode()
|
||||||
|
if (blockOrExpression != null && blockOrExpression.getElementType() == BLOCK) {
|
||||||
|
val leftBrace = blockOrExpression.getFirstChildNode()
|
||||||
|
when {
|
||||||
|
leftBrace != null && leftBrace.getElementType() == LBRACE -> {
|
||||||
|
val previousLeaf = FormatterUtil.getPreviousNonWhitespaceLeaf(leftBrace)
|
||||||
|
val isAfterEolComment = previousLeaf != null && (previousLeaf.getElementType() == EOL_COMMENT)
|
||||||
|
val keepLineBreaks = jetSettings.LBRACE_ON_NEXT_LINE || isAfterEolComment
|
||||||
|
val minimumLF = if (jetSettings.LBRACE_ON_NEXT_LINE) 1 else 0
|
||||||
|
Spacing.createSpacing(1, 1, minimumLF, keepLineBreaks, 0)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
inPosition(parent = IF, right = THEN).customRule(lbraceRuleForControlStructure)
|
||||||
|
inPosition(parent = IF, right = ELSE).customRule(lbraceRuleForControlStructure)
|
||||||
|
}
|
||||||
|
simple {
|
||||||
|
// ============ Line breaks ==============
|
||||||
|
after(PACKAGE_DIRECTIVE).blankLines(1)
|
||||||
|
between(IMPORT_DIRECTIVE, IMPORT_DIRECTIVE).lineBreakInCode()
|
||||||
|
after(IMPORT_LIST).blankLines(1)
|
||||||
|
|
||||||
|
before(DOC_COMMENT).lineBreakInCode()
|
||||||
|
before(FUN).lineBreakInCode()
|
||||||
|
before(PROPERTY).lineBreakInCode()
|
||||||
|
between(FUN, FUN).blankLines(1)
|
||||||
|
between(FUN, PROPERTY).blankLines(1)
|
||||||
|
|
||||||
|
afterInside(LBRACE, BLOCK).lineBreakInCode()
|
||||||
|
beforeInside(RBRACE, CLASS_BODY).lineBreakInCode()
|
||||||
|
beforeInside(RBRACE, BLOCK).lineBreakInCode()
|
||||||
|
|
||||||
|
// =============== Spacing ================
|
||||||
|
before(COMMA).spaceIf(jetCommonSettings.SPACE_BEFORE_COMMA)
|
||||||
|
after(COMMA).spaceIf(jetCommonSettings.SPACE_AFTER_COMMA)
|
||||||
|
|
||||||
|
around(TokenSet.create(EQ, MULTEQ, DIVEQ, PLUSEQ, MINUSEQ, PERCEQ)).spaceIf(jetCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
|
||||||
|
around(TokenSet.create(ANDAND, OROR)).spaceIf(jetCommonSettings.SPACE_AROUND_LOGICAL_OPERATORS)
|
||||||
|
around(TokenSet.create(EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ)).spaceIf(jetCommonSettings.SPACE_AROUND_EQUALITY_OPERATORS)
|
||||||
|
aroundInside(TokenSet.create(LT, GT, LTEQ, GTEQ), BINARY_EXPRESSION).spaceIf(jetCommonSettings.SPACE_AROUND_RELATIONAL_OPERATORS)
|
||||||
|
aroundInside(TokenSet.create(PLUS, MINUS), BINARY_EXPRESSION).spaceIf(jetCommonSettings.SPACE_AROUND_ADDITIVE_OPERATORS)
|
||||||
|
aroundInside(TokenSet.create(MUL, DIV, PERC), BINARY_EXPRESSION).spaceIf(jetCommonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS)
|
||||||
|
around(TokenSet.create(PLUSPLUS, MINUSMINUS, EXCLEXCL, MINUS, PLUS, EXCL)).spaceIf(jetCommonSettings.SPACE_AROUND_UNARY_OPERATOR)
|
||||||
|
around(RANGE).spaceIf(jetSettings.SPACE_AROUND_RANGE)
|
||||||
|
|
||||||
|
beforeInside(BLOCK, FUN).spaceIf(jetCommonSettings.SPACE_BEFORE_METHOD_LBRACE)
|
||||||
|
|
||||||
|
afterInside(LPAR, VALUE_PARAMETER_LIST).spaces(0)
|
||||||
|
beforeInside(RPAR, VALUE_PARAMETER_LIST).spaces(0)
|
||||||
|
afterInside(LT, TYPE_PARAMETER_LIST).spaces(0)
|
||||||
|
beforeInside(GT, TYPE_PARAMETER_LIST).spaces(0)
|
||||||
|
afterInside(LPAR, VALUE_ARGUMENT_LIST).spaces(0)
|
||||||
|
beforeInside(RPAR, VALUE_ARGUMENT_LIST).spaces(0)
|
||||||
|
afterInside(LT, TYPE_ARGUMENT_LIST).spaces(0)
|
||||||
|
beforeInside(GT, TYPE_ARGUMENT_LIST).spaces(0)
|
||||||
|
|
||||||
|
betweenInside(FOR_KEYWORD, LPAR, FOR).spacing(1, 1, 0, false, 0)
|
||||||
|
betweenInside(IF_KEYWORD, LPAR, IF).spacing(1, 1, 0, false, 0)
|
||||||
|
betweenInside(WHILE_KEYWORD, LPAR, WHILE).spacing(1, 1, 0, false, 0)
|
||||||
|
betweenInside(WHILE_KEYWORD, LPAR, DO_WHILE).spacing(1, 1, 0, false, 0)
|
||||||
|
|
||||||
|
aroundInside(WHILE_KEYWORD, DO_WHILE).spaces(1)
|
||||||
|
afterInside(DO_KEYWORD, DO_WHILE).spaces(1)
|
||||||
|
|
||||||
|
// TODO: Ask for better API
|
||||||
|
// Type of the declaration colon
|
||||||
|
beforeInside(COLON, PROPERTY).spaceIf(jetSettings.SPACE_BEFORE_TYPE_COLON)
|
||||||
|
afterInside(COLON, PROPERTY).spaceIf(jetSettings.SPACE_AFTER_TYPE_COLON)
|
||||||
|
beforeInside(COLON, FUN).spaceIf(jetSettings.SPACE_BEFORE_TYPE_COLON)
|
||||||
|
afterInside(COLON, FUN).spaceIf(jetSettings.SPACE_AFTER_TYPE_COLON)
|
||||||
|
beforeInside(COLON, VALUE_PARAMETER).spaceIf(jetSettings.SPACE_BEFORE_TYPE_COLON)
|
||||||
|
afterInside(COLON, VALUE_PARAMETER).spaceIf(jetSettings.SPACE_AFTER_TYPE_COLON)
|
||||||
|
|
||||||
|
// Extends or constraint colon
|
||||||
|
beforeInside(COLON, TYPE_CONSTRAINT).spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON)
|
||||||
|
afterInside(COLON, TYPE_CONSTRAINT).spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON)
|
||||||
|
beforeInside(COLON, CLASS).spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON)
|
||||||
|
afterInside(COLON, CLASS).spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON)
|
||||||
|
beforeInside(COLON, TYPE_PARAMETER).spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON)
|
||||||
|
afterInside(COLON, TYPE_PARAMETER).spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON)
|
||||||
|
|
||||||
|
between(VALUE_ARGUMENT_LIST, FUNCTION_LITERAL_EXPRESSION).spaces(1)
|
||||||
|
beforeInside(ARROW, FUNCTION_LITERAL).spaceIf(jetSettings.SPACE_BEFORE_LAMBDA_ARROW)
|
||||||
|
|
||||||
|
//when
|
||||||
|
aroundInside(ARROW, WHEN_ENTRY).spaceIf(jetSettings.SPACE_AROUND_WHEN_ARROW)
|
||||||
|
beforeInside(LBRACE, WHEN).spacing(1, 1, 0, true, 0) //omit blank lines before '{' in 'when' statement
|
||||||
|
|
||||||
|
aroundInside(ARROW, FUNCTION_TYPE).spaceIf(jetSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW)
|
||||||
|
|
||||||
|
betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_EXPRESSION, CALL_EXPRESSION).spaces(1)
|
||||||
|
|
||||||
|
aroundInside(ELSE_KEYWORD, IF).spaces(1)
|
||||||
|
betweenInside(RPAR, THEN, IF).spaces(1)
|
||||||
|
|
||||||
|
between(RPAR, BODY).spaces(1)
|
||||||
|
}
|
||||||
|
custom {
|
||||||
|
val spacesInSimpleFunction = if (jetSettings.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD) 1 else 0
|
||||||
|
inPosition(parent = FUNCTION_LITERAL,
|
||||||
|
left = LBRACE,
|
||||||
|
right = BLOCK)
|
||||||
|
.lineBreakIfLineBreakInParent(numSpacesOtherwise = spacesInSimpleFunction)
|
||||||
|
|
||||||
|
inPosition(parent = FUNCTION_LITERAL,
|
||||||
|
left = ARROW,
|
||||||
|
right = BLOCK)
|
||||||
|
.lineBreakIfLineBreakInParent(numSpacesOtherwise = 1)
|
||||||
|
|
||||||
|
inPosition(parent = FUNCTION_LITERAL,
|
||||||
|
right = RBRACE)
|
||||||
|
.lineBreakIfLineBreakInParent(numSpacesOtherwise = spacesInSimpleFunction)
|
||||||
|
|
||||||
|
inPosition(parent = FUNCTION_LITERAL,
|
||||||
|
left = LBRACE)
|
||||||
|
.customRule {
|
||||||
|
parent, left, right ->
|
||||||
|
val rightNode = right.getNode()!!
|
||||||
|
val rightType = rightNode.getElementType()
|
||||||
|
var numSpaces = spacesInSimpleFunction
|
||||||
|
if (rightType == VALUE_PARAMETER_LIST) {
|
||||||
|
val firstParamListNode = rightNode.getFirstChildNode()
|
||||||
|
if (firstParamListNode != null && firstParamListNode.getElementType() == LPAR) {
|
||||||
|
// Don't put space for situation {<here>(a: Int) -> a }
|
||||||
|
numSpaces = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacing.createSpacing(numSpaces, numSpaces, 0, settings.KEEP_LINE_BREAKS, settings.KEEP_BLANK_LINES_IN_CODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user