1 use crate::NewlineStyle;
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
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,
14 *formatted_text = match effective_newline_style(newline_style, raw_input_text) {
15 EffectiveNewlineStyle::Windows => convert_to_windows_newlines(formatted_text),
16 EffectiveNewlineStyle::Unix => convert_to_unix_newlines(formatted_text),
20 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
21 enum EffectiveNewlineStyle {
26 fn effective_newline_style(
27 newline_style: NewlineStyle,
29 ) -> EffectiveNewlineStyle {
31 NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
32 NewlineStyle::Native => native_newline_style(),
33 NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
34 NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
38 const LINE_FEED: char = '\n';
39 const CARRIAGE_RETURN: char = '\r';
40 const WINDOWS_NEWLINE: &str = "\r\n";
41 const UNIX_NEWLINE: &str = "\n";
43 fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
44 let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == LINE_FEED);
45 match first_line_feed_pos {
46 Some(first_line_feed_pos) => {
47 let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1);
48 let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos);
49 match char_before_line_feed {
50 Some(CARRIAGE_RETURN) => EffectiveNewlineStyle::Windows,
51 _ => EffectiveNewlineStyle::Unix,
54 None => native_newline_style(),
58 fn native_newline_style() -> EffectiveNewlineStyle {
60 EffectiveNewlineStyle::Windows
62 EffectiveNewlineStyle::Unix
66 fn convert_to_windows_newlines(formatted_text: &String) -> String {
67 let mut transformed = String::with_capacity(2 * formatted_text.capacity());
68 for c in formatted_text.chars() {
70 LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
71 c => transformed.push(c),
77 fn convert_to_unix_newlines(formatted_text: &String) -> String {
78 formatted_text.replace(WINDOWS_NEWLINE, UNIX_NEWLINE)
86 fn auto_detects_unix_newlines() {
88 EffectiveNewlineStyle::Unix,
89 auto_detect_newline_style("One\nTwo\nThree")
94 fn auto_detects_windows_newlines() {
96 EffectiveNewlineStyle::Windows,
97 auto_detect_newline_style("One\r\nTwo\r\nThree")
102 fn auto_detects_windows_newlines_with_multibyte_char_on_first_line() {
104 EffectiveNewlineStyle::Windows,
105 auto_detect_newline_style("A 🎢 of a first line\r\nTwo\r\nThree")
110 fn falls_back_to_native_newlines_if_no_newlines_are_found() {
111 let expected_newline_style = if cfg!(windows) {
112 EffectiveNewlineStyle::Windows
114 EffectiveNewlineStyle::Unix
117 expected_newline_style,
118 auto_detect_newline_style("One Two Three")
123 fn auto_detects_and_applies_unix_newlines() {
124 let formatted_text = "One\nTwo\nThree";
125 let raw_input_text = "One\nTwo\nThree";
127 let mut out = String::from(formatted_text);
128 apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
129 assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
133 fn auto_detects_and_applies_windows_newlines() {
134 let formatted_text = "One\nTwo\nThree";
135 let raw_input_text = "One\r\nTwo\r\nThree";
137 let mut out = String::from(formatted_text);
138 apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
139 assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
143 fn auto_detects_and_applies_native_newlines() {
144 let formatted_text = "One\nTwo\nThree";
145 let raw_input_text = "One Two Three";
147 let mut out = String::from(formatted_text);
148 apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
152 "One\r\nTwo\r\nThree", &out,
153 "auto-native-windows should detect 'crlf'"
157 "One\nTwo\nThree", &out,
158 "auto-native-unix should detect 'lf'"
164 fn applies_unix_newlines() {
165 let formatted_text = "One\r\nTwo\nThree";
166 let raw_input_text = formatted_text;
168 let mut out = String::from(formatted_text);
169 apply_newline_style(NewlineStyle::Unix, &mut out, raw_input_text);
171 assert_eq!("One\nTwo\nThree", &out);
175 fn preserves_standalone_carriage_returns_when_applying_windows_newlines() {
176 let formatted_text = "One\nTwo\nThree\rDrei";
177 let raw_input_text = "One\nTwo\nThree\rDrei";
179 let mut out = String::from(formatted_text);
180 apply_newline_style(NewlineStyle::Windows, &mut out, raw_input_text);
182 assert_eq!("One\r\nTwo\r\nThree\rDrei", &out);
186 fn preserves_standalone_carriage_returns_when_applying_unix_newlines() {
187 let formatted_text = "One\nTwo\nThree\rDrei";
188 let raw_input_text = "One\nTwo\nThree\rDrei";
190 let mut out = String::from(formatted_text);
191 apply_newline_style(NewlineStyle::Unix, &mut out, raw_input_text);
193 assert_eq!("One\nTwo\nThree\rDrei", &out);