From eacd010e7e9d5a76338b0d7deaa972cd635963e4 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 8 Dec 2017 15:31:27 +0100 Subject: [PATCH] Option to wrap elvis expressions #KT-21720 Fixed --- .../idea/core/formatter/KotlinCodeStyleSettings.java | 1 + .../kotlin/idea/formatter/KotlinCommonBlock.kt | 10 ++++++++++ .../kotlin/idea/formatter/kotlinSpacingRules.kt | 8 ++++++-- .../KotlinLanguageCodeStyleSettingsProvider.kt | 9 ++++++++- idea/testData/formatter/Elvis.after.inv.kt | 9 ++++----- idea/testData/formatter/Elvis.after.kt | 9 ++++----- idea/testData/formatter/Elvis.kt | 6 +++--- idea/testData/formatter/ElvisWrap.after.kt | 4 ++++ idea/testData/formatter/ElvisWrap.kt | 3 +++ .../kotlin/formatter/FormatterTestGenerated.java | 6 ++++++ 10 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 idea/testData/formatter/ElvisWrap.after.kt create mode 100644 idea/testData/formatter/ElvisWrap.kt diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java b/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java index 0b23099eec2..34c3c528b0d 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java @@ -47,6 +47,7 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings { public boolean CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true; public int BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES = 0; public int WRAP_EXPRESSION_BODY_FUNCTIONS = 0; + public int WRAP_ELVIS_EXPRESSIONS = 1; public KotlinCodeStyleSettings(CodeStyleSettings container) { super("JetCodeStyleSettings", container); diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt index 8e52e98483b..424512ad6f9 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -439,6 +439,16 @@ abstract class KotlinCommonBlock( } } } + if (nodePsi.operationToken == KtTokens.ELVIS) { + return object : WrappingStrategy { + override fun getWrap(childElement: ASTNode): Wrap? { + if (childElement.elementType == KtNodeTypes.OPERATION_REFERENCE) { + return Wrap.createWrap(settings.kotlinCustomSettings.WRAP_ELVIS_EXPRESSIONS, true) + } + return null + } + } + } return WrappingStrategy.NoWrapping } } diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt index 047f1eb53e2..c5f7abc62c9 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt @@ -50,6 +50,9 @@ fun SpacingBuilder.afterInside(element: IElementType, tokenSet: TokenSet, spacin tokenSet.types.forEach { inType -> afterInside(element, inType).spacingFun() } } +fun SpacingBuilder.RuleBuilder.spacesNoLineBreak(spaces: Int) = + spacing(spaces, spaces, 0, false, 0) + fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacingBuilderUtil): KotlinSpacingBuilder { val kotlinCommonSettings = settings.kotlinCommonSettings val kotlinCustomSettings = settings.kotlinCustomSettings @@ -199,7 +202,7 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing val spacesAroundAssignment = if (kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) 1 else 0 - beforeInside(EQ, PROPERTY).spacing(spacesAroundAssignment, spacesAroundAssignment, 0, false, 0) + beforeInside(EQ, PROPERTY).spacesNoLineBreak(spacesAroundAssignment) beforeInside(EQ, FUN).spacing(spacesAroundAssignment, spacesAroundAssignment, 0, false, 0) around(TokenSet.create(EQ, MULTEQ, DIVEQ, PLUSEQ, MINUSEQ, PERCEQ)).spaceIf(kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) @@ -209,7 +212,8 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing aroundInside(TokenSet.create(PLUS, MINUS), BINARY_EXPRESSION).spaceIf(kotlinCommonSettings.SPACE_AROUND_ADDITIVE_OPERATORS) aroundInside(TokenSet.create(MUL, DIV, PERC), BINARY_EXPRESSION).spaceIf(kotlinCommonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS) around(TokenSet.create(PLUSPLUS, MINUSMINUS, EXCLEXCL, MINUS, PLUS, EXCL)).spaceIf(kotlinCommonSettings.SPACE_AROUND_UNARY_OPERATOR) - around(ELVIS).spaces(1) + before(ELVIS).spaces(1) + after(ELVIS).spacesNoLineBreak(1) around(RANGE).spaceIf(kotlinCustomSettings.SPACE_AROUND_RANGE) after(MODIFIER_LIST).spaces(1) diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt index 9be427230aa..3d013fd1531 100644 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt @@ -55,10 +55,12 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide fun multilineMethod( foo: String, - bar: String + bar: String?, + x: Int? ) { foo.toUpperCase().trim() .length + val barLen = bar?.length() ?: x ?: -1 } } @@ -300,6 +302,11 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide "Use continuation indent", "Expression body functions" ) + showCustomOption( + KotlinCodeStyleSettings::WRAP_ELVIS_EXPRESSIONS, + "Elvis expressions", + options = *arrayOf(CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON, CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON) + ) } LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> { consumer.showStandardOptions( diff --git a/idea/testData/formatter/Elvis.after.inv.kt b/idea/testData/formatter/Elvis.after.inv.kt index 07669066a0c..1c517f85adb 100644 --- a/idea/testData/formatter/Elvis.after.inv.kt +++ b/idea/testData/formatter/Elvis.after.inv.kt @@ -3,15 +3,14 @@ fun test(a: Int?) { a ?: 42 - a ?: - 42 + a ?: 42 a ?: 42 - val some = a ?: - b ?: - 12 + val some = a + ?: b + ?: 12 } // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION \ No newline at end of file diff --git a/idea/testData/formatter/Elvis.after.kt b/idea/testData/formatter/Elvis.after.kt index 0cdda628877..a9dd782829c 100644 --- a/idea/testData/formatter/Elvis.after.kt +++ b/idea/testData/formatter/Elvis.after.kt @@ -3,15 +3,14 @@ fun test(a: Int?) { a ?: 42 - a ?: - 42 + a ?: 42 a ?: 42 - val some = a ?: - b ?: - 12 + val some = a + ?: b + ?: 12 } // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION \ No newline at end of file diff --git a/idea/testData/formatter/Elvis.kt b/idea/testData/formatter/Elvis.kt index c45a121621f..9519495f258 100644 --- a/idea/testData/formatter/Elvis.kt +++ b/idea/testData/formatter/Elvis.kt @@ -9,9 +9,9 @@ fun test(a: Int?) { a ?: 42 - val some = a ?: - b ?: - 12 + val some = a +?: b +?: 12 } // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION \ No newline at end of file diff --git a/idea/testData/formatter/ElvisWrap.after.kt b/idea/testData/formatter/ElvisWrap.after.kt new file mode 100644 index 00000000000..2de25ba06c1 --- /dev/null +++ b/idea/testData/formatter/ElvisWrap.after.kt @@ -0,0 +1,4 @@ +val x = "abc" + ?: "def" + +// SET_INT: WRAP_ELVIS_EXPRESSIONS = 2 diff --git a/idea/testData/formatter/ElvisWrap.kt b/idea/testData/formatter/ElvisWrap.kt new file mode 100644 index 00000000000..a67fa1df73d --- /dev/null +++ b/idea/testData/formatter/ElvisWrap.kt @@ -0,0 +1,3 @@ +val x = "abc" ?: "def" + +// SET_INT: WRAP_ELVIS_EXPRESSIONS = 2 diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java index e577473e310..d4733a74b46 100644 --- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java @@ -284,6 +284,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest { doTest(fileName); } + @TestMetadata("ElvisWrap.after.kt") + public void testElvisWrap() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/ElvisWrap.after.kt"); + doTest(fileName); + } + @TestMetadata("EmptyLineAfterObjectDeclaration.after.kt") public void testEmptyLineAfterObjectDeclaration() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/EmptyLineAfterObjectDeclaration.after.kt");