]> git.lizzy.rs Git - rust.git/blobdiff - src/formatting/newline_style.rs
Rollup merge of #86274 - alexander-melentyev:spaces, r=bjorn3
[rust.git] / src / formatting / newline_style.rs
index dc80715044fd96bcc1b69b4773c573fc74f84c80..ac62009490001ab8d5101cf6d2ddfd419e4c3f0b 100644 (file)
@@ -11,11 +11,9 @@ pub(crate) fn apply_newline_style(
     formatted_text: &mut String,
     raw_input_text: &str,
 ) {
-    match effective_newline_style(newline_style, raw_input_text) {
-        EffectiveNewlineStyle::Windows => {
-            *formatted_text = convert_to_windows_newlines(formatted_text);
-        }
-        EffectiveNewlineStyle::Unix => {}
+    *formatted_text = match effective_newline_style(newline_style, raw_input_text) {
+        EffectiveNewlineStyle::Windows => convert_to_windows_newlines(formatted_text),
+        EffectiveNewlineStyle::Unix => convert_to_unix_newlines(formatted_text),
     }
 }
 
@@ -39,17 +37,21 @@ fn effective_newline_style(
 
 const LINE_FEED: char = '\n';
 const CARRIAGE_RETURN: char = '\r';
+const WINDOWS_NEWLINE: &str = "\r\n";
+const UNIX_NEWLINE: &str = "\n";
 
 fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
-    if let Some(pos) = raw_input_text.find(LINE_FEED) {
-        let pos = pos.saturating_sub(1);
-        if let Some(CARRIAGE_RETURN) = raw_input_text.chars().nth(pos) {
-            EffectiveNewlineStyle::Windows
-        } else {
-            EffectiveNewlineStyle::Unix
+    let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == LINE_FEED);
+    match first_line_feed_pos {
+        Some(first_line_feed_pos) => {
+            let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1);
+            let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos);
+            match char_before_line_feed {
+                Some(CARRIAGE_RETURN) => EffectiveNewlineStyle::Windows,
+                _ => EffectiveNewlineStyle::Unix,
+            }
         }
-    } else {
-        native_newline_style()
+        None => native_newline_style(),
     }
 }
 
@@ -63,17 +65,22 @@ fn native_newline_style() -> EffectiveNewlineStyle {
 
 fn convert_to_windows_newlines(formatted_text: &String) -> String {
     let mut transformed = String::with_capacity(2 * formatted_text.capacity());
-    for c in formatted_text.chars() {
-        const WINDOWS_NEWLINE: &str = "\r\n";
-        match c {
+    let mut chars = formatted_text.chars().peekable();
+    while let Some(current_char) = chars.next() {
+        let next_char = chars.peek();
+        match current_char {
             LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
-            CARRIAGE_RETURN => continue,
-            c => transformed.push(c),
+            CARRIAGE_RETURN if next_char == Some(&LINE_FEED) => {}
+            current_char => transformed.push(current_char),
         }
     }
     transformed
 }
 
+fn convert_to_unix_newlines(formatted_text: &String) -> String {
+    formatted_text.replace(WINDOWS_NEWLINE, UNIX_NEWLINE)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -94,6 +101,14 @@ fn auto_detects_windows_newlines() {
         );
     }
 
+    #[test]
+    fn auto_detects_windows_newlines_with_multibyte_char_on_first_line() {
+        assert_eq!(
+            EffectiveNewlineStyle::Windows,
+            auto_detect_newline_style("A ðŸŽ¢ of a first line\r\nTwo\r\nThree")
+        );
+    }
+
     #[test]
     fn falls_back_to_native_newlines_if_no_newlines_are_found() {
         let expected_newline_style = if cfg!(windows) {
@@ -108,47 +123,128 @@ fn falls_back_to_native_newlines_if_no_newlines_are_found() {
     }
 
     #[test]
-    fn test_newline_style_auto_apply() {
-        let auto = NewlineStyle::Auto;
-
+    fn auto_detects_and_applies_unix_newlines() {
         let formatted_text = "One\nTwo\nThree";
         let raw_input_text = "One\nTwo\nThree";
 
         let mut out = String::from(formatted_text);
-        apply_newline_style(auto, &mut out, raw_input_text);
+        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
         assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
+    }
 
+    #[test]
+    fn auto_detects_and_applies_windows_newlines() {
         let formatted_text = "One\nTwo\nThree";
         let raw_input_text = "One\r\nTwo\r\nThree";
 
         let mut out = String::from(formatted_text);
-        apply_newline_style(auto, &mut out, raw_input_text);
+        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
         assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
+    }
 
-        #[cfg(not(windows))]
-        {
-            let formatted_text = "One\nTwo\nThree";
-            let raw_input_text = "One Two Three";
+    #[test]
+    fn auto_detects_and_applies_native_newlines() {
+        let formatted_text = "One\nTwo\nThree";
+        let raw_input_text = "One Two Three";
+
+        let mut out = String::from(formatted_text);
+        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
 
-            let mut out = String::from(formatted_text);
-            apply_newline_style(auto, &mut out, raw_input_text);
+        if cfg!(windows) {
+            assert_eq!(
+                "One\r\nTwo\r\nThree", &out,
+                "auto-native-windows should detect 'crlf'"
+            );
+        } else {
             assert_eq!(
                 "One\nTwo\nThree", &out,
                 "auto-native-unix should detect 'lf'"
             );
         }
+    }
 
-        #[cfg(windows)]
-        {
-            let formatted_text = "One\nTwo\nThree";
-            let raw_input_text = "One Two Three";
+    #[test]
+    fn applies_unix_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\r\nTwo\nThree",
+            "One\nTwo\nThree",
+            NewlineStyle::Unix,
+        );
+    }
 
-            let mut out = String::from(formatted_text);
-            apply_newline_style(auto, &mut out, raw_input_text);
-            assert_eq!(
-                "One\r\nTwo\r\nThree", &out,
-                "auto-native-windows should detect 'crlf'"
-            );
-        }
+    #[test]
+    fn applying_unix_newlines_changes_nothing_for_unix_newlines() {
+        let formatted_text = "One\nTwo\nThree";
+        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Unix);
+    }
+
+    #[test]
+    fn applies_unix_newlines_to_string_with_unix_and_windows_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\r\nTwo\r\nThree\nFour",
+            "One\nTwo\nThree\nFour",
+            NewlineStyle::Unix,
+        );
+    }
+
+    #[test]
+    fn applies_windows_newlines_to_string_with_unix_and_windows_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\nTwo\nThree\r\nFour",
+            "One\r\nTwo\r\nThree\r\nFour",
+            NewlineStyle::Windows,
+        );
+    }
+
+    #[test]
+    fn applying_windows_newlines_changes_nothing_for_windows_newlines() {
+        let formatted_text = "One\r\nTwo\r\nThree";
+        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Windows);
+    }
+
+    #[test]
+    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_unix_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\nTwo\nThree\rDrei",
+            "One\r\nTwo\r\nThree\rDrei",
+            NewlineStyle::Windows,
+        );
+    }
+
+    #[test]
+    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_unix_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\nTwo\nThree\rDrei",
+            "One\nTwo\nThree\rDrei",
+            NewlineStyle::Unix,
+        );
+    }
+
+    #[test]
+    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_windows_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\r\nTwo\r\nThree\rDrei",
+            "One\r\nTwo\r\nThree\rDrei",
+            NewlineStyle::Windows,
+        );
+    }
+
+    #[test]
+    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_windows_newlines() {
+        test_newlines_are_applied_correctly(
+            "One\r\nTwo\r\nThree\rDrei",
+            "One\nTwo\nThree\rDrei",
+            NewlineStyle::Unix,
+        );
+    }
+
+    fn test_newlines_are_applied_correctly(
+        input: &str,
+        expected: &str,
+        newline_style: NewlineStyle,
+    ) {
+        let mut out = String::from(input);
+        apply_newline_style(newline_style, &mut out, input);
+        assert_eq!(expected, &out);
     }
 }