From 947833cad69db1a6342f55c8e8493b660393e2fb Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 30 Nov 2017 17:57:39 +0100 Subject: [PATCH] Add wrap option for expression body functions #KT-21470 Fixed --- .../formatter/KotlinCodeStyleSettings.java | 1 + .../idea/formatter/KotlinCommonBlock.kt | 40 ++++++++----- .../formatter/KotlinIndentOptionsEditor.kt | 58 ------------------- ...KotlinLanguageCodeStyleSettingsProvider.kt | 20 ++++++- .../formatter/ExpressionBodyWrap.after.kt | 4 ++ idea/testData/formatter/ExpressionBodyWrap.kt | 3 + .../formatter/FormatterTestGenerated.java | 6 ++ 7 files changed, 58 insertions(+), 74 deletions(-) delete mode 100644 idea/src/org/jetbrains/kotlin/idea/formatter/KotlinIndentOptionsEditor.kt create mode 100644 idea/testData/formatter/ExpressionBodyWrap.after.kt create mode 100644 idea/testData/formatter/ExpressionBodyWrap.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 cbc981c83d5..0b23099eec2 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 @@ -46,6 +46,7 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings { public boolean CONTINUATION_INDENT_FOR_CHAINED_CALLS = true; 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 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 9ba4fd5fc99..ac86d69dc6d 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -337,6 +337,7 @@ abstract class KotlinCommonBlock( private fun getWrappingStrategy(): WrappingStrategy { val commonSettings = settings.kotlinCommonSettings val elementType = node.elementType + val parentElementType = node.treeParent?.elementType val nodePsi = node.psi when { @@ -344,7 +345,6 @@ abstract class KotlinCommonBlock( return getWrappingStrategyForItemList(commonSettings.CALL_PARAMETERS_WRAP, KtNodeTypes.VALUE_ARGUMENT) elementType === KtNodeTypes.VALUE_PARAMETER_LIST -> { - val parentElementType = node.treeParent.elementType if (parentElementType === KtNodeTypes.FUN || parentElementType === KtNodeTypes.PRIMARY_CONSTRUCTOR || parentElementType === KtNodeTypes.SECONDARY_CONSTRUCTOR) { @@ -402,7 +402,17 @@ abstract class KotlinCommonBlock( return wrapAfterAnnotation(commonSettings.CLASS_ANNOTATION_WRAP) nodePsi is KtNamedFunction -> - return wrapAfterAnnotation(commonSettings.METHOD_ANNOTATION_WRAP) + return object : WrappingStrategy { + override fun getWrap(childElement: ASTNode): Wrap? { + getWrapAfterAnnotation(childElement, commonSettings.METHOD_ANNOTATION_WRAP)?.let { + return it + } + if (getPrevWithoutWhitespaceAndComments(childElement)?.elementType == KtTokens.EQ) { + return Wrap.createWrap(settings.kotlinCustomSettings.WRAP_EXPRESSION_BODY_FUNCTIONS, true) + } + return null + } + } nodePsi is KtProperty -> return wrapAfterAnnotation(if (nodePsi.isLocal) @@ -422,21 +432,25 @@ private fun ASTNode.isFirstParameter(): Boolean = treePrev?.elementType == KtTok private fun wrapAfterAnnotation(wrapType: Int): WrappingStrategy { return object : WrappingStrategy { override fun getWrap(childElement: ASTNode): Wrap? { - if (childElement.elementType in KtTokens.COMMENTS) return null - var prevLeaf = childElement.treePrev - while (prevLeaf?.elementType == TokenType.WHITE_SPACE) { - prevLeaf = prevLeaf.treePrev - } - if (prevLeaf?.elementType == KtNodeTypes.MODIFIER_LIST) { - if (prevLeaf?.lastChildNode?.elementType in ANNOTATIONS) { - return Wrap.createWrap(wrapType, true) - } - } - return null + return getWrapAfterAnnotation(childElement, wrapType) } } } +private fun getWrapAfterAnnotation(childElement: ASTNode, wrapType: Int): Wrap? { + if (childElement.elementType in COMMENTS) return null + var prevLeaf = childElement.treePrev + while (prevLeaf?.elementType == TokenType.WHITE_SPACE) { + prevLeaf = prevLeaf.treePrev + } + if (prevLeaf?.elementType == KtNodeTypes.MODIFIER_LIST) { + if (prevLeaf?.lastChildNode?.elementType in ANNOTATIONS) { + return Wrap.createWrap(wrapType, true) + } + } + return null +} + private val INDENT_RULES = arrayOf( strategy("No indent for braces in blocks") .within(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL) diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinIndentOptionsEditor.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinIndentOptionsEditor.kt deleted file mode 100644 index 2cf3e1ced54..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinIndentOptionsEditor.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010-2017 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.kotlin.idea.formatter - -import com.intellij.application.options.IndentOptionsEditor -import com.intellij.application.options.SmartIndentOptionsEditor -import com.intellij.psi.codeStyle.CodeStyleSettings -import com.intellij.psi.codeStyle.CommonCodeStyleSettings -import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings -import javax.swing.JCheckBox - -class KotlinIndentOptionsEditor : SmartIndentOptionsEditor() { - private val useContinuationIndentForExpressionBodies = JCheckBox("Use continuation indent for expression bodies") - - override fun addComponents() { - super.addComponents() - add(useContinuationIndentForExpressionBodies) - } - - override fun isModified(settings: CodeStyleSettings, options: CommonCodeStyleSettings.IndentOptions): Boolean { - var isModified = super.isModified(settings, options) - val kotlinSettings = settings.kotlinCustomSettings - isModified = isModified || IndentOptionsEditor.isFieldModified(useContinuationIndentForExpressionBodies, - kotlinSettings.CONTINUATION_INDENT_FOR_EXPRESSION_BODIES) - return isModified - } - - override fun apply(settings: CodeStyleSettings, options: CommonCodeStyleSettings.IndentOptions) { - super.apply(settings, options) - val kotlinSettings = settings.getCustomSettings(KotlinCodeStyleSettings::class.java) - kotlinSettings.CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = useContinuationIndentForExpressionBodies.isSelected - } - - override fun reset(settings: CodeStyleSettings, options: CommonCodeStyleSettings.IndentOptions) { - super.reset(settings, options) - val kotlinSettings = settings.getCustomSettings(KotlinCodeStyleSettings::class.java) - useContinuationIndentForExpressionBodies.isSelected = kotlinSettings.CONTINUATION_INDENT_FOR_EXPRESSION_BODIES - } - - override fun setEnabled(enabled: Boolean) { - super.setEnabled(enabled) - useContinuationIndentForExpressionBodies.isEnabled = enabled - } -} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt index 546cb6ec94b..3149f99bf6b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.idea.formatter import com.intellij.application.options.IndentOptionsEditor +import com.intellij.application.options.SmartIndentOptionsEditor import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable import com.intellij.psi.codeStyle.CommonCodeStyleSettings import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider @@ -66,6 +67,8 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide enum class Enumeration { A, B } + + fun veryLongExpressionBodyMethod() = "abc" """.trimIndent() LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> @@ -167,8 +170,8 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide override fun getLanguageName(): String = KotlinLanguage.NAME override fun customizeSettings(consumer: CodeStyleSettingsCustomizable, settingsType: LanguageCodeStyleSettingsProvider.SettingsType) { - fun showCustomOption(field: KProperty<*>, title: String, groupName: String? = null) { - consumer.showCustomOption(KotlinCodeStyleSettings::class.java, field.name, title, groupName) + fun showCustomOption(field: KProperty<*>, title: String, groupName: String? = null, vararg options: Any) { + consumer.showCustomOption(KotlinCodeStyleSettings::class.java, field.name, title, groupName, *options) } when (settingsType) { @@ -285,6 +288,17 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_SUPERTYPE_LISTS, "Use continuation indent", CodeStyleSettingsCustomizable.WRAPPING_EXTENDS_LIST) + + showCustomOption( + KotlinCodeStyleSettings::WRAP_EXPRESSION_BODY_FUNCTIONS, + "Expression body functions", + options = *arrayOf(CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON, CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON) + ) + showCustomOption( + KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_EXPRESSION_BODIES, + "Use continuation indent", + "Expression body functions" + ) } LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> { consumer.showStandardOptions( @@ -301,7 +315,7 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide } } - override fun getIndentOptionsEditor(): IndentOptionsEditor = KotlinIndentOptionsEditor() + override fun getIndentOptionsEditor(): IndentOptionsEditor = SmartIndentOptionsEditor() override fun getDefaultCommonSettings(): CommonCodeStyleSettings = CommonCodeStyleSettings(language).apply { diff --git a/idea/testData/formatter/ExpressionBodyWrap.after.kt b/idea/testData/formatter/ExpressionBodyWrap.after.kt new file mode 100644 index 00000000000..e2156b5bffa --- /dev/null +++ b/idea/testData/formatter/ExpressionBodyWrap.after.kt @@ -0,0 +1,4 @@ +fun foo() = + "abc" + +// SET_INT: WRAP_EXPRESSION_BODY_FUNCTIONS = 2 diff --git a/idea/testData/formatter/ExpressionBodyWrap.kt b/idea/testData/formatter/ExpressionBodyWrap.kt new file mode 100644 index 00000000000..f4057349775 --- /dev/null +++ b/idea/testData/formatter/ExpressionBodyWrap.kt @@ -0,0 +1,3 @@ +fun foo() = "abc" + +// SET_INT: WRAP_EXPRESSION_BODY_FUNCTIONS = 2 diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java index 1a1e2e9b3cb..dcfe9ac089a 100644 --- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java @@ -344,6 +344,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest { doTest(fileName); } + @TestMetadata("ExpressionBodyWrap.after.kt") + public void testExpressionBodyWrap() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/ExpressionBodyWrap.after.kt"); + doTest(fileName); + } + @TestMetadata("ExtendsListWrap.after.kt") public void testExtendsListWrap() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/ExtendsListWrap.after.kt");