rumdl_lib/utils/
line_ending.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum LineEnding {
3 Lf,
4 Crlf,
5 Mixed,
6}
7
8pub fn detect_line_ending_enum(content: &str) -> LineEnding {
9 let has_crlf = content.contains("\r\n");
10 let content_without_crlf = content.replace("\r\n", "");
12 let has_standalone_lf = content_without_crlf.contains('\n');
13
14 match (has_crlf, has_standalone_lf) {
15 (true, true) => LineEnding::Mixed, (true, false) => LineEnding::Crlf, (false, true) => LineEnding::Lf, (false, false) => LineEnding::Lf, }
20}
21
22pub fn detect_line_ending(content: &str) -> &'static str {
23 let crlf_count = content.matches("\r\n").count();
25 let lf_count = content.matches('\n').count() - crlf_count;
26
27 if crlf_count > lf_count { "\r\n" } else { "\n" }
28}
29
30pub fn normalize_line_ending(content: &str, target: LineEnding) -> String {
31 match target {
32 LineEnding::Lf => content.replace("\r\n", "\n"),
33 LineEnding::Crlf => {
34 let normalized = content.replace("\r\n", "\n");
36 normalized.replace('\n', "\r\n")
37 }
38 LineEnding::Mixed => content.to_string(), }
40}
41
42pub fn ensure_consistent_line_endings(original: &str, modified: &str) -> String {
43 let original_ending = detect_line_ending_enum(original);
44
45 let target_ending = if original_ending == LineEnding::Mixed {
47 let crlf_count = original.matches("\r\n").count();
49 let lf_count = original.matches('\n').count() - crlf_count;
50 if crlf_count > lf_count {
51 LineEnding::Crlf
52 } else {
53 LineEnding::Lf
54 }
55 } else {
56 original_ending
57 };
58
59 let modified_ending = detect_line_ending_enum(modified);
60
61 if target_ending != modified_ending {
62 normalize_line_ending(modified, target_ending)
63 } else {
64 modified.to_string()
65 }
66}
67
68pub fn get_line_ending_str(ending: LineEnding) -> &'static str {
69 match ending {
70 LineEnding::Lf => "\n",
71 LineEnding::Crlf => "\r\n",
72 LineEnding::Mixed => "\n", }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_detect_line_ending_enum() {
82 assert_eq!(detect_line_ending_enum("hello\nworld"), LineEnding::Lf);
83 assert_eq!(detect_line_ending_enum("hello\r\nworld"), LineEnding::Crlf);
84 assert_eq!(detect_line_ending_enum("hello\r\nworld\nmixed"), LineEnding::Mixed);
85 assert_eq!(detect_line_ending_enum("no line endings"), LineEnding::Lf);
86 }
87
88 #[test]
89 fn test_detect_line_ending() {
90 assert_eq!(detect_line_ending("hello\nworld"), "\n");
91 assert_eq!(detect_line_ending("hello\r\nworld"), "\r\n");
92 assert_eq!(detect_line_ending("hello\r\nworld\nmixed"), "\n"); assert_eq!(detect_line_ending("no line endings"), "\n");
94 }
95
96 #[test]
97 fn test_normalize_line_ending() {
98 assert_eq!(normalize_line_ending("hello\r\nworld", LineEnding::Lf), "hello\nworld");
99 assert_eq!(
100 normalize_line_ending("hello\nworld", LineEnding::Crlf),
101 "hello\r\nworld"
102 );
103 assert_eq!(
104 normalize_line_ending("hello\r\nworld\nmixed", LineEnding::Lf),
105 "hello\nworld\nmixed"
106 );
107 }
108
109 #[test]
110 fn test_ensure_consistent_line_endings() {
111 let original = "hello\r\nworld";
112 let modified = "hello\nworld\nextra";
113 assert_eq!(
114 ensure_consistent_line_endings(original, modified),
115 "hello\r\nworld\r\nextra"
116 );
117
118 let original = "hello\nworld";
119 let modified = "hello\r\nworld\r\nextra";
120 assert_eq!(
121 ensure_consistent_line_endings(original, modified),
122 "hello\nworld\nextra"
123 );
124 }
125}