diff --git a/annotations/com/intellij/formatting/annotations.xml b/annotations/com/intellij/formatting/annotations.xml new file mode 100644 index 00000000000..1b6175d1c7d --- /dev/null +++ b/annotations/com/intellij/formatting/annotations.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java index 3ecca8d8668..31591519897 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java @@ -47,7 +47,7 @@ public class JetBlock extends AbstractBlock { private final ASTAlignmentStrategy myAlignmentStrategy; private final Indent myIndent; private final CodeStyleSettings mySettings; - private final SpacingBuilder mySpacingBuilder; + private final KotlinSpacingBuilder mySpacingBuilder; private List mySubBlocks; @@ -63,7 +63,8 @@ public class JetBlock extends AbstractBlock { Indent indent, Wrap wrap, CodeStyleSettings settings, - SpacingBuilder spacingBuilder) { + KotlinSpacingBuilder spacingBuilder + ) { super(node, wrap, alignmentStrategy.getAlignment(node)); myAlignmentStrategy = alignmentStrategy; @@ -136,73 +137,9 @@ public class JetBlock extends AbstractBlock { @Override 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); } - @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 {(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 @Override public ChildAttributes getChildAttributes(int newChildIndex) { diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java index 5a8fd779048..923143b0039 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java @@ -16,20 +16,18 @@ 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.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; 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.jet.plugin.JetLanguage; -import static org.jetbrains.jet.JetNodeTypes.*; -import static org.jetbrains.jet.lexer.JetTokens.*; - public class JetFormattingModelBuilder implements FormattingModelBuilder { @NotNull @Override @@ -37,102 +35,12 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder { PsiFile containingFile = element.getContainingFile().getViewProvider().getPsi(JetLanguage.INSTANCE); JetBlock block = new JetBlock( containingFile.getNode(), ASTAlignmentStrategy.getNullStrategy(), Indent.getNoneIndent(), null, settings, - createSpacingBuilder(settings)); + FormatterPackage.createSpacingBuilder(settings)); return FormattingModelProvider.createFormattingModelForPsiFile( 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 public TextRange getRangeAffectingIndent(PsiFile psiFile, int i, ASTNode astNode) { return null; diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt b/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt new file mode 100644 index 00000000000..3789482b76c --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt @@ -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() + + 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.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())!! + 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 {(a: Int) -> a } + numSpaces = 0 + } + } + + Spacing.createSpacing(numSpaces, numSpaces, 0, settings.KEEP_LINE_BREAKS, settings.KEEP_BLANK_LINES_IN_CODE) + } + } + } +} +