Use `gpui::test` macro for synchronous tests in zed

Antonio Scandurra created

Change summary

zed/src/editor/buffer/mod.rs           |  979 +++++------
zed/src/editor/buffer_view.rs          | 2305 +++++++++++++--------------
zed/src/editor/display_map/fold_map.rs |  639 +++---
zed/src/editor/display_map/mod.rs      |  101 
zed/src/workspace.rs                   |  112 
5 files changed, 2,007 insertions(+), 2,129 deletions(-)

Detailed changes

zed/src/editor/buffer/mod.rs 🔗

@@ -2393,259 +2393,245 @@ mod tests {
         sync::atomic::{self, AtomicUsize},
     };
 
-    #[test]
-    fn test_edit() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
-                let mut buffer = Buffer::new(0, "abc", ctx);
-                assert_eq!(buffer.text(), "abc");
-                buffer.edit(vec![3..3], "def", None).unwrap();
-                assert_eq!(buffer.text(), "abcdef");
-                buffer.edit(vec![0..0], "ghi", None).unwrap();
-                assert_eq!(buffer.text(), "ghiabcdef");
-                buffer.edit(vec![5..5], "jkl", None).unwrap();
-                assert_eq!(buffer.text(), "ghiabjklcdef");
-                buffer.edit(vec![6..7], "", None).unwrap();
-                assert_eq!(buffer.text(), "ghiabjlcdef");
-                buffer.edit(vec![4..9], "mno", None).unwrap();
-                assert_eq!(buffer.text(), "ghiamnoef");
-                buffer
-            });
-        })
+    #[gpui::test]
+    fn test_edit(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
+            let mut buffer = Buffer::new(0, "abc", ctx);
+            assert_eq!(buffer.text(), "abc");
+            buffer.edit(vec![3..3], "def", None).unwrap();
+            assert_eq!(buffer.text(), "abcdef");
+            buffer.edit(vec![0..0], "ghi", None).unwrap();
+            assert_eq!(buffer.text(), "ghiabcdef");
+            buffer.edit(vec![5..5], "jkl", None).unwrap();
+            assert_eq!(buffer.text(), "ghiabjklcdef");
+            buffer.edit(vec![6..7], "", None).unwrap();
+            assert_eq!(buffer.text(), "ghiabjlcdef");
+            buffer.edit(vec![4..9], "mno", None).unwrap();
+            assert_eq!(buffer.text(), "ghiamnoef");
+            buffer
+        });
     }
 
-    #[test]
-    fn test_edit_events() {
-        App::test((), |app| {
-            let mut now = Instant::now();
-            let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
-            let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
-
-            let buffer1 = app.add_model(|ctx| Buffer::new(0, "abcdef", ctx));
-            let buffer2 = app.add_model(|ctx| Buffer::new(1, "abcdef", ctx));
-            let mut buffer_ops = Vec::new();
-            buffer1.update(app, |buffer, ctx| {
-                let buffer_1_events = buffer_1_events.clone();
-                ctx.subscribe(&buffer1, move |_, event, _| {
-                    buffer_1_events.borrow_mut().push(event.clone())
-                });
-                let buffer_2_events = buffer_2_events.clone();
-                ctx.subscribe(&buffer2, move |_, event, _| {
-                    buffer_2_events.borrow_mut().push(event.clone())
-                });
+    #[gpui::test]
+    fn test_edit_events(app: &mut gpui::MutableAppContext) {
+        let mut now = Instant::now();
+        let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
+        let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
 
-                // An edit emits an edited event, followed by a dirtied event,
-                // since the buffer was previously in a clean state.
-                let ops = buffer.edit(Some(2..4), "XYZ", Some(ctx)).unwrap();
-                buffer_ops.extend_from_slice(&ops);
-
-                // An empty transaction does not emit any events.
-                buffer.start_transaction(None).unwrap();
-                buffer.end_transaction(None, Some(ctx)).unwrap();
-
-                // A transaction containing two edits emits one edited event.
-                now += Duration::from_secs(1);
-                buffer.start_transaction_at(None, now).unwrap();
-                let ops = buffer.edit(Some(5..5), "u", Some(ctx)).unwrap();
-                buffer_ops.extend_from_slice(&ops);
-                let ops = buffer.edit(Some(6..6), "w", Some(ctx)).unwrap();
-                buffer_ops.extend_from_slice(&ops);
-                buffer.end_transaction_at(None, now, Some(ctx)).unwrap();
-
-                // Undoing a transaction emits one edited event.
-                let ops = buffer.undo(Some(ctx));
-                buffer_ops.extend_from_slice(&ops);
+        let buffer1 = app.add_model(|ctx| Buffer::new(0, "abcdef", ctx));
+        let buffer2 = app.add_model(|ctx| Buffer::new(1, "abcdef", ctx));
+        let mut buffer_ops = Vec::new();
+        buffer1.update(app, |buffer, ctx| {
+            let buffer_1_events = buffer_1_events.clone();
+            ctx.subscribe(&buffer1, move |_, event, _| {
+                buffer_1_events.borrow_mut().push(event.clone())
             });
-
-            // Incorporating a set of remote ops emits a single edited event,
-            // followed by a dirtied event.
-            buffer2.update(app, |buffer, ctx| {
-                buffer.apply_ops(buffer_ops, Some(ctx)).unwrap();
+            let buffer_2_events = buffer_2_events.clone();
+            ctx.subscribe(&buffer2, move |_, event, _| {
+                buffer_2_events.borrow_mut().push(event.clone())
             });
 
-            let buffer_1_events = buffer_1_events.borrow();
-            assert_eq!(
-                *buffer_1_events,
-                vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
-            );
+            // An edit emits an edited event, followed by a dirtied event,
+            // since the buffer was previously in a clean state.
+            let ops = buffer.edit(Some(2..4), "XYZ", Some(ctx)).unwrap();
+            buffer_ops.extend_from_slice(&ops);
+
+            // An empty transaction does not emit any events.
+            buffer.start_transaction(None).unwrap();
+            buffer.end_transaction(None, Some(ctx)).unwrap();
+
+            // A transaction containing two edits emits one edited event.
+            now += Duration::from_secs(1);
+            buffer.start_transaction_at(None, now).unwrap();
+            let ops = buffer.edit(Some(5..5), "u", Some(ctx)).unwrap();
+            buffer_ops.extend_from_slice(&ops);
+            let ops = buffer.edit(Some(6..6), "w", Some(ctx)).unwrap();
+            buffer_ops.extend_from_slice(&ops);
+            buffer.end_transaction_at(None, now, Some(ctx)).unwrap();
+
+            // Undoing a transaction emits one edited event.
+            let ops = buffer.undo(Some(ctx));
+            buffer_ops.extend_from_slice(&ops);
+        });
 
-            let buffer_2_events = buffer_2_events.borrow();
-            assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
+        // Incorporating a set of remote ops emits a single edited event,
+        // followed by a dirtied event.
+        buffer2.update(app, |buffer, ctx| {
+            buffer.apply_ops(buffer_ops, Some(ctx)).unwrap();
         });
+
+        let buffer_1_events = buffer_1_events.borrow();
+        assert_eq!(
+            *buffer_1_events,
+            vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
+        );
+
+        let buffer_2_events = buffer_2_events.borrow();
+        assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
     }
 
-    #[test]
-    fn test_random_edits() {
+    #[gpui::test]
+    fn test_random_edits(ctx: &mut gpui::MutableAppContext) {
         for seed in 0..100 {
-            App::test((), |ctx| {
-                println!("{:?}", seed);
-                let mut rng = &mut StdRng::seed_from_u64(seed);
-
-                let reference_string_len = rng.gen_range(0..3);
-                let mut reference_string = RandomCharIter::new(&mut rng)
-                    .take(reference_string_len)
-                    .collect::<String>();
-                ctx.add_model(|ctx| {
-                    let mut buffer = Buffer::new(0, reference_string.as_str(), ctx);
-                    let mut buffer_versions = Vec::new();
-                    for _i in 0..10 {
-                        let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None);
-                        for old_range in old_ranges.iter().rev() {
-                            reference_string = [
-                                &reference_string[0..old_range.start],
-                                new_text.as_str(),
-                                &reference_string[old_range.end..],
-                            ]
-                            .concat();
-                        }
-                        assert_eq!(buffer.text(), reference_string);
+            println!("{:?}", seed);
+            let mut rng = &mut StdRng::seed_from_u64(seed);
 
-                        if rng.gen_bool(0.25) {
-                            buffer.randomly_undo_redo(rng);
-                            reference_string = buffer.text();
-                        }
+            let reference_string_len = rng.gen_range(0..3);
+            let mut reference_string = RandomCharIter::new(&mut rng)
+                .take(reference_string_len)
+                .collect::<String>();
+            ctx.add_model(|ctx| {
+                let mut buffer = Buffer::new(0, reference_string.as_str(), ctx);
+                let mut buffer_versions = Vec::new();
+                for _i in 0..10 {
+                    let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None);
+                    for old_range in old_ranges.iter().rev() {
+                        reference_string = [
+                            &reference_string[0..old_range.start],
+                            new_text.as_str(),
+                            &reference_string[old_range.end..],
+                        ]
+                        .concat();
+                    }
+                    assert_eq!(buffer.text(), reference_string);
 
-                        {
-                            let line_lengths = line_lengths_in_range(&buffer, 0..buffer.len());
+                    if rng.gen_bool(0.25) {
+                        buffer.randomly_undo_redo(rng);
+                        reference_string = buffer.text();
+                    }
 
-                            for (len, rows) in &line_lengths {
-                                for row in rows {
-                                    assert_eq!(buffer.line_len(*row).unwrap(), *len);
-                                }
-                            }
+                    {
+                        let line_lengths = line_lengths_in_range(&buffer, 0..buffer.len());
 
-                            let (longest_column, longest_rows) =
-                                line_lengths.iter().next_back().unwrap();
-                            let rightmost_point = buffer.rightmost_point();
-                            assert_eq!(rightmost_point.column, *longest_column);
-                            assert!(longest_rows.contains(&rightmost_point.row));
+                        for (len, rows) in &line_lengths {
+                            for row in rows {
+                                assert_eq!(buffer.line_len(*row).unwrap(), *len);
+                            }
                         }
 
-                        for _ in 0..5 {
-                            let end = rng.gen_range(0..buffer.len() + 1);
-                            let start = rng.gen_range(0..end + 1);
-
-                            let line_lengths = line_lengths_in_range(&buffer, start..end);
-                            let (longest_column, longest_rows) =
-                                line_lengths.iter().next_back().unwrap();
-                            let range_sum = buffer.text_summary_for_range(start..end);
-                            assert_eq!(range_sum.rightmost_point.column, *longest_column);
-                            assert!(longest_rows.contains(&range_sum.rightmost_point.row));
-                            let range_text = &buffer.text()[start..end];
-                            assert_eq!(range_sum.chars, range_text.chars().count());
-                            assert_eq!(range_sum.bytes, range_text.len());
-                        }
+                        let (longest_column, longest_rows) =
+                            line_lengths.iter().next_back().unwrap();
+                        let rightmost_point = buffer.rightmost_point();
+                        assert_eq!(rightmost_point.column, *longest_column);
+                        assert!(longest_rows.contains(&rightmost_point.row));
+                    }
 
-                        if rng.gen_bool(0.3) {
-                            buffer_versions.push(buffer.clone());
-                        }
+                    for _ in 0..5 {
+                        let end = rng.gen_range(0..buffer.len() + 1);
+                        let start = rng.gen_range(0..end + 1);
+
+                        let line_lengths = line_lengths_in_range(&buffer, start..end);
+                        let (longest_column, longest_rows) =
+                            line_lengths.iter().next_back().unwrap();
+                        let range_sum = buffer.text_summary_for_range(start..end);
+                        assert_eq!(range_sum.rightmost_point.column, *longest_column);
+                        assert!(longest_rows.contains(&range_sum.rightmost_point.row));
+                        let range_text = &buffer.text()[start..end];
+                        assert_eq!(range_sum.chars, range_text.chars().count());
+                        assert_eq!(range_sum.bytes, range_text.len());
                     }
 
-                    for mut old_buffer in buffer_versions {
-                        let mut delta = 0_isize;
-                        for Edit {
-                            old_range,
-                            new_range,
-                        } in buffer.edits_since(old_buffer.version.clone())
-                        {
-                            let old_len = old_range.end - old_range.start;
-                            let new_len = new_range.end - new_range.start;
-                            let old_start = (old_range.start as isize + delta) as usize;
-                            let new_text: String =
-                                buffer.text_for_range(new_range).unwrap().collect();
-                            old_buffer
-                                .edit(Some(old_start..old_start + old_len), new_text, None)
-                                .unwrap();
-
-                            delta += new_len as isize - old_len as isize;
-                        }
-                        assert_eq!(old_buffer.text(), buffer.text());
+                    if rng.gen_bool(0.3) {
+                        buffer_versions.push(buffer.clone());
                     }
+                }
 
-                    buffer
-                })
+                for mut old_buffer in buffer_versions {
+                    let mut delta = 0_isize;
+                    for Edit {
+                        old_range,
+                        new_range,
+                    } in buffer.edits_since(old_buffer.version.clone())
+                    {
+                        let old_len = old_range.end - old_range.start;
+                        let new_len = new_range.end - new_range.start;
+                        let old_start = (old_range.start as isize + delta) as usize;
+                        let new_text: String = buffer.text_for_range(new_range).unwrap().collect();
+                        old_buffer
+                            .edit(Some(old_start..old_start + old_len), new_text, None)
+                            .unwrap();
+
+                        delta += new_len as isize - old_len as isize;
+                    }
+                    assert_eq!(old_buffer.text(), buffer.text());
+                }
+
+                buffer
             });
         }
     }
 
-    #[test]
-    fn test_line_len() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
-                let mut buffer = Buffer::new(0, "", ctx);
-                buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap();
-                buffer.edit(vec![12..12], "kl\nmno", None).unwrap();
-                buffer.edit(vec![18..18], "\npqrs\n", None).unwrap();
-                buffer.edit(vec![18..21], "\nPQ", None).unwrap();
-
-                assert_eq!(buffer.line_len(0).unwrap(), 4);
-                assert_eq!(buffer.line_len(1).unwrap(), 3);
-                assert_eq!(buffer.line_len(2).unwrap(), 5);
-                assert_eq!(buffer.line_len(3).unwrap(), 3);
-                assert_eq!(buffer.line_len(4).unwrap(), 4);
-                assert_eq!(buffer.line_len(5).unwrap(), 0);
-                assert!(buffer.line_len(6).is_err());
-                buffer
-            });
+    #[gpui::test]
+    fn test_line_len(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
+            let mut buffer = Buffer::new(0, "", ctx);
+            buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap();
+            buffer.edit(vec![12..12], "kl\nmno", None).unwrap();
+            buffer.edit(vec![18..18], "\npqrs\n", None).unwrap();
+            buffer.edit(vec![18..21], "\nPQ", None).unwrap();
+
+            assert_eq!(buffer.line_len(0).unwrap(), 4);
+            assert_eq!(buffer.line_len(1).unwrap(), 3);
+            assert_eq!(buffer.line_len(2).unwrap(), 5);
+            assert_eq!(buffer.line_len(3).unwrap(), 3);
+            assert_eq!(buffer.line_len(4).unwrap(), 4);
+            assert_eq!(buffer.line_len(5).unwrap(), 0);
+            assert!(buffer.line_len(6).is_err());
+            buffer
         });
     }
 
-    #[test]
-    fn test_rightmost_point() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
-                let mut buffer = Buffer::new(0, "", ctx);
-                assert_eq!(buffer.rightmost_point().row, 0);
-                buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap();
-                assert_eq!(buffer.rightmost_point().row, 0);
-                buffer.edit(vec![12..12], "kl\nmno", None).unwrap();
-                assert_eq!(buffer.rightmost_point().row, 2);
-                buffer.edit(vec![18..18], "\npqrs", None).unwrap();
-                assert_eq!(buffer.rightmost_point().row, 2);
-                buffer.edit(vec![10..12], "", None).unwrap();
-                assert_eq!(buffer.rightmost_point().row, 0);
-                buffer.edit(vec![24..24], "tuv", None).unwrap();
-                assert_eq!(buffer.rightmost_point().row, 4);
-                buffer
-            });
+    #[gpui::test]
+    fn test_rightmost_point(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
+            let mut buffer = Buffer::new(0, "", ctx);
+            assert_eq!(buffer.rightmost_point().row, 0);
+            buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap();
+            assert_eq!(buffer.rightmost_point().row, 0);
+            buffer.edit(vec![12..12], "kl\nmno", None).unwrap();
+            assert_eq!(buffer.rightmost_point().row, 2);
+            buffer.edit(vec![18..18], "\npqrs", None).unwrap();
+            assert_eq!(buffer.rightmost_point().row, 2);
+            buffer.edit(vec![10..12], "", None).unwrap();
+            assert_eq!(buffer.rightmost_point().row, 0);
+            buffer.edit(vec![24..24], "tuv", None).unwrap();
+            assert_eq!(buffer.rightmost_point().row, 4);
+            buffer
         });
     }
 
-    #[test]
-    fn test_text_summary_for_range() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
-                let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", ctx);
-                let text = Text::from(buffer.text());
-                assert_eq!(
-                    buffer.text_summary_for_range(1..3),
-                    text.slice(1..3).summary()
-                );
-                assert_eq!(
-                    buffer.text_summary_for_range(1..12),
-                    text.slice(1..12).summary()
-                );
-                assert_eq!(
-                    buffer.text_summary_for_range(0..20),
-                    text.slice(0..20).summary()
-                );
-                assert_eq!(
-                    buffer.text_summary_for_range(0..22),
-                    text.slice(0..22).summary()
-                );
-                assert_eq!(
-                    buffer.text_summary_for_range(7..22),
-                    text.slice(7..22).summary()
-                );
-                buffer
-            });
+    #[gpui::test]
+    fn test_text_summary_for_range(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
+            let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", ctx);
+            let text = Text::from(buffer.text());
+            assert_eq!(
+                buffer.text_summary_for_range(1..3),
+                text.slice(1..3).summary()
+            );
+            assert_eq!(
+                buffer.text_summary_for_range(1..12),
+                text.slice(1..12).summary()
+            );
+            assert_eq!(
+                buffer.text_summary_for_range(0..20),
+                text.slice(0..20).summary()
+            );
+            assert_eq!(
+                buffer.text_summary_for_range(0..22),
+                text.slice(0..22).summary()
+            );
+            assert_eq!(
+                buffer.text_summary_for_range(7..22),
+                text.slice(7..22).summary()
+            );
+            buffer
         });
     }
 
-    #[test]
-    fn test_chars_at() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
+    #[gpui::test]
+    fn test_chars_at(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
                 let mut buffer = Buffer::new(0, "", ctx);
                 buffer.edit(vec![0..0], "abcd\nefgh\nij", None).unwrap();
                 buffer.edit(vec![12..12], "kl\nmno", None).unwrap();
@@ -2677,7 +2663,6 @@ mod tests {
 
                 buffer
             });
-        });
     }
 
     // #[test]
@@ -2794,196 +2779,192 @@ mod tests {
         }
     }
 
-    #[test]
-    fn test_anchors() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
-                let mut buffer = Buffer::new(0, "", ctx);
-                buffer.edit(vec![0..0], "abc", None).unwrap();
-                let left_anchor = buffer.anchor_before(2).unwrap();
-                let right_anchor = buffer.anchor_after(2).unwrap();
-
-                buffer.edit(vec![1..1], "def\n", None).unwrap();
-                assert_eq!(buffer.text(), "adef\nbc");
-                assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 6);
-                assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 6);
-                assert_eq!(
-                    left_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 1 }
-                );
-                assert_eq!(
-                    right_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 1 }
-                );
+    #[gpui::test]
+    fn test_anchors(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
+            let mut buffer = Buffer::new(0, "", ctx);
+            buffer.edit(vec![0..0], "abc", None).unwrap();
+            let left_anchor = buffer.anchor_before(2).unwrap();
+            let right_anchor = buffer.anchor_after(2).unwrap();
 
-                buffer.edit(vec![2..3], "", None).unwrap();
-                assert_eq!(buffer.text(), "adf\nbc");
-                assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5);
-                assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 5);
-                assert_eq!(
-                    left_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 1 }
-                );
-                assert_eq!(
-                    right_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 1 }
-                );
+            buffer.edit(vec![1..1], "def\n", None).unwrap();
+            assert_eq!(buffer.text(), "adef\nbc");
+            assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 6);
+            assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 6);
+            assert_eq!(
+                left_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 1 }
+            );
+            assert_eq!(
+                right_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 1 }
+            );
 
-                buffer.edit(vec![5..5], "ghi\n", None).unwrap();
-                assert_eq!(buffer.text(), "adf\nbghi\nc");
-                assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5);
-                assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 9);
-                assert_eq!(
-                    left_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 1 }
-                );
-                assert_eq!(
-                    right_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 2, column: 0 }
-                );
+            buffer.edit(vec![2..3], "", None).unwrap();
+            assert_eq!(buffer.text(), "adf\nbc");
+            assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5);
+            assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 5);
+            assert_eq!(
+                left_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 1 }
+            );
+            assert_eq!(
+                right_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 1 }
+            );
 
-                buffer.edit(vec![7..9], "", None).unwrap();
-                assert_eq!(buffer.text(), "adf\nbghc");
-                assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5);
-                assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 7);
-                assert_eq!(
-                    left_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 1 },
-                );
-                assert_eq!(
-                    right_anchor.to_point(&buffer).unwrap(),
-                    Point { row: 1, column: 3 }
-                );
+            buffer.edit(vec![5..5], "ghi\n", None).unwrap();
+            assert_eq!(buffer.text(), "adf\nbghi\nc");
+            assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5);
+            assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 9);
+            assert_eq!(
+                left_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 1 }
+            );
+            assert_eq!(
+                right_anchor.to_point(&buffer).unwrap(),
+                Point { row: 2, column: 0 }
+            );
 
-                // Ensure anchoring to a point is equivalent to anchoring to an offset.
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 0, column: 0 }).unwrap(),
-                    buffer.anchor_before(0).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 0, column: 1 }).unwrap(),
-                    buffer.anchor_before(1).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 0, column: 2 }).unwrap(),
-                    buffer.anchor_before(2).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 0, column: 3 }).unwrap(),
-                    buffer.anchor_before(3).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 1, column: 0 }).unwrap(),
-                    buffer.anchor_before(4).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 1, column: 1 }).unwrap(),
-                    buffer.anchor_before(5).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 1, column: 2 }).unwrap(),
-                    buffer.anchor_before(6).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 1, column: 3 }).unwrap(),
-                    buffer.anchor_before(7).unwrap()
-                );
-                assert_eq!(
-                    buffer.anchor_before(Point { row: 1, column: 4 }).unwrap(),
-                    buffer.anchor_before(8).unwrap()
-                );
+            buffer.edit(vec![7..9], "", None).unwrap();
+            assert_eq!(buffer.text(), "adf\nbghc");
+            assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5);
+            assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 7);
+            assert_eq!(
+                left_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 1 },
+            );
+            assert_eq!(
+                right_anchor.to_point(&buffer).unwrap(),
+                Point { row: 1, column: 3 }
+            );
 
-                // Comparison between anchors.
-                let anchor_at_offset_0 = buffer.anchor_before(0).unwrap();
-                let anchor_at_offset_1 = buffer.anchor_before(1).unwrap();
-                let anchor_at_offset_2 = buffer.anchor_before(2).unwrap();
+            // Ensure anchoring to a point is equivalent to anchoring to an offset.
+            assert_eq!(
+                buffer.anchor_before(Point { row: 0, column: 0 }).unwrap(),
+                buffer.anchor_before(0).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 0, column: 1 }).unwrap(),
+                buffer.anchor_before(1).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 0, column: 2 }).unwrap(),
+                buffer.anchor_before(2).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 0, column: 3 }).unwrap(),
+                buffer.anchor_before(3).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 1, column: 0 }).unwrap(),
+                buffer.anchor_before(4).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 1, column: 1 }).unwrap(),
+                buffer.anchor_before(5).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 1, column: 2 }).unwrap(),
+                buffer.anchor_before(6).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 1, column: 3 }).unwrap(),
+                buffer.anchor_before(7).unwrap()
+            );
+            assert_eq!(
+                buffer.anchor_before(Point { row: 1, column: 4 }).unwrap(),
+                buffer.anchor_before(8).unwrap()
+            );
 
-                assert_eq!(
-                    anchor_at_offset_0
-                        .cmp(&anchor_at_offset_0, &buffer)
-                        .unwrap(),
-                    Ordering::Equal
-                );
-                assert_eq!(
-                    anchor_at_offset_1
-                        .cmp(&anchor_at_offset_1, &buffer)
-                        .unwrap(),
-                    Ordering::Equal
-                );
-                assert_eq!(
-                    anchor_at_offset_2
-                        .cmp(&anchor_at_offset_2, &buffer)
-                        .unwrap(),
-                    Ordering::Equal
-                );
+            // Comparison between anchors.
+            let anchor_at_offset_0 = buffer.anchor_before(0).unwrap();
+            let anchor_at_offset_1 = buffer.anchor_before(1).unwrap();
+            let anchor_at_offset_2 = buffer.anchor_before(2).unwrap();
 
-                assert_eq!(
-                    anchor_at_offset_0
-                        .cmp(&anchor_at_offset_1, &buffer)
-                        .unwrap(),
-                    Ordering::Less
-                );
-                assert_eq!(
-                    anchor_at_offset_1
-                        .cmp(&anchor_at_offset_2, &buffer)
-                        .unwrap(),
-                    Ordering::Less
-                );
-                assert_eq!(
-                    anchor_at_offset_0
-                        .cmp(&anchor_at_offset_2, &buffer)
-                        .unwrap(),
-                    Ordering::Less
-                );
+            assert_eq!(
+                anchor_at_offset_0
+                    .cmp(&anchor_at_offset_0, &buffer)
+                    .unwrap(),
+                Ordering::Equal
+            );
+            assert_eq!(
+                anchor_at_offset_1
+                    .cmp(&anchor_at_offset_1, &buffer)
+                    .unwrap(),
+                Ordering::Equal
+            );
+            assert_eq!(
+                anchor_at_offset_2
+                    .cmp(&anchor_at_offset_2, &buffer)
+                    .unwrap(),
+                Ordering::Equal
+            );
 
-                assert_eq!(
-                    anchor_at_offset_1
-                        .cmp(&anchor_at_offset_0, &buffer)
-                        .unwrap(),
-                    Ordering::Greater
-                );
-                assert_eq!(
-                    anchor_at_offset_2
-                        .cmp(&anchor_at_offset_1, &buffer)
-                        .unwrap(),
-                    Ordering::Greater
-                );
-                assert_eq!(
-                    anchor_at_offset_2
-                        .cmp(&anchor_at_offset_0, &buffer)
-                        .unwrap(),
-                    Ordering::Greater
-                );
-                buffer
-            });
+            assert_eq!(
+                anchor_at_offset_0
+                    .cmp(&anchor_at_offset_1, &buffer)
+                    .unwrap(),
+                Ordering::Less
+            );
+            assert_eq!(
+                anchor_at_offset_1
+                    .cmp(&anchor_at_offset_2, &buffer)
+                    .unwrap(),
+                Ordering::Less
+            );
+            assert_eq!(
+                anchor_at_offset_0
+                    .cmp(&anchor_at_offset_2, &buffer)
+                    .unwrap(),
+                Ordering::Less
+            );
+
+            assert_eq!(
+                anchor_at_offset_1
+                    .cmp(&anchor_at_offset_0, &buffer)
+                    .unwrap(),
+                Ordering::Greater
+            );
+            assert_eq!(
+                anchor_at_offset_2
+                    .cmp(&anchor_at_offset_1, &buffer)
+                    .unwrap(),
+                Ordering::Greater
+            );
+            assert_eq!(
+                anchor_at_offset_2
+                    .cmp(&anchor_at_offset_0, &buffer)
+                    .unwrap(),
+                Ordering::Greater
+            );
+            buffer
         });
     }
 
-    #[test]
-    fn test_anchors_at_start_and_end() {
-        App::test((), |ctx| {
-            ctx.add_model(|ctx| {
-                let mut buffer = Buffer::new(0, "", ctx);
-                let before_start_anchor = buffer.anchor_before(0).unwrap();
-                let after_end_anchor = buffer.anchor_after(0).unwrap();
-
-                buffer.edit(vec![0..0], "abc", None).unwrap();
-                assert_eq!(buffer.text(), "abc");
-                assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0);
-                assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 3);
-
-                let after_start_anchor = buffer.anchor_after(0).unwrap();
-                let before_end_anchor = buffer.anchor_before(3).unwrap();
-
-                buffer.edit(vec![3..3], "def", None).unwrap();
-                buffer.edit(vec![0..0], "ghi", None).unwrap();
-                assert_eq!(buffer.text(), "ghiabcdef");
-                assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0);
-                assert_eq!(after_start_anchor.to_offset(&buffer).unwrap(), 3);
-                assert_eq!(before_end_anchor.to_offset(&buffer).unwrap(), 6);
-                assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 9);
-                buffer
-            });
+    #[gpui::test]
+    fn test_anchors_at_start_and_end(ctx: &mut gpui::MutableAppContext) {
+        ctx.add_model(|ctx| {
+            let mut buffer = Buffer::new(0, "", ctx);
+            let before_start_anchor = buffer.anchor_before(0).unwrap();
+            let after_end_anchor = buffer.anchor_after(0).unwrap();
+
+            buffer.edit(vec![0..0], "abc", None).unwrap();
+            assert_eq!(buffer.text(), "abc");
+            assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0);
+            assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 3);
+
+            let after_start_anchor = buffer.anchor_after(0).unwrap();
+            let before_end_anchor = buffer.anchor_before(3).unwrap();
+
+            buffer.edit(vec![3..3], "def", None).unwrap();
+            buffer.edit(vec![0..0], "ghi", None).unwrap();
+            assert_eq!(buffer.text(), "ghiabcdef");
+            assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0);
+            assert_eq!(after_start_anchor.to_offset(&buffer).unwrap(), 3);
+            assert_eq!(before_end_anchor.to_offset(&buffer).unwrap(), 6);
+            assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 9);
+            buffer
         });
     }
 
@@ -3105,115 +3086,111 @@ mod tests {
         });
     }
 
-    #[test]
-    fn test_undo_redo() {
-        App::test((), |app| {
-            app.add_model(|ctx| {
-                let mut buffer = Buffer::new(0, "1234", ctx);
-
-                let edit1 = buffer.edit(vec![1..1], "abx", None).unwrap();
-                let edit2 = buffer.edit(vec![3..4], "yzef", None).unwrap();
-                let edit3 = buffer.edit(vec![3..5], "cd", None).unwrap();
-                assert_eq!(buffer.text(), "1abcdef234");
-
-                buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1cdef234");
-                buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1abcdef234");
-
-                buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1abcdx234");
-                buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1abx234");
-                buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1abyzef234");
-                buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1abcdef234");
-
-                buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1abyzef234");
-                buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1yzef234");
-                buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap();
-                assert_eq!(buffer.text(), "1234");
-
-                buffer
-            });
+    #[gpui::test]
+    fn test_undo_redo(app: &mut gpui::MutableAppContext) {
+        app.add_model(|ctx| {
+            let mut buffer = Buffer::new(0, "1234", ctx);
+
+            let edit1 = buffer.edit(vec![1..1], "abx", None).unwrap();
+            let edit2 = buffer.edit(vec![3..4], "yzef", None).unwrap();
+            let edit3 = buffer.edit(vec![3..5], "cd", None).unwrap();
+            assert_eq!(buffer.text(), "1abcdef234");
+
+            buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1cdef234");
+            buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1abcdef234");
+
+            buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1abcdx234");
+            buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1abx234");
+            buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1abyzef234");
+            buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1abcdef234");
+
+            buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1abyzef234");
+            buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1yzef234");
+            buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap();
+            assert_eq!(buffer.text(), "1234");
+
+            buffer
         });
     }
 
-    #[test]
-    fn test_history() {
-        App::test((), |app| {
-            app.add_model(|ctx| {
-                let mut now = Instant::now();
-                let mut buffer = Buffer::new(0, "123456", ctx);
-
-                let (set_id, _) = buffer
-                    .add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap(), None);
-                buffer.start_transaction_at(Some(set_id), now).unwrap();
-                buffer.edit(vec![2..4], "cd", None).unwrap();
-                buffer.end_transaction_at(Some(set_id), now, None).unwrap();
-                assert_eq!(buffer.text(), "12cd56");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]);
-
-                buffer.start_transaction_at(Some(set_id), now).unwrap();
-                buffer
-                    .update_selection_set(
-                        set_id,
-                        buffer.selections_from_ranges(vec![1..3]).unwrap(),
-                        None,
-                    )
-                    .unwrap();
-                buffer.edit(vec![4..5], "e", None).unwrap();
-                buffer.end_transaction_at(Some(set_id), now, None).unwrap();
-                assert_eq!(buffer.text(), "12cde6");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
-
-                now += UNDO_GROUP_INTERVAL + Duration::from_millis(1);
-                buffer.start_transaction_at(Some(set_id), now).unwrap();
-                buffer
-                    .update_selection_set(
-                        set_id,
-                        buffer.selections_from_ranges(vec![2..2]).unwrap(),
-                        None,
-                    )
-                    .unwrap();
-                buffer.edit(vec![0..1], "a", None).unwrap();
-                buffer.edit(vec![1..1], "b", None).unwrap();
-                buffer.end_transaction_at(Some(set_id), now, None).unwrap();
-                assert_eq!(buffer.text(), "ab2cde6");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]);
-
-                // Last transaction happened past the group interval, undo it on its
-                // own.
-                buffer.undo(None);
-                assert_eq!(buffer.text(), "12cde6");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
-
-                // First two transactions happened within the group interval, undo them
-                // together.
-                buffer.undo(None);
-                assert_eq!(buffer.text(), "123456");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]);
-
-                // Redo the first two transactions together.
-                buffer.redo(None);
-                assert_eq!(buffer.text(), "12cde6");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
-
-                // Redo the last transaction on its own.
-                buffer.redo(None);
-                assert_eq!(buffer.text(), "ab2cde6");
-                assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]);
-
-                buffer
-            });
+    #[gpui::test]
+    fn test_history(app: &mut gpui::MutableAppContext) {
+        app.add_model(|ctx| {
+            let mut now = Instant::now();
+            let mut buffer = Buffer::new(0, "123456", ctx);
+
+            let (set_id, _) =
+                buffer.add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap(), None);
+            buffer.start_transaction_at(Some(set_id), now).unwrap();
+            buffer.edit(vec![2..4], "cd", None).unwrap();
+            buffer.end_transaction_at(Some(set_id), now, None).unwrap();
+            assert_eq!(buffer.text(), "12cd56");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]);
+
+            buffer.start_transaction_at(Some(set_id), now).unwrap();
+            buffer
+                .update_selection_set(
+                    set_id,
+                    buffer.selections_from_ranges(vec![1..3]).unwrap(),
+                    None,
+                )
+                .unwrap();
+            buffer.edit(vec![4..5], "e", None).unwrap();
+            buffer.end_transaction_at(Some(set_id), now, None).unwrap();
+            assert_eq!(buffer.text(), "12cde6");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
+
+            now += UNDO_GROUP_INTERVAL + Duration::from_millis(1);
+            buffer.start_transaction_at(Some(set_id), now).unwrap();
+            buffer
+                .update_selection_set(
+                    set_id,
+                    buffer.selections_from_ranges(vec![2..2]).unwrap(),
+                    None,
+                )
+                .unwrap();
+            buffer.edit(vec![0..1], "a", None).unwrap();
+            buffer.edit(vec![1..1], "b", None).unwrap();
+            buffer.end_transaction_at(Some(set_id), now, None).unwrap();
+            assert_eq!(buffer.text(), "ab2cde6");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]);
+
+            // Last transaction happened past the group interval, undo it on its
+            // own.
+            buffer.undo(None);
+            assert_eq!(buffer.text(), "12cde6");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
+
+            // First two transactions happened within the group interval, undo them
+            // together.
+            buffer.undo(None);
+            assert_eq!(buffer.text(), "123456");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]);
+
+            // Redo the first two transactions together.
+            buffer.redo(None);
+            assert_eq!(buffer.text(), "12cde6");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
+
+            // Redo the last transaction on its own.
+            buffer.redo(None);
+            assert_eq!(buffer.text(), "ab2cde6");
+            assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]);
+
+            buffer
         });
     }
 
-    #[test]
-    fn test_random_concurrent_edits() {
+    #[gpui::test]
+    fn test_random_concurrent_edits(ctx: &mut gpui::MutableAppContext) {
         use crate::test::Network;
 
         const PEERS: usize = 5;

zed/src/editor/buffer_view.rs 🔗

@@ -2511,222 +2511,207 @@ impl workspace::ItemView for BufferView {
 mod tests {
     use super::*;
     use crate::{editor::Point, settings, test::sample_text};
-    use gpui::App;
     use unindent::Unindent;
 
-    #[test]
-    fn test_selection_with_mouse() {
-        App::test((), |app| {
-            let buffer =
-                app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, buffer_view) =
-                app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-
-            buffer_view.update(app, |view, ctx| {
-                view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
-            });
+    #[gpui::test]
+    fn test_selection_with_mouse(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, buffer_view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
 
-            let view = buffer_view.read(app);
-            let selections = view
-                .selections_in_range(
-                    DisplayPoint::zero()..view.max_point(app.as_ref()),
-                    app.as_ref(),
-                )
-                .collect::<Vec<_>>();
-            assert_eq!(
-                selections,
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
-            );
+        buffer_view.update(app, |view, ctx| {
+            view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
+        });
 
-            buffer_view.update(app, |view, ctx| {
-                view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
-            });
+        let view = buffer_view.read(app);
+        let selections = view
+            .selections_in_range(
+                DisplayPoint::zero()..view.max_point(app.as_ref()),
+                app.as_ref(),
+            )
+            .collect::<Vec<_>>();
+        assert_eq!(
+            selections,
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
+        );
 
-            let view = buffer_view.read(app);
-            let selections = view
-                .selections_in_range(
-                    DisplayPoint::zero()..view.max_point(app.as_ref()),
-                    app.as_ref(),
-                )
-                .collect::<Vec<_>>();
-            assert_eq!(
-                selections,
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
-            );
+        buffer_view.update(app, |view, ctx| {
+            view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
+        });
 
-            buffer_view.update(app, |view, ctx| {
-                view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
-            });
+        let view = buffer_view.read(app);
+        let selections = view
+            .selections_in_range(
+                DisplayPoint::zero()..view.max_point(app.as_ref()),
+                app.as_ref(),
+            )
+            .collect::<Vec<_>>();
+        assert_eq!(
+            selections,
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
+        );
 
-            let view = buffer_view.read(app);
-            let selections = view
-                .selections_in_range(
-                    DisplayPoint::zero()..view.max_point(app.as_ref()),
-                    app.as_ref(),
-                )
-                .collect::<Vec<_>>();
-            assert_eq!(
-                selections,
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
-            );
+        buffer_view.update(app, |view, ctx| {
+            view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
+        });
 
-            buffer_view.update(app, |view, ctx| {
-                view.end_selection(ctx);
-                view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
-            });
+        let view = buffer_view.read(app);
+        let selections = view
+            .selections_in_range(
+                DisplayPoint::zero()..view.max_point(app.as_ref()),
+                app.as_ref(),
+            )
+            .collect::<Vec<_>>();
+        assert_eq!(
+            selections,
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
+        );
 
-            let view = buffer_view.read(app);
-            let selections = view
-                .selections_in_range(
-                    DisplayPoint::zero()..view.max_point(app.as_ref()),
-                    app.as_ref(),
-                )
-                .collect::<Vec<_>>();
-            assert_eq!(
-                selections,
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
-            );
+        buffer_view.update(app, |view, ctx| {
+            view.end_selection(ctx);
+            view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
+        });
 
-            buffer_view.update(app, |view, ctx| {
-                view.begin_selection(DisplayPoint::new(3, 3), true, ctx);
-                view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
-            });
+        let view = buffer_view.read(app);
+        let selections = view
+            .selections_in_range(
+                DisplayPoint::zero()..view.max_point(app.as_ref()),
+                app.as_ref(),
+            )
+            .collect::<Vec<_>>();
+        assert_eq!(
+            selections,
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
+        );
 
-            let view = buffer_view.read(app);
-            let selections = view
-                .selections_in_range(
-                    DisplayPoint::zero()..view.max_point(app.as_ref()),
-                    app.as_ref(),
-                )
-                .collect::<Vec<_>>();
-            assert_eq!(
-                selections,
-                [
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
-                ]
-            );
+        buffer_view.update(app, |view, ctx| {
+            view.begin_selection(DisplayPoint::new(3, 3), true, ctx);
+            view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
+        });
 
-            buffer_view.update(app, |view, ctx| {
-                view.end_selection(ctx);
-            });
+        let view = buffer_view.read(app);
+        let selections = view
+            .selections_in_range(
+                DisplayPoint::zero()..view.max_point(app.as_ref()),
+                app.as_ref(),
+            )
+            .collect::<Vec<_>>();
+        assert_eq!(
+            selections,
+            [
+                DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
+            ]
+        );
 
-            let view = buffer_view.read(app);
-            let selections = view
-                .selections_in_range(
-                    DisplayPoint::zero()..view.max_point(app.as_ref()),
-                    app.as_ref(),
-                )
-                .collect::<Vec<_>>();
-            assert_eq!(
-                selections,
-                [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
-            );
+        buffer_view.update(app, |view, ctx| {
+            view.end_selection(ctx);
         });
+
+        let view = buffer_view.read(app);
+        let selections = view
+            .selections_in_range(
+                DisplayPoint::zero()..view.max_point(app.as_ref()),
+                app.as_ref(),
+            )
+            .collect::<Vec<_>>();
+        assert_eq!(
+            selections,
+            [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
+        );
     }
 
-    #[test]
-    fn test_canceling_pending_selection() {
-        App::test((), |app| {
-            let buffer =
-                app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+    #[gpui::test]
+    fn test_canceling_pending_selection(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
 
-            view.update(app, |view, ctx| {
-                view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
-            );
+        view.update(app, |view, ctx| {
+            view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
+        );
 
-            view.update(app, |view, ctx| {
-                view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
-            );
+        view.update(app, |view, ctx| {
+            view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
+        );
 
-            view.update(app, |view, ctx| {
-                view.cancel(&(), ctx);
-                view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
-            );
+        view.update(app, |view, ctx| {
+            view.cancel(&(), ctx);
+            view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
         });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
+        );
     }
 
-    #[test]
-    fn test_cancel() {
-        App::test((), |app| {
-            let buffer =
-                app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+    #[gpui::test]
+    fn test_cancel(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
 
-            view.update(app, |view, ctx| {
-                view.begin_selection(DisplayPoint::new(3, 4), false, ctx);
-                view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
-                view.end_selection(ctx);
+        view.update(app, |view, ctx| {
+            view.begin_selection(DisplayPoint::new(3, 4), false, ctx);
+            view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
+            view.end_selection(ctx);
 
-                view.begin_selection(DisplayPoint::new(0, 1), true, ctx);
-                view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), ctx);
-                view.end_selection(ctx);
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
-                ]
-            );
+            view.begin_selection(DisplayPoint::new(0, 1), true, ctx);
+            view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), ctx);
+            view.end_selection(ctx);
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.cancel(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
-            );
+        view.update(app, |view, ctx| view.cancel(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
+        );
 
-            view.update(app, |view, ctx| view.cancel(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
-            );
-        });
+        view.update(app, |view, ctx| view.cancel(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
+        );
     }
 
-    #[test]
-    fn test_layout_line_numbers() {
-        App::test((), |app| {
-            let layout_cache = TextLayoutCache::new(app.platform().fonts());
-            let font_cache = app.font_cache().clone();
+    #[gpui::test]
+    fn test_layout_line_numbers(app: &mut gpui::MutableAppContext) {
+        let layout_cache = TextLayoutCache::new(app.platform().fonts());
+        let font_cache = app.font_cache().clone();
 
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
 
-            let settings = settings::channel(&font_cache).unwrap().1;
-            let (_, view) =
-                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
+        let settings = settings::channel(&font_cache).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
 
-            let layouts = view
-                .read(app)
-                .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref())
-                .unwrap();
-            assert_eq!(layouts.len(), 6);
-        })
+        let layouts = view
+            .read(app)
+            .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref())
+            .unwrap();
+        assert_eq!(layouts.len(), 6);
     }
 
-    #[test]
-    fn test_fold() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| {
-                Buffer::new(
-                    0,
-                    "
+    #[gpui::test]
+    fn test_fold(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| {
+            Buffer::new(
+                0,
+                "
                     impl Foo {
                         // Hello!
 
@@ -2743,24 +2728,20 @@ mod tests {
                         }
                     }
                 "
-                    .unindent(),
-                    ctx,
-                )
-            });
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) =
-                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
-
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)],
-                    ctx,
-                )
+                .unindent(),
+                ctx,
+            )
+        });
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
+
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx)
                 .unwrap();
-                view.fold(&(), ctx);
-                assert_eq!(
-                    view.text(ctx.as_ref()),
-                    "
+            view.fold(&(), ctx);
+            assert_eq!(
+                view.text(ctx.as_ref()),
+                "
                     impl Foo {
                         // Hello!
 
@@ -2775,23 +2756,23 @@ mod tests {
                         }
                     }
                 "
-                    .unindent(),
-                );
+                .unindent(),
+            );
 
-                view.fold(&(), ctx);
-                assert_eq!(
-                    view.text(ctx.as_ref()),
-                    "
+            view.fold(&(), ctx);
+            assert_eq!(
+                view.text(ctx.as_ref()),
+                "
                     impl Foo {…
                     }
                 "
-                    .unindent(),
-                );
+                .unindent(),
+            );
 
-                view.unfold(&(), ctx);
-                assert_eq!(
-                    view.text(ctx.as_ref()),
-                    "
+            view.unfold(&(), ctx);
+            assert_eq!(
+                view.text(ctx.as_ref()),
+                "
                     impl Foo {
                         // Hello!
 
@@ -2806,1109 +2787,1055 @@ mod tests {
                         }
                     }
                 "
-                    .unindent(),
-                );
+                .unindent(),
+            );
 
-                view.unfold(&(), ctx);
-                assert_eq!(view.text(ctx.as_ref()), buffer.read(ctx).text());
-            });
+            view.unfold(&(), ctx);
+            assert_eq!(view.text(ctx.as_ref()), buffer.read(ctx).text());
         });
     }
 
-    #[test]
-    fn test_move_cursor() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) =
-                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
-
-            buffer.update(app, |buffer, ctx| {
-                buffer
-                    .edit(
-                        vec![
-                            Point::new(1, 0)..Point::new(1, 0),
-                            Point::new(1, 1)..Point::new(1, 1),
-                        ],
-                        "\t",
-                        Some(ctx),
-                    )
-                    .unwrap();
-            });
-
-            view.update(app, |view, ctx| {
-                view.move_down(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
-                );
-
-                view.move_right(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
-                );
-
-                view.move_left(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
-                );
-
-                view.move_up(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
-                );
-
-                view.move_to_end(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
-                );
-
-                view.move_to_beginning(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
-                );
-
-                view.select_display_ranges(
-                    &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)],
-                    ctx,
-                )
-                .unwrap();
-                view.select_to_beginning(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
-                );
-
-                view.select_to_end(&(), ctx);
-                assert_eq!(
-                    view.selection_ranges(ctx.as_ref()),
-                    &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
-                );
-            });
-        });
-    }
+    #[gpui::test]
+    fn test_move_cursor(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
 
-    #[test]
-    fn test_beginning_end_of_line() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n  def", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
+        buffer.update(app, |buffer, ctx| {
+            buffer
+                .edit(
+                    vec![
+                        Point::new(1, 0)..Point::new(1, 0),
+                        Point::new(1, 1)..Point::new(1, 1),
                     ],
-                    ctx,
+                    "\t",
+                    Some(ctx),
                 )
                 .unwrap();
-            });
-
-            view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
-                ]
-            );
+        });
 
-            view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx));
+        view.update(app, |view, ctx| {
+            view.move_down(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
             );
 
-            view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx));
+            view.move_right(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
             );
 
-            view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx));
+            view.move_left(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
             );
 
-            // Moving to the end of line again is a no-op.
-            view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx));
+            view.move_up(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
             );
 
-            view.update(app, |view, ctx| {
-                view.move_left(&(), ctx);
-                view.select_to_beginning_of_line(&true, ctx);
-            });
+            view.move_to_end(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
             );
 
-            view.update(app, |view, ctx| {
-                view.select_to_beginning_of_line(&true, ctx)
-            });
+            view.move_to_beginning(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
             );
 
-            view.update(app, |view, ctx| {
-                view.select_to_beginning_of_line(&true, ctx)
-            });
+            view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], ctx)
+                .unwrap();
+            view.select_to_beginning(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
             );
 
-            view.update(app, |view, ctx| view.select_to_end_of_line(&(), ctx));
+            view.select_to_end(&(), ctx);
             assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
-                ]
+                view.selection_ranges(ctx.as_ref()),
+                &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
             );
+        });
+    }
 
-            view.update(app, |view, ctx| view.delete_to_end_of_line(&(), ctx));
-            assert_eq!(view.read(app).text(app.as_ref()), "ab\n  de");
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
+    #[gpui::test]
+    fn test_beginning_end_of_line(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n  def", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
                 &[
-                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
                     DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
-                ]
-            );
-
-            view.update(app, |view, ctx| view.delete_to_beginning_of_line(&(), ctx));
-            assert_eq!(view.read(app).text(app.as_ref()), "\n");
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                ]
-            );
+                ],
+                ctx,
+            )
+            .unwrap();
         });
-    }
 
-    #[test]
-    fn test_prev_next_word_boundary() {
-        App::test((), |app| {
-            let buffer = app
-                .add_model(|ctx| Buffer::new(0, "use std::str::{foo, bar}\n\n  {baz.qux()}", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
-                        DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-            });
+        view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.move_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
-                ]
-            );
+        view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.move_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
-                ]
-            );
+        view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.move_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
-                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
-                ]
-            );
+        view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.move_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                ]
-            );
+        // Moving to the end of line again is a no-op.
+        view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.move_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.move_left(&(), ctx);
+            view.select_to_beginning_of_line(&true, ctx);
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.move_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.select_to_beginning_of_line(&true, ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.select_to_beginning_of_line(&true, ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
-                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                ]
-            );
+        view.update(app, |view, ctx| view.select_to_end_of_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
-                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
-                ]
-            );
+        view.update(app, |view, ctx| view.delete_to_end_of_line(&(), ctx));
+        assert_eq!(view.read(app).text(app.as_ref()), "ab\n  de");
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
-                ]
-            );
+        view.update(app, |view, ctx| view.delete_to_beginning_of_line(&(), ctx));
+        assert_eq!(view.read(app).text(app.as_ref()), "\n");
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+            ]
+        );
+    }
 
-            view.update(app, |view, ctx| {
-                view.move_right(&(), ctx);
-                view.select_to_previous_word_boundary(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
+    #[gpui::test]
+    fn test_prev_next_word_boundary(app: &mut gpui::MutableAppContext) {
+        let buffer =
+            app.add_model(|ctx| Buffer::new(0, "use std::str::{foo, bar}\n\n  {baz.qux()}", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
                 &[
-                    DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
-                ]
-            );
+                    DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
+                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
+                ],
+                ctx,
+            )
+            .unwrap();
+        });
 
-            view.update(app, |view, ctx| {
-                view.select_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.move_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
+                DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.select_to_next_word_boundary(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.move_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
+                DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.delete_to_next_word_boundary(&(), ctx));
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "use std::s::{foo, bar}\n\n  {az.qux()}"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10),
-                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.move_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
+                DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.delete_to_previous_word_boundary(&(), ctx)
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "use std::::{foo, bar}\n\n  az.qux()}"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.move_to_previous_word_boundary(&(), ctx)
         });
-    }
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+            ]
+        );
 
-    #[test]
-    fn test_backspace() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| {
-                Buffer::new(
-                    0,
-                    "one two three\nfour five six\nseven eight nine\nten\n",
-                    ctx,
-                )
-            });
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) =
-                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
-
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        // an empty selection - the preceding character is deleted
-                        DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                        // one character selected - it is deleted
-                        DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
-                        // a line suffix selected - it is deleted
-                        DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.backspace(&(), ctx);
-            });
+        view.update(app, |view, ctx| {
+            view.move_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
+            ]
+        );
 
-            assert_eq!(
-                buffer.read(app).text(),
-                "oe two three\nfou five six\nseven ten\n"
-            );
-        })
+        view.update(app, |view, ctx| {
+            view.move_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
+                DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
+                DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
+                DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
+            ]
+        );
+
+        view.update(app, |view, ctx| {
+            view.move_right(&(), ctx);
+            view.select_to_previous_word_boundary(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
+                DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
+            ]
+        );
+
+        view.update(app, |view, ctx| {
+            view.select_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7),
+                DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.select_to_next_word_boundary(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
+                DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.delete_to_next_word_boundary(&(), ctx));
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "use std::s::{foo, bar}\n\n  {az.qux()}"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10),
+                DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
+            ]
+        );
+
+        view.update(app, |view, ctx| {
+            view.delete_to_previous_word_boundary(&(), ctx)
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "use std::::{foo, bar}\n\n  az.qux()}"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
+                DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
+            ]
+        );
     }
 
-    #[test]
-    fn test_delete() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| {
-                Buffer::new(
-                    0,
-                    "one two three\nfour five six\nseven eight nine\nten\n",
-                    ctx,
-                )
-            });
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) =
-                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
-
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        // an empty selection - the following character is deleted
-                        DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                        // one character selected - it is deleted
-                        DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
-                        // a line suffix selected - it is deleted
-                        DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.delete(&(), ctx);
-            });
+    #[gpui::test]
+    fn test_backspace(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| {
+            Buffer::new(
+                0,
+                "one two three\nfour five six\nseven eight nine\nten\n",
+                ctx,
+            )
+        });
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
 
-            assert_eq!(
-                buffer.read(app).text(),
-                "on two three\nfou five six\nseven ten\n"
-            );
-        })
-    }
-
-    #[test]
-    fn test_delete_line() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
-                        DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.delete_line(&(), ctx);
-            });
-            assert_eq!(view.read(app).text(app.as_ref()), "ghi");
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
-                ]
-            );
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    // an empty selection - the preceding character is deleted
+                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                    // one character selected - it is deleted
+                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
+                    // a line suffix selected - it is deleted
+                    DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.backspace(&(), ctx);
+        });
 
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)],
-                    ctx,
-                )
-                .unwrap();
-                view.delete_line(&(), ctx);
-            });
-            assert_eq!(view.read(app).text(app.as_ref()), "ghi\n");
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
-            );
+        assert_eq!(
+            buffer.read(app).text(),
+            "oe two three\nfou five six\nseven ten\n"
+        );
+    }
+
+    #[gpui::test]
+    fn test_delete(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| {
+            Buffer::new(
+                0,
+                "one two three\nfour five six\nseven eight nine\nten\n",
+                ctx,
+            )
+        });
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
+
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    // an empty selection - the following character is deleted
+                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                    // one character selected - it is deleted
+                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
+                    // a line suffix selected - it is deleted
+                    DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.delete(&(), ctx);
         });
+
+        assert_eq!(
+            buffer.read(app).text(),
+            "on two three\nfou five six\nseven ten\n"
+        );
     }
 
-    #[test]
-    fn test_duplicate_line() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                        DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                        DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.duplicate_line(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "abc\nabc\ndef\ndef\nghi\n\n"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
+    #[gpui::test]
+    fn test_delete_line(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
                     DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
                     DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
-                    DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
-                ]
-            );
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.delete_line(&(), ctx);
+        });
+        assert_eq!(view.read(app).text(app.as_ref()), "ghi");
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
+            ]
+        );
 
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
-                        DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
-                    ],
-                    ctx,
-                )
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], ctx)
                 .unwrap();
-                view.duplicate_line(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "abc\ndef\nghi\nabc\ndef\nghi\n"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
-                    DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
-                ]
-            );
+            view.delete_line(&(), ctx);
         });
+        assert_eq!(view.read(app).text(app.as_ref()), "ghi\n");
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
+        );
     }
 
-    #[test]
-    fn test_move_line_up_down() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(10, 5), ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.fold_ranges(
-                    vec![
-                        Point::new(0, 2)..Point::new(1, 2),
-                        Point::new(2, 3)..Point::new(4, 1),
-                        Point::new(7, 0)..Point::new(8, 4),
-                    ],
-                    ctx,
-                );
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
-                        DisplayPoint::new(3, 2)..DisplayPoint::new(4, 2),
-                        DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"
-            );
+    #[gpui::test]
+    fn test_duplicate_line(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
+                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.duplicate_line(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "abc\nabc\ndef\ndef\nghi\n\n"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
+                DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
+                DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.move_line_up(&(), ctx));
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(3, 2),
-                    DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
-                ]
-            );
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
+                    DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.duplicate_line(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "abc\ndef\nghi\nabc\ndef\nghi\n"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
+                DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
+            ]
+        );
+    }
 
-            view.update(app, |view, ctx| view.move_line_down(&(), ctx));
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
+    #[gpui::test]
+    fn test_move_line_up_down(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(10, 5), ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.fold_ranges(
                 vec![
-                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
-                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 2),
-                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
-                ]
+                    Point::new(0, 2)..Point::new(1, 2),
+                    Point::new(2, 3)..Point::new(4, 1),
+                    Point::new(7, 0)..Point::new(8, 4),
+                ],
+                ctx,
             );
-
-            view.update(app, |view, ctx| view.move_line_down(&(), ctx));
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
                     DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
                     DisplayPoint::new(3, 2)..DisplayPoint::new(4, 2),
-                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
-                ]
-            );
-
-            view.update(app, |view, ctx| view.move_line_up(&(), ctx));
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
-                    DisplayPoint::new(2, 2)..DisplayPoint::new(3, 2),
-                    DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
-                ]
-            );
+                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
+                ],
+                ctx,
+            )
+            .unwrap();
         });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"
+        );
+
+        view.update(app, |view, ctx| view.move_line_up(&(), ctx));
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
+                DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
+                DisplayPoint::new(2, 2)..DisplayPoint::new(3, 2),
+                DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_line_down(&(), ctx));
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
+                DisplayPoint::new(3, 2)..DisplayPoint::new(4, 2),
+                DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_line_down(&(), ctx));
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
+                DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
+                DisplayPoint::new(3, 2)..DisplayPoint::new(4, 2),
+                DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
+            ]
+        );
+
+        view.update(app, |view, ctx| view.move_line_up(&(), ctx));
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
+                DisplayPoint::new(2, 2)..DisplayPoint::new(3, 2),
+                DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
+            ]
+        );
     }
 
-    #[test]
-    fn test_clipboard() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let view = app
-                .add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx))
-                .1;
+    #[gpui::test]
+    fn test_clipboard(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let view = app
+            .add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx))
+            .1;
 
-            // Cut with three selections. Clipboard text is divided into three slices.
-            view.update(app, |view, ctx| {
-                view.select_ranges(vec![0..4, 8..14, 19..24], false, ctx);
-                view.cut(&(), ctx);
-            });
-            assert_eq!(view.read(app).text(app.as_ref()), "two four six ");
+        // Cut with three selections. Clipboard text is divided into three slices.
+        view.update(app, |view, ctx| {
+            view.select_ranges(vec![0..4, 8..14, 19..24], false, ctx);
+            view.cut(&(), ctx);
+        });
+        assert_eq!(view.read(app).text(app.as_ref()), "two four six ");
 
-            // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
-            view.update(app, |view, ctx| {
-                view.select_ranges(vec![4..4, 9..9, 13..13], false, ctx);
-                view.paste(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "two one four three six five "
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8),
-                    DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19),
-                    DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28)
-                ]
-            );
+        // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
+        view.update(app, |view, ctx| {
+            view.select_ranges(vec![4..4, 9..9, 13..13], false, ctx);
+            view.paste(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "two one four three six five "
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8),
+                DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19),
+                DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28)
+            ]
+        );
 
-            // Paste again but with only two cursors. Since the number of cursors doesn't
-            // match the number of slices in the clipboard, the entire clipboard text
-            // is pasted at each cursor.
-            view.update(app, |view, ctx| {
-                view.select_ranges(vec![0..0, 28..28], false, ctx);
-                view.insert(&"( ".to_string(), ctx);
-                view.paste(&(), ctx);
-                view.insert(&") ".to_string(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "( one three five ) two one four three six five ( one three five ) "
-            );
+        // Paste again but with only two cursors. Since the number of cursors doesn't
+        // match the number of slices in the clipboard, the entire clipboard text
+        // is pasted at each cursor.
+        view.update(app, |view, ctx| {
+            view.select_ranges(vec![0..0, 28..28], false, ctx);
+            view.insert(&"( ".to_string(), ctx);
+            view.paste(&(), ctx);
+            view.insert(&") ".to_string(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "( one three five ) two one four three six five ( one three five ) "
+        );
 
-            view.update(app, |view, ctx| {
-                view.select_ranges(vec![0..0], false, ctx);
-                view.insert(&"123\n4567\n89\n".to_string(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) "
-            );
+        view.update(app, |view, ctx| {
+            view.select_ranges(vec![0..0], false, ctx);
+            view.insert(&"123\n4567\n89\n".to_string(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) "
+        );
 
-            // Cut with three selections, one of which is full-line.
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
-                        DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
-                        DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.cut(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "13\n9\n( one three five ) two one four three six five ( one three five ) "
-            );
+        // Cut with three selections, one of which is full-line.
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
+                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
+                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.cut(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "13\n9\n( one three five ) two one four three six five ( one three five ) "
+        );
 
-            // Paste with three selections, noticing how the copied selection that was full-line
-            // gets inserted before the second cursor.
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
-                        DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.paste(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) "
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
+        // Paste with three selections, noticing how the copied selection that was full-line
+        // gets inserted before the second cursor.
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
                 &[
-                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
-                    DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
-                ]
-            );
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
+                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
+                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.paste(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) "
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
+                DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
+            ]
+        );
 
-            // Copy with a single cursor only, which writes the whole line into the clipboard.
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)],
-                    ctx,
-                )
+        // Copy with a single cursor only, which writes the whole line into the clipboard.
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], ctx)
                 .unwrap();
-                view.copy(&(), ctx);
-            });
+            view.copy(&(), ctx);
+        });
 
-            // Paste with three selections, noticing how the copied full-line selection is inserted
-            // before the empty selections but replaces the selection that is non-empty.
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
-                        DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.paste(&(), ctx);
-            });
-            assert_eq!(
+        // Paste with three selections, noticing how the copied full-line selection is inserted
+        // before the empty selections but replaces the selection that is non-empty.
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
+                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
+                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.paste(&(), ctx);
+        });
+        assert_eq!(
                 view.read(app).text(app.as_ref()),
                 "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) "
             );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[
-                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
-                    DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
-                ]
-            );
-        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[
+                DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
+                DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
+            ]
+        );
     }
 
-    #[test]
-    fn test_select_all() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\nde\nfgh", ctx));
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |b, ctx| b.select_all(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
-            );
-        });
+    #[gpui::test]
+    fn test_select_all(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\nde\nfgh", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |b, ctx| b.select_all(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
+        );
     }
 
-    #[test]
-    fn test_select_line() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 5), ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                        DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                        DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-                view.select_line(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
-                    DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
-                ]
-            );
+    #[gpui::test]
+    fn test_select_line(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 5), ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
+                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+                    DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
+                ],
+                ctx,
+            )
+            .unwrap();
+            view.select_line(&(), ctx);
+        });
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
+                DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.select_line(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
-                    DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
-                ]
-            );
+        view.update(app, |view, ctx| view.select_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
+                DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.select_line(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
-            );
-        });
+        view.update(app, |view, ctx| view.select_line(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
+        );
     }
 
-    #[test]
-    fn test_split_selection_into_lines() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(9, 5), ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
-            view.update(app, |view, ctx| {
-                view.fold_ranges(
-                    vec![
-                        Point::new(0, 2)..Point::new(1, 2),
-                        Point::new(2, 3)..Point::new(4, 1),
-                        Point::new(7, 0)..Point::new(8, 4),
-                    ],
-                    ctx,
-                );
-                view.select_display_ranges(
-                    &[
-                        DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
-                        DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                        DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                        DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
-                    ],
-                    ctx,
-                )
-                .unwrap();
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"
-            );
-
-            view.update(app, |view, ctx| view.split_selection_into_lines(&(), ctx));
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"
+    #[gpui::test]
+    fn test_split_selection_into_lines(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(9, 5), ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+        view.update(app, |view, ctx| {
+            view.fold_ranges(
+                vec![
+                    Point::new(0, 2)..Point::new(1, 2),
+                    Point::new(2, 3)..Point::new(4, 1),
+                    Point::new(7, 0)..Point::new(8, 4),
+                ],
+                ctx,
             );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
+            view.select_display_ranges(
+                &[
+                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
                     DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
                     DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                    DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2)
-                ]
-            );
+                    DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
+                ],
+                ctx,
+            )
+            .unwrap();
+        });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"
+        );
 
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)],
-                    ctx,
-                )
+        view.update(app, |view, ctx| view.split_selection_into_lines(&(), ctx));
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
+                DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
+                DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
+                DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2)
+            ]
+        );
+
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], ctx)
                 .unwrap();
-                view.split_selection_into_lines(&(), ctx);
-            });
-            assert_eq!(
-                view.read(app).text(app.as_ref()),
-                "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i"
-            );
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                [
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
-                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
-                    DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
-                    DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
-                    DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
-                    DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
-                    DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
-                    DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
-                ]
-            );
+            view.split_selection_into_lines(&(), ctx);
         });
+        assert_eq!(
+            view.read(app).text(app.as_ref()),
+            "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i"
+        );
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            [
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
+                DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
+                DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
+                DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
+                DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
+                DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
+                DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
+                DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
+            ]
+        );
     }
 
-    #[test]
-    fn test_add_selection_above_below() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", ctx));
-            let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
+    #[gpui::test]
+    fn test_add_selection_above_below(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", ctx));
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
 
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)],
-                    ctx,
-                )
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], ctx)
                 .unwrap();
-            });
-            view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
-                ]
-            );
+        });
+        view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
-                ]
-            );
+        view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
-            );
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
-                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
-                ]
-            );
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
+                DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
-                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
-                ]
-            );
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
+                DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)],
-                    ctx,
-                )
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], ctx)
                 .unwrap();
-            });
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
-                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
-                ]
-            );
+        });
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
+                DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
-                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
-                ]
-            );
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
+                DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
-            );
+        view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
-            );
+        view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
+        );
 
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)],
-                    ctx,
-                )
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], ctx)
                 .unwrap();
-            });
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
-                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
-                ]
-            );
+        });
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
+                DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
-                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
-                    DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
-                ]
-            );
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
+                DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
+                DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
+            ]
+        );
 
-            view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
-                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
-                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
-                ]
-            );
+        view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
+                DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
+                DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
+            ]
+        );
 
-            view.update(app, |view, ctx| {
-                view.select_display_ranges(
-                    &[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)],
-                    ctx,
-                )
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], ctx)
                 .unwrap();
-            });
-            view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
-                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
-                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
-                ]
-            );
-
-            view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
-            assert_eq!(
-                view.read(app).selection_ranges(app.as_ref()),
-                vec![
-                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
-                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
-                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
-                ]
-            );
         });
+        view.update(app, |view, ctx| view.add_selection_above(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
+                DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
+                DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
+            ]
+        );
+
+        view.update(app, |view, ctx| view.add_selection_below(&(), ctx));
+        assert_eq!(
+            view.read(app).selection_ranges(app.as_ref()),
+            vec![
+                DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
+                DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
+                DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
+            ]
+        );
     }
 
     impl BufferView {

zed/src/editor/display_map/fold_map.rs 🔗

@@ -671,176 +671,163 @@ mod tests {
     use super::*;
     use crate::test::sample_text;
     use buffer::ToPoint;
-    use gpui::App;
 
-    #[test]
-    fn test_basic_folds() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
-            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
-
-            map.fold(
-                vec![
-                    Point::new(0, 2)..Point::new(2, 2),
-                    Point::new(2, 4)..Point::new(4, 1),
-                ],
-                app.as_ref(),
-            )
-            .unwrap();
-            assert_eq!(map.text(app.as_ref()), "aa…cc…eeeee");
-
-            buffer.update(app, |buffer, ctx| {
-                buffer
-                    .edit(
-                        vec![
-                            Point::new(0, 0)..Point::new(0, 1),
-                            Point::new(2, 3)..Point::new(2, 3),
-                        ],
-                        "123",
-                        Some(ctx),
-                    )
-                    .unwrap();
-            });
-            assert_eq!(map.text(app.as_ref()), "123a…c123c…eeeee");
-
-            buffer.update(app, |buffer, ctx| {
-                let start_version = buffer.version.clone();
-                buffer
-                    .edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(ctx))
-                    .unwrap();
-                buffer.edits_since(start_version).collect::<Vec<_>>()
-            });
-            assert_eq!(map.text(app.as_ref()), "123a…c123456eee");
+    #[gpui::test]
+    fn test_basic_folds(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
+        let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+
+        map.fold(
+            vec![
+                Point::new(0, 2)..Point::new(2, 2),
+                Point::new(2, 4)..Point::new(4, 1),
+            ],
+            app.as_ref(),
+        )
+        .unwrap();
+        assert_eq!(map.text(app.as_ref()), "aa…cc…eeeee");
+
+        buffer.update(app, |buffer, ctx| {
+            buffer
+                .edit(
+                    vec![
+                        Point::new(0, 0)..Point::new(0, 1),
+                        Point::new(2, 3)..Point::new(2, 3),
+                    ],
+                    "123",
+                    Some(ctx),
+                )
+                .unwrap();
+        });
+        assert_eq!(map.text(app.as_ref()), "123a…c123c…eeeee");
 
-            map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), app.as_ref())
+        buffer.update(app, |buffer, ctx| {
+            let start_version = buffer.version.clone();
+            buffer
+                .edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(ctx))
                 .unwrap();
-            assert_eq!(map.text(app.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee");
+            buffer.edits_since(start_version).collect::<Vec<_>>()
         });
+        assert_eq!(map.text(app.as_ref()), "123a…c123456eee");
+
+        map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), app.as_ref())
+            .unwrap();
+        assert_eq!(map.text(app.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee");
     }
 
-    #[test]
-    fn test_adjacent_folds() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, "abcdefghijkl", ctx));
+    #[gpui::test]
+    fn test_adjacent_folds(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "abcdefghijkl", ctx));
 
-            {
-                let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+        {
+            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
 
-                map.fold(vec![5..8], app.as_ref()).unwrap();
-                map.check_invariants(app.as_ref());
-                assert_eq!(map.text(app.as_ref()), "abcde…ijkl");
+            map.fold(vec![5..8], app.as_ref()).unwrap();
+            map.check_invariants(app.as_ref());
+            assert_eq!(map.text(app.as_ref()), "abcde…ijkl");
 
-                // Create an fold adjacent to the start of the first fold.
-                map.fold(vec![0..1, 2..5], app.as_ref()).unwrap();
-                map.check_invariants(app.as_ref());
-                assert_eq!(map.text(app.as_ref()), "…b…ijkl");
+            // Create an fold adjacent to the start of the first fold.
+            map.fold(vec![0..1, 2..5], app.as_ref()).unwrap();
+            map.check_invariants(app.as_ref());
+            assert_eq!(map.text(app.as_ref()), "…b…ijkl");
 
-                // Create an fold adjacent to the end of the first fold.
-                map.fold(vec![11..11, 8..10], app.as_ref()).unwrap();
-                map.check_invariants(app.as_ref());
-                assert_eq!(map.text(app.as_ref()), "…b…kl");
-            }
+            // Create an fold adjacent to the end of the first fold.
+            map.fold(vec![11..11, 8..10], app.as_ref()).unwrap();
+            map.check_invariants(app.as_ref());
+            assert_eq!(map.text(app.as_ref()), "…b…kl");
+        }
 
-            {
-                let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+        {
+            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
 
-                // Create two adjacent folds.
-                map.fold(vec![0..2, 2..5], app.as_ref()).unwrap();
-                map.check_invariants(app.as_ref());
-                assert_eq!(map.text(app.as_ref()), "…fghijkl");
+            // Create two adjacent folds.
+            map.fold(vec![0..2, 2..5], app.as_ref()).unwrap();
+            map.check_invariants(app.as_ref());
+            assert_eq!(map.text(app.as_ref()), "…fghijkl");
 
-                // Edit within one of the folds.
-                buffer.update(app, |buffer, ctx| {
-                    let version = buffer.version();
-                    buffer.edit(vec![0..1], "12345", Some(ctx)).unwrap();
-                    buffer.edits_since(version).collect::<Vec<_>>()
-                });
-                map.check_invariants(app.as_ref());
-                assert_eq!(map.text(app.as_ref()), "12345…fghijkl");
-            }
-        });
+            // Edit within one of the folds.
+            buffer.update(app, |buffer, ctx| {
+                let version = buffer.version();
+                buffer.edit(vec![0..1], "12345", Some(ctx)).unwrap();
+                buffer.edits_since(version).collect::<Vec<_>>()
+            });
+            map.check_invariants(app.as_ref());
+            assert_eq!(map.text(app.as_ref()), "12345…fghijkl");
+        }
     }
 
-    #[test]
-    fn test_overlapping_folds() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
-            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
-            map.fold(
-                vec![
-                    Point::new(0, 2)..Point::new(2, 2),
-                    Point::new(0, 4)..Point::new(1, 0),
-                    Point::new(1, 2)..Point::new(3, 2),
-                    Point::new(3, 1)..Point::new(4, 1),
-                ],
-                app.as_ref(),
-            )
-            .unwrap();
-            assert_eq!(map.text(app.as_ref()), "aa…eeeee");
-        })
+    #[gpui::test]
+    fn test_overlapping_folds(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
+        let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+        map.fold(
+            vec![
+                Point::new(0, 2)..Point::new(2, 2),
+                Point::new(0, 4)..Point::new(1, 0),
+                Point::new(1, 2)..Point::new(3, 2),
+                Point::new(3, 1)..Point::new(4, 1),
+            ],
+            app.as_ref(),
+        )
+        .unwrap();
+        assert_eq!(map.text(app.as_ref()), "aa…eeeee");
     }
 
-    #[test]
-    fn test_merging_folds_via_edit() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
-            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
-
-            map.fold(
-                vec![
-                    Point::new(0, 2)..Point::new(2, 2),
-                    Point::new(3, 1)..Point::new(4, 1),
-                ],
-                app.as_ref(),
-            )
-            .unwrap();
-            assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee");
-
-            buffer.update(app, |buffer, ctx| {
-                buffer
-                    .edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(ctx))
-                    .unwrap();
-            });
-            assert_eq!(map.text(app.as_ref()), "aa…eeeee");
+    #[gpui::test]
+    fn test_merging_folds_via_edit(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
+        let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+
+        map.fold(
+            vec![
+                Point::new(0, 2)..Point::new(2, 2),
+                Point::new(3, 1)..Point::new(4, 1),
+            ],
+            app.as_ref(),
+        )
+        .unwrap();
+        assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee");
+
+        buffer.update(app, |buffer, ctx| {
+            buffer
+                .edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(ctx))
+                .unwrap();
         });
+        assert_eq!(map.text(app.as_ref()), "aa…eeeee");
     }
 
-    #[test]
-    fn test_folds_in_range() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
-            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
-            let buffer = buffer.read(app);
-
-            map.fold(
-                vec![
-                    Point::new(0, 2)..Point::new(2, 2),
-                    Point::new(0, 4)..Point::new(1, 0),
-                    Point::new(1, 2)..Point::new(3, 2),
-                    Point::new(3, 1)..Point::new(4, 1),
-                ],
-                app.as_ref(),
-            )
-            .unwrap();
-            let fold_ranges = map
-                .folds_in_range(Point::new(1, 0)..Point::new(1, 3), app.as_ref())
-                .unwrap()
-                .map(|fold| {
-                    fold.start.to_point(buffer).unwrap()..fold.end.to_point(buffer).unwrap()
-                })
-                .collect::<Vec<_>>();
-            assert_eq!(
-                fold_ranges,
-                vec![
-                    Point::new(0, 2)..Point::new(2, 2),
-                    Point::new(1, 2)..Point::new(3, 2)
-                ]
-            );
-        });
+    #[gpui::test]
+    fn test_folds_in_range(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
+        let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+        let buffer = buffer.read(app);
+
+        map.fold(
+            vec![
+                Point::new(0, 2)..Point::new(2, 2),
+                Point::new(0, 4)..Point::new(1, 0),
+                Point::new(1, 2)..Point::new(3, 2),
+                Point::new(3, 1)..Point::new(4, 1),
+            ],
+            app.as_ref(),
+        )
+        .unwrap();
+        let fold_ranges = map
+            .folds_in_range(Point::new(1, 0)..Point::new(1, 3), app.as_ref())
+            .unwrap()
+            .map(|fold| fold.start.to_point(buffer).unwrap()..fold.end.to_point(buffer).unwrap())
+            .collect::<Vec<_>>();
+        assert_eq!(
+            fold_ranges,
+            vec![
+                Point::new(0, 2)..Point::new(2, 2),
+                Point::new(1, 2)..Point::new(3, 2)
+            ]
+        );
     }
 
-    #[test]
-    fn test_random_folds() {
+    #[gpui::test]
+    fn test_random_folds(app: &mut gpui::MutableAppContext) {
         use crate::editor::ToPoint;
         use crate::util::RandomCharIter;
         use rand::prelude::*;
@@ -863,203 +850,197 @@ mod tests {
             dbg!(seed);
             let mut rng = StdRng::seed_from_u64(seed);
 
-            App::test((), |app| {
-                let buffer = app.add_model(|ctx| {
-                    let len = rng.gen_range(0..10);
-                    let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
-                    Buffer::new(0, text, ctx)
-                });
-                let mut map = FoldMap::new(buffer.clone(), app.as_ref());
-
-                for _ in 0..operations {
-                    log::info!("text: {:?}", buffer.read(app).text());
-                    match rng.gen_range(0..=100) {
-                        0..=34 => {
-                            let buffer = buffer.read(app);
-                            let mut to_fold = Vec::new();
-                            for _ in 0..rng.gen_range(1..=5) {
-                                let end = rng.gen_range(0..=buffer.len());
-                                let start = rng.gen_range(0..=end);
-                                to_fold.push(start..end);
-                            }
-                            log::info!("folding {:?}", to_fold);
-                            map.fold(to_fold, app.as_ref()).unwrap();
-                        }
-                        35..=59 if !map.folds.is_empty() => {
-                            let buffer = buffer.read(app);
-                            let mut to_unfold = Vec::new();
-                            for _ in 0..rng.gen_range(1..=3) {
-                                let end = rng.gen_range(0..=buffer.len());
-                                let start = rng.gen_range(0..=end);
-                                to_unfold.push(start..end);
-                            }
-                            log::info!("unfolding {:?}", to_unfold);
-                            map.unfold(to_unfold, app.as_ref()).unwrap();
+            let buffer = app.add_model(|ctx| {
+                let len = rng.gen_range(0..10);
+                let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
+                Buffer::new(0, text, ctx)
+            });
+            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+
+            for _ in 0..operations {
+                log::info!("text: {:?}", buffer.read(app).text());
+                match rng.gen_range(0..=100) {
+                    0..=34 => {
+                        let buffer = buffer.read(app);
+                        let mut to_fold = Vec::new();
+                        for _ in 0..rng.gen_range(1..=5) {
+                            let end = rng.gen_range(0..=buffer.len());
+                            let start = rng.gen_range(0..=end);
+                            to_fold.push(start..end);
                         }
-                        _ => {
-                            let edits = buffer.update(app, |buffer, ctx| {
-                                let start_version = buffer.version.clone();
-                                let edit_count = rng.gen_range(1..=5);
-                                buffer.randomly_edit(&mut rng, edit_count, Some(ctx));
-                                buffer.edits_since(start_version).collect::<Vec<_>>()
-                            });
-                            log::info!("editing {:?}", edits);
+                        log::info!("folding {:?}", to_fold);
+                        map.fold(to_fold, app.as_ref()).unwrap();
+                    }
+                    35..=59 if !map.folds.is_empty() => {
+                        let buffer = buffer.read(app);
+                        let mut to_unfold = Vec::new();
+                        for _ in 0..rng.gen_range(1..=3) {
+                            let end = rng.gen_range(0..=buffer.len());
+                            let start = rng.gen_range(0..=end);
+                            to_unfold.push(start..end);
                         }
+                        log::info!("unfolding {:?}", to_unfold);
+                        map.unfold(to_unfold, app.as_ref()).unwrap();
                     }
-                    map.check_invariants(app.as_ref());
-
-                    let buffer = map.buffer.read(app);
-                    let mut expected_text = buffer.text();
-                    let mut expected_buffer_rows = Vec::new();
-                    let mut next_row = buffer.max_point().row;
-                    for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() {
-                        let fold_start = buffer.point_for_offset(fold_range.start).unwrap();
-                        let fold_end = buffer.point_for_offset(fold_range.end).unwrap();
-                        expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev());
-                        next_row = fold_start.row;
-
-                        expected_text.replace_range(fold_range.start..fold_range.end, "…");
+                    _ => {
+                        let edits = buffer.update(app, |buffer, ctx| {
+                            let start_version = buffer.version.clone();
+                            let edit_count = rng.gen_range(1..=5);
+                            buffer.randomly_edit(&mut rng, edit_count, Some(ctx));
+                            buffer.edits_since(start_version).collect::<Vec<_>>()
+                        });
+                        log::info!("editing {:?}", edits);
                     }
-                    expected_buffer_rows.extend((0..=next_row).rev());
-                    expected_buffer_rows.reverse();
-
-                    assert_eq!(map.text(app.as_ref()), expected_text);
+                }
+                map.check_invariants(app.as_ref());
 
-                    for (display_row, line) in expected_text.lines().enumerate() {
-                        let line_len = map.line_len(display_row as u32, app.as_ref()).unwrap();
-                        assert_eq!(line_len, line.chars().count() as u32);
-                    }
+                let buffer = map.buffer.read(app);
+                let mut expected_text = buffer.text();
+                let mut expected_buffer_rows = Vec::new();
+                let mut next_row = buffer.max_point().row;
+                for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() {
+                    let fold_start = buffer.point_for_offset(fold_range.start).unwrap();
+                    let fold_end = buffer.point_for_offset(fold_range.end).unwrap();
+                    expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev());
+                    next_row = fold_start.row;
+
+                    expected_text.replace_range(fold_range.start..fold_range.end, "…");
+                }
+                expected_buffer_rows.extend((0..=next_row).rev());
+                expected_buffer_rows.reverse();
 
-                    let mut display_point = DisplayPoint::new(0, 0);
-                    let mut display_offset = DisplayOffset(0);
-                    for c in expected_text.chars() {
-                        let buffer_point = map.to_buffer_point(display_point, app.as_ref());
-                        let buffer_offset = buffer_point.to_offset(buffer).unwrap();
-                        assert_eq!(
-                            map.to_display_point(buffer_point, app.as_ref()),
-                            display_point
-                        );
-                        assert_eq!(
-                            map.to_buffer_offset(display_point, app.as_ref()).unwrap(),
-                            buffer_offset
-                        );
-                        assert_eq!(
-                            map.to_display_offset(display_point, app.as_ref()).unwrap(),
-                            display_offset
-                        );
-
-                        if c == '\n' {
-                            *display_point.row_mut() += 1;
-                            *display_point.column_mut() = 0;
-                        } else {
-                            *display_point.column_mut() += 1;
-                        }
-                        display_offset.0 += 1;
-                    }
+                assert_eq!(map.text(app.as_ref()), expected_text);
 
-                    for _ in 0..5 {
-                        let row = rng.gen_range(0..=map.max_point(app.as_ref()).row());
-                        let column = rng.gen_range(0..=map.line_len(row, app.as_ref()).unwrap());
-                        let point = DisplayPoint::new(row, column);
-                        let offset = map.to_display_offset(point, app.as_ref()).unwrap().0;
-                        let len = rng.gen_range(0..=map.len(app.as_ref()) - offset);
-                        assert_eq!(
-                            map.snapshot(app.as_ref())
-                                .chars_at(point, app.as_ref())
-                                .unwrap()
-                                .take(len)
-                                .collect::<String>(),
-                            expected_text
-                                .chars()
-                                .skip(offset)
-                                .take(len)
-                                .collect::<String>()
-                        );
-                    }
+                for (display_row, line) in expected_text.lines().enumerate() {
+                    let line_len = map.line_len(display_row as u32, app.as_ref()).unwrap();
+                    assert_eq!(line_len, line.chars().count() as u32);
+                }
 
-                    for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() {
-                        let display_row = map
-                            .to_display_point(Point::new(*buffer_row, 0), app.as_ref())
-                            .row();
-                        assert_eq!(
-                            map.snapshot(app.as_ref())
-                                .buffer_rows(display_row)
-                                .unwrap()
-                                .collect::<Vec<_>>(),
-                            expected_buffer_rows[idx..],
-                        );
-                    }
+                let mut display_point = DisplayPoint::new(0, 0);
+                let mut display_offset = DisplayOffset(0);
+                for c in expected_text.chars() {
+                    let buffer_point = map.to_buffer_point(display_point, app.as_ref());
+                    let buffer_offset = buffer_point.to_offset(buffer).unwrap();
+                    assert_eq!(
+                        map.to_display_point(buffer_point, app.as_ref()),
+                        display_point
+                    );
+                    assert_eq!(
+                        map.to_buffer_offset(display_point, app.as_ref()).unwrap(),
+                        buffer_offset
+                    );
+                    assert_eq!(
+                        map.to_display_offset(display_point, app.as_ref()).unwrap(),
+                        display_offset
+                    );
 
-                    for fold_range in map.merged_fold_ranges(app.as_ref()) {
-                        let display_point = map.to_display_point(
-                            fold_range.start.to_point(buffer).unwrap(),
-                            app.as_ref(),
-                        );
-                        assert!(map.is_line_folded(display_point.row(), app.as_ref()));
+                    if c == '\n' {
+                        *display_point.row_mut() += 1;
+                        *display_point.column_mut() = 0;
+                    } else {
+                        *display_point.column_mut() += 1;
                     }
+                    display_offset.0 += 1;
+                }
 
-                    for _ in 0..5 {
-                        let end = rng.gen_range(0..=buffer.len());
-                        let start = rng.gen_range(0..=end);
-                        let expected_folds = map
-                            .folds
-                            .items()
-                            .into_iter()
-                            .filter(|fold| {
-                                let start = buffer.anchor_before(start).unwrap();
-                                let end = buffer.anchor_after(end).unwrap();
-                                start.cmp(&fold.0.end, buffer).unwrap() == Ordering::Less
-                                    && end.cmp(&fold.0.start, buffer).unwrap() == Ordering::Greater
-                            })
-                            .map(|fold| fold.0)
-                            .collect::<Vec<_>>();
-
-                        assert_eq!(
-                            map.folds_in_range(start..end, app.as_ref())
-                                .unwrap()
-                                .cloned()
-                                .collect::<Vec<_>>(),
-                            expected_folds
-                        );
-                    }
+                for _ in 0..5 {
+                    let row = rng.gen_range(0..=map.max_point(app.as_ref()).row());
+                    let column = rng.gen_range(0..=map.line_len(row, app.as_ref()).unwrap());
+                    let point = DisplayPoint::new(row, column);
+                    let offset = map.to_display_offset(point, app.as_ref()).unwrap().0;
+                    let len = rng.gen_range(0..=map.len(app.as_ref()) - offset);
+                    assert_eq!(
+                        map.snapshot(app.as_ref())
+                            .chars_at(point, app.as_ref())
+                            .unwrap()
+                            .take(len)
+                            .collect::<String>(),
+                        expected_text
+                            .chars()
+                            .skip(offset)
+                            .take(len)
+                            .collect::<String>()
+                    );
                 }
-            });
-        }
-    }
 
-    #[test]
-    fn test_buffer_rows() {
-        App::test((), |app| {
-            let text = sample_text(6, 6) + "\n";
-            let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
+                for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() {
+                    let display_row = map
+                        .to_display_point(Point::new(*buffer_row, 0), app.as_ref())
+                        .row();
+                    assert_eq!(
+                        map.snapshot(app.as_ref())
+                            .buffer_rows(display_row)
+                            .unwrap()
+                            .collect::<Vec<_>>(),
+                        expected_buffer_rows[idx..],
+                    );
+                }
 
-            let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+                for fold_range in map.merged_fold_ranges(app.as_ref()) {
+                    let display_point = map
+                        .to_display_point(fold_range.start.to_point(buffer).unwrap(), app.as_ref());
+                    assert!(map.is_line_folded(display_point.row(), app.as_ref()));
+                }
 
-            map.fold(
-                vec![
-                    Point::new(0, 2)..Point::new(2, 2),
-                    Point::new(3, 1)..Point::new(4, 1),
-                ],
-                app.as_ref(),
-            )
-            .unwrap();
+                for _ in 0..5 {
+                    let end = rng.gen_range(0..=buffer.len());
+                    let start = rng.gen_range(0..=end);
+                    let expected_folds = map
+                        .folds
+                        .items()
+                        .into_iter()
+                        .filter(|fold| {
+                            let start = buffer.anchor_before(start).unwrap();
+                            let end = buffer.anchor_after(end).unwrap();
+                            start.cmp(&fold.0.end, buffer).unwrap() == Ordering::Less
+                                && end.cmp(&fold.0.start, buffer).unwrap() == Ordering::Greater
+                        })
+                        .map(|fold| fold.0)
+                        .collect::<Vec<_>>();
+
+                    assert_eq!(
+                        map.folds_in_range(start..end, app.as_ref())
+                            .unwrap()
+                            .cloned()
+                            .collect::<Vec<_>>(),
+                        expected_folds
+                    );
+                }
+            }
+        }
+    }
 
-            assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee\nffffff\n");
-            assert_eq!(
-                map.snapshot(app.as_ref())
-                    .buffer_rows(0)
-                    .unwrap()
-                    .collect::<Vec<_>>(),
-                vec![0, 3, 5, 6]
-            );
-            assert_eq!(
-                map.snapshot(app.as_ref())
-                    .buffer_rows(3)
-                    .unwrap()
-                    .collect::<Vec<_>>(),
-                vec![6]
-            );
-        });
+    #[gpui::test]
+    fn test_buffer_rows(app: &mut gpui::MutableAppContext) {
+        let text = sample_text(6, 6) + "\n";
+        let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
+
+        let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+
+        map.fold(
+            vec![
+                Point::new(0, 2)..Point::new(2, 2),
+                Point::new(3, 1)..Point::new(4, 1),
+            ],
+            app.as_ref(),
+        )
+        .unwrap();
+
+        assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee\nffffff\n");
+        assert_eq!(
+            map.snapshot(app.as_ref())
+                .buffer_rows(0)
+                .unwrap()
+                .collect::<Vec<_>>(),
+            vec![0, 3, 5, 6]
+        );
+        assert_eq!(
+            map.snapshot(app.as_ref())
+                .buffer_rows(3)
+                .unwrap()
+                .collect::<Vec<_>>(),
+            vec![6]
+        );
     }
 
     impl FoldMap {

zed/src/editor/display_map/mod.rs 🔗

@@ -339,53 +339,50 @@ pub fn collapse_tabs(
 mod tests {
     use super::*;
     use crate::test::*;
-    use gpui::App;
 
-    #[test]
-    fn test_chars_at() {
-        App::test((), |app| {
-            let text = sample_text(6, 6);
-            let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
-            let map = DisplayMap::new(buffer.clone(), 4, app.as_ref());
-            buffer
-                .update(app, |buffer, ctx| {
-                    buffer.edit(
-                        vec![
-                            Point::new(1, 0)..Point::new(1, 0),
-                            Point::new(1, 1)..Point::new(1, 1),
-                            Point::new(2, 1)..Point::new(2, 1),
-                        ],
-                        "\t",
-                        Some(ctx),
-                    )
-                })
-                .unwrap();
-
-            assert_eq!(
-                map.snapshot(app.as_ref())
-                    .chars_at(DisplayPoint::new(1, 0), app.as_ref())
-                    .unwrap()
-                    .take(10)
-                    .collect::<String>(),
-                "    b   bb"
-            );
-            assert_eq!(
-                map.snapshot(app.as_ref())
-                    .chars_at(DisplayPoint::new(1, 2), app.as_ref())
-                    .unwrap()
-                    .take(10)
-                    .collect::<String>(),
-                "  b   bbbb"
-            );
-            assert_eq!(
-                map.snapshot(app.as_ref())
-                    .chars_at(DisplayPoint::new(1, 6), app.as_ref())
-                    .unwrap()
-                    .take(13)
-                    .collect::<String>(),
-                "  bbbbb\nc   c"
-            );
-        });
+    #[gpui::test]
+    fn test_chars_at(app: &mut gpui::MutableAppContext) {
+        let text = sample_text(6, 6);
+        let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
+        let map = DisplayMap::new(buffer.clone(), 4, app.as_ref());
+        buffer
+            .update(app, |buffer, ctx| {
+                buffer.edit(
+                    vec![
+                        Point::new(1, 0)..Point::new(1, 0),
+                        Point::new(1, 1)..Point::new(1, 1),
+                        Point::new(2, 1)..Point::new(2, 1),
+                    ],
+                    "\t",
+                    Some(ctx),
+                )
+            })
+            .unwrap();
+
+        assert_eq!(
+            map.snapshot(app.as_ref())
+                .chars_at(DisplayPoint::new(1, 0), app.as_ref())
+                .unwrap()
+                .take(10)
+                .collect::<String>(),
+            "    b   bb"
+        );
+        assert_eq!(
+            map.snapshot(app.as_ref())
+                .chars_at(DisplayPoint::new(1, 2), app.as_ref())
+                .unwrap()
+                .take(10)
+                .collect::<String>(),
+            "  b   bbbb"
+        );
+        assert_eq!(
+            map.snapshot(app.as_ref())
+                .chars_at(DisplayPoint::new(1, 6), app.as_ref())
+                .unwrap()
+                .take(13)
+                .collect::<String>(),
+            "  bbbbb\nc   c"
+        );
     }
 
     #[test]
@@ -411,12 +408,10 @@ mod tests {
         assert_eq!(collapse_tabs("\ta".chars(), 5, Bias::Right, 4), (2, 0));
     }
 
-    #[test]
-    fn test_max_point() {
-        App::test((), |app| {
-            let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx));
-            let map = DisplayMap::new(buffer.clone(), 4, app.as_ref());
-            assert_eq!(map.max_point(app.as_ref()), DisplayPoint::new(1, 11))
-        });
+    #[gpui::test]
+    fn test_max_point(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx));
+        let map = DisplayMap::new(buffer.clone(), 4, app.as_ref());
+        assert_eq!(map.max_point(app.as_ref()), DisplayPoint::new(1, 11))
     }
 }

zed/src/workspace.rs 🔗

@@ -734,65 +734,63 @@ mod tests {
     use std::collections::HashSet;
     use tempdir::TempDir;
 
-    #[test]
-    fn test_open_paths_action() {
-        App::test((), |app| {
-            let settings = settings::channel(&app.font_cache()).unwrap().1;
-
-            init(app);
+    #[gpui::test]
+    fn test_open_paths_action(app: &mut gpui::MutableAppContext) {
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
 
-            let dir = temp_tree(json!({
-                "a": {
-                    "aa": null,
-                    "ab": null,
-                },
-                "b": {
-                    "ba": null,
-                    "bb": null,
-                },
-                "c": {
-                    "ca": null,
-                    "cb": null,
-                },
-            }));
+        init(app);
 
-            app.dispatch_global_action(
-                "workspace:open_paths",
-                OpenParams {
-                    paths: vec![
-                        dir.path().join("a").to_path_buf(),
-                        dir.path().join("b").to_path_buf(),
-                    ],
-                    settings: settings.clone(),
-                },
-            );
-            assert_eq!(app.window_ids().count(), 1);
-
-            app.dispatch_global_action(
-                "workspace:open_paths",
-                OpenParams {
-                    paths: vec![dir.path().join("a").to_path_buf()],
-                    settings: settings.clone(),
-                },
-            );
-            assert_eq!(app.window_ids().count(), 1);
-            let workspace_view_1 = app
-                .root_view::<Workspace>(app.window_ids().next().unwrap())
-                .unwrap();
-            assert_eq!(workspace_view_1.read(app).worktrees().len(), 2);
-
-            app.dispatch_global_action(
-                "workspace:open_paths",
-                OpenParams {
-                    paths: vec![
-                        dir.path().join("b").to_path_buf(),
-                        dir.path().join("c").to_path_buf(),
-                    ],
-                    settings: settings.clone(),
-                },
-            );
-            assert_eq!(app.window_ids().count(), 2);
-        });
+        let dir = temp_tree(json!({
+            "a": {
+                "aa": null,
+                "ab": null,
+            },
+            "b": {
+                "ba": null,
+                "bb": null,
+            },
+            "c": {
+                "ca": null,
+                "cb": null,
+            },
+        }));
+
+        app.dispatch_global_action(
+            "workspace:open_paths",
+            OpenParams {
+                paths: vec![
+                    dir.path().join("a").to_path_buf(),
+                    dir.path().join("b").to_path_buf(),
+                ],
+                settings: settings.clone(),
+            },
+        );
+        assert_eq!(app.window_ids().count(), 1);
+
+        app.dispatch_global_action(
+            "workspace:open_paths",
+            OpenParams {
+                paths: vec![dir.path().join("a").to_path_buf()],
+                settings: settings.clone(),
+            },
+        );
+        assert_eq!(app.window_ids().count(), 1);
+        let workspace_view_1 = app
+            .root_view::<Workspace>(app.window_ids().next().unwrap())
+            .unwrap();
+        assert_eq!(workspace_view_1.read(app).worktrees().len(), 2);
+
+        app.dispatch_global_action(
+            "workspace:open_paths",
+            OpenParams {
+                paths: vec![
+                    dir.path().join("b").to_path_buf(),
+                    dir.path().join("c").to_path_buf(),
+                ],
+                settings: settings.clone(),
+            },
+        );
+        assert_eq!(app.window_ids().count(), 2);
     }
 
     #[test]