Change summary
crates/editor/src/editor.rs | 59 +++++++++++++++++---------------
crates/editor/src/editor_tests.rs | 14 +++++++
2 files changed, 45 insertions(+), 28 deletions(-)
Detailed changes
@@ -832,34 +832,9 @@ impl CompletionsMenu {
if let Some(query) = query {
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 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);
-
- if !current_upper && next_upper {
- return Some(&text[start_index..index]);
- }
- }
-
- index = text.len();
- if start_index < text.len() {
- return Some(&text[start_index..]);
- }
- None
- })
- .flat_map(|word| word.split_inclusive('_'))
- .any(|word| {
+ split_words(&string_match.string).any(|word| {
+ //Check that the first codepoint of the word as lowercase matches the first
+ //codepoint of the query as lowercase
word.chars()
.flat_map(|codepoint| codepoint.to_lowercase())
.zip(query_start.to_lowercase())
@@ -6841,6 +6816,34 @@ pub fn styled_runs_for_code_label<'a>(
})
}
+pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
+ let mut index = 0;
+ let mut codepoints = text.char_indices().peekable();
+
+ std::iter::from_fn(move || {
+ let start_index = index;
+ 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);
+
+ if !current_upper && next_upper {
+ return Some(&text[start_index..index]);
+ }
+ }
+
+ index = text.len();
+ if start_index < text.len() {
+ return Some(&text[start_index..]);
+ }
+ None
+ })
+ .flat_map(|word| word.split_inclusive('_'))
+}
+
trait RangeExt<T> {
fn sorted(&self) -> Range<T>;
fn to_inclusive(&self) -> RangeInclusive<T>;
@@ -5439,6 +5439,20 @@ async fn go_to_hunk(deterministic: Arc<Deterministic>, cx: &mut gpui::TestAppCon
);
}
+#[test]
+fn test_split_words() {
+ fn split<'a>(text: &'a str) -> Vec<&'a str> {
+ split_words(text).collect()
+ }
+
+ assert_eq!(split("HelloWorld"), &["Hello", "World"]);
+ assert_eq!(split("hello_world"), &["hello_", "world"]);
+ assert_eq!(split("_hello_world_"), &["_", "hello_", "world_"]);
+ assert_eq!(split("Hello_World"), &["Hello_", "World"]);
+ assert_eq!(split("helloWOrld"), &["hello", "WOrld"]);
+ assert_eq!(split("helloworld"), &["helloworld"]);
+}
+
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
let point = DisplayPoint::new(row as u32, column as u32);
point..point