Completion word start filtering which is codepoint aware

Julia created

Change summary

crates/editor/src/editor.rs | 38 +++++++++++++++++++++++---------------
1 file changed, 23 insertions(+), 15 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -830,33 +830,41 @@ impl CompletionsMenu {
 
         //Remove all candidates where the query's start does not match the start of any word in the candidate
         if let Some(query) = query {
-            if let Some(&start) = query.as_bytes().get(0) {
-                let start = start.to_ascii_lowercase();
-                matches.retain(|m| {
-                    let bytes = m.string.as_bytes();
+            if let Some(query_start) = query.chars().next() {
+                matches.retain(|string_match| {
+                    let text = &string_match.string;
+
                     let mut index = 0;
+                    let mut codepoints = text.char_indices().peekable();
 
                     std::iter::from_fn(move || {
                         let start_index = index;
-                        while index < bytes.len() {
-                            let current_upper = bytes[index].is_ascii_uppercase();
-                            let has_more = index + 1 < bytes.len();
-                            let next_upper = has_more && bytes[index + 1].is_ascii_uppercase();
+                        while let Some((new_index, codepoint)) = codepoints.next() {
+                            index = new_index + codepoint.len_utf8();
+                            let current_upper = codepoint.is_uppercase();
+                            let next_upper = codepoints
+                                .peek()
+                                .map(|(_, c)| c.is_uppercase())
+                                .unwrap_or(false);
 
-                            index += 1;
                             if !current_upper && next_upper {
-                                return Some(&m.string[start_index..index]);
+                                return Some(&text[start_index..index]);
                             }
                         }
 
-                        index = bytes.len();
-                        if start_index < bytes.len() {
-                            return Some(&m.string[start_index..]);
+                        index = text.len();
+                        if start_index < text.len() {
+                            return Some(&text[start_index..]);
                         }
                         None
                     })
-                    .flat_map(|w| w.split_inclusive('_'))
-                    .any(|w| w.as_bytes().first().map(|&b| b.to_ascii_lowercase()) == Some(start))
+                    .flat_map(|word| word.split_inclusive('_'))
+                    .any(|word| {
+                        word.chars()
+                            .flat_map(|codepoint| codepoint.to_lowercase())
+                            .zip(query_start.to_lowercase())
+                            .all(|(word_cp, query_cp)| word_cp == query_cp)
+                    })
                 });
             }
         }