From 2893960ab1afcc6958c65ec0b1386c36b507dae2 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 02:32:25 +0100 Subject: [PATCH 1/3] Add wrap test for future attribute punctuation --- src/wrap.rs | 34 +++++++++++++++++++++++++++++++--- tests/integration.rs | 22 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index 91253ae2..f0a6eaac 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -76,11 +76,39 @@ fn wrap_preserving_code(text: &str, width: usize) -> Vec { let mut lines = Vec::new(); let mut current = String::new(); let mut current_width = 0; + let mut last_split: Option = None; for token in tokenize_markdown(text) { let token_width = UnicodeWidthStr::width(token.as_str()); if current_width + token_width <= width { current.push_str(&token); current_width += token_width; + if token.chars().all(char::is_whitespace) { + last_split = Some(current.len()); + } + continue; + } + + if let Some(pos) = last_split { + let line = current[..pos].to_string(); + let mut rest = current[pos..].trim_start().to_string(); + let trimmed = line.trim_end(); + if !trimmed.is_empty() { + lines.push(trimmed.to_string()); + } + rest.push_str(&token); + current = rest; + current_width = UnicodeWidthStr::width(current.as_str()); + last_split = if token.chars().all(char::is_whitespace) { + Some(current.len()) + } else { + None + }; + if current_width > width { + lines.push(current.trim_end().to_string()); + current.clear(); + current_width = 0; + last_split = None; + } continue; } @@ -326,8 +354,8 @@ mod tests { wrapped, vec![ "with their own escaping rules. On Windows, scripts default".to_string(), - "to `powershell -Command` unless the manifest's `interpreter`".to_string(), - "field overrides the setting.".to_string(), + "to `powershell -Command` unless the manifest's".to_string(), + "`interpreter` field overrides the setting.".to_string(), ] ); } @@ -364,7 +392,7 @@ mod tests { let wrapped = wrap_text(&input, 20); assert_eq!( wrapped, - vec!["This has a `dangling".to_string(), "code span.".to_string()] + vec!["This has a".to_string(), "`dangling code span.".to_string()] ); } diff --git a/tests/integration.rs b/tests/integration.rs index 97e90344..ddd2618e 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -736,6 +736,28 @@ fn test_wrap_long_inline_code_item() { ); } +#[test] +fn test_wrap_future_attribute_punctuation() { + let input = vec![ + concat!( + "- Test function (`#[awt]`) or a specific `#[future]` argument ", + "(`#[future(awt)]`), tells `rstest` to automatically insert `.await` ", + "calls for those futures." + ) + .to_string(), + ]; + let output = process_stream(&input); + assert_eq!( + output, + vec![ + "- Test function (`#[awt]`) or a specific `#[future]` argument".to_string(), + " (`#[future(awt)]`), tells `rstest` to automatically insert `.await` calls for" + .to_string(), + " those futures.".to_string(), + ] + ); +} + #[test] fn test_wrap_footnote_multiline() { let input = vec![ From e2b7a65955f640e10ff54bbabcb8beffd593aac5 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 10:53:02 +0100 Subject: [PATCH 2/3] Refactor line split logic --- src/wrap.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/wrap.rs b/src/wrap.rs index f0a6eaac..3e04f7e2 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -70,6 +70,22 @@ pub(crate) fn tokenize_markdown(text: &str) -> Vec { tokens } +/// Determine if the current line should break at the last whitespace. +/// +/// Returns `true` if `current_width` exceeds `width` and a whitespace split +/// position is available. +/// +/// # Examples +/// +/// ``` +/// use mdtablefix::wrap::should_break_line; +/// assert!(should_break_line(10, 12, Some(3))); +/// assert!(!should_break_line(10, 8, Some(3))); +/// ``` +fn should_break_line(width: usize, current_width: usize, last_split: Option) -> bool { + current_width > width && last_split.is_some() +} + fn wrap_preserving_code(text: &str, width: usize) -> Vec { use unicode_width::UnicodeWidthStr; @@ -88,7 +104,8 @@ fn wrap_preserving_code(text: &str, width: usize) -> Vec { continue; } - if let Some(pos) = last_split { + if should_break_line(width, current_width + token_width, last_split) { + let pos = last_split.unwrap(); let line = current[..pos].to_string(); let mut rest = current[pos..].trim_start().to_string(); let trimmed = line.trim_end(); From 3f51163f2c3d0c72a30d90bd080d98101cdf00db Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 11:25:54 +0100 Subject: [PATCH 3/3] Fix doctest failure --- src/wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wrap.rs b/src/wrap.rs index 3e04f7e2..813bc5fe 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -77,7 +77,7 @@ pub(crate) fn tokenize_markdown(text: &str) -> Vec { /// /// # Examples /// -/// ``` +/// ```ignore /// use mdtablefix::wrap::should_break_line; /// assert!(should_break_line(10, 12, Some(3))); /// assert!(!should_break_line(10, 8, Some(3)));