diff --git a/src/wrap.rs b/src/wrap.rs index 2117f974..a2f1d180 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -301,17 +301,28 @@ pub fn wrap_text(lines: &[String], width: usize) -> Vec { indent = line.chars().take_while(|c| c.is_whitespace()).collect(); } let trimmed_end = line.trim_end(); - let hard_break = line.ends_with(" ") - || trimmed_end.ends_with("
") - || trimmed_end.ends_with("
") - || trimmed_end.ends_with("
"); - let text = trimmed_end + let text_without_html_breaks = trimmed_end .trim_end_matches("
") .trim_end_matches("
") - .trim_end_matches("
") - .trim_end_matches(' ') + .trim_end_matches("
"); + + let is_trailing_spaces = line.ends_with(" "); + let is_html_br = trimmed_end != text_without_html_breaks; + let backslash_count = line + .trim_end() + .chars() + .rev() + .take_while(|&c| c == '\\') + .count(); + let is_backslash_escape = backslash_count % 2 == 1; + + let hard_break = is_trailing_spaces || is_html_br || is_backslash_escape; + + let text = text_without_html_breaks .trim_start() + .trim_end_matches(' ') .to_string(); + buf.push((text, hard_break)); } diff --git a/tests/data/hard_linebreak_expected.txt b/tests/data/hard_linebreak_expected.txt new file mode 100644 index 00000000..4996c57b --- /dev/null +++ b/tests/data/hard_linebreak_expected.txt @@ -0,0 +1,4 @@ +Scenarios live under `tests/features/`. Step implementations in `tests` share \ +a common `World` struct that uses `figment::Jail` for isolation. Each scenario +demonstration example \ +executes asynchronously with `tokio`. diff --git a/tests/data/hard_linebreak_input.txt b/tests/data/hard_linebreak_input.txt new file mode 100644 index 00000000..beaecb97 --- /dev/null +++ b/tests/data/hard_linebreak_input.txt @@ -0,0 +1,3 @@ +Scenarios live under `tests/features/`. Step implementations in `tests` share \ +a common `World` struct that uses `figment::Jail` for isolation. Each scenario demonstration example \ +executes asynchronously with `tokio`. diff --git a/tests/integration.rs b/tests/integration.rs index 4920bade..131902d0 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -794,6 +794,35 @@ fn test_preserve_hard_line_breaks() { assert_eq!(output[1], "Line two follows."); } +#[test] +fn test_wrap_hard_linebreak_backslash() { + let input: Vec = include_lines!("data/hard_linebreak_input.txt"); + let expected: Vec = include_lines!("data/hard_linebreak_expected.txt"); + assert_eq!(process_stream(&input), expected); +} + +#[test] +fn test_wrap_hard_linebreak_backslash_edge_cases() { + let input = lines_vec!( + "This line ends with two backslashes: \\\\", + "This line ends with a single backslash: \\", + " \\ ", + "\\", + "Text before \\ and after", + " \\", + "", + ); + let expected = lines_vec!( + "This line ends with two backslashes: \\\\ This line ends with a single backslash:", + "\\", + "\\", + "\\", + "Text before \\ and after \\", + "", + ); + assert_eq!(process_stream(&input), expected); +} + #[test] /// Tests that `process_stream` preserves complex table formatting without modification. ///