Skip to content

Commit 097bb33

Browse files
committed
Merge pull request #340 from ParkerM
* pr/340: Polish 'Detect and preserve line separators' Detect and preserve line separators Closes gh-340
2 parents b543266 + f50024a commit 097bb33

File tree

7 files changed

+95
-24
lines changed

7 files changed

+95
-24
lines changed

spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ void applyToProjectWithFileMergesToDotSettings() throws Exception {
9595
}).given(projectFile).setContents((InputStream) any(), anyInt(), any());
9696
files.applyToProject(project, monitor);
9797
verify(projectFile).setContents((InputStream) any(), eq(1), eq(monitor));
98-
assertThat(out.toString(StandardCharsets.UTF_8)).isEqualTo("a=b\ny=z\n");
98+
assertThat(out.toString(StandardCharsets.UTF_8))
99+
.isEqualToNormalizingNewlines("a=b\ny=z\n");
99100
}
100101

101102
private ProjectSettingsFile createPrefsFile() throws IOException {

spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java

+9-7
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.nio.charset.StandardCharsets;
2122
import java.nio.file.Files;
2223
import java.nio.file.Path;
23-
import java.nio.file.StandardCopyOption;
2424
import java.nio.file.StandardOpenOption;
2525
import java.util.Arrays;
26-
import java.util.Collections;
2726
import java.util.stream.Stream;
2827

2928
import org.gradle.testkit.runner.BuildResult;
@@ -68,12 +67,12 @@ void whenFirstInvocationSucceedsThenSecondInvocationIsUpToDate() throws IOExcept
6867

6968
@Test
7069
void whenFirstInvocationSucceedsAndSourceIsModifiedThenSecondInvocationSucceeds() throws IOException {
71-
copyFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath());
70+
copyNormalizedFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath());
7271
GradleBuild gradleBuild = this.gradleBuild.source(this.temp);
7372
BuildResult result = gradleBuild.build("check");
7473
assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
7574
Files.write(new File(this.temp, "src/main/java/simple/Simple.java").toPath(),
76-
Collections.singletonList("// A change to the file"), StandardOpenOption.APPEND);
75+
"// A change to the file\n".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
7776
result = gradleBuild.build("--debug", "check");
7877
assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
7978
}
@@ -129,14 +128,17 @@ void whenFirstInvocationFailsThenSecondInvocationFails() throws IOException {
129128
assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED);
130129
}
131130

132-
private void copyFolder(Path source, Path target) throws IOException {
131+
private void copyNormalizedFolder(Path source, Path target) throws IOException {
133132
try (Stream<Path> stream = Files.walk(source)) {
134133
stream.forEach((child) -> {
135134
try {
136135
Path relative = source.relativize(child);
137136
Path destination = target.resolve(relative);
138-
if (!destination.toFile().isDirectory()) {
139-
Files.copy(child, destination, StandardCopyOption.REPLACE_EXISTING);
137+
if (!Files.isDirectory(child)) {
138+
String content = new String(Files.readAllBytes(child), StandardCharsets.UTF_8);
139+
String normalized = content.replace("\n\r", "\n").replace('\r', '\n');
140+
Files.createDirectories(destination.getParent());
141+
Files.write(destination, normalized.getBytes(StandardCharsets.UTF_8));
140142
}
141143
}
142144
catch (Exception ex) {

spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java

+7-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,16 +30,14 @@
3030
*/
3131
public class VerifyApply {
3232

33-
private static final String LF = System.lineSeparator();
34-
3533
private static final String JAVA_FILE = "src/main/java/simple/Simple.java";
3634

3735
public void verify(File base) throws IOException {
38-
verify(base, LF);
36+
verify(base, null);
3937
}
4038

4139
public void verify(File base, boolean spaces) throws IOException {
42-
verify(base, LF, spaces);
40+
verify(base, null, spaces);
4341
}
4442

4543
public void verify(File base, String lineSeparator) throws IOException {
@@ -48,16 +46,14 @@ public void verify(File base, String lineSeparator) throws IOException {
4846

4947
public void verify(File base, String lineSeparator, boolean spaces) throws IOException {
5048
String formated = new String(Files.readAllBytes(base.toPath().resolve(JAVA_FILE)), StandardCharsets.UTF_8);
49+
if (lineSeparator == null) {
50+
formated = formated.replace("\r\n", "\n").replace('\r', '\n');
51+
lineSeparator = "\n";
52+
}
5153
String indent = (!spaces) ? " " : " ";
5254
assertThat(formated).contains("Simple." + lineSeparator + " *" + lineSeparator + " * @author")
5355
.contains("public class Simple {")
5456
.contains(indent + "public static void main");
5557
}
5658

57-
public static void main(String[] args) throws IOException {
58-
new VerifyApply().verify(new File(
59-
"/Users/pwebb/projects/spring-javaformat/code/spring-javaformat-maven/spring-javaformat-maven-plugin/target/it/apply-line-separator"),
60-
"\r");
61-
}
62-
6359
}

spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java

+45-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,10 +17,11 @@
1717
package io.spring.javaformat.formatter;
1818

1919
import java.io.File;
20+
import java.io.IOException;
2021
import java.nio.charset.StandardCharsets;
2122
import java.nio.file.Files;
2223
import java.util.ArrayList;
23-
import java.util.Collection;
24+
import java.util.List;
2425

2526
import io.spring.javaformat.config.JavaBaseline;
2627
import io.spring.javaformat.config.JavaFormatConfig;
@@ -47,7 +48,7 @@ protected final String read(File file) throws Exception {
4748
}
4849

4950
protected static Item[] items(String expectedOverride) {
50-
Collection<Item> items = new ArrayList<>();
51+
List<Item> items = new ArrayList<>();
5152
File sourceDir = new File("src/test/resources/source");
5253
File expectedDir = new File("src/test/resources/expected");
5354
File configDir = new File("src/test/resources/config");
@@ -59,12 +60,52 @@ protected static Item[] items(String expectedOverride) {
5960
}
6061
File config = new File(configDir, source.getName());
6162
for (JavaBaseline javaBaseline : JavaBaseline.values()) {
62-
items.add(new Item(javaBaseline, source, expected, config));
63+
addItem(items, javaBaseline, source, expected, config);
6364
}
6465
}
6566
return items.toArray(new Item[0]);
6667
}
6768

69+
private static void addItem(List<Item> items, JavaBaseline javaBaseline, File source, File expected, File config) {
70+
if (source.getName().contains("lineendings")) {
71+
items.add(new Item(javaBaseline, copy(source, LineEnding.CR), copy(expected, LineEnding.CR), config));
72+
items.add(new Item(javaBaseline, copy(source, LineEnding.LF), copy(expected, LineEnding.LF), config));
73+
items.add(new Item(javaBaseline, copy(source, LineEnding.CRLF), copy(expected, LineEnding.CRLF), config));
74+
}
75+
else {
76+
items.add(new Item(javaBaseline, source, expected, config));
77+
}
78+
}
79+
80+
private static File copy(File file, LineEnding lineEnding) {
81+
try {
82+
String[] name = file.getName().split("\\.");
83+
File result = File.createTempFile(name[0] + "_" + lineEnding + "_", "." + name[1]);
84+
String content = Files.readString(file.toPath());
85+
content = content.replace("\r\n", "\n").replace('\r', '\n').replace("\n", lineEnding.ending());
86+
Files.writeString(result.toPath(), content);
87+
return result;
88+
}
89+
catch (IOException ex) {
90+
throw new IllegalStateException(ex);
91+
}
92+
}
93+
94+
enum LineEnding {
95+
96+
CR("\r"), LF("\n"), CRLF("\r\n");
97+
98+
private final String ending;
99+
100+
LineEnding(String ending) {
101+
this.ending = ending;
102+
}
103+
104+
String ending() {
105+
return this.ending;
106+
}
107+
};
108+
68109
static class Item {
69110

70111
private final JavaBaseline javaBaseline;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package correct;
2+
3+
public class CorrectLf {
4+
5+
public static void main(String[] args) throws Exception {
6+
}
7+
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package correct;
2+
3+
public class CorrectLf {
4+
5+
public static void main(String[] args) throws Exception { }
6+
7+
}

spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -123,6 +123,7 @@ public TextEdit format(String source, int offset, int length, String lineSeparat
123123

124124
public TextEdit format(int kind, String source, int offset, int length, int indentationLevel,
125125
String lineSeparator) {
126+
lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source);
126127
return this.delegate.format(kind, source, offset, length, indentationLevel, lineSeparator);
127128
}
128129

@@ -148,6 +149,7 @@ public TextEdit format(String source, IRegion[] regions, String lineSeparator) {
148149
}
149150

150151
public TextEdit format(int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) {
152+
lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source);
151153
return this.delegate.format(kind, source, regions, indentationLevel, lineSeparator);
152154
}
153155

@@ -159,4 +161,18 @@ public void setOptions(Map<String, String> options) {
159161
this.delegate.setOptions(options);
160162
}
161163

164+
private String detectLineSeparator(String contents) {
165+
int length = contents.length();
166+
for (int i = 0; i < length; i++) {
167+
char ch = contents.charAt(i);
168+
boolean isLastChar = (i + 1) == length;
169+
if (ch == '\r') {
170+
return (isLastChar || contents.charAt(i + 1) != '\n') ? "\r" : "\r\n";
171+
}
172+
if (ch == '\n') {
173+
return "\n";
174+
}
175+
}
176+
return null;
177+
}
162178
}

0 commit comments

Comments
 (0)