From aca46285944193512ab8c5ad4d6a7c11527e1e18 Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Sun, 11 Feb 2024 16:54:48 +0100 Subject: [PATCH] Correct-ish implementation with binary search --- src/tui/app/selection.rs | 44 +++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/tui/app/selection.rs b/src/tui/app/selection.rs index edc3a96..147cd50 100644 --- a/src/tui/app/selection.rs +++ b/src/tui/app/selection.rs @@ -192,26 +192,42 @@ impl ArtistSelection { } } - // FIXME: think about converting punctuation characters to some common character. + fn normalize_search_string(search: &str, lowercase: bool) -> String { + let normalized = if lowercase { + search.to_lowercase() + } else { + search.to_owned() + }; + + // Unlikely that this covers all possible strings, but it should at least cover strings + // relevant for music (at least in English). The list of characters handled is based on + // https://wiki.musicbrainz.org/User:Yurim/Punctuation_and_Special_Characters. + normalized + .replace("‐", "-") // U+2010 hyphen + .replace("‒", "-") // U+2012 figure dash + .replace("–", "-") // U+2013 en dash + .replace("—", "-") // U+2014 em dash + .replace("―", "-") // U+2015 horizontal bar + .replace("‘", "'") // U+2018 + .replace("’", "'") // U+2019 + .replace("“", "\"") // U+201C + .replace("”", "\"") // U+201D + .replace("…", "...") // U+2026 + .replace("−", "-") // U+2212 minus sign + } + fn incremental_search(&mut self, artists: &[Artist], artist_name: &str) { if let Some(index) = self.state.list.selected() { let case_sensitive = artist_name .chars() - .any(|ch| !(ch.is_lowercase() || ch.is_whitespace() || ch.is_ascii_punctuation())); + .any(|ch| ch.is_alphabetic() && ch.is_uppercase()); + let search_name = Self::normalize_search_string(artist_name, !case_sensitive); let slice = &artists[index..]; - let result = if case_sensitive { - slice.binary_search_by(|probe| probe.get_sort_key().name.as_str().cmp(artist_name)) - } else { - slice.binary_search_by(|probe| { - probe - .get_sort_key() - .name - .to_lowercase() - .as_str() - .cmp(artist_name) - }) - }; + let result = slice.binary_search_by(|probe| { + Self::normalize_search_string(&probe.get_sort_key().name, !case_sensitive) + .cmp(&search_name) + }); let new_index = match result { Ok(slice_index) | Err(slice_index) => index + slice_index,