From fa6207a0b58b749c57b0a75aae58e0650362d69b Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 3 Apr 2026 20:58:22 -0400 Subject: [PATCH] Fix panic on non-ASCII thread titles in archive search The archive view's fuzzy_match_positions used chars().enumerate() which produces character indices, not byte indices. When thread titles contain multi-byte UTF-8 characters (emoji, CJK, etc.), these character indices don't correspond to valid byte boundaries, causing a panic in HighlightedLabel::new. Switch to char_indices() and eq_ignore_ascii_case() to produce correct byte positions, matching the approach used by the sidebar's version of the same function. --- crates/agent_ui/src/threads_archive_view.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/agent_ui/src/threads_archive_view.rs b/crates/agent_ui/src/threads_archive_view.rs index 9aca31e1edbe729fccecfc0dd8f0530d2aed2564..9d243ee60a9b0e3889c9ebcb780b9668f6edcae2 100644 --- a/crates/agent_ui/src/threads_archive_view.rs +++ b/crates/agent_ui/src/threads_archive_view.rs @@ -91,14 +91,16 @@ impl TimeBucket { } fn fuzzy_match_positions(query: &str, text: &str) -> Option> { - let query = query.to_lowercase(); - let text_lower = text.to_lowercase(); let mut positions = Vec::new(); let mut query_chars = query.chars().peekable(); - for (i, c) in text_lower.chars().enumerate() { - if query_chars.peek() == Some(&c) { - positions.push(i); - query_chars.next(); + for (byte_idx, candidate_char) in text.char_indices() { + if let Some(&query_char) = query_chars.peek() { + if candidate_char.eq_ignore_ascii_case(&query_char) { + positions.push(byte_idx); + query_chars.next(); + } + } else { + break; } } if query_chars.peek().is_none() {