1
- use crate :: NewlineStyle ;
1
+ use crate :: { FileName , NewlineStyle } ;
2
+ use std:: borrow:: Cow ;
3
+ use std:: fs;
2
4
3
5
/// Apply this newline style to the formatted text. When the style is set
4
- /// to `Auto`, the `raw_input_text` is used to detect the existing line
5
- /// endings.
6
+ /// to `Auto`, the `path` and `raw_input_text` are used to detect the existing line
7
+ /// endings. The `path` is prefered when present, and the `raw_input_text` is used
8
+ /// when the input was passed from stdin, or we fail to read the file content from the `path`.
6
9
///
7
- /// If the style is set to `Auto` and `raw_input_text` contains no
10
+ /// If the style is set to `Auto` and `path` or ` raw_input_text` contain no
8
11
/// newlines, the `Native` style will be used.
9
12
pub ( crate ) fn apply_newline_style (
10
13
newline_style : NewlineStyle ,
14
+ path : & FileName ,
11
15
formatted_text : & mut String ,
12
16
raw_input_text : & str ,
13
17
) {
14
- * formatted_text = match effective_newline_style ( newline_style, raw_input_text) {
18
+ * formatted_text = match effective_newline_style ( newline_style, path , raw_input_text) {
15
19
EffectiveNewlineStyle :: Windows => convert_to_windows_newlines ( formatted_text) ,
16
20
EffectiveNewlineStyle :: Unix => convert_to_unix_newlines ( formatted_text) ,
17
21
}
@@ -25,10 +29,19 @@ enum EffectiveNewlineStyle {
25
29
26
30
fn effective_newline_style (
27
31
newline_style : NewlineStyle ,
32
+ path : & FileName ,
28
33
raw_input_text : & str ,
29
34
) -> EffectiveNewlineStyle {
30
35
match newline_style {
31
- NewlineStyle :: Auto => auto_detect_newline_style ( raw_input_text) ,
36
+ NewlineStyle :: Auto => match path. as_path ( ) {
37
+ Some ( path) => auto_detect_newline_style (
38
+ & fs:: read_to_string ( path)
39
+ . map ( |s| Cow :: Owned ( s) )
40
+ . unwrap_or_else ( |_| Cow :: Borrowed ( raw_input_text) ) ,
41
+ ) ,
42
+ None => auto_detect_newline_style ( raw_input_text) ,
43
+ } ,
44
+
32
45
NewlineStyle :: Native => native_newline_style ( ) ,
33
46
NewlineStyle :: Windows => EffectiveNewlineStyle :: Windows ,
34
47
NewlineStyle :: Unix => EffectiveNewlineStyle :: Unix ,
@@ -84,6 +97,8 @@ fn convert_to_unix_newlines(formatted_text: &str) -> String {
84
97
#[ cfg( test) ]
85
98
mod tests {
86
99
use super :: * ;
100
+ use std:: fs;
101
+ use tempdir:: TempDir ;
87
102
88
103
#[ test]
89
104
fn auto_detects_unix_newlines ( ) {
@@ -128,7 +143,28 @@ mod tests {
128
143
let raw_input_text = "One\n Two\n Three" ;
129
144
130
145
let mut out = String :: from ( formatted_text) ;
131
- apply_newline_style ( NewlineStyle :: Auto , & mut out, raw_input_text) ;
146
+ apply_newline_style (
147
+ NewlineStyle :: Auto ,
148
+ & FileName :: Stdin ,
149
+ & mut out,
150
+ raw_input_text,
151
+ ) ;
152
+ assert_eq ! ( "One\n Two\n Three" , & out, "auto should detect 'lf'" ) ;
153
+ }
154
+
155
+ #[ test]
156
+ fn auto_detects_and_applies_unix_newlines_from_real_file ( ) {
157
+ let formatted_text = "One\n Two\n Three" ;
158
+ let raw_input_text = "One\n Two\n Three" ;
159
+
160
+ let tmpdir = TempDir :: new ( "unix_newlines_from_real_file" ) . unwrap ( ) ;
161
+ let path = tmpdir. path ( ) . join ( "test.rs" ) ;
162
+ fs:: write ( & path, raw_input_text) . unwrap ( ) ;
163
+
164
+ let path = FileName :: Real ( path) ;
165
+
166
+ let mut out = String :: from ( formatted_text) ;
167
+ apply_newline_style ( NewlineStyle :: Auto , & path, & mut out, raw_input_text) ;
132
168
assert_eq ! ( "One\n Two\n Three" , & out, "auto should detect 'lf'" ) ;
133
169
}
134
170
@@ -138,17 +174,81 @@ mod tests {
138
174
let raw_input_text = "One\r \n Two\r \n Three" ;
139
175
140
176
let mut out = String :: from ( formatted_text) ;
141
- apply_newline_style ( NewlineStyle :: Auto , & mut out, raw_input_text) ;
177
+ apply_newline_style (
178
+ NewlineStyle :: Auto ,
179
+ & FileName :: Stdin ,
180
+ & mut out,
181
+ raw_input_text,
182
+ ) ;
142
183
assert_eq ! ( "One\r \n Two\r \n Three" , & out, "auto should detect 'crlf'" ) ;
143
184
}
144
185
186
+ #[ test]
187
+ fn auto_detects_and_applies_windows_newlines_from_real_file ( ) {
188
+ let formatted_text = "One\n Two\n Three" ;
189
+ let raw_input_text = "One\r \n Two\r \n Three" ;
190
+
191
+ let tmpdir = TempDir :: new ( "windows_newlines_from_real_file" ) . unwrap ( ) ;
192
+ let path = tmpdir. path ( ) . join ( "test.rs" ) ;
193
+ fs:: write ( & path, raw_input_text) . unwrap ( ) ;
194
+
195
+ let path = FileName :: Real ( path) ;
196
+
197
+ let mut out = String :: from ( formatted_text) ;
198
+ apply_newline_style ( NewlineStyle :: Auto , & path, & mut out, raw_input_text) ;
199
+ assert_eq ! ( "One\r \n Two\r \n Three" , & out, "auto should detect 'crlf'" ) ;
200
+ }
201
+
202
+ #[ test]
203
+ fn auto_detect_and_applies_windows_newlines_if_windows_newlines_read_from_file ( ) {
204
+ // Even if the `raw_input_text` does not contain crlf chars, we should still apply
205
+ // Them if we can read crlf from the input `FileName::Real(path)`.
206
+ // see issue https://github.com/rust-lang/rustfmt/issues/4097
207
+ let text = "One\n Two\n Three" ;
208
+
209
+ let tmpdir = TempDir :: new ( "windows_newlines_if_windows_newlines_read_from_file" ) . unwrap ( ) ;
210
+ let path = tmpdir. path ( ) . join ( "test.rs" ) ;
211
+ fs:: write ( & path, "One\r \n Two\r \n Three" ) . unwrap ( ) ;
212
+
213
+ let path = FileName :: Real ( path) ;
214
+
215
+ let mut out = String :: from ( text) ;
216
+ // Note that the source file contains `crlf`, while the `raw_input_text` contains `lf`
217
+ apply_newline_style ( NewlineStyle :: Auto , & path, & mut out, text) ;
218
+ assert_eq ! ( "One\r \n Two\r \n Three" , & out, "auto should detect 'crlf'" ) ;
219
+ }
220
+
221
+ #[ test]
222
+ fn auto_detect_and_applies_unix_newlines_if_unix_newlines_read_from_file ( ) {
223
+ // This following test is unlikely to happen in practice, but it is meant to illustrate
224
+ // that line endings found in the source files take precedence over the `raw_input_text`
225
+ // passed to apply_newline_style.
226
+ let text = "One\r \n Two\r \n Three" ;
227
+
228
+ let tmpdir = TempDir :: new ( "unix_newlines_if_unix_newlines_read_from_file" ) . unwrap ( ) ;
229
+ let path = tmpdir. path ( ) . join ( "test.rs" ) ;
230
+ fs:: write ( & path, "One\n Two\n Three" ) . unwrap ( ) ;
231
+
232
+ let path = FileName :: Real ( path) ;
233
+
234
+ let mut out = String :: from ( text) ;
235
+ // Note that the source file contains `lf`, while the `raw_input_text` contains `crlf`
236
+ apply_newline_style ( NewlineStyle :: Auto , & path, & mut out, text) ;
237
+ assert_eq ! ( "One\n Two\n Three" , & out, "auto should detect 'crlf'" ) ;
238
+ }
239
+
145
240
#[ test]
146
241
fn auto_detects_and_applies_native_newlines ( ) {
147
242
let formatted_text = "One\n Two\n Three" ;
148
243
let raw_input_text = "One Two Three" ;
149
244
150
245
let mut out = String :: from ( formatted_text) ;
151
- apply_newline_style ( NewlineStyle :: Auto , & mut out, raw_input_text) ;
246
+ apply_newline_style (
247
+ NewlineStyle :: Auto ,
248
+ & FileName :: Stdin ,
249
+ & mut out,
250
+ raw_input_text,
251
+ ) ;
152
252
153
253
if cfg ! ( windows) {
154
254
assert_eq ! (
@@ -244,7 +344,7 @@ mod tests {
244
344
newline_style : NewlineStyle ,
245
345
) {
246
346
let mut out = String :: from ( input) ;
247
- apply_newline_style ( newline_style, & mut out, input) ;
347
+ apply_newline_style ( newline_style, & FileName :: Stdin , & mut out, input) ;
248
348
assert_eq ! ( expected, & out) ;
249
349
}
250
350
}
0 commit comments