From db9a14f09f3ba708f51e70224aca52a1317045f4 Mon Sep 17 00:00:00 2001 From: DDeg Date: Fri, 11 Mar 2022 10:37:07 +0300 Subject: [PATCH 1/2] Implemented configuration options for Kotlin ktfmt formatter. --- lib/build.gradle | 10 ++ .../glue/ktfmt/KtfmtFormatterFunc.java | 88 +++++++++++++ .../glue/ktfmt/KtfmtFormattingOptions.java | 92 +++++++++++++ .../spotless/glue/ktfmt/KtfmtStyle.java | 20 +++ .../diffplug/spotless/kotlin/KtfmtStep.java | 124 +++++++++++++++--- .../gradle/spotless/KotlinExtension.java | 43 ++++-- .../spotless/KotlinGradleExtension.java | 38 ++++-- .../gradle/spotless/KotlinExtensionTest.java | 46 ++++++- .../diffplug/spotless/maven/kotlin/Ktfmt.java | 20 ++- .../spotless/maven/kotlin/KtfmtTest.java | 20 ++- .../kotlin/ktfmt/max-width-dropbox.clean | 12 ++ .../resources/kotlin/ktfmt/max-width.clean | 12 ++ .../resources/kotlin/ktfmt/max-width.dirty | 12 ++ .../spotless/kotlin/KtfmtStepTest.java | 6 +- 14 files changed, 499 insertions(+), 44 deletions(-) create mode 100644 lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java create mode 100644 lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java create mode 100644 lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java create mode 100644 testlib/src/main/resources/kotlin/ktfmt/max-width-dropbox.clean create mode 100644 testlib/src/main/resources/kotlin/ktfmt/max-width.clean create mode 100644 testlib/src/main/resources/kotlin/ktfmt/max-width.dirty diff --git a/lib/build.gradle b/lib/build.gradle index 567e1f786c..a585d8328e 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -9,6 +9,7 @@ apply from: rootProject.file('gradle/java-publish.gradle') def NEEDS_GLUE = [ 'sortPom', 'palantirJavaFormat', + 'ktfmt', 'ktlint', 'flexmark' ] @@ -34,6 +35,15 @@ dependencies { palantirJavaFormatCompileOnly 'com.palantir.javaformat:palantir-java-format:1.1.0' + String VER_KTFMT = '0.34' + ktfmtCompileOnly "com.facebook:ktfmt:$VER_KTFMT" + String VER_KTLINT_GOOGLE_JAVA_FORMAT = '1.7' // for JDK 8 compatibility + ktfmtCompileOnly("com.google.googlejavaformat:google-java-format") { + version { + strictly VER_KTLINT_GOOGLE_JAVA_FORMAT + } + } + String VER_KTLINT='0.43.2' ktlintCompileOnly "com.pinterest:ktlint:$VER_KTLINT" ktlintCompileOnly "com.pinterest.ktlint:ktlint-core:$VER_KTLINT" diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java new file mode 100644 index 0000000000..72e0e50e3c --- /dev/null +++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java @@ -0,0 +1,88 @@ +/* + * Copyright 2022 DiffPlug + * + * 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 com.diffplug.spotless.glue.ktfmt; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.facebook.ktfmt.format.Formatter; +import com.facebook.ktfmt.format.FormattingOptions; + +import com.diffplug.spotless.FormatterFunc; + +public final class KtfmtFormatterFunc implements FormatterFunc { + + @Nonnull + private final KtfmtStyle style; + + @Nullable + private final KtfmtFormattingOptions ktfmtFormattingOptions; + + public KtfmtFormatterFunc() { + this(KtfmtStyle.DEFAULT, null); + } + + public KtfmtFormatterFunc(@Nonnull KtfmtStyle style) { + this(style, null); + } + + public KtfmtFormatterFunc(@Nullable KtfmtFormattingOptions ktfmtFormattingOptions) { + this(KtfmtStyle.DEFAULT, ktfmtFormattingOptions); + } + + public KtfmtFormatterFunc(@Nonnull KtfmtStyle style, @Nullable KtfmtFormattingOptions ktfmtFormattingOptions) { + this.style = style; + this.ktfmtFormattingOptions = ktfmtFormattingOptions; + } + + @Nonnull + @Override + public String apply(@Nonnull String input) throws Exception { + return Formatter.format(createFormattingOptions(), input); + } + + private FormattingOptions createFormattingOptions() { + FormattingOptions formattingOptions; + switch (style) { + case DEFAULT: + formattingOptions = new FormattingOptions(); + break; + case DROPBOX: + formattingOptions = Formatter.DROPBOX_FORMAT; + break; + case GOOGLE: + formattingOptions = Formatter.GOOGLE_FORMAT; + break; + case KOTLIN_LANG: + formattingOptions = Formatter.KOTLINLANG_FORMAT; + break; + default: + throw new IllegalStateException("Unknown formatting option"); + } + + if (ktfmtFormattingOptions != null) { + formattingOptions = formattingOptions.copy( + formattingOptions.getStyle(), + ktfmtFormattingOptions.getMaxWidth().orElse(formattingOptions.getMaxWidth()), + ktfmtFormattingOptions.getBlockIndent().orElse(formattingOptions.getBlockIndent()), + ktfmtFormattingOptions.getContinuationIndent().orElse(formattingOptions.getBlockIndent()), + ktfmtFormattingOptions.getRemoveUnusedImport().orElse(formattingOptions.getRemoveUnusedImports()), + formattingOptions.getDebuggingPrintOpsAfterFormatting()); + } + + return formattingOptions; + } +} diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java new file mode 100644 index 0000000000..ff8e522aae --- /dev/null +++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java @@ -0,0 +1,92 @@ +/* + * Copyright 2022 DiffPlug + * + * 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 com.diffplug.spotless.glue.ktfmt; + +import java.util.Optional; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public final class KtfmtFormattingOptions { + + @Nullable + private Integer maxWidth; + + @Nullable + private Integer blockIndent; + + @Nullable + private Integer continuationIndent; + + @Nullable + private Boolean removeUnusedImport; + + public KtfmtFormattingOptions( + @Nullable Integer maxWidth, + @Nullable Integer blockIndent, + @Nullable Integer continuationIndent, + @Nullable Boolean removeUnusedImport) { + this.maxWidth = maxWidth; + this.blockIndent = blockIndent; + this.continuationIndent = continuationIndent; + this.removeUnusedImport = removeUnusedImport; + } + + @Nonnull + public Optional getMaxWidth() { + return Optional.ofNullable(maxWidth); + } + + @Nonnull + public Optional getBlockIndent() { + return Optional.ofNullable(blockIndent); + } + + @Nonnull + public Optional getContinuationIndent() { + return Optional.ofNullable(continuationIndent); + } + + @Nonnull + public Optional getRemoveUnusedImport() { + return Optional.ofNullable(removeUnusedImport); + } + + public void setMaxWidth(int maxWidth) { + if (maxWidth <= 0) { + throw new IllegalArgumentException("Max width cannot be negative value or 0"); + } + this.maxWidth = maxWidth; + } + + public void setBlockIndent(int blockIndent) { + if (blockIndent < 0) { + throw new IllegalArgumentException("Block indent cannot be negative value"); + } + this.blockIndent = blockIndent; + } + + public void setContinuationIndent(int continuationIndent) { + if (continuationIndent < 0) { + throw new IllegalArgumentException("Continuation indent cannot be negative value"); + } + this.continuationIndent = continuationIndent; + } + + public void setRemoveUnusedImport(boolean removeUnusedImport) { + this.removeUnusedImport = removeUnusedImport; + } +} diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java new file mode 100644 index 0000000000..34b81175ec --- /dev/null +++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java @@ -0,0 +1,20 @@ +/* + * Copyright 2022 DiffPlug + * + * 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 com.diffplug.spotless.glue.ktfmt; + +public enum KtfmtStyle { + DEFAULT, DROPBOX, GOOGLE, KOTLIN_LANG +} diff --git a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java index 9f3b62dadb..e5e2e57f01 100644 --- a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java +++ b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java @@ -19,11 +19,18 @@ import java.io.IOException; import java.io.Serializable; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Objects; -import com.diffplug.spotless.*; +import javax.annotation.Nullable; + +import com.diffplug.spotless.FormatterFunc; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.JarState; +import com.diffplug.spotless.Provisioner; +import com.diffplug.spotless.ThrowingEx; /** * Wraps up ktfmt as a FormatterStep. @@ -32,7 +39,7 @@ public class KtfmtStep { // prevent direct instantiation private KtfmtStep() {} - private static final String DEFAULT_VERSION = "0.31"; + private static final String DEFAULT_VERSION = "0.34"; static final String NAME = "ktfmt"; static final String PACKAGE = "com.facebook"; static final String MAVEN_COORDINATE = PACKAGE + ":ktfmt:"; @@ -62,7 +69,35 @@ String getSince() { } } - private static final String DROPBOX_STYLE_METHOD = "dropboxStyle"; + public static class KtfmtFormattingOptions implements Serializable { + + private static final long serialVersionUID = 1L; + + @Nullable + private Integer maxWidth = null; + + @Nullable + private Integer blockIndent = null; + + @Nullable + private Integer continuationIndent = null; + + @Nullable + private Boolean removeUnusedImport = null; + + public KtfmtFormattingOptions() {} + + public KtfmtFormattingOptions( + @Nullable Integer maxWidth, + @Nullable Integer blockIndent, + @Nullable Integer continuationIndent, + @Nullable Boolean removeUnusedImport) { + this.maxWidth = maxWidth; + this.blockIndent = blockIndent; + this.continuationIndent = continuationIndent; + this.removeUnusedImport = removeUnusedImport; + } + } /** * The format method is available in the link below. @@ -78,26 +113,21 @@ public static FormatterStep create(Provisioner provisioner) { /** Creates a step which formats everything - code, import order, and unused imports. */ public static FormatterStep create(String version, Provisioner provisioner) { - return create(version, provisioner, DEFAULT); + return create(version, provisioner, null, null); } /** Creates a step which formats everything - code, import order, and unused imports. */ - public static FormatterStep create(String version, Provisioner provisioner, Style style) { + public static FormatterStep create(String version, Provisioner provisioner, @Nullable Style style, @Nullable KtfmtFormattingOptions options) { Objects.requireNonNull(version, "version"); Objects.requireNonNull(provisioner, "provisioner"); - Objects.requireNonNull(style, "style"); return FormatterStep.createLazy( - NAME, () -> new State(version, provisioner, style), State::createFormat); + NAME, () -> new State(version, provisioner, style, options), State::createFormat); } public static String defaultVersion() { return DEFAULT_VERSION; } - public static String defaultStyle() { - return Style.DEFAULT.name(); - } - static final class State implements Serializable { private static final long serialVersionUID = 1L; @@ -107,26 +137,90 @@ static final class State implements Serializable { /** * Option that allows to apply formatting options to perform a 4 spaces block and continuation indent. */ + @Nullable private final Style style; + /** + * + */ + @Nullable + private final KtfmtFormattingOptions options; /** The jar that contains the formatter. */ final JarState jarState; - State(String version, Provisioner provisioner, Style style) throws IOException { + State(String version, Provisioner provisioner, @Nullable Style style, @Nullable KtfmtFormattingOptions options) throws IOException { this.version = version; + this.options = options; this.pkg = PACKAGE; this.style = style; this.jarState = JarState.from(MAVEN_COORDINATE + version, provisioner); } FormatterFunc createFormat() throws Exception { - ClassLoader classLoader = jarState.getClassLoader(); + final ClassLoader classLoader = jarState.getClassLoader(); + + if (BadSemver.version(version) < BadSemver.version(0, 32)) { + if (options != null) { + throw new IllegalStateException("Ktfmt formatting options supported for version 0.32 and later"); + } + return getFormatterFuncFallback(style != null ? style : DEFAULT, classLoader); + } + + final Class formatterFuncClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtFormatterFunc"); + final Class ktfmtStyleClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtStyle"); + final Class ktfmtFormattingOptionsClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtFormattingOptions"); + + if (style == null && options == null) { + final Constructor constructor = formatterFuncClass.getConstructor(); + return (FormatterFunc) constructor.newInstance(); + } + + final Object ktfmtStyle = style == null ? null : Enum.valueOf((Class) ktfmtStyleClass, getKtfmtStyleOption(style)); + if (options == null) { + final Constructor constructor = formatterFuncClass.getConstructor(ktfmtStyleClass); + return (FormatterFunc) constructor.newInstance(ktfmtStyle); + } + + final Constructor optionsConstructor = ktfmtFormattingOptionsClass.getConstructor( + Integer.class, Integer.class, Integer.class, Boolean.class); + final Object ktfmtFormattingOptions = optionsConstructor.newInstance( + options.maxWidth, options.blockIndent, options.continuationIndent, options.removeUnusedImport); + if (style == null) { + final Constructor constructor = formatterFuncClass.getConstructor(ktfmtFormattingOptionsClass); + return (FormatterFunc) constructor.newInstance(ktfmtFormattingOptions); + } + + final Constructor constructor = formatterFuncClass.getConstructor(ktfmtStyleClass, ktfmtFormattingOptionsClass); + return (FormatterFunc) constructor.newInstance(ktfmtStyle, ktfmtFormattingOptions); + } + + /** + * @param style + * @return com.diffplug.spotless.glue.ktfmt.KtfmtStyle enum value name + */ + private String getKtfmtStyleOption(Style style) { + switch (style) { + case DEFAULT: + return "DEFAULT"; + case DROPBOX: + return "DROPBOX"; + case GOOGLE: + return "GOOGLE"; + case KOTLINLANG: + return "KOTLIN_LANG"; + default: + throw new IllegalStateException("Unsupported style: " + style); + } + } + + private FormatterFunc getFormatterFuncFallback(Style style, ClassLoader classLoader) { return input -> { try { if (style == DEFAULT) { Method formatterMethod = getFormatterClazz(classLoader).getMethod(FORMATTER_METHOD, String.class); return (String) formatterMethod.invoke(getFormatterClazz(classLoader), input); } else { - Method formatterMethod = getFormatterClazz(classLoader).getMethod(FORMATTER_METHOD, getFormattingOptionsClazz(classLoader), + Method formatterMethod = getFormatterClazz(classLoader).getMethod(FORMATTER_METHOD, + getFormattingOptionsClazz(classLoader), String.class); Object formattingOptions = getCustomFormattingOptions(classLoader, style); return (String) formatterMethod.invoke(getFormatterClazz(classLoader), formattingOptions, input); @@ -151,7 +245,7 @@ private Object getCustomFormattingOptions(ClassLoader classLoader, Style style) if (style == Style.DEFAULT || style == Style.DROPBOX) { Class formattingOptionsCompanionClazz = classLoader.loadClass(pkg + ".ktfmt.FormattingOptions$Companion"); Object companion = formattingOptionsCompanionClazz.getConstructors()[0].newInstance((Object) null); - Method formattingOptionsMethod = formattingOptionsCompanionClazz.getDeclaredMethod(DROPBOX_STYLE_METHOD); + Method formattingOptionsMethod = formattingOptionsCompanionClazz.getDeclaredMethod("dropboxStyle"); return formattingOptionsMethod.invoke(companion); } else { throw new IllegalStateException("Versions pre-0.19 can only use Default and Dropbox styles"); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java index d88b4aac7f..56d925caa3 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; import javax.inject.Inject; @@ -34,6 +35,7 @@ import com.diffplug.spotless.kotlin.DiktatStep; import com.diffplug.spotless.kotlin.KtLintStep; import com.diffplug.spotless.kotlin.KtfmtStep; +import com.diffplug.spotless.kotlin.KtfmtStep.KtfmtFormattingOptions; import com.diffplug.spotless.kotlin.KtfmtStep.Style; public class KotlinExtension extends FormatExtension implements HasBuiltinDelimiterForLicense { @@ -104,32 +106,49 @@ public KtfmtConfig ktfmt(String version) { public class KtfmtConfig { final String version; Style style; + KtfmtFormattingOptions options; + + private final ConfigurableStyle configurableStyle = new ConfigurableStyle(); KtfmtConfig(String version) { this.version = Objects.requireNonNull(version); - this.style = Style.DEFAULT; addStep(createStep()); } - public void dropboxStyle() { - style(Style.DROPBOX); + private ConfigurableStyle style(Style style) { + this.style = style; + replaceStep(createStep()); + return configurableStyle; } - public void googleStyle() { - style(Style.GOOGLE); + public ConfigurableStyle dropboxStyle() { + return style(Style.DROPBOX); } - public void kotlinlangStyle() { - style(Style.KOTLINLANG); + public ConfigurableStyle googleStyle() { + return style(Style.GOOGLE); } - public void style(Style style) { - this.style = style; - replaceStep(createStep()); + public ConfigurableStyle kotlinlangStyle() { + return style(Style.KOTLINLANG); + } + + public void configure(Consumer optionsConfiguration) { + this.configurableStyle.configure(optionsConfiguration); } private FormatterStep createStep() { - return KtfmtStep.create(version, provisioner(), style); + return KtfmtStep.create(version, provisioner(), style, options); + } + + class ConfigurableStyle { + + void configure(Consumer optionsConfiguration) { + KtfmtFormattingOptions ktfmtFormattingOptions = new KtfmtFormattingOptions(); + optionsConfiguration.accept(ktfmtFormattingOptions); + options = ktfmtFormattingOptions; + replaceStep(createStep()); + } } } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java index 5ea3c29594..1ff2b0c332 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; import javax.inject.Inject; @@ -28,6 +29,7 @@ import com.diffplug.spotless.kotlin.DiktatStep; import com.diffplug.spotless.kotlin.KtLintStep; import com.diffplug.spotless.kotlin.KtfmtStep; +import com.diffplug.spotless.kotlin.KtfmtStep.KtfmtFormattingOptions; import com.diffplug.spotless.kotlin.KtfmtStep.Style; public class KotlinGradleExtension extends FormatExtension { @@ -90,6 +92,9 @@ public KtfmtConfig ktfmt(String version) { public class KtfmtConfig { final String version; Style style; + KtfmtFormattingOptions options; + + private final ConfigurableStyle configurableStyle = new ConfigurableStyle(); KtfmtConfig(String version) { this.version = Objects.requireNonNull(version); @@ -97,25 +102,40 @@ public class KtfmtConfig { addStep(createStep()); } - public void style(Style style) { + private ConfigurableStyle style(Style style) { this.style = style; replaceStep(createStep()); + return configurableStyle; + } + + public ConfigurableStyle dropboxStyle() { + return style(Style.DROPBOX); } - public void dropboxStyle() { - style(Style.DROPBOX); + public ConfigurableStyle googleStyle() { + return style(Style.GOOGLE); } - public void googleStyle() { - style(Style.GOOGLE); + public ConfigurableStyle kotlinlangStyle() { + return style(Style.KOTLINLANG); } - public void kotlinlangStyle() { - style(Style.KOTLINLANG); + public void configure(Consumer optionsConfiguration) { + this.configurableStyle.configure(optionsConfiguration); } private FormatterStep createStep() { - return KtfmtStep.create(version, provisioner(), style); + return KtfmtStep.create(version, provisioner(), style, options); + } + + class ConfigurableStyle { + + void configure(Consumer optionsConfiguration) { + KtfmtFormattingOptions ktfmtFormattingOptions = new KtfmtFormattingOptions(); + optionsConfiguration.accept(ktfmtFormattingOptions); + options = ktfmtFormattingOptions; + replaceStep(createStep()); + } } } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java index f3d8ad442d..3bbd44d63d 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -269,4 +269,48 @@ void testWithNonStandardYearSeparatorKtfmt() throws IOException { matcher.startsWith("// License Header 2012, 2014"); }); } + + @Test + @EnabledForJreRange(min = JAVA_11) // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+. + void testWithCustomMaxWidthDefaultStyleKtfmt() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'org.jetbrains.kotlin.jvm' version '1.5.31'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "spotless {", + " kotlin {", + " ktfmt().configure { options ->", + " options.maxWidth = 120", + " }", + " }", + "}"); + + setFile("src/main/kotlin/max-width.kt").toResource("kotlin/ktfmt/max-width.dirty"); + gradleRunner().withArguments("spotlessApply").build(); + assertFile("src/main/kotlin/max-width.kt").sameAsResource("kotlin/ktfmt/max-width.clean"); + } + + @Test + @EnabledForJreRange(min = JAVA_11) // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+. + void testWithCustomMaxWidthDropboxStyleKtfmt() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'org.jetbrains.kotlin.jvm' version '1.5.31'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "spotless {", + " kotlin {", + " ktfmt().dropboxStyle().configure { options ->", + " options.maxWidth = 120", + " }", + " }", + "}"); + + setFile("src/main/kotlin/max-width.kt").toResource("kotlin/ktfmt/max-width.dirty"); + gradleRunner().withArguments("spotlessApply").build(); + assertFile("src/main/kotlin/max-width.kt").sameAsResource("kotlin/ktfmt/max-width-dropbox.clean"); + } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java index c1258a15fe..b917d33a44 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.kotlin.KtfmtStep; +import com.diffplug.spotless.kotlin.KtfmtStep.KtfmtFormattingOptions; import com.diffplug.spotless.kotlin.KtfmtStep.Style; import com.diffplug.spotless.maven.FormatterStepConfig; import com.diffplug.spotless.maven.FormatterStepFactory; @@ -31,10 +32,23 @@ public class Ktfmt implements FormatterStepFactory { @Parameter private String style; + @Parameter + private Integer maxWidth; + + @Parameter + private Integer blockIndent; + + @Parameter + private Integer continuationIndent; + + @Parameter + private Boolean removeUnusedImport; + @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { String version = this.version != null ? this.version : KtfmtStep.defaultVersion(); - String style = this.style != null ? this.style : KtfmtStep.defaultStyle(); - return KtfmtStep.create(version, config.getProvisioner(), Style.valueOf(style)); + Style style = this.style != null ? Style.valueOf(this.style) : null; + KtfmtFormattingOptions options = new KtfmtFormattingOptions(maxWidth, blockIndent, continuationIndent, removeUnusedImport); + return KtfmtStep.create(version, config.getProvisioner(), style, options); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java index 7b0ca069fc..88dcd172e0 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,4 +48,22 @@ void testKtfmtStyle() throws Exception { mavenRunner().withArguments("spotless:apply").runNoError(); assertFile("src/main/kotlin/main.kt").sameAsResource("kotlin/ktfmt/basic-dropboxstyle.clean"); } + + @Test + void testKtfmtWithMaxWidthOption() throws Exception { + writePomWithKotlinSteps("120"); + + setFile("src/main/kotlin/main.kt").toResource("kotlin/ktfmt/max-width.dirty"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile("src/main/kotlin/main.kt").sameAsResource("kotlin/ktfmt/max-width.clean"); + } + + @Test + void testKtfmtStyleWithMaxWidthOption() throws Exception { + writePomWithKotlinSteps("120"); + + setFile("src/main/kotlin/main.kt").toResource("kotlin/ktfmt/max-width.dirty"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile("src/main/kotlin/main.kt").sameAsResource("kotlin/ktfmt/max-width-dropbox.clean"); + } } diff --git a/testlib/src/main/resources/kotlin/ktfmt/max-width-dropbox.clean b/testlib/src/main/resources/kotlin/ktfmt/max-width-dropbox.clean new file mode 100644 index 0000000000..0fce31c7ec --- /dev/null +++ b/testlib/src/main/resources/kotlin/ktfmt/max-width-dropbox.clean @@ -0,0 +1,12 @@ +import a.* +import a.b +import a.b.c.* +import kotlinx.android.synthetic.main.layout_name.* + +fun main() {} + +fun foo(param1: Any, param2: Any, param3: Any, param4: Any, param5: Any, param6: Any, param7: Any, param8: Any) { + a() + functionNameWithAlmost120SymbolsToValidateThatKtfmtNotBreakLineAtDefault100(param1, param2, param3, param4, param5) + return b +} diff --git a/testlib/src/main/resources/kotlin/ktfmt/max-width.clean b/testlib/src/main/resources/kotlin/ktfmt/max-width.clean new file mode 100644 index 0000000000..4592181044 --- /dev/null +++ b/testlib/src/main/resources/kotlin/ktfmt/max-width.clean @@ -0,0 +1,12 @@ +import a.* +import a.b +import a.b.c.* +import kotlinx.android.synthetic.main.layout_name.* + +fun main() {} + +fun foo(param1: Any, param2: Any, param3: Any, param4: Any, param5: Any, param6: Any, param7: Any, param8: Any) { + a() + functionNameWithAlmost120SymbolsToValidateThatKtfmtNotBreakLineAtDefault100(param1, param2, param3, param4, param5) + return b +} diff --git a/testlib/src/main/resources/kotlin/ktfmt/max-width.dirty b/testlib/src/main/resources/kotlin/ktfmt/max-width.dirty new file mode 100644 index 0000000000..ef9504e1c3 --- /dev/null +++ b/testlib/src/main/resources/kotlin/ktfmt/max-width.dirty @@ -0,0 +1,12 @@ +import a.* + +import kotlinx.android.synthetic.main.layout_name.* + +import a.b.c.* +import a.b + +fun main() {} +fun foo(param1: Any, param2: Any, param3: Any, param4: Any, param5: Any, param6: Any, param7: Any, param8: Any) { + a(); functionNameWithAlmost120SymbolsToValidateThatKtfmtNotBreakLineAtDefault100(param1, param2, param3, param4, param5) + return b +} diff --git a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java index 3416e6d297..ddaf1b324b 100644 --- a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,14 +35,14 @@ void behavior() throws Exception { @Test @EnabledForJreRange(min = JAVA_11) // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+. void dropboxStyle_0_18() throws Exception { - FormatterStep step = KtfmtStep.create("0.18", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX); + FormatterStep step = KtfmtStep.create("0.18", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, null); StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic-dropboxstyle.clean"); } @Test @EnabledForJreRange(min = JAVA_11) // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+. void dropboxStyle_0_19() throws Exception { - FormatterStep step = KtfmtStep.create("0.19", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX); + FormatterStep step = KtfmtStep.create("0.19", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, null); StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic-dropboxstyle.clean"); } From fb62f361f1478cef675ceb7df029e26b078bbea8 Mon Sep 17 00:00:00 2001 From: DDeg Date: Fri, 11 Mar 2022 10:47:52 +0300 Subject: [PATCH 2/2] Updated unreleased block in changelog with ktfmt custom parameters. --- CHANGES.md | 1 + plugin-gradle/CHANGES.md | 1 + plugin-maven/CHANGES.md | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 36be0237d7..79c97cb411 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +* Added support for setting custom parameters for Kotlin ktfmt in Gradle and Maven plugins. ([#1145](https://github.com/diffplug/spotless/pull/1145)) ## [2.23.0] - 2022-02-15 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 9f22285976..4eb101c7a0 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -5,6 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Accept `java.nio.charset.Charset` type when setting the character encoding via `encoding` ([#1128](https://github.com/diffplug/spotless/issues/1128)) +* Added support for setting custom parameters for Kotlin ktfmt in Gradle plugin. ([#1145](https://github.com/diffplug/spotless/pull/1145)) ## [6.3.0] - 2022-02-15 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index a41995ef1f..c320da7d31 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +* Added support for setting custom parameters for Kotlin ktfmt in Maven plugin. ([#1145](https://github.com/diffplug/spotless/pull/1145)) ## [2.21.0] - 2022-02-19 ### Added