]> git.lizzy.rs Git - rust.git/blob - src/formatting/newline_style.rs
Introduce effective newline style
[rust.git] / src / formatting / newline_style.rs
1 use crate::NewlineStyle;
2
3 /// 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 ///
7 /// If the style is set to `Auto` and `raw_input_text` contains no
8 /// newlines, the `Native` style will be used.
9 pub(crate) fn apply_newline_style(
10     newline_style: NewlineStyle,
11     formatted_text: &mut String,
12     raw_input_text: &str,
13 ) {
14     match effective_newline_style(newline_style, raw_input_text) {
15         EffectiveNewlineStyle::Windows => {
16             let mut transformed = String::with_capacity(2 * formatted_text.capacity());
17             for c in formatted_text.chars() {
18                 match c {
19                     '\n' => transformed.push_str("\r\n"),
20                     '\r' => continue,
21                     c => transformed.push(c),
22                 }
23             }
24             *formatted_text = transformed;
25         }
26         EffectiveNewlineStyle::Unix => {}
27     }
28 }
29
30 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
31 enum EffectiveNewlineStyle {
32     Windows,
33     Unix,
34 }
35
36 fn effective_newline_style(
37     newline_style: NewlineStyle,
38     raw_input_text: &str,
39 ) -> EffectiveNewlineStyle {
40     match newline_style {
41         NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
42         NewlineStyle::Native => native_newline_style(),
43         NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
44         NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
45     }
46 }
47
48 fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
49     if let Some(pos) = raw_input_text.find('\n') {
50         let pos = pos.saturating_sub(1);
51         if let Some('\r') = raw_input_text.chars().nth(pos) {
52             EffectiveNewlineStyle::Windows
53         } else {
54             EffectiveNewlineStyle::Unix
55         }
56     } else {
57         native_newline_style()
58     }
59 }
60
61 fn native_newline_style() -> EffectiveNewlineStyle {
62     if cfg!(windows) {
63         EffectiveNewlineStyle::Windows
64     } else {
65         EffectiveNewlineStyle::Unix
66     }
67 }
68
69 #[cfg(test)]
70 mod tests {
71     use super::*;
72
73     #[test]
74     fn test_newline_style_auto_detect() {
75         let lf = "One\nTwo\nThree";
76         let crlf = "One\r\nTwo\r\nThree";
77         let none = "One Two Three";
78
79         assert_eq!(EffectiveNewlineStyle::Unix, auto_detect_newline_style(lf));
80         assert_eq!(
81             EffectiveNewlineStyle::Windows,
82             auto_detect_newline_style(crlf)
83         );
84
85         if cfg!(windows) {
86             assert_eq!(
87                 EffectiveNewlineStyle::Windows,
88                 auto_detect_newline_style(none)
89             );
90         } else {
91             assert_eq!(EffectiveNewlineStyle::Unix, auto_detect_newline_style(none));
92         }
93     }
94
95     #[test]
96     fn test_newline_style_auto_apply() {
97         let auto = NewlineStyle::Auto;
98
99         let formatted_text = "One\nTwo\nThree";
100         let raw_input_text = "One\nTwo\nThree";
101
102         let mut out = String::from(formatted_text);
103         apply_newline_style(auto, &mut out, raw_input_text);
104         assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
105
106         let formatted_text = "One\nTwo\nThree";
107         let raw_input_text = "One\r\nTwo\r\nThree";
108
109         let mut out = String::from(formatted_text);
110         apply_newline_style(auto, &mut out, raw_input_text);
111         assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
112
113         #[cfg(not(windows))]
114         {
115             let formatted_text = "One\nTwo\nThree";
116             let raw_input_text = "One Two Three";
117
118             let mut out = String::from(formatted_text);
119             apply_newline_style(auto, &mut out, raw_input_text);
120             assert_eq!(
121                 "One\nTwo\nThree", &out,
122                 "auto-native-unix should detect 'lf'"
123             );
124         }
125
126         #[cfg(windows)]
127         {
128             let formatted_text = "One\nTwo\nThree";
129             let raw_input_text = "One Two Three";
130
131             let mut out = String::from(formatted_text);
132             apply_newline_style(auto, &mut out, raw_input_text);
133             assert_eq!(
134                 "One\r\nTwo\r\nThree", &out,
135                 "auto-native-windows should detect 'crlf'"
136             );
137         }
138     }
139 }