16
16
package com .diffplug .spotless ;
17
17
18
18
import java .io .File ;
19
+ import java .io .FileReader ;
20
+ import java .io .IOException ;
21
+ import java .io .Reader ;
19
22
import java .io .Serializable ;
20
23
import java .lang .reflect .Method ;
24
+ import java .nio .charset .StandardCharsets ;
21
25
import java .util .Objects ;
22
26
import java .util .function .Supplier ;
23
27
@@ -47,9 +51,11 @@ public Policy createPolicy() {
47
51
/** {@code \r\n} */
48
52
WINDOWS ,
49
53
/** {@code \n} */
50
- UNIX ,
54
+ UNIX ,
51
55
/** {@code \r} */
52
- MAC_CLASSIC ;
56
+ MAC_CLASSIC ,
57
+ /** preserve the line ending of the first line (no matter which format) */
58
+ PRESERVE ;
53
59
// @formatter:on
54
60
55
61
/** Returns a {@link Policy} appropriate for files which are contained within the given rootFolder. */
@@ -81,6 +87,7 @@ public Policy createPolicy() {
81
87
case WINDOWS : return WINDOWS_POLICY ;
82
88
case UNIX : return UNIX_POLICY ;
83
89
case MAC_CLASSIC : return MAC_CLASSIC_POLICY ;
90
+ case PRESERVE : return PRESERVE_POLICY ;
84
91
default : throw new UnsupportedOperationException (this + " is a path-specific line ending." );
85
92
}
86
93
}
@@ -100,9 +107,50 @@ public String getEndingFor(File file) {
100
107
}
101
108
}
102
109
110
+ static class PreserveLineEndingPolicy extends NoLambda .EqualityBasedOnSerialization implements Policy {
111
+ private static final long serialVersionUID = 2L ;
112
+
113
+ @ Override
114
+ public String getEndingFor (File file ) {
115
+ // assume US-ASCII encoding (only line ending characters need to be decoded anyways)
116
+ try (Reader reader = new FileReader (file , StandardCharsets .US_ASCII )) {
117
+ return getEndingFor (reader );
118
+ } catch (IOException e ) {
119
+ throw new IllegalArgumentException ("Could not determine line ending of file: " + file , e );
120
+ }
121
+ }
122
+
123
+ static String getEndingFor (Reader reader ) throws IOException {
124
+ char previousCharacter = 0 ;
125
+ char currentCharacter = 0 ;
126
+ int readResult ;
127
+ while ((readResult = reader .read ()) != -1 ) {
128
+ currentCharacter = (char )readResult ;
129
+ if (currentCharacter == '\n' ) {
130
+ if (previousCharacter == '\r' ) {
131
+ return WINDOWS .str ();
132
+ } else {
133
+ return UNIX .str ();
134
+ }
135
+ } else {
136
+ if (previousCharacter == '\r' ) {
137
+ return MAC_CLASSIC .str ();
138
+ }
139
+ }
140
+ previousCharacter = currentCharacter ;
141
+ }
142
+ if (previousCharacter == '\r' ) {
143
+ return MAC_CLASSIC .str ();
144
+ }
145
+ // assume UNIX line endings if no line ending was found
146
+ return UNIX .str ();
147
+ }
148
+ }
149
+
103
150
private static final Policy WINDOWS_POLICY = new ConstantLineEndingPolicy (WINDOWS .str ());
104
151
private static final Policy UNIX_POLICY = new ConstantLineEndingPolicy (UNIX .str ());
105
152
private static final Policy MAC_CLASSIC_POLICY = new ConstantLineEndingPolicy (MAC_CLASSIC .str ());
153
+ private static final Policy PRESERVE_POLICY = new PreserveLineEndingPolicy ();
106
154
private static final String _platformNative = System .getProperty ("line.separator" );
107
155
private static final Policy _platformNativePolicy = new ConstantLineEndingPolicy (_platformNative );
108
156
private static final boolean nativeIsWin = _platformNative .equals (WINDOWS .str ());
0 commit comments