From b555680534838d64180f6686ac5c72b1f49663ff Mon Sep 17 00:00:00 2001 From: ColonelBucket8 Date: Mon, 15 Jun 2026 12:02:03 +0800 Subject: [PATCH] fix: truncated message with emoji --- Cargo.toml | 2 +- src/screen/mod.rs | 29 ++++++++++++++--------------- src/ui.rs | 3 ++- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 95e7c0947d..02e94e7162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ pretty_assertions = "1.4.1" temp-dir = "0.1.16" criterion = "0.8.1" insta = "1.46.0" -unicode-width = "0.2.0" temp-env = "0.3.6" stdext = "0.3.3" url = "2.5.7" @@ -71,6 +70,7 @@ tree-sitter-elixir = "=0.3.4" regex = "1.12.2" strip-ansi-escapes = "0.2.1" unicode-segmentation = "1.12.0" +unicode-width = "0.2.0" cached = "0.56.0" strum = { version = "0.26.3", features = ["strum_macros"] } tinyvec = "1.10.0" diff --git a/src/screen/mod.rs b/src/screen/mod.rs index d7ded5a596..c9edd2f9b7 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -4,6 +4,7 @@ use crate::ui::{UiTree, layout_span}; use crate::{item_data::ItemData, ui}; use ratatui::{layout::Size, style::Style, text::Line}; use unicode_segmentation::UnicodeSegmentation; +use unicode_width::UnicodeWidthStr; use crate::{Res, config::Config, items::hash}; @@ -473,26 +474,24 @@ pub(crate) fn layout_screen<'a>( line.display.spans.into_iter().for_each(|span| { let style = bg.patch(line.display.style).patch(span.style); - let span_width = span.content.graphemes(true).count(); + let span_width = UnicodeWidthStr::width(span.content.as_ref()); if line_end + span_width >= size.width as usize { - // Truncate the span and insert an ellipsis to indicate overflow - let overflow = line_end + span_width - size.width as usize; + let budget = size.width as usize; + let mut accumulated = 0; + let mut truncated = String::new(); + for grapheme in span.content.graphemes(true) { + let w = UnicodeWidthStr::width(grapheme); + if line_end + accumulated + w + 1 > budget { + break; + } + accumulated += w; + truncated.push_str(grapheme); + } line_end = size.width as usize; - ui::layout_span( - layout, - ( - span.content - .graphemes(true) - .take(span_width.saturating_sub(overflow + 1)) - .collect::() - .into(), - style, - ), - ); + ui::layout_span(layout, (truncated.into(), style)); layout_span(layout, ("…".into(), bg)); } else { - // Insert the span as normal line_end += span_width; ui::layout_span(layout, (span.content, style)); } diff --git a/src/ui.rs b/src/ui.rs index 6a8a5426b0..822960c9d5 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -10,6 +10,7 @@ use ratatui::Frame; use ratatui::prelude::*; use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; +use unicode_width::UnicodeWidthStr; pub(crate) mod layout; mod menu; @@ -127,7 +128,7 @@ pub(crate) fn layout_line<'a>(layout: &mut UiTree<'a>, line: Line<'a>) { } pub(crate) fn layout_span<'a>(layout: &mut UiTree<'a>, span: (Cow<'a, str>, Style)) { - let width = span.0.graphemes(true).count() as u16; + let width = UnicodeWidthStr::width(span.0.as_ref()) as u16; layout.leaf_with_size(span, [width, 1]); }