From 8a1cdd92156d563d8e3143f530ca1fde4a458571 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Wed, 16 Oct 2024 18:26:18 +0900 Subject: [PATCH] text_util: extract generic truncation helpers to support &[u8] --- cli/src/text_util.rs | 62 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/cli/src/text_util.rs b/cli/src/text_util.rs index 5d0307efa..cd7990ce2 100644 --- a/cli/src/text_util.rs +++ b/cli/src/text_util.rs @@ -96,12 +96,23 @@ pub fn elide_end<'a>(text: &'a str, ellipsis: &'a str, max_width: usize) -> (Cow /// /// The truncated string may have 0-width decomposed characters at start. fn truncate_start_pos(text: &str, max_width: usize) -> (usize, usize) { + truncate_start_pos_with_indices( + text.char_indices() + .rev() + .map(|(start, c)| (start + c.len_utf8(), c)), + max_width, + ) +} + +fn truncate_start_pos_with_indices( + char_indices_rev: impl Iterator, + max_width: usize, +) -> (usize, usize) { let mut acc_width = 0; - for (i, c) in text.char_indices().rev() { + for (end, c) in char_indices_rev { let new_width = acc_width + c.width().unwrap_or(0); if new_width > max_width { - let prev_index = i + c.len_utf8(); - return (prev_index, acc_width); + return (end, acc_width); } acc_width = new_width; } @@ -111,15 +122,23 @@ fn truncate_start_pos(text: &str, max_width: usize) -> (usize, usize) { /// Shortens `text` to `max_width` by removing trailing characters, returning /// `(end_index, width)`. fn truncate_end_pos(text: &str, max_width: usize) -> (usize, usize) { + truncate_end_pos_with_indices(text.char_indices(), text.len(), max_width) +} + +fn truncate_end_pos_with_indices( + char_indices_fwd: impl Iterator, + text_len: usize, + max_width: usize, +) -> (usize, usize) { let mut acc_width = 0; - for (i, c) in text.char_indices() { + for (start, c) in char_indices_fwd { let new_width = acc_width + c.width().unwrap_or(0); if new_width > max_width { - return (i, acc_width); + return (start, acc_width); } acc_width = new_width; } - (text.len(), acc_width) + (text_len, acc_width) } /// Skips `width` leading characters, returning `(start_index, skipped_width)`. @@ -129,14 +148,22 @@ fn truncate_end_pos(text: &str, max_width: usize) -> (usize, usize) { /// /// The truncated string may have 0-width decomposed characters at start. fn skip_start_pos(text: &str, width: usize) -> (usize, usize) { + skip_start_pos_with_indices(text.char_indices(), text.len(), width) +} + +fn skip_start_pos_with_indices( + char_indices_fwd: impl Iterator, + text_len: usize, + width: usize, +) -> (usize, usize) { let mut acc_width = 0; - for (i, c) in text.char_indices() { + for (start, c) in char_indices_fwd { if acc_width >= width { - return (i, acc_width); + return (start, acc_width); } acc_width += c.width().unwrap_or(0); } - (text.len(), acc_width) + (text_len, acc_width) } /// Skips `width` trailing characters, returning `(end_index, skipped_width)`. @@ -144,11 +171,22 @@ fn skip_start_pos(text: &str, width: usize) -> (usize, usize) { /// The `skipped_width` may exceed the given `width` if `width` is not at /// character boundary. fn skip_end_pos(text: &str, width: usize) -> (usize, usize) { + skip_end_pos_with_indices( + text.char_indices() + .rev() + .map(|(start, c)| (start + c.len_utf8(), c)), + width, + ) +} + +fn skip_end_pos_with_indices( + char_indices_rev: impl Iterator, + width: usize, +) -> (usize, usize) { let mut acc_width = 0; - for (i, c) in text.char_indices().rev() { + for (end, c) in char_indices_rev { if acc_width >= width { - let prev_index = i + c.len_utf8(); - return (prev_index, acc_width); + return (end, acc_width); } acc_width += c.width().unwrap_or(0); }