diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index d3d5c437c5..a4a7a520ae 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -259,11 +259,7 @@ impl Item for ProjectSearchView { .boxed(), ) .with_children(self.model.read(cx).active_query.as_ref().map(|query| { - let query_text = if query.as_str().len() > MAX_TAB_TITLE_LEN { - query.as_str()[..MAX_TAB_TITLE_LEN].to_string() + "…" - } else { - query.as_str().to_string() - }; + let query_text = util::truncate_and_trailoff(query.as_str(), MAX_TAB_TITLE_LEN); Label::new(query_text, tab_theme.label.clone()) .aligned() diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index 8cdbfc6438..ea8fdee2a8 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -46,10 +46,10 @@ pub fn truncate(s: &str, max_chars: usize) -> &str { pub fn truncate_and_trailoff(s: &str, max_chars: usize) -> String { debug_assert!(max_chars >= 5); - if s.len() > max_chars { - format!("{}…", truncate(s, max_chars.saturating_sub(3))) - } else { - s.to_string() + let truncation_ix = s.char_indices().map(|(i, _)| i).nth(max_chars); + match truncation_ix { + Some(length) => s[..length].to_string() + "…", + None => s.to_string(), } } @@ -276,4 +276,12 @@ mod tests { assert_eq!(foo, None); } + + #[test] + fn test_trancate_and_trailoff() { + assert_eq!(truncate_and_trailoff("", 5), ""); + assert_eq!(truncate_and_trailoff("èèèèèè", 7), "èèèèèè"); + assert_eq!(truncate_and_trailoff("èèèèèè", 6), "èèèèèè"); + assert_eq!(truncate_and_trailoff("èèèèèè", 5), "èèèèè…"); + } }