diff --git a/Cargo.lock b/Cargo.lock index 09a6897334..9c6d2fb7b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11006,6 +11006,7 @@ dependencies = [ "text", "theme", "ui", + "unicode-segmentation", "util", "windows 0.58.0", ] diff --git a/crates/supermaven/Cargo.toml b/crates/supermaven/Cargo.toml index b8f85c0f05..e04d0ef51b 100644 --- a/crates/supermaven/Cargo.toml +++ b/crates/supermaven/Cargo.toml @@ -29,6 +29,7 @@ supermaven_api.workspace = true smol.workspace = true text.workspace = true ui.workspace = true +unicode-segmentation.workspace = true util.workspace = true [target.'cfg(target_os = "windows")'.dependencies] diff --git a/crates/supermaven/src/supermaven_completion_provider.rs b/crates/supermaven/src/supermaven_completion_provider.rs index 261ce372d9..2a7fc31c0d 100644 --- a/crates/supermaven/src/supermaven_completion_provider.rs +++ b/crates/supermaven/src/supermaven_completion_provider.rs @@ -12,6 +12,7 @@ use std::{ time::Duration, }; use text::{ToOffset, ToPoint}; +use unicode_segmentation::UnicodeSegmentation; pub const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75); @@ -54,33 +55,34 @@ fn completion_state_from_diff( ) -> CompletionProposal { let buffer_text = snapshot .text_for_range(delete_range.clone()) - .collect::() - .chars() - .collect::>(); + .collect::(); let mut inlays: Vec = Vec::new(); - let completion = completion_text.chars().collect::>(); + let completion_graphemes: Vec<&str> = completion_text.graphemes(true).collect(); + let buffer_graphemes: Vec<&str> = buffer_text.graphemes(true).collect(); let mut offset = position.to_offset(&snapshot); let mut i = 0; let mut j = 0; - while i < completion.len() && j < buffer_text.len() { + while i < completion_graphemes.len() && j < buffer_graphemes.len() { // find the next instance of the buffer text in the completion text. - let k = completion[i..].iter().position(|c| *c == buffer_text[j]); + let k = completion_graphemes[i..] + .iter() + .position(|c| *c == buffer_graphemes[j]); match k { Some(k) => { if k != 0 { // the range from the current position to item is an inlay. inlays.push(InlayProposal::Suggestion( snapshot.anchor_after(offset), - completion_text[i..i + k].into(), + completion_graphemes[i..i + k].join("").into(), )); } i += k + 1; j += 1; - offset.add_assign(1); + offset.add_assign(buffer_graphemes[j - 1].len()); } None => { // there are no more matching completions, so drop the remaining @@ -90,11 +92,11 @@ fn completion_state_from_diff( } } - if j == buffer_text.len() && i < completion.len() { + if j == buffer_graphemes.len() && i < completion_graphemes.len() { // there is leftover completion text, so drop it as an inlay. inlays.push(InlayProposal::Suggestion( snapshot.anchor_after(offset), - completion_text[i..completion_text.len()].into(), + completion_graphemes[i..].join("").into(), )); }