diff --git a/zed/src/editor.rs b/zed/src/editor.rs
index 4a5958267e..dbc1cf71a0 100644
--- a/zed/src/editor.rs
+++ b/zed/src/editor.rs
@@ -1493,8 +1493,26 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         self.start_transaction(cx);
-        self.select_to_previous_word_boundary(&SelectToPreviousWordBoundary, cx);
-        self.backspace(&Backspace, cx);
+        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        let mut selections = self.selections(cx.as_ref()).to_vec();
+        {
+            let buffer = self.buffer.read(cx);
+            for selection in &mut selections {
+                let range = selection.point_range(buffer);
+                if range.start == range.end {
+                    let head = selection.head().to_display_point(&display_map, Bias::Left);
+                    let cursor = display_map.anchor_before(
+                        movement::prev_word_boundary(&display_map, head).unwrap(),
+                        Bias::Right,
+                    );
+                    selection.set_head(&buffer, cursor);
+                    selection.goal = SelectionGoal::None;
+                }
+            }
+        }
+
+        self.update_selections(selections, true, cx);
+        self.insert(&Insert(String::new()), cx);
         self.end_transaction(cx);
     }
 
@@ -1545,8 +1563,26 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         self.start_transaction(cx);
-        self.select_to_next_word_boundary(&SelectToNextWordBoundary, cx);
-        self.delete(&Delete, cx);
+        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        let mut selections = self.selections(cx.as_ref()).to_vec();
+        {
+            let buffer = self.buffer.read(cx);
+            for selection in &mut selections {
+                let range = selection.point_range(buffer);
+                if range.start == range.end {
+                    let head = selection.head().to_display_point(&display_map, Bias::Left);
+                    let cursor = display_map.anchor_before(
+                        movement::next_word_boundary(&display_map, head).unwrap(),
+                        Bias::Right,
+                    );
+                    selection.set_head(&buffer, cursor);
+                    selection.goal = SelectionGoal::None;
+                }
+            }
+        }
+
+        self.update_selections(selections, true, cx);
+        self.insert(&Insert(String::new()), cx);
         self.end_transaction(cx);
     }
 
@@ -3226,24 +3262,13 @@ mod tests {
             );
         });
 
-        view.update(cx, |view, cx| {
-            view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
-            assert_eq!(
-                view.selection_ranges(cx),
-                &[
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                ]
-            );
-        });
-
         view.update(cx, |view, cx| {
             view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
             assert_eq!(
                 view.selection_ranges(cx),
                 &[
                     DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
+                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
                 ]
             );
         });
@@ -3275,30 +3300,19 @@ mod tests {
             assert_eq!(
                 view.selection_ranges(cx),
                 &[
-                    DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
+                    DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
                     DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
                 ]
             );
         });
 
-        view.update(cx, |view, cx| {
-            view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
-            assert_eq!(
-                view.selection_ranges(cx),
-                &[
-                    DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
-                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
-                ]
-            );
-        });
-
         view.update(cx, |view, cx| {
             view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
             assert_eq!(
                 view.selection_ranges(cx),
                 &[
                     DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
+                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
                 ]
             );
         });
@@ -3310,7 +3324,7 @@ mod tests {
                 view.selection_ranges(cx),
                 &[
                     DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
+                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 3),
                 ]
             );
         });
@@ -3321,7 +3335,7 @@ mod tests {
                 view.selection_ranges(cx),
                 &[
                     DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0),
+                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 2),
                 ]
             );
         });
@@ -3332,37 +3346,7 @@ mod tests {
                 view.selection_ranges(cx),
                 &[
                     DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
-                ]
-            );
-        });
-
-        view.update(cx, |view, cx| {
-            view.delete_to_next_word_boundary(&DeleteToNextWordBoundary, cx);
-            assert_eq!(
-                view.display_text(cx),
-                "use std::s::{foo, bar}\n\n  {az.qux()}"
-            );
-            assert_eq!(
-                view.selection_ranges(cx),
-                &[
-                    DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
-                ]
-            );
-        });
-
-        view.update(cx, |view, cx| {
-            view.delete_to_previous_word_boundary(&DeleteToPreviousWordBoundary, cx);
-            assert_eq!(
-                view.display_text(cx),
-                "use std::::{foo, bar}\n\n  az.qux()}"
-            );
-            assert_eq!(
-                view.selection_ranges(cx),
-                &[
-                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
+                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 3),
                 ]
             );
         });
@@ -3418,11 +3402,52 @@ mod tests {
             view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
             assert_eq!(
                 view.selection_ranges(cx),
-                &[DisplayPoint::new(1, 15)..DisplayPoint::new(1, 15)]
+                &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
             );
         });
     }
 
+    #[gpui::test]
+    fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
+        let buffer = cx.add_model(|cx| Buffer::new(0, "one two three four", cx));
+        let settings = settings::test(&cx).1;
+        let (_, view) = cx.add_window(Default::default(), |cx| {
+            build_editor(buffer.clone(), settings, cx)
+        });
+
+        view.update(cx, |view, cx| {
+            view.select_display_ranges(
+                &[
+                    // an empty selection - the preceding word fragment is deleted
+                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                    // characters selected - they are deleted
+                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 12),
+                ],
+                cx,
+            )
+            .unwrap();
+            view.delete_to_previous_word_boundary(&DeleteToPreviousWordBoundary, cx);
+        });
+
+        assert_eq!(buffer.read(cx).text(), "e two te four");
+
+        view.update(cx, |view, cx| {
+            view.select_display_ranges(
+                &[
+                    // an empty selection - the following word fragment is deleted
+                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                    // characters selected - they are deleted
+                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 10),
+                ],
+                cx,
+            )
+            .unwrap();
+            view.delete_to_next_word_boundary(&DeleteToNextWordBoundary, cx);
+        });
+
+        assert_eq!(buffer.read(cx).text(), "e t te our");
+    }
+
     #[gpui::test]
     fn test_backspace(cx: &mut gpui::MutableAppContext) {
         let buffer = cx.add_model(|cx| {
diff --git a/zed/src/editor/movement.rs b/zed/src/editor/movement.rs
index 8f5bc6f20a..d86aa9ca53 100644
--- a/zed/src/editor/movement.rs
+++ b/zed/src/editor/movement.rs
@@ -101,7 +101,10 @@ pub fn line_end(map: &DisplayMapSnapshot, point: DisplayPoint) -> Result<Display
     Ok(map.clip_point(line_end, Bias::Left))
 }
 
-pub fn prev_word_boundary(map: &DisplayMapSnapshot, point: DisplayPoint) -> Result<DisplayPoint> {
+pub fn prev_word_boundary(
+    map: &DisplayMapSnapshot,
+    mut point: DisplayPoint,
+) -> Result<DisplayPoint> {
     let mut line_start = 0;
     if point.row() > 0 {
         if let Some(indent) = map.soft_wrap_indent(point.row() - 1) {
@@ -111,39 +114,52 @@ pub fn prev_word_boundary(map: &DisplayMapSnapshot, point: DisplayPoint) -> Resu
 
     if point.column() == line_start {
         if point.row() == 0 {
-            Ok(DisplayPoint::new(0, 0))
+            return Ok(DisplayPoint::new(0, 0));
         } else {
             let row = point.row() - 1;
-            Ok(map.clip_point(DisplayPoint::new(row, map.line_len(row)), Bias::Left))
+            point = map.clip_point(DisplayPoint::new(row, map.line_len(row)), Bias::Left);
         }
-    } else {
-        let mut boundary = DisplayPoint::new(point.row(), 0);
-        let mut column = 0;
-        let mut prev_c = None;
-        for c in map.chars_at(DisplayPoint::new(point.row(), 0)) {
-            if column >= point.column() {
-                break;
-            }
-
-            if prev_c.is_none() || char_kind(prev_c.unwrap()) != char_kind(c) {
-                *boundary.column_mut() = column;
-            }
-
-            prev_c = Some(c);
-            column += c.len_utf8() as u32;
-        }
-        Ok(boundary)
     }
+
+    let mut boundary = DisplayPoint::new(point.row(), 0);
+    let mut column = 0;
+    let mut prev_char_kind = CharKind::Newline;
+    for c in map.chars_at(DisplayPoint::new(point.row(), 0)) {
+        if column >= point.column() {
+            break;
+        }
+
+        let char_kind = char_kind(c);
+        if char_kind != prev_char_kind
+            && char_kind != CharKind::Whitespace
+            && char_kind != CharKind::Newline
+        {
+            *boundary.column_mut() = column;
+        }
+
+        prev_char_kind = char_kind;
+        column += c.len_utf8() as u32;
+    }
+    Ok(boundary)
 }
 
 pub fn next_word_boundary(
     map: &DisplayMapSnapshot,
     mut point: DisplayPoint,
 ) -> Result<DisplayPoint> {
-    let mut prev_c = None;
+    let mut prev_char_kind = None;
     for c in map.chars_at(point) {
-        if prev_c.is_some() && (c == '\n' || char_kind(prev_c.unwrap()) != char_kind(c)) {
-            break;
+        let char_kind = char_kind(c);
+        if let Some(prev_char_kind) = prev_char_kind {
+            if c == '\n' {
+                break;
+            }
+            if prev_char_kind != char_kind
+                && prev_char_kind != CharKind::Whitespace
+                && prev_char_kind != CharKind::Newline
+            {
+                break;
+            }
         }
 
         if c == '\n' {
@@ -152,7 +168,7 @@ pub fn next_word_boundary(
         } else {
             *point.column_mut() += c.len_utf8() as u32;
         }
-        prev_c = Some(c);
+        prev_char_kind = Some(char_kind);
     }
     Ok(point)
 }
@@ -192,7 +208,7 @@ mod tests {
             .unwrap();
         let font_size = 14.0;
 
-        let buffer = cx.add_model(|cx| Buffer::new(0, "a bcΔ defγ", cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, "a bcΔ defγ hi—jk", cx));
         let display_map =
             cx.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, cx));
         let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -202,7 +218,7 @@ mod tests {
         );
         assert_eq!(
             prev_word_boundary(&snapshot, DisplayPoint::new(0, 7)).unwrap(),
-            DisplayPoint::new(0, 6)
+            DisplayPoint::new(0, 2)
         );
         assert_eq!(
             prev_word_boundary(&snapshot, DisplayPoint::new(0, 6)).unwrap(),
@@ -210,7 +226,7 @@ mod tests {
         );
         assert_eq!(
             prev_word_boundary(&snapshot, DisplayPoint::new(0, 2)).unwrap(),
-            DisplayPoint::new(0, 1)
+            DisplayPoint::new(0, 0)
         );
         assert_eq!(
             prev_word_boundary(&snapshot, DisplayPoint::new(0, 1)).unwrap(),
@@ -223,7 +239,7 @@ mod tests {
         );
         assert_eq!(
             next_word_boundary(&snapshot, DisplayPoint::new(0, 1)).unwrap(),
-            DisplayPoint::new(0, 2)
+            DisplayPoint::new(0, 6)
         );
         assert_eq!(
             next_word_boundary(&snapshot, DisplayPoint::new(0, 2)).unwrap(),
@@ -231,7 +247,7 @@ mod tests {
         );
         assert_eq!(
             next_word_boundary(&snapshot, DisplayPoint::new(0, 6)).unwrap(),
-            DisplayPoint::new(0, 7)
+            DisplayPoint::new(0, 12)
         );
         assert_eq!(
             next_word_boundary(&snapshot, DisplayPoint::new(0, 7)).unwrap(),