Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump ktfmt to 0.21 and add support to Google and Kotlinlang formats #812

Merged
merged 1 commit into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ 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
* Bump ktfmt to 0.21 and add support to Google and Kotlinlang formats ([#812](https://github.com/diffplug/spotless/pull/812))

## [2.12.1] - 2021-02-16
### Fixed
Expand Down
38 changes: 38 additions & 0 deletions lib/src/main/java/com/diffplug/spotless/kotlin/BadSemver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2021 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.kotlin;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class BadSemver {
protected static int version(String input) {
Matcher matcher = BAD_SEMVER.matcher(input);
if (!matcher.find() || matcher.start() != 0) {
throw new IllegalArgumentException("Version must start with " + BAD_SEMVER.pattern());
}
String major = matcher.group(1);
String minor = matcher.group(2);
return version(Integer.parseInt(major), Integer.parseInt(minor));
}

/** Ambiguous after 2147.483647.blah-blah */
protected static int version(int major, int minor) {
return major * 1_000_000 + minor;
}

private static final Pattern BAD_SEMVER = Pattern.compile("(\\d+)\\.(\\d+)");
}
25 changes: 3 additions & 22 deletions lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2020 DiffPlug
* Copyright 2016-2021 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -25,8 +25,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterStep;
Expand All @@ -39,23 +37,6 @@ public class KtLintStep {
// prevent direct instantiation
private KtLintStep() {}

private static int badSemver(String input) {
Matcher matcher = BAD_SEMVER.matcher(input);
if (!matcher.find() || matcher.start() != 0) {
throw new IllegalArgumentException("Version must start with " + BAD_SEMVER.pattern());
}
String major = matcher.group(1);
String minor = matcher.group(2);
return badSemver(Integer.parseInt(major), Integer.parseInt(minor));
}

/** Ambiguous after 2147.483647.blah-blah */
private static int badSemver(int major, int minor) {
return major * 1_000_000 + minor;
}

private static final Pattern BAD_SEMVER = Pattern.compile("(\\d+)\\.(\\d+)\\.");

private static final String DEFAULT_VERSION = "0.35.0";
static final String NAME = "ktlint";
static final String PACKAGE_PRE_0_32 = "com.github.shyiko";
Expand Down Expand Up @@ -109,14 +90,14 @@ static final class State implements Serializable {
State(String version, Provisioner provisioner, boolean isScript, Map<String, String> userData) throws IOException {
this.userData = new TreeMap<>(userData);
String coordinate;
if (badSemver(version) < badSemver(0, 32)) {
if (BadSemver.version(version) < BadSemver.version(0, 32)) {
coordinate = MAVEN_COORDINATE_PRE_0_32;
this.pkg = PACKAGE_PRE_0_32;
} else {
coordinate = MAVEN_COORDINATE;
this.pkg = PACKAGE;
}
this.useParams = badSemver(version) >= badSemver(0, 34);
this.useParams = BadSemver.version(version) >= BadSemver.version(0, 34);
this.jarState = JarState.from(coordinate + version, provisioner);
this.isScript = isScript;
}
Expand Down
56 changes: 41 additions & 15 deletions lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package com.diffplug.spotless.kotlin;

import static com.diffplug.spotless.kotlin.KtfmtStep.Style.DEFAULT;
import static com.diffplug.spotless.kotlin.KtfmtStep.Style.DROPBOX;

import java.io.IOException;
import java.io.Serializable;
Expand All @@ -33,18 +32,34 @@ public class KtfmtStep {
// prevent direct instantiation
private KtfmtStep() {}

private static final String DEFAULT_VERSION = "0.19";
private static final String DEFAULT_VERSION = "0.21";
static final String NAME = "ktfmt";
static final String PACKAGE = "com.facebook";
static final String MAVEN_COORDINATE = PACKAGE + ":ktfmt:";

/**
* Used to allow dropbox style option through formatting options.
* Used to allow multiple style option through formatting options and since when is each of them available.
*
* @see <a href="https://github.com/facebookincubator/ktfmt/blob/38486b0fb2edcabeba5540fcb69c6f1fa336c331/core/src/main/java/com/facebook/ktfmt/Formatter.kt#L47-L80">ktfmt source</a>
*/
public enum Style {
DEFAULT, DROPBOX
DEFAULT("DEFAULT_FORMAT", "0.0"), DROPBOX("DROPBOX_FORMAT", "0.11"), GOOGLE("GOOGLE_FORMAT", "0.21"), KOTLINLANG("KOTLINLANG_FORMAT", "0.21");

final private String format;
final private String since;

Style(String format, String since) {
this.format = format;
this.since = since;
}

String getFormat() {
return format;
}

String getSince() {
return since;
}
}

private static final String DROPBOX_STYLE_METHOD = "dropboxStyle";
Expand Down Expand Up @@ -86,6 +101,8 @@ public static String defaultStyle() {
static final class State implements Serializable {
private static final long serialVersionUID = 1L;

private final String version;

private final String pkg;
/**
* Option that allows to apply formatting options to perform a 4 spaces block and continuation indent.
Expand All @@ -95,6 +112,7 @@ static final class State implements Serializable {
final JarState jarState;

State(String version, Provisioner provisioner, Style style) throws IOException {
this.version = version;
this.pkg = PACKAGE;
this.style = style;
this.jarState = JarState.from(MAVEN_COORDINATE + version, provisioner);
Expand All @@ -105,33 +123,41 @@ FormatterFunc createFormat() throws Exception {
Class<?> formatterClazz = classLoader.loadClass(pkg + ".ktfmt.FormatterKt");
return input -> {
try {
if (style == DROPBOX) {
if (style == DEFAULT) {
Method formatterMethod = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
return (String) formatterMethod.invoke(formatterClazz, input);
} else {
Class<?> formattingOptionsClazz = classLoader.loadClass(pkg + ".ktfmt.FormattingOptions");
Method formatterMethod = formatterClazz.getMethod(FORMATTER_METHOD, formattingOptionsClazz,
String.class);
Object formattingOptions = getDropboxStyleFormattingOptions(classLoader);
Object formattingOptions = getCustomFormattingOptions(classLoader, style);
return (String) formatterMethod.invoke(formatterClazz, formattingOptions, input);
} else {
Method formatterMethod = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
return (String) formatterMethod.invoke(formatterClazz, input);
}
} catch (InvocationTargetException e) {
throw ThrowingEx.unwrapCause(e);
}
};
}

private Object getDropboxStyleFormattingOptions(ClassLoader classLoader) throws Exception {
private Object getCustomFormattingOptions(ClassLoader classLoader, Style style) throws Exception {
if (BadSemver.version(version) < BadSemver.version(style.since)) {
throw new IllegalStateException(String.format("The style %s is available from version %s (current version: %s)", style.name(), style.since, version));
}

try {
// ktfmt v0.19 and later
return classLoader.loadClass(pkg + ".ktfmt.FormatterKt").getField("DROPBOX_FORMAT").get(null);
return classLoader.loadClass(pkg + ".ktfmt.FormatterKt").getField(style.getFormat()).get(null);
} catch (NoSuchFieldException ignored) {}

// fallback to old, pre-0.19 ktfmt interface.
Class<?> formattingOptionsCompanionClazz = classLoader.loadClass(pkg + ".ktfmt.FormattingOptions$Companion");
Object companion = formattingOptionsCompanionClazz.getConstructors()[0].newInstance((Object) null);
Method formattingOptionsMethod = formattingOptionsCompanionClazz.getDeclaredMethod(DROPBOX_STYLE_METHOD);
return formattingOptionsMethod.invoke(companion);
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);
return formattingOptionsMethod.invoke(companion);
} else {
throw new IllegalStateException("Versions pre-0.19 can only use Default and Dropbox styles");
}
}
}
}
2 changes: 2 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`).

## [Unreleased]
### Added
* Bump ktfmt to 0.21 and add support to Google and Kotlinlang formats ([#812](https://github.com/diffplug/spotless/pull/812))

## [5.10.2] - 2021-02-16
### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ public void dropboxStyle() {
style(Style.DROPBOX);
}

public void googleStyle() {
style(Style.GOOGLE);
}

public void kotlinlangStyle() {
style(Style.KOTLINLANG);
}

public void style(Style style) {
this.style = style;
replaceStep(createStep());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,23 @@ public class KtfmtConfig {
addStep(createStep());
}

public void dropboxStyle() {
style = Style.DROPBOX;
public void style(Style style) {
this.style = style;
replaceStep(createStep());
}

public void dropboxStyle() {
style(Style.DROPBOX);
}

public void googleStyle() {
style(Style.GOOGLE);
}

public void kotlinlangStyle() {
style(Style.KOTLINLANG);
}

private FormatterStep createStep() {
return KtfmtStep.create(version, provisioner(), style);
}
Expand Down
2 changes: 2 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Added
* Bump ktfmt to 0.21 and add support to Google and Kotlinlang formats ([#812](https://github.com/diffplug/spotless/pull/812))

## [2.8.1] - 2021-02-16
### Fixed
Expand Down