From b618560fd4c69117d14f69e4c3cdbfafcc5d0060 Mon Sep 17 00:00:00 2001 From: Parker Mauney Date: Thu, 25 Nov 2021 13:09:35 -0600 Subject: [PATCH 1/2] Detect and preserve line separators Update `Formatter` so that line endings are now detected based on the contents of the file. This mirrors the behavior of the Eclipse plugin when used in the IDE, specifically the `nextDelimiterInfo` method in `org.eclipse.jface.text.DefaultLineTracker`. See gh-340 --- .../ProjectSettingsFilesTests.java | 3 ++- .../javaformat/gradle/CheckTaskTests.java | 16 +++++++++--- .../src/it/.gitattributes | 2 ++ .../io/spring/format/maven/VerifyApply.java | 2 +- .../src/test/resources/.gitattributes | 4 +++ .../test/resources/expected/correct-cr.txt | 1 + .../test/resources/expected/correct-crlf.txt | 9 +++++++ .../test/resources/expected/correct-lf.txt | 9 +++++++ .../src/test/resources/source/correct-cr.txt | 1 + .../test/resources/source/correct-crlf.txt | 9 +++++++ .../src/test/resources/source/correct-lf.txt | 9 +++++++ .../javaformat/formatter/Formatter.java | 26 +++++++++++++++++++ 12 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java index a75b92b1..20c06744 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java @@ -95,7 +95,8 @@ void applyToProjectWithFileMergesToDotSettings() throws Exception { }).given(projectFile).setContents((InputStream) any(), anyInt(), any()); files.applyToProject(project, monitor); verify(projectFile).setContents((InputStream) any(), eq(1), eq(monitor)); - assertThat(out.toString(StandardCharsets.UTF_8)).isEqualTo("a=b\ny=z\n"); + assertThat(out.toString(StandardCharsets.UTF_8)) + .isEqualToNormalizingNewlines("a=b\ny=z\n"); } private ProjectSettingsFile createPrefsFile() throws IOException { diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java index a5554177..0420e1c2 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java @@ -23,7 +23,7 @@ import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.Arrays; -import java.util.Collections; +import java.util.List; import java.util.stream.Stream; import org.gradle.testkit.runner.BuildResult; @@ -72,8 +72,8 @@ void whenFirstInvocationSucceedsAndSourceIsModifiedThenSecondInvocationSucceeds( GradleBuild gradleBuild = this.gradleBuild.source(this.temp); BuildResult result = gradleBuild.build("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); - Files.write(new File(this.temp, "src/main/java/simple/Simple.java").toPath(), - Collections.singletonList("// A change to the file"), StandardOpenOption.APPEND); + appendToFileNormalizingNewlines(new File(this.temp, "src/main/java/simple/Simple.java").toPath(), + "// A change to the file"); result = gradleBuild.build("--debug", "check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } @@ -146,4 +146,14 @@ private void copyFolder(Path source, Path target) throws IOException { } } + /** + * Uses a read/modify/truncate approach to append a line to a file. + * This avoids issues where the standard append option results in mixed line-endings. + */ + private void appendToFileNormalizingNewlines(Path sourceFilePath, String lineToAppend) throws IOException { + List lines = Files.readAllLines(sourceFilePath); + lines.add(lineToAppend); + Files.write(sourceFilePath, lines, StandardOpenOption.TRUNCATE_EXISTING); + } + } diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes new file mode 100644 index 00000000..525113da --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes @@ -0,0 +1,2 @@ +# Test resources that need a predictable eol +apply*/src/main/java/simple/Simple.java eol=lf diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java index 3707cfee..3f8e76e1 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java @@ -30,7 +30,7 @@ */ public class VerifyApply { - private static final String LF = System.lineSeparator(); + private static final String LF = "\n"; private static final String JAVA_FILE = "src/main/java/simple/Simple.java"; diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes new file mode 100644 index 00000000..95175246 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes @@ -0,0 +1,4 @@ +# Test resources that need specific eol +**/correct-crlf.txt eol=crlf +**/correct-cr.txt eol=cr +**/correct-lf.txt eol=lf diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt new file mode 100644 index 00000000..a72e4bf3 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt @@ -0,0 +1 @@ +package correct; public class CorrectCr { public static void main(String[] args) throws Exception { // FIXME } } \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt new file mode 100644 index 00000000..5a609678 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt @@ -0,0 +1,9 @@ +package correct; + +public class CorrectCrlf { + + public static void main(String[] args) throws Exception { + // FIXME + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt new file mode 100644 index 00000000..3b6208a2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt @@ -0,0 +1,9 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { + // FIXME + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt new file mode 100644 index 00000000..a72e4bf3 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt @@ -0,0 +1 @@ +package correct; public class CorrectCr { public static void main(String[] args) throws Exception { // FIXME } } \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt new file mode 100644 index 00000000..5a609678 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt @@ -0,0 +1,9 @@ +package correct; + +public class CorrectCrlf { + + public static void main(String[] args) throws Exception { + // FIXME + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt new file mode 100644 index 00000000..3b6208a2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt @@ -0,0 +1,9 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { + // FIXME + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java index 83f6406c..c76873cf 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java @@ -17,6 +17,8 @@ package io.spring.javaformat.formatter; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.jface.text.IRegion; import org.eclipse.text.edits.TextEdit; @@ -56,6 +58,11 @@ public class Formatter { */ private static final int DEFAULT_INDENTATION_LEVEL = 0; + /** + * Pattern that matches all line separators into named-capturing group "sep". + */ + private static final Pattern LINE_SEPARATOR_PATTERN = Pattern.compile("(?(\r\n|\r|\n))"); + /** * The default line separator. */ @@ -123,6 +130,9 @@ public TextEdit format(String source, int offset, int length, String lineSeparat public TextEdit format(int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) { + if (lineSeparator == null) { + lineSeparator = detectLineSeparator(source); + } return this.delegate.format(kind, source, offset, length, indentationLevel, lineSeparator); } @@ -148,6 +158,9 @@ public TextEdit format(String source, IRegion[] regions, String lineSeparator) { } public TextEdit format(int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) { + if (lineSeparator == null) { + lineSeparator = detectLineSeparator(source); + } return this.delegate.format(kind, source, regions, indentationLevel, lineSeparator); } @@ -159,4 +172,17 @@ public void setOptions(Map options) { this.delegate.setOptions(options); } + private String detectLineSeparator(String contents) { + Matcher matcher = LINE_SEPARATOR_PATTERN.matcher(contents); + if (!matcher.find()) { + return DEFAULT_LINE_SEPARATOR; + } + String firstMatch = matcher.group("sep"); + while (matcher.find()) { + if (!matcher.group("sep").equals(firstMatch)) { + return DEFAULT_LINE_SEPARATOR; + } + } + return firstMatch; + } } From f50024aca40d369443a5966e6eba81ce828590f6 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 15 Feb 2023 20:05:04 -0800 Subject: [PATCH 2/2] Polish 'Detect and preserve line separators' See gh-340 --- .../javaformat/gradle/CheckTaskTests.java | 28 ++++------- .../src/it/.gitattributes | 2 - .../io/spring/format/maven/VerifyApply.java | 18 +++---- .../formatter/AbstractFormatterTests.java | 49 +++++++++++++++++-- .../src/test/resources/.gitattributes | 4 -- .../test/resources/expected/correct-cr.txt | 1 - .../test/resources/expected/correct-crlf.txt | 9 ---- .../{correct-lf.txt => lineendings.txt} | 1 - .../src/test/resources/source/correct-cr.txt | 1 - .../test/resources/source/correct-crlf.txt | 9 ---- .../src/test/resources/source/correct-lf.txt | 9 ---- .../src/test/resources/source/lineendings.txt | 7 +++ .../javaformat/formatter/Formatter.java | 36 +++++--------- 13 files changed, 82 insertions(+), 92 deletions(-) delete mode 100644 spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes delete mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes delete mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt delete mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt rename spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/{correct-lf.txt => lineendings.txt} (90%) delete mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt delete mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt delete mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt create mode 100644 spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java index 0420e1c2..16d3aa4a 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java @@ -18,12 +18,11 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.Arrays; -import java.util.List; import java.util.stream.Stream; import org.gradle.testkit.runner.BuildResult; @@ -68,12 +67,12 @@ void whenFirstInvocationSucceedsThenSecondInvocationIsUpToDate() throws IOExcept @Test void whenFirstInvocationSucceedsAndSourceIsModifiedThenSecondInvocationSucceeds() throws IOException { - copyFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath()); + copyNormalizedFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath()); GradleBuild gradleBuild = this.gradleBuild.source(this.temp); BuildResult result = gradleBuild.build("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); - appendToFileNormalizingNewlines(new File(this.temp, "src/main/java/simple/Simple.java").toPath(), - "// A change to the file"); + Files.write(new File(this.temp, "src/main/java/simple/Simple.java").toPath(), + "// A change to the file\n".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND); result = gradleBuild.build("--debug", "check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } @@ -129,14 +128,17 @@ void whenFirstInvocationFailsThenSecondInvocationFails() throws IOException { assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); } - private void copyFolder(Path source, Path target) throws IOException { + private void copyNormalizedFolder(Path source, Path target) throws IOException { try (Stream stream = Files.walk(source)) { stream.forEach((child) -> { try { Path relative = source.relativize(child); Path destination = target.resolve(relative); - if (!destination.toFile().isDirectory()) { - Files.copy(child, destination, StandardCopyOption.REPLACE_EXISTING); + if (!Files.isDirectory(child)) { + String content = new String(Files.readAllBytes(child), StandardCharsets.UTF_8); + String normalized = content.replace("\n\r", "\n").replace('\r', '\n'); + Files.createDirectories(destination.getParent()); + Files.write(destination, normalized.getBytes(StandardCharsets.UTF_8)); } } catch (Exception ex) { @@ -146,14 +148,4 @@ private void copyFolder(Path source, Path target) throws IOException { } } - /** - * Uses a read/modify/truncate approach to append a line to a file. - * This avoids issues where the standard append option results in mixed line-endings. - */ - private void appendToFileNormalizingNewlines(Path sourceFilePath, String lineToAppend) throws IOException { - List lines = Files.readAllLines(sourceFilePath); - lines.add(lineToAppend); - Files.write(sourceFilePath, lines, StandardOpenOption.TRUNCATE_EXISTING); - } - } diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes deleted file mode 100644 index 525113da..00000000 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Test resources that need a predictable eol -apply*/src/main/java/simple/Simple.java eol=lf diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java index 3f8e76e1..bb7871ec 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,16 +30,14 @@ */ public class VerifyApply { - private static final String LF = "\n"; - private static final String JAVA_FILE = "src/main/java/simple/Simple.java"; public void verify(File base) throws IOException { - verify(base, LF); + verify(base, null); } public void verify(File base, boolean spaces) throws IOException { - verify(base, LF, spaces); + verify(base, null, spaces); } public void verify(File base, String lineSeparator) throws IOException { @@ -48,16 +46,14 @@ public void verify(File base, String lineSeparator) throws IOException { public void verify(File base, String lineSeparator, boolean spaces) throws IOException { String formated = new String(Files.readAllBytes(base.toPath().resolve(JAVA_FILE)), StandardCharsets.UTF_8); + if (lineSeparator == null) { + formated = formated.replace("\r\n", "\n").replace('\r', '\n'); + lineSeparator = "\n"; + } String indent = (!spaces) ? " " : " "; assertThat(formated).contains("Simple." + lineSeparator + " *" + lineSeparator + " * @author") .contains("public class Simple {") .contains(indent + "public static void main"); } - public static void main(String[] args) throws IOException { - new VerifyApply().verify(new File( - "/Users/pwebb/projects/spring-javaformat/code/spring-javaformat-maven/spring-javaformat-maven-plugin/target/it/apply-line-separator"), - "\r"); - } - } diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java index f039acfd..445daff9 100644 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,11 @@ package io.spring.javaformat.formatter; import java.io.File; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; import io.spring.javaformat.config.JavaBaseline; import io.spring.javaformat.config.JavaFormatConfig; @@ -47,7 +48,7 @@ protected final String read(File file) throws Exception { } protected static Item[] items(String expectedOverride) { - Collection items = new ArrayList<>(); + List items = new ArrayList<>(); File sourceDir = new File("src/test/resources/source"); File expectedDir = new File("src/test/resources/expected"); File configDir = new File("src/test/resources/config"); @@ -59,12 +60,52 @@ protected static Item[] items(String expectedOverride) { } File config = new File(configDir, source.getName()); for (JavaBaseline javaBaseline : JavaBaseline.values()) { - items.add(new Item(javaBaseline, source, expected, config)); + addItem(items, javaBaseline, source, expected, config); } } return items.toArray(new Item[0]); } + private static void addItem(List items, JavaBaseline javaBaseline, File source, File expected, File config) { + if (source.getName().contains("lineendings")) { + items.add(new Item(javaBaseline, copy(source, LineEnding.CR), copy(expected, LineEnding.CR), config)); + items.add(new Item(javaBaseline, copy(source, LineEnding.LF), copy(expected, LineEnding.LF), config)); + items.add(new Item(javaBaseline, copy(source, LineEnding.CRLF), copy(expected, LineEnding.CRLF), config)); + } + else { + items.add(new Item(javaBaseline, source, expected, config)); + } + } + + private static File copy(File file, LineEnding lineEnding) { + try { + String[] name = file.getName().split("\\."); + File result = File.createTempFile(name[0] + "_" + lineEnding + "_", "." + name[1]); + String content = Files.readString(file.toPath()); + content = content.replace("\r\n", "\n").replace('\r', '\n').replace("\n", lineEnding.ending()); + Files.writeString(result.toPath(), content); + return result; + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + enum LineEnding { + + CR("\r"), LF("\n"), CRLF("\r\n"); + + private final String ending; + + LineEnding(String ending) { + this.ending = ending; + } + + String ending() { + return this.ending; + } + }; + static class Item { private final JavaBaseline javaBaseline; diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes deleted file mode 100644 index 95175246..00000000 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -# Test resources that need specific eol -**/correct-crlf.txt eol=crlf -**/correct-cr.txt eol=cr -**/correct-lf.txt eol=lf diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt deleted file mode 100644 index a72e4bf3..00000000 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-cr.txt +++ /dev/null @@ -1 +0,0 @@ -package correct; public class CorrectCr { public static void main(String[] args) throws Exception { // FIXME } } \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt deleted file mode 100644 index 5a609678..00000000 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-crlf.txt +++ /dev/null @@ -1,9 +0,0 @@ -package correct; - -public class CorrectCrlf { - - public static void main(String[] args) throws Exception { - // FIXME - } - -} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt similarity index 90% rename from spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt index 3b6208a2..92ad853f 100644 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/correct-lf.txt +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt @@ -3,7 +3,6 @@ package correct; public class CorrectLf { public static void main(String[] args) throws Exception { - // FIXME } } diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt deleted file mode 100644 index a72e4bf3..00000000 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-cr.txt +++ /dev/null @@ -1 +0,0 @@ -package correct; public class CorrectCr { public static void main(String[] args) throws Exception { // FIXME } } \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt deleted file mode 100644 index 5a609678..00000000 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-crlf.txt +++ /dev/null @@ -1,9 +0,0 @@ -package correct; - -public class CorrectCrlf { - - public static void main(String[] args) throws Exception { - // FIXME - } - -} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt deleted file mode 100644 index 3b6208a2..00000000 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/correct-lf.txt +++ /dev/null @@ -1,9 +0,0 @@ -package correct; - -public class CorrectLf { - - public static void main(String[] args) throws Exception { - // FIXME - } - -} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt new file mode 100644 index 00000000..e56b3941 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt @@ -0,0 +1,7 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java index c76873cf..97d20003 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,6 @@ package io.spring.javaformat.formatter; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.eclipse.jface.text.IRegion; import org.eclipse.text.edits.TextEdit; @@ -58,11 +56,6 @@ public class Formatter { */ private static final int DEFAULT_INDENTATION_LEVEL = 0; - /** - * Pattern that matches all line separators into named-capturing group "sep". - */ - private static final Pattern LINE_SEPARATOR_PATTERN = Pattern.compile("(?(\r\n|\r|\n))"); - /** * The default line separator. */ @@ -130,9 +123,7 @@ public TextEdit format(String source, int offset, int length, String lineSeparat public TextEdit format(int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) { - if (lineSeparator == null) { - lineSeparator = detectLineSeparator(source); - } + lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source); return this.delegate.format(kind, source, offset, length, indentationLevel, lineSeparator); } @@ -158,9 +149,7 @@ public TextEdit format(String source, IRegion[] regions, String lineSeparator) { } public TextEdit format(int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) { - if (lineSeparator == null) { - lineSeparator = detectLineSeparator(source); - } + lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source); return this.delegate.format(kind, source, regions, indentationLevel, lineSeparator); } @@ -173,16 +162,17 @@ public void setOptions(Map options) { } private String detectLineSeparator(String contents) { - Matcher matcher = LINE_SEPARATOR_PATTERN.matcher(contents); - if (!matcher.find()) { - return DEFAULT_LINE_SEPARATOR; - } - String firstMatch = matcher.group("sep"); - while (matcher.find()) { - if (!matcher.group("sep").equals(firstMatch)) { - return DEFAULT_LINE_SEPARATOR; + int length = contents.length(); + for (int i = 0; i < length; i++) { + char ch = contents.charAt(i); + boolean isLastChar = (i + 1) == length; + if (ch == '\r') { + return (isLastChar || contents.charAt(i + 1) != '\n') ? "\r" : "\r\n"; + } + if (ch == '\n') { + return "\n"; } } - return firstMatch; + return null; } }