Implement whole word mode

Antonio Scandurra created

Change summary

crates/editor/src/editor.rs   | 20 ++++++++++++++++++++
crates/editor/src/movement.rs | 22 +---------------------
crates/find/src/find.rs       | 25 ++++++++++++++++++++++---
3 files changed, 43 insertions(+), 24 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -438,6 +438,14 @@ pub struct NavigationData {
     offset: usize,
 }
 
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
+pub enum CharKind {
+    Newline,
+    Punctuation,
+    Whitespace,
+    Word,
+}
+
 impl Editor {
     pub fn single_line(build_settings: BuildSettings, cx: &mut ViewContext<Self>) -> Self {
         let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
@@ -4215,6 +4223,18 @@ pub fn settings_builder(
     })
 }
 
+pub fn char_kind(c: char) -> CharKind {
+    if c == '\n' {
+        CharKind::Newline
+    } else if c.is_whitespace() {
+        CharKind::Whitespace
+    } else if c.is_alphanumeric() || c == '_' {
+        CharKind::Word
+    } else {
+        CharKind::Punctuation
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;

crates/editor/src/movement.rs 🔗

@@ -1,5 +1,5 @@
 use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
-use crate::ToPoint;
+use crate::{char_kind, CharKind, ToPoint};
 use anyhow::Result;
 use std::{cmp, ops::Range};
 
@@ -215,26 +215,6 @@ pub fn surrounding_word(map: &DisplaySnapshot, point: DisplayPoint) -> Range<Dis
         ..end.to_point(&map.buffer_snapshot).to_display_point(map)
 }
 
-#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
-enum CharKind {
-    Newline,
-    Punctuation,
-    Whitespace,
-    Word,
-}
-
-fn char_kind(c: char) -> CharKind {
-    if c == '\n' {
-        CharKind::Newline
-    } else if c.is_whitespace() {
-        CharKind::Whitespace
-    } else if c.is_alphanumeric() || c == '_' {
-        CharKind::Word
-    } else {
-        CharKind::Punctuation
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;

crates/find/src/find.rs 🔗

@@ -1,5 +1,5 @@
 use aho_corasick::AhoCorasickBuilder;
-use editor::{Editor, EditorSettings};
+use editor::{char_kind, Editor, EditorSettings};
 use gpui::{
     action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View,
     ViewContext, ViewHandle,
@@ -200,9 +200,28 @@ impl FindBar {
                 let buffer = editor.buffer().read(cx).snapshot(cx);
                 let ranges = search
                     .stream_find_iter(buffer.bytes_in_range(0..buffer.len()))
-                    .map(|mat| {
+                    .filter_map(|mat| {
                         let mat = mat.unwrap();
-                        buffer.anchor_after(mat.start())..buffer.anchor_before(mat.end())
+
+                        if self.whole_word_mode {
+                            let prev_kind =
+                                buffer.reversed_chars_at(mat.start()).next().map(char_kind);
+                            let start_kind =
+                                char_kind(buffer.chars_at(mat.start()).next().unwrap());
+                            let end_kind =
+                                char_kind(buffer.reversed_chars_at(mat.end()).next().unwrap());
+                            let next_kind = buffer.chars_at(mat.end()).next().map(char_kind);
+                            if Some(start_kind) != prev_kind && Some(end_kind) != next_kind {
+                                Some(
+                                    buffer.anchor_after(mat.start())
+                                        ..buffer.anchor_before(mat.end()),
+                                )
+                            } else {
+                                None
+                            }
+                        } else {
+                            Some(buffer.anchor_after(mat.start())..buffer.anchor_before(mat.end()))
+                        }
                     })
                     .collect();
                 editor.highlight_ranges::<Self>(ranges, theme.match_background, cx);