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