Skip to content

Commit

Permalink
Add LineEnding.PRESERVE policy (#2304)
Browse files Browse the repository at this point in the history
  • Loading branch information
nedtwigg authored Oct 20, 2024
2 parents 4d35c32 + 71c61e0 commit b307c97
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 5 deletions.
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
* Support for line ending policy `PRESERVE` which just takes the first line ending of every given file as setting (no matter if `\n`, `\r\n` or `\r`) ([#2304](https://github.com/diffplug/spotless/pull/2304))
### Fixed
* `ktlint` steps now read from the `string` instead of the `file` so they don't clobber earlier steps. (fixes [#1599](https://github.com/diffplug/spotless/issues/1599))

Expand Down
52 changes: 50 additions & 2 deletions lib/src/main/java/com/diffplug/spotless/LineEnding.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 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 @@ -16,8 +16,12 @@
package com.diffplug.spotless;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.Supplier;

Expand Down Expand Up @@ -49,7 +53,9 @@ public Policy createPolicy() {
/** {@code \n} */
UNIX,
/** {@code \r} */
MAC_CLASSIC;
MAC_CLASSIC,
/** preserve the line ending of the first line (no matter which format) */
PRESERVE;
// @formatter:on

/** Returns a {@link Policy} appropriate for files which are contained within the given rootFolder. */
Expand Down Expand Up @@ -81,6 +87,7 @@ public Policy createPolicy() {
case WINDOWS: return WINDOWS_POLICY;
case UNIX: return UNIX_POLICY;
case MAC_CLASSIC: return MAC_CLASSIC_POLICY;
case PRESERVE: return PRESERVE_POLICY;
default: throw new UnsupportedOperationException(this + " is a path-specific line ending.");
}
}
Expand All @@ -100,9 +107,50 @@ public String getEndingFor(File file) {
}
}

static class PreserveLineEndingPolicy extends NoLambda.EqualityBasedOnSerialization implements Policy {
private static final long serialVersionUID = 2L;

@Override
public String getEndingFor(File file) {
// assume US-ASCII encoding (only line ending characters need to be decoded anyways)
try (Reader reader = new FileReader(file, StandardCharsets.US_ASCII)) {
return getEndingFor(reader);
} catch (IOException e) {
throw new IllegalArgumentException("Could not determine line ending of file: " + file, e);
}
}

static String getEndingFor(Reader reader) throws IOException {
char previousCharacter = 0;
char currentCharacter = 0;
int readResult;
while ((readResult = reader.read()) != -1) {
currentCharacter = (char)readResult;
if (currentCharacter == '\n') {
if (previousCharacter == '\r') {
return WINDOWS.str();
} else {
return UNIX.str();
}
} else {
if (previousCharacter == '\r') {
return MAC_CLASSIC.str();
}
}
previousCharacter = currentCharacter;
}
if (previousCharacter == '\r') {
return MAC_CLASSIC.str();
}
// assume UNIX line endings if no line ending was found
return UNIX.str();
}
}

private static final Policy WINDOWS_POLICY = new ConstantLineEndingPolicy(WINDOWS.str());
private static final Policy UNIX_POLICY = new ConstantLineEndingPolicy(UNIX.str());
private static final Policy MAC_CLASSIC_POLICY = new ConstantLineEndingPolicy(MAC_CLASSIC.str());
private static final Policy PRESERVE_POLICY = new PreserveLineEndingPolicy();
private static final String _platformNative = System.getProperty("line.separator");
private static final Policy _platformNativePolicy = new ConstantLineEndingPolicy(_platformNative);
private static final boolean nativeIsWin = _platformNative.equals(WINDOWS.str());
Expand Down
50 changes: 50 additions & 0 deletions lib/src/test/java/com/diffplug/spotless/LineEndingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2024 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;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class LineEndingTest {

@Test
void testGetEndingFor() throws IOException {
assertLineEnding("\r", "\r");
assertLineEnding("\r", "Test\r");
assertLineEnding("\r", "Test\rTest2\n");

assertLineEnding("\n", "Test");

assertLineEnding("\r\n", "\r\n");
assertLineEnding("\r\n", "Test\r\n");
assertLineEnding("\r\n", "Test\r\nTest2\n");

assertLineEnding("\n", "\n");
assertLineEnding("\n", "Test\n");
assertLineEnding("\n", "Test\nTest2\r");
assertLineEnding("\n", "\n\t");
}

static void assertLineEnding(String ending, String input) throws IOException {
try (Reader reader = new StringReader(input)) {
Assertions.assertEquals(ending, LineEnding.PreserveLineEndingPolicy.getEndingFor(reader));
}
}
}
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
* Support for line ending policy `PRESERVE` which just takes the first line ending of every given file as setting (no matter if `\n`, `\r\n` or `\r`) ([#2304](https://github.com/diffplug/spotless/pull/2304))
### Fixed
* `ktlint` steps now read from the `string` instead of the `file` so they don't clobber earlier steps. (fixes [#1599](https://github.com/diffplug/spotless/issues/1599))

Expand Down
8 changes: 7 additions & 1 deletion plugin-gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1577,7 +1577,13 @@ spotless {
encoding 'Cp1252' // except java, which will be Cp1252
```

Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `MAC_CLASSIC`, `PLATFORM_NATIVE`, `GIT_ATTRIBUTES`, and `GIT_ATTRIBUTES_FAST_ALLSAME`. The default value is `GIT_ATTRIBUTES_FAST_ALLSAME`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. `FAST_ALLSAME` just means that Spotless can assume that every file being formatted has the same line endings ([more info](https://github.com/diffplug/spotless/pull/1838)).
Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports

- constant modes (`UNIX`, `WINDOWS`, `MAC_CLASSIC`)
- simple modes (`PLATFORM_NATIVE`, `PRESERVE`)
- and git-aware modes (`GIT_ATTRIBUTES`, `GIT_ATTRIBUTES_FAST_ALLSAME`)

The default value is `GIT_ATTRIBUTES_FAST_ALLSAME`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. `FAST_ALLSAME` just means that Spotless can assume that every file being formatted has the same line endings ([more info](https://github.com/diffplug/spotless/pull/1838)).
You can easily set the line endings of different files using [a `.gitattributes` file](https://help.github.com/articles/dealing-with-line-endings/). Here's an example `.gitattributes` which sets all files to unix newlines: `* text eol=lf`.

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
* Support for line ending policy `PRESERVE` which just takes the first line ending of every given file as setting (no matter if `\n`, `\r\n` or `\r`) ([#2304](https://github.com/diffplug/spotless/pull/2304))
### Fixed
* `ktlint` steps now read from the `string` instead of the `file` so they don't clobber earlier steps. (fixes [#1599](https://github.com/diffplug/spotless/issues/1599))

Expand Down
10 changes: 8 additions & 2 deletions plugin-maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1784,9 +1784,15 @@ Spotless uses UTF-8 by default, but you can use [any encoding which Java support
</configuration>
```

Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `MAC_CLASSIC`, `PLATFORM_NATIVE`, `GIT_ATTRIBUTES`, and `GIT_ATTRIBUTES_FAST_ALLSAME`. The default value is `GIT_ATTRIBUTES_FAST_ALLSAME`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. `FAST_ALLSAME` just means that Spotless can assume that every file being formatted has the same line endings ([more info](https://github.com/diffplug/spotless/pull/1838)).
Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports

You can easily set the line endings of different files using [a `.gitattributes` file](https://help.github.com/articles/dealing-with-line-endings/). Here's an example `.gitattributes` which sets all files to unix newlines: `* text eol=lf`.
- constant modes (`UNIX`, `WINDOWS`, `MAC_CLASSIC`)
- simple modes (`PLATFORM_NATIVE`, `PRESERVE`)
- and git-aware modes (`GIT_ATTRIBUTES`, `GIT_ATTRIBUTES_FAST_ALLSAME`)

The default value is `GIT_ATTRIBUTES_FAST_ALLSAME`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. `FAST_ALLSAME` just means that Spotless can assume that every file being formatted has the same line endings ([more info](https://github.com/diffplug/spotless/pull/1838)).

You can easily set the line endings of different files using [a `.gitattributes` file](https://help.github.com/articles/dealing-with-line-endings/). Here's an example `.gitattributes` which sets all files to unix newlines: `* text eol=lf`.

<a name="enforceCheck"></a>

Expand Down

0 comments on commit b307c97

Please sign in to comment.