Skip to content

Commit 3c4856f

Browse files
authored
Adds associated functions for NewlineStyle (#1894)
* adds functions and tests for newline style
1 parent 30c349c commit 3c4856f

File tree

4 files changed

+265
-9
lines changed

4 files changed

+265
-9
lines changed

sway-fmt-v2/src/config/whitespace.rs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Standard system and editor whitespace configuration options. Advanced whitespace options will be deferred to their corresponding sub-classes.
22
use serde::{Deserialize, Serialize};
33

4-
use crate::constants::{DEFAULT_MAX_LINE_WIDTH, DEFAULT_TAB_SPACES};
4+
use crate::constants::{CARRIAGE_RETURN, DEFAULT_MAX_LINE_WIDTH, DEFAULT_TAB_SPACES, LINE_FEED};
55

66
use super::user_opts::WhitespaceOptions;
77

@@ -45,6 +45,16 @@ impl Whitespace {
4545
}
4646
}
4747

48+
/// Handling of line indentation for expressions or items.
49+
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
50+
pub enum IndentStyle {
51+
/// First line on the same line as the opening brace, all lines aligned with
52+
/// the first line.
53+
Visual,
54+
/// First line is on a new line and all lines align with **block** indent.
55+
Block,
56+
}
57+
4858
/// Handling of which OS new-line style should be applied.
4959
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
5060
pub enum NewlineStyle {
@@ -58,12 +68,43 @@ pub enum NewlineStyle {
5868
Native,
5969
}
6070

61-
/// Handling of line indentation for expressions or items.
62-
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
63-
pub enum IndentStyle {
64-
/// First line on the same line as the opening brace, all lines aligned with
65-
/// the first line.
66-
Visual,
67-
/// First line is on a new line and all lines align with **block** indent.
68-
Block,
71+
/// The definitive system type for `[NewlineStyle]`.
72+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
73+
pub enum NewlineSystemType {
74+
Windows,
75+
Unix,
76+
}
77+
78+
impl NewlineSystemType {
79+
pub fn get_newline_style(newline_style: NewlineStyle, raw_input_text: &str) -> Self {
80+
match newline_style {
81+
NewlineStyle::Auto => Self::auto_detect_newline_style(raw_input_text),
82+
NewlineStyle::Native => Self::native_newline_style(),
83+
NewlineStyle::Windows => Self::Windows,
84+
NewlineStyle::Unix => Self::Unix,
85+
}
86+
}
87+
88+
pub fn auto_detect_newline_style(raw_input_text: &str) -> Self {
89+
let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == LINE_FEED);
90+
match first_line_feed_pos {
91+
Some(first_line_feed_pos) => {
92+
let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1);
93+
let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos);
94+
match char_before_line_feed {
95+
Some(CARRIAGE_RETURN) => Self::Windows,
96+
_ => Self::Unix,
97+
}
98+
}
99+
None => Self::native_newline_style(),
100+
}
101+
}
102+
103+
fn native_newline_style() -> Self {
104+
if cfg!(windows) {
105+
Self::Windows
106+
} else {
107+
Self::Unix
108+
}
109+
}
69110
}

sway-fmt-v2/src/constants.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,9 @@ pub const DEFAULT_ENUM_VARIANT_ALIGN_THRESHOLD: usize = 0;
4747

4848
/// Default max length of comments.
4949
pub const DEFAULT_MAX_COMMENT_WIDTH: usize = 80;
50+
51+
/////NEWLINE_STYLE/////
52+
pub const LINE_FEED: char = '\n';
53+
pub const CARRIAGE_RETURN: char = '\r';
54+
pub const WINDOWS_NEWLINE: &str = "\r\n";
55+
pub const UNIX_NEWLINE: &str = "\n";

sway-fmt-v2/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod constants;
99
mod error;
1010
mod fmt;
1111
mod items;
12+
mod newline_style;
1213

1314
pub use crate::fmt::Formatter;
1415
pub use error::FormatterError;

sway-fmt-v2/src/newline_style.rs

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
//! Functions and tests that determine and apply the user defined [NewlineStyle].
2+
use crate::{
3+
config::whitespace::{NewlineStyle, NewlineSystemType},
4+
constants::{CARRIAGE_RETURN, LINE_FEED, UNIX_NEWLINE, WINDOWS_NEWLINE},
5+
};
6+
7+
/// Apply this newline style to the formatted text. When the style is set
8+
/// to `Auto`, the `raw_input_text` is used to detect the existing line
9+
/// endings.
10+
///
11+
/// If the style is set to `Auto` and `raw_input_text` contains no
12+
/// newlines, the `Native` style will be used.
13+
pub(crate) fn apply_newline_style(
14+
newline_style: NewlineStyle,
15+
formatted_text: &mut String,
16+
raw_input_text: &str,
17+
) {
18+
*formatted_text = match NewlineSystemType::get_newline_style(newline_style, raw_input_text) {
19+
NewlineSystemType::Windows => convert_to_windows_newlines(formatted_text),
20+
NewlineSystemType::Unix => convert_to_unix_newlines(formatted_text),
21+
}
22+
}
23+
24+
fn convert_to_windows_newlines(formatted_text: &String) -> String {
25+
let mut transformed = String::with_capacity(2 * formatted_text.capacity());
26+
let mut chars = formatted_text.chars().peekable();
27+
while let Some(current_char) = chars.next() {
28+
let next_char = chars.peek();
29+
match current_char {
30+
LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
31+
CARRIAGE_RETURN if next_char == Some(&LINE_FEED) => {}
32+
current_char => transformed.push(current_char),
33+
}
34+
}
35+
transformed
36+
}
37+
38+
fn convert_to_unix_newlines(formatted_text: &str) -> String {
39+
formatted_text.replace(WINDOWS_NEWLINE, UNIX_NEWLINE)
40+
}
41+
42+
#[cfg(test)]
43+
mod tests {
44+
use super::*;
45+
46+
#[test]
47+
fn auto_detects_unix_newlines() {
48+
assert_eq!(
49+
NewlineSystemType::Unix,
50+
NewlineSystemType::auto_detect_newline_style("One\nTwo\nThree")
51+
);
52+
}
53+
54+
#[test]
55+
fn auto_detects_windows_newlines() {
56+
assert_eq!(
57+
NewlineSystemType::Windows,
58+
NewlineSystemType::auto_detect_newline_style("One\r\nTwo\r\nThree")
59+
);
60+
}
61+
62+
#[test]
63+
fn auto_detects_windows_newlines_with_multibyte_char_on_first_line() {
64+
assert_eq!(
65+
NewlineSystemType::Windows,
66+
NewlineSystemType::auto_detect_newline_style("A 🎢 of a first line\r\nTwo\r\nThree")
67+
);
68+
}
69+
70+
#[test]
71+
fn falls_back_to_native_newlines_if_no_newlines_are_found() {
72+
let expected_newline_style = if cfg!(windows) {
73+
NewlineSystemType::Windows
74+
} else {
75+
NewlineSystemType::Unix
76+
};
77+
assert_eq!(
78+
expected_newline_style,
79+
NewlineSystemType::auto_detect_newline_style("One Two Three")
80+
);
81+
}
82+
83+
#[test]
84+
fn auto_detects_and_applies_unix_newlines() {
85+
let formatted_text = "One\nTwo\nThree";
86+
let raw_input_text = "One\nTwo\nThree";
87+
88+
let mut out = String::from(formatted_text);
89+
apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
90+
assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
91+
}
92+
93+
#[test]
94+
fn auto_detects_and_applies_windows_newlines() {
95+
let formatted_text = "One\nTwo\nThree";
96+
let raw_input_text = "One\r\nTwo\r\nThree";
97+
98+
let mut out = String::from(formatted_text);
99+
apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
100+
assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
101+
}
102+
103+
#[test]
104+
fn auto_detects_and_applies_native_newlines() {
105+
let formatted_text = "One\nTwo\nThree";
106+
let raw_input_text = "One Two Three";
107+
108+
let mut out = String::from(formatted_text);
109+
apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
110+
111+
if cfg!(windows) {
112+
assert_eq!(
113+
"One\r\nTwo\r\nThree", &out,
114+
"auto-native-windows should detect 'crlf'"
115+
);
116+
} else {
117+
assert_eq!(
118+
"One\nTwo\nThree", &out,
119+
"auto-native-unix should detect 'lf'"
120+
);
121+
}
122+
}
123+
124+
#[test]
125+
fn applies_unix_newlines() {
126+
test_newlines_are_applied_correctly(
127+
"One\r\nTwo\nThree",
128+
"One\nTwo\nThree",
129+
NewlineStyle::Unix,
130+
);
131+
}
132+
133+
#[test]
134+
fn applying_unix_newlines_changes_nothing_for_unix_newlines() {
135+
let formatted_text = "One\nTwo\nThree";
136+
test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Unix);
137+
}
138+
139+
#[test]
140+
fn applies_unix_newlines_to_string_with_unix_and_windows_newlines() {
141+
test_newlines_are_applied_correctly(
142+
"One\r\nTwo\r\nThree\nFour",
143+
"One\nTwo\nThree\nFour",
144+
NewlineStyle::Unix,
145+
);
146+
}
147+
148+
#[test]
149+
fn applies_windows_newlines_to_string_with_unix_and_windows_newlines() {
150+
test_newlines_are_applied_correctly(
151+
"One\nTwo\nThree\r\nFour",
152+
"One\r\nTwo\r\nThree\r\nFour",
153+
NewlineStyle::Windows,
154+
);
155+
}
156+
157+
#[test]
158+
fn applying_windows_newlines_changes_nothing_for_windows_newlines() {
159+
let formatted_text = "One\r\nTwo\r\nThree";
160+
test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Windows);
161+
}
162+
163+
#[test]
164+
fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_unix_newlines() {
165+
test_newlines_are_applied_correctly(
166+
"One\nTwo\nThree\rDrei",
167+
"One\r\nTwo\r\nThree\rDrei",
168+
NewlineStyle::Windows,
169+
);
170+
}
171+
172+
#[test]
173+
fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_unix_newlines() {
174+
test_newlines_are_applied_correctly(
175+
"One\nTwo\nThree\rDrei",
176+
"One\nTwo\nThree\rDrei",
177+
NewlineStyle::Unix,
178+
);
179+
}
180+
181+
#[test]
182+
fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_windows_newlines() {
183+
test_newlines_are_applied_correctly(
184+
"One\r\nTwo\r\nThree\rDrei",
185+
"One\r\nTwo\r\nThree\rDrei",
186+
NewlineStyle::Windows,
187+
);
188+
}
189+
190+
#[test]
191+
fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_windows_newlines() {
192+
test_newlines_are_applied_correctly(
193+
"One\r\nTwo\r\nThree\rDrei",
194+
"One\nTwo\nThree\rDrei",
195+
NewlineStyle::Unix,
196+
);
197+
}
198+
199+
fn test_newlines_are_applied_correctly(
200+
input: &str,
201+
expected: &str,
202+
newline_style: NewlineStyle,
203+
) {
204+
let mut out = String::from(input);
205+
apply_newline_style(newline_style, &mut out, input);
206+
assert_eq!(expected, &out);
207+
}
208+
}

0 commit comments

Comments
 (0)