From 6e185ade97de688cb2a8aebe6c590d29be56c66c Mon Sep 17 00:00:00 2001 From: 依云 Date: Tue, 31 Mar 2026 11:05:38 +0800 Subject: fix(ui): make preview line breaking algorithm aware of CJK double-width characters (#3360) ## Checks - [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle - [x] I have checked that there are no existing pull requests for the same thing Or part of the command may be missing and the user may be misled to run a wrong command. --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../atuin/src/command/client/search/interactive.rs | 33 ++++++++++++++-------- 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'crates') diff --git a/crates/atuin/src/command/client/search/interactive.rs b/crates/atuin/src/command/client/search/interactive.rs index 74600520..2910d129 100644 --- a/crates/atuin/src/command/client/search/interactive.rs +++ b/crates/atuin/src/command/client/search/interactive.rs @@ -11,7 +11,7 @@ use eyre::Result; use futures_util::FutureExt; use semver::Version; use time::OffsetDateTime; -use unicode_width::UnicodeWidthStr; +use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; use super::{ cursor::Cursor, @@ -1239,18 +1239,27 @@ impl State { let command = if results.is_empty() { String::new() } else { - use itertools::Itertools as _; let s = &results[selected].command; - s.split('\n') - .flat_map(|line| { - line.char_indices() - .step_by(preview_width.into()) - .map(|(i, _)| i) - .chain(Some(line.len())) - .tuple_windows() - .map(|(a, b)| (&line[a..b]).escape_control().to_string()) - }) - .join("\n") + let mut lines = Vec::new(); + for line in s.split('\n') { + let line = line.escape_control(); + let mut width = 0; + let mut start = 0; + for (idx, ch) in line.char_indices() { + let w = ch.width().unwrap_or(0); // None for control chars which should not happen + if width + w > preview_width.into() { + lines.push(line[start..idx].to_owned()); + start = idx; + width = w; + } else { + width += w; + } + } + if width != 0 { + lines.push(line[start..].to_owned()); + } + } + lines.join("\n") }; match compactness { -- cgit v1.3.1