diff --git a/crates/pi-natives/src/text.rs b/crates/pi-natives/src/text.rs index cfcf8a185..22c9ca770 100644 --- a/crates/pi-natives/src/text.rs +++ b/crates/pi-natives/src/text.rs @@ -1000,7 +1000,12 @@ fn split_into_tokens_with_ansi(line: &[u16]) -> SmallVec<[Vec; 4]> { if line[i] == ESC && let Some(seq_len) = ansi_seq_len_u16(line, i) { - pending_ansi.extend_from_slice(&line[i..i + seq_len]); + let seq = &line[i..i + seq_len]; + if current.is_empty() { + pending_ansi.extend_from_slice(seq); + } else { + current.extend_from_slice(seq); + } i += seq_len; continue; } @@ -2003,6 +2008,18 @@ mod tests { assert!(second.contains("world")); } + #[test] + fn test_wrap_text_with_ansi_keeps_trailing_color_reset_before_soft_wrap() { + let data = to_u16("plain \x1b[33mcode\x1b[39m next"); + let lines = wrap_text_with_ansi_impl(&data, 10, DEFAULT_TAB_WIDTH); + let actual: Vec = lines + .iter() + .map(|line| String::from_utf16_lossy(line)) + .collect(); + + assert_eq!(actual, ["plain \x1b[33mcode\x1b[39m", "next"]); + } + #[test] fn test_wrap_text_with_ansi_resets_strike_without_resetting_colors() { let data = diff --git a/packages/natives/CHANGELOG.md b/packages/natives/CHANGELOG.md index f171b5206..fc74e3886 100644 --- a/packages/natives/CHANGELOG.md +++ b/packages/natives/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Fixed the native `xargs` builtin panicking in `-I`/`-i` replace mode when stdin is empty; it now exits successfully without running the command, matching GNU behavior ([#8595](https://github.com/can1357/oh-my-pi/issues/8595)). +- Fixed inline-code foreground color carrying into plain text when a Markdown codespan ended exactly at a soft-wrap boundary ([#8582](https://github.com/can1357/oh-my-pi/issues/8582)). ## [17.3.4] - 2026-08-14