diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt b/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt index d964fcf5f46..dc09a03f712 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/formatter/KotlinSpacingBuilder.kt @@ -18,16 +18,11 @@ 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 -import com.intellij.lang.ASTNode -import org.jetbrains.jet.plugin.formatter.KotlinSpacingBuilder.CustomSpacingBuilder +import org.jetbrains.jet.plugin.JetLanguage + class KotlinSpacingBuilder(val codeStyleSettings: CodeStyleSettings) { @@ -118,186 +113,4 @@ fun rules(codeStyleSettings: CodeStyleSettings, init: 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) { - 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) - - // =============== 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) - - 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) - - // 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) - - aroundInside(ARROW, FUNCTION_TYPE).spaceIf(jetSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW) - - betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_EXPRESSION, CALL_EXPRESSION).spaces(1) - } - custom { - - fun CustomSpacingBuilder.ruleForKeywordOnNewLine(shouldBeOnNewLine: Boolean, keyword: IElementType, parent: IElementType) { - if (shouldBeOnNewLine) { - inPosition(parent = parent, right = keyword) - .lineBreakIfLineBreakInParent(numSpacesOtherwise = 1, allowBlankLines = false) - } - else { - inPosition(parent = parent, right = keyword).customRule { - parent, left, right -> - // do not remove linebreak if expression to the left is not a block - val previousNonWhitespaceLeaf = FormatterUtil.getPreviousNonWhitespaceLeaf(right.getNode()) - val keepLineBreaks = previousNonWhitespaceLeaf == null || previousNonWhitespaceLeaf.getElementType() != RBRACE - Spacing.createSpacing(1, 1, 0, keepLineBreaks, 0) - } - } - } - - ruleForKeywordOnNewLine(jetCommonSettings.ELSE_ON_NEW_LINE, keyword = ELSE_KEYWORD, parent = IF) - ruleForKeywordOnNewLine(jetCommonSettings.WHILE_ON_NEW_LINE, keyword = WHILE_KEYWORD, parent = DO_WHILE) - ruleForKeywordOnNewLine(jetCommonSettings.CATCH_ON_NEW_LINE, keyword = CATCH, parent = TRY) - ruleForKeywordOnNewLine(jetCommonSettings.FINALLY_ON_NEW_LINE, keyword = FINALLY, parent = TRY) - - - fun spacingForLeftBrace(block: ASTNode?, blockType: IElementType = BLOCK): Spacing? { - if (block != null && block.getElementType() == blockType) { - val leftBrace = block.findChildByType(LBRACE) - if (leftBrace != null) { - 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 - return Spacing.createSpacing(1, 1, minimumLF, keepLineBreaks, 0) - } - } - return Spacing.createSpacing(1, 1, 0, settings.KEEP_LINE_BREAKS, settings.KEEP_BLANK_LINES_IN_CODE) - } - - fun leftBraceRule(blockType: IElementType = BLOCK) = { - (parent: ASTBlock, left: ASTBlock, right: ASTBlock) -> - spacingForLeftBrace(right.getNode(), blockType) - } - - val leftBraceRuleIfBlockIsWrapped = { - (parent: ASTBlock, left: ASTBlock, right: ASTBlock) -> - spacingForLeftBrace(right.getNode()!!.getFirstChildNode()) - } - - inPosition(parent = IF, right = THEN).customRule(leftBraceRuleIfBlockIsWrapped) - inPosition(parent = IF, right = ELSE).customRule(leftBraceRuleIfBlockIsWrapped) - - inPosition(parent = FOR, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped) - inPosition(parent = WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped) - inPosition(parent = DO_WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped) - - inPosition(parent = TRY, right = BLOCK).customRule(leftBraceRule()) - inPosition(parent = CATCH, right = BLOCK).customRule(leftBraceRule()) - inPosition(parent = FINALLY, right = BLOCK).customRule(leftBraceRule()) - - inPosition(parent = FUN, right = BLOCK).customRule(leftBraceRule()) - - inPosition(right = CLASS_BODY).customRule(leftBraceRule(blockType = CLASS_BODY)) - - inPosition(parent = WHEN_ENTRY, right = BLOCK).customRule(leftBraceRule()) - inPosition(parent = WHEN, right = LBRACE).customRule { - parent, left, right -> - spacingForLeftBrace(block = parent.getNode(), blockType = WHEN) - } - - 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) - } - } - - simple { - afterInside(LBRACE, BLOCK).lineBreakInCode() - beforeInside(RBRACE, CLASS_BODY).lineBreakInCode() - beforeInside(RBRACE, BLOCK).lineBreakInCode() - between(RPAR, BODY).spaces(1) - - // if when entry has block, spacing after arrow should be set by lbrace rule - aroundInside(ARROW, WHEN_ENTRY).spaceIf(jetSettings.SPACE_AROUND_WHEN_ARROW) - } - } -} +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/kotlinSpacingRules.kt b/idea/src/org/jetbrains/jet/plugin/formatter/kotlinSpacingRules.kt new file mode 100644 index 00000000000..5f22c589fdf --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/formatter/kotlinSpacingRules.kt @@ -0,0 +1,211 @@ +/* + * 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 org.jetbrains.jet.JetNodeTypes.* +import org.jetbrains.jet.lexer.JetTokens.* +import com.intellij.psi.tree.TokenSet +import com.intellij.psi.formatter.FormatterUtil +import com.intellij.psi.tree.IElementType +import com.intellij.psi.codeStyle.CodeStyleSettings +import org.jetbrains.jet.plugin.JetLanguage +import com.intellij.formatting.Spacing +import com.intellij.lang.ASTNode +import com.intellij.formatting.ASTBlock +import org.jetbrains.jet.plugin.formatter.KotlinSpacingBuilder.CustomSpacingBuilder + +fun createSpacingBuilder(settings: CodeStyleSettings): KotlinSpacingBuilder { + val jetSettings = settings.getCustomSettings(javaClass())!! + val jetCommonSettings = settings.getCommonSettings(JetLanguage.INSTANCE)!! + return rules(settings) { + 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) + + // =============== 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) + + 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) + + // 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) + + aroundInside(ARROW, FUNCTION_TYPE).spaceIf(jetSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW) + + betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_EXPRESSION, CALL_EXPRESSION).spaces(1) + } + custom { + + fun CustomSpacingBuilder.ruleForKeywordOnNewLine(shouldBeOnNewLine: Boolean, keyword: IElementType, parent: IElementType) { + if (shouldBeOnNewLine) { + inPosition(parent = parent, right = keyword) + .lineBreakIfLineBreakInParent(numSpacesOtherwise = 1, allowBlankLines = false) + } + else { + inPosition(parent = parent, right = keyword).customRule { + parent, left, right -> + // do not remove linebreak if expression to the left is not a block + val previousNonWhitespaceLeaf = FormatterUtil.getPreviousNonWhitespaceLeaf(right.getNode()) + val keepLineBreaks = previousNonWhitespaceLeaf == null || previousNonWhitespaceLeaf.getElementType() != RBRACE + Spacing.createSpacing(1, 1, 0, keepLineBreaks, 0) + } + } + } + + ruleForKeywordOnNewLine(jetCommonSettings.ELSE_ON_NEW_LINE, keyword = ELSE_KEYWORD, parent = IF) + ruleForKeywordOnNewLine(jetCommonSettings.WHILE_ON_NEW_LINE, keyword = WHILE_KEYWORD, parent = DO_WHILE) + ruleForKeywordOnNewLine(jetCommonSettings.CATCH_ON_NEW_LINE, keyword = CATCH, parent = TRY) + ruleForKeywordOnNewLine(jetCommonSettings.FINALLY_ON_NEW_LINE, keyword = FINALLY, parent = TRY) + + + fun spacingForLeftBrace(block: ASTNode?, blockType: IElementType = BLOCK): Spacing? { + if (block != null && block.getElementType() == blockType) { + val leftBrace = block.findChildByType(LBRACE) + if (leftBrace != null) { + 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 + return Spacing.createSpacing(1, 1, minimumLF, keepLineBreaks, 0) + } + } + return Spacing.createSpacing(1, 1, 0, settings.KEEP_LINE_BREAKS, settings.KEEP_BLANK_LINES_IN_CODE) + } + + fun leftBraceRule(blockType: IElementType = BLOCK) = { + (parent: ASTBlock, left: ASTBlock, right: ASTBlock) -> + spacingForLeftBrace(right.getNode(), blockType) + } + + val leftBraceRuleIfBlockIsWrapped = { + (parent: ASTBlock, left: ASTBlock, right: ASTBlock) -> + spacingForLeftBrace(right.getNode()!!.getFirstChildNode()) + } + + inPosition(parent = IF, right = THEN).customRule(leftBraceRuleIfBlockIsWrapped) + inPosition(parent = IF, right = ELSE).customRule(leftBraceRuleIfBlockIsWrapped) + + inPosition(parent = FOR, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped) + inPosition(parent = WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped) + inPosition(parent = DO_WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped) + + inPosition(parent = TRY, right = BLOCK).customRule(leftBraceRule()) + inPosition(parent = CATCH, right = BLOCK).customRule(leftBraceRule()) + inPosition(parent = FINALLY, right = BLOCK).customRule(leftBraceRule()) + + inPosition(parent = FUN, right = BLOCK).customRule(leftBraceRule()) + + inPosition(right = CLASS_BODY).customRule(leftBraceRule(blockType = CLASS_BODY)) + + inPosition(parent = WHEN_ENTRY, right = BLOCK).customRule(leftBraceRule()) + inPosition(parent = WHEN, right = LBRACE).customRule { + parent, left, right -> + spacingForLeftBrace(block = parent.getNode(), blockType = WHEN) + } + + 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) + } + } + + simple { + afterInside(LBRACE, BLOCK).lineBreakInCode() + beforeInside(RBRACE, CLASS_BODY).lineBreakInCode() + beforeInside(RBRACE, BLOCK).lineBreakInCode() + between(RPAR, BODY).spaces(1) + + // if when entry has block, spacing after arrow should be set by lbrace rule + aroundInside(ARROW, WHEN_ENTRY).spaceIf(jetSettings.SPACE_AROUND_WHEN_ARROW) + } + } +}