WIP

Conrad Irwin created

Change summary

Cargo.lock                                  |    55 
crates/editor2/Cargo.toml                   |    44 
crates/editor2/src/blink_manager.rs         |     6 
crates/editor2/src/display_map.rs           |    11 
crates/editor2/src/display_map/block_map.rs |  1358 +-
crates/editor2/src/display_map/fold_map.rs  |     4 
crates/editor2/src/display_map/inlay_map.rs |     2 
crates/editor2/src/display_map/wrap_map.rs  |   678 
crates/editor2/src/editor.rs                | 14741 +++++++++++-----------
crates/editor2/src/editor_settings.rs       |     4 
crates/editor2/src/element.rs               |  3430 ++--
crates/editor2/src/hover_popover.rs         |     2 
crates/editor2/src/inlay_hint_cache.rs      |     4 
crates/editor2/src/items.rs                 |   316 
crates/editor2/src/movement.rs              |     2 
crates/editor2/src/scroll/actions.rs        |   292 
crates/editor2/src/selections_collection.rs |     2 
crates/editor2/src/test.rs                  |     2 
crates/language2/src/buffer.rs              |     1 
crates/workspace2/src/workspace2.rs         |    15 
crates/zed2/Cargo.toml                      |     2 
21 files changed, 10,474 insertions(+), 10,497 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2622,6 +2622,60 @@ dependencies = [
  "workspace",
 ]
 
+[[package]]
+name = "editor2"
+version = "0.1.0"
+dependencies = [
+ "aho-corasick",
+ "anyhow",
+ "client2",
+ "clock",
+ "collections",
+ "context_menu",
+ "convert_case 0.6.0",
+ "copilot2",
+ "ctor",
+ "db2",
+ "drag_and_drop",
+ "env_logger 0.9.3",
+ "futures 0.3.28",
+ "fuzzy2",
+ "git",
+ "gpui2",
+ "indoc",
+ "itertools 0.10.5",
+ "language2",
+ "lazy_static",
+ "log",
+ "lsp2",
+ "multi_buffer",
+ "ordered-float 2.10.0",
+ "parking_lot 0.11.2",
+ "postage",
+ "project2",
+ "rand 0.8.5",
+ "rich_text",
+ "rpc2",
+ "schemars",
+ "serde",
+ "serde_derive",
+ "settings2",
+ "smallvec",
+ "smol",
+ "snippet",
+ "sqlez",
+ "sum_tree",
+ "text2",
+ "theme2",
+ "tree-sitter",
+ "tree-sitter-html",
+ "tree-sitter-rust",
+ "tree-sitter-typescript",
+ "unindent",
+ "util",
+ "workspace2",
+]
+
 [[package]]
 name = "either"
 version = "1.9.0"
@@ -11071,6 +11125,7 @@ dependencies = [
  "copilot2",
  "ctor",
  "db2",
+ "editor2",
  "env_logger 0.9.3",
  "feature_flags2",
  "fs2",

crates/editor2/Cargo.toml 🔗

@@ -1,5 +1,5 @@
 [package]
-name = "editor"
+name = "editor2"
 version = "0.1.0"
 edition = "2021"
 publish = false
@@ -23,30 +23,30 @@ test-support = [
 ]
 
 [dependencies]
-client = { path = "../client" }
+client = { package = "client2", path = "../client2" }
 clock = { path = "../clock" }
-copilot = { path = "../copilot" }
-db = { path = "../db" }
+copilot = { package="copilot2", path = "../copilot2" }
+db = { package="db2", path = "../db2" }
 drag_and_drop = { path = "../drag_and_drop" }
 collections = { path = "../collections" }
 context_menu = { path = "../context_menu" }
-fuzzy = { path = "../fuzzy" }
+fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
 git = { path = "../git" }
-gpui = { path = "../gpui" }
-language = { path = "../language" }
-lsp = { path = "../lsp" }
+gpui = { package = "gpui2", path = "../gpui2" }
+language = { package = "language2", path = "../language2" }
+lsp = { package = "lsp2", path = "../lsp2" }
 multi_buffer = { path = "../multi_buffer" }
-project = { path = "../project" }
-rpc = { path = "../rpc" }
+project = { package = "project2", path = "../project2" }
+rpc = { package = "rpc2", path = "../rpc2" }
 rich_text = { path = "../rich_text" }
-settings = { path = "../settings" }
+settings = { package="settings2", path = "../settings2" }
 snippet = { path = "../snippet" }
 sum_tree = { path = "../sum_tree" }
-text = { path = "../text" }
-theme = { path = "../theme" }
+text = { package="text2", path = "../text2" }
+theme = { package="theme2", path = "../theme2" }
 util = { path = "../util" }
 sqlez = { path = "../sqlez" }
-workspace = { path = "../workspace" }
+workspace = { package="workspace2", path = "../workspace2" }
 
 aho-corasick = "1.1"
 anyhow.workspace = true
@@ -71,15 +71,15 @@ tree-sitter-html = { workspace = true, optional = true }
 tree-sitter-typescript = { workspace = true, optional = true }
 
 [dev-dependencies]
-copilot = { path = "../copilot", features = ["test-support"] }
-text = { path = "../text", features = ["test-support"] }
-language = { path = "../language", features = ["test-support"] }
-lsp = { path = "../lsp", features = ["test-support"] }
-gpui = { path = "../gpui", features = ["test-support"] }
+copilot = { package="copilot2", path = "../copilot2", features = ["test-support"] }
+text = { package="text2", path = "../text2", features = ["test-support"] }
+language = { package="language2", path = "../language2", features = ["test-support"] }
+lsp = { package = "lsp2", path = "../lsp2", features = ["test-support"] }
+gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
 util = { path = "../util", features = ["test-support"] }
-project = { path = "../project", features = ["test-support"] }
-settings = { path = "../settings", features = ["test-support"] }
-workspace = { path = "../workspace", features = ["test-support"] }
+project = { package = "project2", path = "../project2", features = ["test-support"] }
+settings = { package = "settings2", path = "../settings2", features = ["test-support"] }
+workspace = { package = "workspace2", path = "../workspace2", features = ["test-support"] }
 multi_buffer = { path = "../multi_buffer", features = ["test-support"] }
 
 ctor.workspace = true
@@ -61,7 +61,7 @@ impl BlinkManager {
     }
 
     fn blink_cursors(&mut self, epoch: usize, cx: &mut ModelContext<Self>) {
-        if settings::get::<EditorSettings>(cx).cursor_blink {
+        if EditorSettings::get_global(cx).cursor_blink {
             if epoch == self.blink_epoch && self.enabled && !self.blinking_paused {
                 self.visible = !self.visible;
                 cx.notify();
@@ -107,7 +107,3 @@ impl BlinkManager {
         self.visible
     }
 }
-
-impl Entity for BlinkManager {
-    type Event = ();
-}

crates/editor2/src/display_map.rs 🔗

@@ -12,10 +12,9 @@ pub use block_map::{BlockMap, BlockPoint};
 use collections::{BTreeMap, HashMap, HashSet};
 use fold_map::FoldMap;
 use gpui::{
-    color::Color,
     fonts::{FontId, HighlightStyle, Underline},
     text_layout::{Line, RunStyle},
-    Entity, ModelContext, ModelHandle,
+    Entity, Hsla, Model, ModelContext,
 };
 use inlay_map::InlayMap;
 use language::{
@@ -49,12 +48,12 @@ type TextHighlights = TreeMap<Option<TypeId>, Arc<(HighlightStyle, Vec<Range<Anc
 type InlayHighlights = BTreeMap<TypeId, HashMap<InlayId, (HighlightStyle, InlayHighlight)>>;
 
 pub struct DisplayMap {
-    buffer: ModelHandle<MultiBuffer>,
+    buffer: Model<MultiBuffer>,
     buffer_subscription: BufferSubscription,
     fold_map: FoldMap,
     inlay_map: InlayMap,
     tab_map: TabMap,
-    wrap_map: ModelHandle<WrapMap>,
+    wrap_map: Model<WrapMap>,
     block_map: BlockMap,
     text_highlights: TextHighlights,
     inlay_highlights: InlayHighlights,
@@ -67,7 +66,7 @@ impl Entity for DisplayMap {
 
 impl DisplayMap {
     pub fn new(
-        buffer: ModelHandle<MultiBuffer>,
+        buffer: Model<MultiBuffer>,
         font_id: FontId,
         font_size: f32,
         wrap_width: Option<f32>,
@@ -1015,7 +1014,7 @@ pub mod tests {
         movement,
         test::{editor_test_context::EditorTestContext, marked_display_snapshot},
     };
-    use gpui::{color::Color, elements::*, test::observe, AppContext};
+    use gpui::{elements::*, test::observe, AppContext, Hsla};
     use language::{
         language_settings::{AllLanguageSettings, AllLanguageSettingsContent},
         Buffer, Language, LanguageConfig, SelectionGoal,

crates/editor2/src/display_map/block_map.rs 🔗

@@ -80,8 +80,8 @@ pub enum BlockStyle {
     Sticky,
 }
 
-pub struct BlockContext<'a, 'b, 'c> {
-    pub view_context: &'c mut ViewContext<'a, 'b, Editor>,
+pub struct BlockContext<'a, 'b> {
+    pub view_context: &'b mut ViewContext<'a, Editor>,
     pub anchor_x: f32,
     pub scroll_x: f32,
     pub gutter_width: f32,
@@ -988,680 +988,680 @@ fn offset_for_row(s: &str, target: u32) -> (u32, usize) {
     (row, offset)
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::display_map::inlay_map::InlayMap;
-    use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap};
-    use gpui::{elements::Empty, Element};
-    use multi_buffer::MultiBuffer;
-    use rand::prelude::*;
-    use settings::SettingsStore;
-    use std::env;
-    use util::RandomCharIter;
-
-    #[gpui::test]
-    fn test_offset_for_row() {
-        assert_eq!(offset_for_row("", 0), (0, 0));
-        assert_eq!(offset_for_row("", 1), (0, 0));
-        assert_eq!(offset_for_row("abcd", 0), (0, 0));
-        assert_eq!(offset_for_row("abcd", 1), (0, 4));
-        assert_eq!(offset_for_row("\n", 0), (0, 0));
-        assert_eq!(offset_for_row("\n", 1), (1, 1));
-        assert_eq!(offset_for_row("abc\ndef\nghi", 0), (0, 0));
-        assert_eq!(offset_for_row("abc\ndef\nghi", 1), (1, 4));
-        assert_eq!(offset_for_row("abc\ndef\nghi", 2), (2, 8));
-        assert_eq!(offset_for_row("abc\ndef\nghi", 3), (2, 11));
-    }
-
-    #[gpui::test]
-    fn test_basic_blocks(cx: &mut gpui::AppContext) {
-        init_test(cx);
-
-        let family_id = cx
-            .font_cache()
-            .load_family(&["Helvetica"], &Default::default())
-            .unwrap();
-        let font_id = cx
-            .font_cache()
-            .select_font(family_id, &Default::default())
-            .unwrap();
-
-        let text = "aaa\nbbb\nccc\nddd";
-
-        let buffer = MultiBuffer::build_simple(text, cx);
-        let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
-        let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
-        let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap());
-        let (wrap_map, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, None, cx);
-        let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
-
-        let mut writer = block_map.write(wraps_snapshot.clone(), Default::default());
-        let block_ids = writer.insert(vec![
-            BlockProperties {
-                style: BlockStyle::Fixed,
-                position: buffer_snapshot.anchor_after(Point::new(1, 0)),
-                height: 1,
-                disposition: BlockDisposition::Above,
-                render: Arc::new(|_| Empty::new().into_any_named("block 1")),
-            },
-            BlockProperties {
-                style: BlockStyle::Fixed,
-                position: buffer_snapshot.anchor_after(Point::new(1, 2)),
-                height: 2,
-                disposition: BlockDisposition::Above,
-                render: Arc::new(|_| Empty::new().into_any_named("block 2")),
-            },
-            BlockProperties {
-                style: BlockStyle::Fixed,
-                position: buffer_snapshot.anchor_after(Point::new(3, 3)),
-                height: 3,
-                disposition: BlockDisposition::Below,
-                render: Arc::new(|_| Empty::new().into_any_named("block 3")),
-            },
-        ]);
-
-        let snapshot = block_map.read(wraps_snapshot, Default::default());
-        assert_eq!(snapshot.text(), "aaa\n\n\n\nbbb\nccc\nddd\n\n\n");
-
-        let blocks = snapshot
-            .blocks_in_range(0..8)
-            .map(|(start_row, block)| {
-                let block = block.as_custom().unwrap();
-                (start_row..start_row + block.height as u32, block.id)
-            })
-            .collect::<Vec<_>>();
-
-        // When multiple blocks are on the same line, the newer blocks appear first.
-        assert_eq!(
-            blocks,
-            &[
-                (1..2, block_ids[0]),
-                (2..4, block_ids[1]),
-                (7..10, block_ids[2]),
-            ]
-        );
-
-        assert_eq!(
-            snapshot.to_block_point(WrapPoint::new(0, 3)),
-            BlockPoint::new(0, 3)
-        );
-        assert_eq!(
-            snapshot.to_block_point(WrapPoint::new(1, 0)),
-            BlockPoint::new(4, 0)
-        );
-        assert_eq!(
-            snapshot.to_block_point(WrapPoint::new(3, 3)),
-            BlockPoint::new(6, 3)
-        );
-
-        assert_eq!(
-            snapshot.to_wrap_point(BlockPoint::new(0, 3)),
-            WrapPoint::new(0, 3)
-        );
-        assert_eq!(
-            snapshot.to_wrap_point(BlockPoint::new(1, 0)),
-            WrapPoint::new(1, 0)
-        );
-        assert_eq!(
-            snapshot.to_wrap_point(BlockPoint::new(3, 0)),
-            WrapPoint::new(1, 0)
-        );
-        assert_eq!(
-            snapshot.to_wrap_point(BlockPoint::new(7, 0)),
-            WrapPoint::new(3, 3)
-        );
-
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(1, 0), Bias::Left),
-            BlockPoint::new(0, 3)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(1, 0), Bias::Right),
-            BlockPoint::new(4, 0)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(1, 1), Bias::Left),
-            BlockPoint::new(0, 3)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(1, 1), Bias::Right),
-            BlockPoint::new(4, 0)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(4, 0), Bias::Left),
-            BlockPoint::new(4, 0)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(4, 0), Bias::Right),
-            BlockPoint::new(4, 0)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(6, 3), Bias::Left),
-            BlockPoint::new(6, 3)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(6, 3), Bias::Right),
-            BlockPoint::new(6, 3)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(7, 0), Bias::Left),
-            BlockPoint::new(6, 3)
-        );
-        assert_eq!(
-            snapshot.clip_point(BlockPoint::new(7, 0), Bias::Right),
-            BlockPoint::new(6, 3)
-        );
-
-        assert_eq!(
-            snapshot.buffer_rows(0).collect::<Vec<_>>(),
-            &[
-                Some(0),
-                None,
-                None,
-                None,
-                Some(1),
-                Some(2),
-                Some(3),
-                None,
-                None,
-                None
-            ]
-        );
-
-        // Insert a line break, separating two block decorations into separate lines.
-        let buffer_snapshot = buffer.update(cx, |buffer, cx| {
-            buffer.edit([(Point::new(1, 1)..Point::new(1, 1), "!!!\n")], None, cx);
-            buffer.snapshot(cx)
-        });
-
-        let (inlay_snapshot, inlay_edits) =
-            inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
-        let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
-        let (tab_snapshot, tab_edits) =
-            tab_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap());
-        let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
-            wrap_map.sync(tab_snapshot, tab_edits, cx)
-        });
-        let snapshot = block_map.read(wraps_snapshot, wrap_edits);
-        assert_eq!(snapshot.text(), "aaa\n\nb!!!\n\n\nbb\nccc\nddd\n\n\n");
-    }
-
-    #[gpui::test]
-    fn test_blocks_on_wrapped_lines(cx: &mut gpui::AppContext) {
-        init_test(cx);
-
-        let family_id = cx
-            .font_cache()
-            .load_family(&["Helvetica"], &Default::default())
-            .unwrap();
-        let font_id = cx
-            .font_cache()
-            .select_font(family_id, &Default::default())
-            .unwrap();
-
-        let text = "one two three\nfour five six\nseven eight";
-
-        let buffer = MultiBuffer::build_simple(text, cx);
-        let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
-        let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
-        let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
-        let (_, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, Some(60.), cx);
-        let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
-
-        let mut writer = block_map.write(wraps_snapshot.clone(), Default::default());
-        writer.insert(vec![
-            BlockProperties {
-                style: BlockStyle::Fixed,
-                position: buffer_snapshot.anchor_after(Point::new(1, 12)),
-                disposition: BlockDisposition::Above,
-                render: Arc::new(|_| Empty::new().into_any_named("block 1")),
-                height: 1,
-            },
-            BlockProperties {
-                style: BlockStyle::Fixed,
-                position: buffer_snapshot.anchor_after(Point::new(1, 1)),
-                disposition: BlockDisposition::Below,
-                render: Arc::new(|_| Empty::new().into_any_named("block 2")),
-                height: 1,
-            },
-        ]);
-
-        // Blocks with an 'above' disposition go above their corresponding buffer line.
-        // Blocks with a 'below' disposition go below their corresponding buffer line.
-        let snapshot = block_map.read(wraps_snapshot, Default::default());
-        assert_eq!(
-            snapshot.text(),
-            "one two \nthree\n\nfour five \nsix\n\nseven \neight"
-        );
-    }
-
-    #[gpui::test(iterations = 100)]
-    fn test_random_blocks(cx: &mut gpui::AppContext, mut rng: StdRng) {
-        init_test(cx);
-
-        let operations = env::var("OPERATIONS")
-            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
-            .unwrap_or(10);
-
-        let wrap_width = if rng.gen_bool(0.2) {
-            None
-        } else {
-            Some(rng.gen_range(0.0..=100.0))
-        };
-        let tab_size = 1.try_into().unwrap();
-        let family_id = cx
-            .font_cache()
-            .load_family(&["Helvetica"], &Default::default())
-            .unwrap();
-        let font_id = cx
-            .font_cache()
-            .select_font(family_id, &Default::default())
-            .unwrap();
-        let font_size = 14.0;
-        let buffer_start_header_height = rng.gen_range(1..=5);
-        let excerpt_header_height = rng.gen_range(1..=5);
-
-        log::info!("Wrap width: {:?}", wrap_width);
-        log::info!("Excerpt Header Height: {:?}", excerpt_header_height);
-
-        let buffer = if rng.gen() {
-            let len = rng.gen_range(0..10);
-            let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
-            log::info!("initial buffer text: {:?}", text);
-            MultiBuffer::build_simple(&text, cx)
-        } else {
-            MultiBuffer::build_random(&mut rng, cx)
-        };
-
-        let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
-        let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
-        let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
-        let (wrap_map, wraps_snapshot) =
-            WrapMap::new(tab_snapshot, font_id, font_size, wrap_width, cx);
-        let mut block_map = BlockMap::new(
-            wraps_snapshot,
-            buffer_start_header_height,
-            excerpt_header_height,
-        );
-        let mut custom_blocks = Vec::new();
-
-        for _ in 0..operations {
-            let mut buffer_edits = Vec::new();
-            match rng.gen_range(0..=100) {
-                0..=19 => {
-                    let wrap_width = if rng.gen_bool(0.2) {
-                        None
-                    } else {
-                        Some(rng.gen_range(0.0..=100.0))
-                    };
-                    log::info!("Setting wrap width to {:?}", wrap_width);
-                    wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
-                }
-                20..=39 => {
-                    let block_count = rng.gen_range(1..=5);
-                    let block_properties = (0..block_count)
-                        .map(|_| {
-                            let buffer = buffer.read(cx).read(cx);
-                            let position = buffer.anchor_after(
-                                buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Left),
-                            );
-
-                            let disposition = if rng.gen() {
-                                BlockDisposition::Above
-                            } else {
-                                BlockDisposition::Below
-                            };
-                            let height = rng.gen_range(1..5);
-                            log::info!(
-                                "inserting block {:?} {:?} with height {}",
-                                disposition,
-                                position.to_point(&buffer),
-                                height
-                            );
-                            BlockProperties {
-                                style: BlockStyle::Fixed,
-                                position,
-                                height,
-                                disposition,
-                                render: Arc::new(|_| Empty::new().into_any()),
-                            }
-                        })
-                        .collect::<Vec<_>>();
-
-                    let (inlay_snapshot, inlay_edits) =
-                        inlay_map.sync(buffer_snapshot.clone(), vec![]);
-                    let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
-                    let (tab_snapshot, tab_edits) =
-                        tab_map.sync(fold_snapshot, fold_edits, tab_size);
-                    let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
-                        wrap_map.sync(tab_snapshot, tab_edits, cx)
-                    });
-                    let mut block_map = block_map.write(wraps_snapshot, wrap_edits);
-                    let block_ids = block_map.insert(block_properties.clone());
-                    for (block_id, props) in block_ids.into_iter().zip(block_properties) {
-                        custom_blocks.push((block_id, props));
-                    }
-                }
-                40..=59 if !custom_blocks.is_empty() => {
-                    let block_count = rng.gen_range(1..=4.min(custom_blocks.len()));
-                    let block_ids_to_remove = (0..block_count)
-                        .map(|_| {
-                            custom_blocks
-                                .remove(rng.gen_range(0..custom_blocks.len()))
-                                .0
-                        })
-                        .collect();
-
-                    let (inlay_snapshot, inlay_edits) =
-                        inlay_map.sync(buffer_snapshot.clone(), vec![]);
-                    let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
-                    let (tab_snapshot, tab_edits) =
-                        tab_map.sync(fold_snapshot, fold_edits, tab_size);
-                    let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
-                        wrap_map.sync(tab_snapshot, tab_edits, cx)
-                    });
-                    let mut block_map = block_map.write(wraps_snapshot, wrap_edits);
-                    block_map.remove(block_ids_to_remove);
-                }
-                _ => {
-                    buffer.update(cx, |buffer, cx| {
-                        let mutation_count = rng.gen_range(1..=5);
-                        let subscription = buffer.subscribe();
-                        buffer.randomly_mutate(&mut rng, mutation_count, cx);
-                        buffer_snapshot = buffer.snapshot(cx);
-                        buffer_edits.extend(subscription.consume());
-                        log::info!("buffer text: {:?}", buffer_snapshot.text());
-                    });
-                }
-            }
-
-            let (inlay_snapshot, inlay_edits) =
-                inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
-            let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
-            let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
-            let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
-                wrap_map.sync(tab_snapshot, tab_edits, cx)
-            });
-            let blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits);
-            assert_eq!(
-                blocks_snapshot.transforms.summary().input_rows,
-                wraps_snapshot.max_point().row() + 1
-            );
-            log::info!("blocks text: {:?}", blocks_snapshot.text());
-
-            let mut expected_blocks = Vec::new();
-            expected_blocks.extend(custom_blocks.iter().map(|(id, block)| {
-                let mut position = block.position.to_point(&buffer_snapshot);
-                match block.disposition {
-                    BlockDisposition::Above => {
-                        position.column = 0;
-                    }
-                    BlockDisposition::Below => {
-                        position.column = buffer_snapshot.line_len(position.row);
-                    }
-                };
-                let row = wraps_snapshot.make_wrap_point(position, Bias::Left).row();
-                (
-                    row,
-                    ExpectedBlock::Custom {
-                        disposition: block.disposition,
-                        id: *id,
-                        height: block.height,
-                    },
-                )
-            }));
-            expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map(
-                |boundary| {
-                    let position =
-                        wraps_snapshot.make_wrap_point(Point::new(boundary.row, 0), Bias::Left);
-                    (
-                        position.row(),
-                        ExpectedBlock::ExcerptHeader {
-                            height: if boundary.starts_new_buffer {
-                                buffer_start_header_height
-                            } else {
-                                excerpt_header_height
-                            },
-                            starts_new_buffer: boundary.starts_new_buffer,
-                        },
-                    )
-                },
-            ));
-            expected_blocks.sort_unstable();
-            let mut sorted_blocks_iter = expected_blocks.into_iter().peekable();
-
-            let input_buffer_rows = buffer_snapshot.buffer_rows(0).collect::<Vec<_>>();
-            let mut expected_buffer_rows = Vec::new();
-            let mut expected_text = String::new();
-            let mut expected_block_positions = Vec::new();
-            let input_text = wraps_snapshot.text();
-            for (row, input_line) in input_text.split('\n').enumerate() {
-                let row = row as u32;
-                if row > 0 {
-                    expected_text.push('\n');
-                }
-
-                let buffer_row = input_buffer_rows[wraps_snapshot
-                    .to_point(WrapPoint::new(row, 0), Bias::Left)
-                    .row as usize];
-
-                while let Some((block_row, block)) = sorted_blocks_iter.peek() {
-                    if *block_row == row && block.disposition() == BlockDisposition::Above {
-                        let (_, block) = sorted_blocks_iter.next().unwrap();
-                        let height = block.height() as usize;
-                        expected_block_positions
-                            .push((expected_text.matches('\n').count() as u32, block));
-                        let text = "\n".repeat(height);
-                        expected_text.push_str(&text);
-                        for _ in 0..height {
-                            expected_buffer_rows.push(None);
-                        }
-                    } else {
-                        break;
-                    }
-                }
-
-                let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
-                expected_buffer_rows.push(if soft_wrapped { None } else { buffer_row });
-                expected_text.push_str(input_line);
-
-                while let Some((block_row, block)) = sorted_blocks_iter.peek() {
-                    if *block_row == row && block.disposition() == BlockDisposition::Below {
-                        let (_, block) = sorted_blocks_iter.next().unwrap();
-                        let height = block.height() as usize;
-                        expected_block_positions
-                            .push((expected_text.matches('\n').count() as u32 + 1, block));
-                        let text = "\n".repeat(height);
-                        expected_text.push_str(&text);
-                        for _ in 0..height {
-                            expected_buffer_rows.push(None);
-                        }
-                    } else {
-                        break;
-                    }
-                }
-            }
-
-            let expected_lines = expected_text.split('\n').collect::<Vec<_>>();
-            let expected_row_count = expected_lines.len();
-            for start_row in 0..expected_row_count {
-                let expected_text = expected_lines[start_row..].join("\n");
-                let actual_text = blocks_snapshot
-                    .chunks(
-                        start_row as u32..blocks_snapshot.max_point().row + 1,
-                        false,
-                        Highlights::default(),
-                    )
-                    .map(|chunk| chunk.text)
-                    .collect::<String>();
-                assert_eq!(
-                    actual_text, expected_text,
-                    "incorrect text starting from row {}",
-                    start_row
-                );
-                assert_eq!(
-                    blocks_snapshot
-                        .buffer_rows(start_row as u32)
-                        .collect::<Vec<_>>(),
-                    &expected_buffer_rows[start_row..]
-                );
-            }
-
-            assert_eq!(
-                blocks_snapshot
-                    .blocks_in_range(0..(expected_row_count as u32))
-                    .map(|(row, block)| (row, block.clone().into()))
-                    .collect::<Vec<_>>(),
-                expected_block_positions
-            );
-
-            let mut expected_longest_rows = Vec::new();
-            let mut longest_line_len = -1_isize;
-            for (row, line) in expected_lines.iter().enumerate() {
-                let row = row as u32;
-
-                assert_eq!(
-                    blocks_snapshot.line_len(row),
-                    line.len() as u32,
-                    "invalid line len for row {}",
-                    row
-                );
-
-                let line_char_count = line.chars().count() as isize;
-                match line_char_count.cmp(&longest_line_len) {
-                    Ordering::Less => {}
-                    Ordering::Equal => expected_longest_rows.push(row),
-                    Ordering::Greater => {
-                        longest_line_len = line_char_count;
-                        expected_longest_rows.clear();
-                        expected_longest_rows.push(row);
-                    }
-                }
-            }
-
-            let longest_row = blocks_snapshot.longest_row();
-            assert!(
-                expected_longest_rows.contains(&longest_row),
-                "incorrect longest row {}. expected {:?} with length {}",
-                longest_row,
-                expected_longest_rows,
-                longest_line_len,
-            );
-
-            for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
-                let wrap_point = WrapPoint::new(row, 0);
-                let block_point = blocks_snapshot.to_block_point(wrap_point);
-                assert_eq!(blocks_snapshot.to_wrap_point(block_point), wrap_point);
-            }
-
-            let mut block_point = BlockPoint::new(0, 0);
-            for c in expected_text.chars() {
-                let left_point = blocks_snapshot.clip_point(block_point, Bias::Left);
-                let left_buffer_point = blocks_snapshot.to_point(left_point, Bias::Left);
-                assert_eq!(
-                    blocks_snapshot.to_block_point(blocks_snapshot.to_wrap_point(left_point)),
-                    left_point
-                );
-                assert_eq!(
-                    left_buffer_point,
-                    buffer_snapshot.clip_point(left_buffer_point, Bias::Right),
-                    "{:?} is not valid in buffer coordinates",
-                    left_point
-                );
-
-                let right_point = blocks_snapshot.clip_point(block_point, Bias::Right);
-                let right_buffer_point = blocks_snapshot.to_point(right_point, Bias::Right);
-                assert_eq!(
-                    blocks_snapshot.to_block_point(blocks_snapshot.to_wrap_point(right_point)),
-                    right_point
-                );
-                assert_eq!(
-                    right_buffer_point,
-                    buffer_snapshot.clip_point(right_buffer_point, Bias::Left),
-                    "{:?} is not valid in buffer coordinates",
-                    right_point
-                );
-
-                if c == '\n' {
-                    block_point.0 += Point::new(1, 0);
-                } else {
-                    block_point.column += c.len_utf8() as u32;
-                }
-            }
-        }
-
-        #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
-        enum ExpectedBlock {
-            ExcerptHeader {
-                height: u8,
-                starts_new_buffer: bool,
-            },
-            Custom {
-                disposition: BlockDisposition,
-                id: BlockId,
-                height: u8,
-            },
-        }
-
-        impl ExpectedBlock {
-            fn height(&self) -> u8 {
-                match self {
-                    ExpectedBlock::ExcerptHeader { height, .. } => *height,
-                    ExpectedBlock::Custom { height, .. } => *height,
-                }
-            }
-
-            fn disposition(&self) -> BlockDisposition {
-                match self {
-                    ExpectedBlock::ExcerptHeader { .. } => BlockDisposition::Above,
-                    ExpectedBlock::Custom { disposition, .. } => *disposition,
-                }
-            }
-        }
-
-        impl From<TransformBlock> for ExpectedBlock {
-            fn from(block: TransformBlock) -> Self {
-                match block {
-                    TransformBlock::Custom(block) => ExpectedBlock::Custom {
-                        id: block.id,
-                        disposition: block.disposition,
-                        height: block.height,
-                    },
-                    TransformBlock::ExcerptHeader {
-                        height,
-                        starts_new_buffer,
-                        ..
-                    } => ExpectedBlock::ExcerptHeader {
-                        height,
-                        starts_new_buffer,
-                    },
-                }
-            }
-        }
-    }
-
-    fn init_test(cx: &mut gpui::AppContext) {
-        cx.set_global(SettingsStore::test(cx));
-        theme::init((), cx);
-    }
-
-    impl TransformBlock {
-        fn as_custom(&self) -> Option<&Block> {
-            match self {
-                TransformBlock::Custom(block) => Some(block),
-                TransformBlock::ExcerptHeader { .. } => None,
-            }
-        }
-    }
-
-    impl BlockSnapshot {
-        fn to_point(&self, point: BlockPoint, bias: Bias) -> Point {
-            self.wrap_snapshot.to_point(self.to_wrap_point(point), bias)
-        }
-    }
-}
+// #[cfg(test)]
+// mod tests {
+//     use super::*;
+//     use crate::display_map::inlay_map::InlayMap;
+//     use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap};
+//     use gpui::Element;
+//     use multi_buffer::MultiBuffer;
+//     use rand::prelude::*;
+//     use settings::SettingsStore;
+//     use std::env;
+//     use util::RandomCharIter;
+
+//     #[gpui::test]
+//     fn test_offset_for_row() {
+//         assert_eq!(offset_for_row("", 0), (0, 0));
+//         assert_eq!(offset_for_row("", 1), (0, 0));
+//         assert_eq!(offset_for_row("abcd", 0), (0, 0));
+//         assert_eq!(offset_for_row("abcd", 1), (0, 4));
+//         assert_eq!(offset_for_row("\n", 0), (0, 0));
+//         assert_eq!(offset_for_row("\n", 1), (1, 1));
+//         assert_eq!(offset_for_row("abc\ndef\nghi", 0), (0, 0));
+//         assert_eq!(offset_for_row("abc\ndef\nghi", 1), (1, 4));
+//         assert_eq!(offset_for_row("abc\ndef\nghi", 2), (2, 8));
+//         assert_eq!(offset_for_row("abc\ndef\nghi", 3), (2, 11));
+//     }
+
+//     #[gpui::test]
+//     fn test_basic_blocks(cx: &mut gpui::AppContext) {
+//         init_test(cx);
+
+//         let family_id = cx
+//             .font_cache()
+//             .load_family(&["Helvetica"], &Default::default())
+//             .unwrap();
+//         let font_id = cx
+//             .font_cache()
+//             .select_font(family_id, &Default::default())
+//             .unwrap();
+
+//         let text = "aaa\nbbb\nccc\nddd";
+
+//         let buffer = MultiBuffer::build_simple(text, cx);
+//         let buffer_snapshot = buffer.read(cx).snapshot(cx);
+//         let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
+//         let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+//         let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
+//         let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap());
+//         let (wrap_map, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, None, cx);
+//         let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
+
+//         let mut writer = block_map.write(wraps_snapshot.clone(), Default::default());
+//         let block_ids = writer.insert(vec![
+//             BlockProperties {
+//                 style: BlockStyle::Fixed,
+//                 position: buffer_snapshot.anchor_after(Point::new(1, 0)),
+//                 height: 1,
+//                 disposition: BlockDisposition::Above,
+//                 render: Arc::new(|_| Empty::new().into_any_named("block 1")),
+//             },
+//             BlockProperties {
+//                 style: BlockStyle::Fixed,
+//                 position: buffer_snapshot.anchor_after(Point::new(1, 2)),
+//                 height: 2,
+//                 disposition: BlockDisposition::Above,
+//                 render: Arc::new(|_| Empty::new().into_any_named("block 2")),
+//             },
+//             BlockProperties {
+//                 style: BlockStyle::Fixed,
+//                 position: buffer_snapshot.anchor_after(Point::new(3, 3)),
+//                 height: 3,
+//                 disposition: BlockDisposition::Below,
+//                 render: Arc::new(|_| Empty::new().into_any_named("block 3")),
+//             },
+//         ]);
+
+//         let snapshot = block_map.read(wraps_snapshot, Default::default());
+//         assert_eq!(snapshot.text(), "aaa\n\n\n\nbbb\nccc\nddd\n\n\n");
+
+//         let blocks = snapshot
+//             .blocks_in_range(0..8)
+//             .map(|(start_row, block)| {
+//                 let block = block.as_custom().unwrap();
+//                 (start_row..start_row + block.height as u32, block.id)
+//             })
+//             .collect::<Vec<_>>();
+
+//         // When multiple blocks are on the same line, the newer blocks appear first.
+//         assert_eq!(
+//             blocks,
+//             &[
+//                 (1..2, block_ids[0]),
+//                 (2..4, block_ids[1]),
+//                 (7..10, block_ids[2]),
+//             ]
+//         );
+
+//         assert_eq!(
+//             snapshot.to_block_point(WrapPoint::new(0, 3)),
+//             BlockPoint::new(0, 3)
+//         );
+//         assert_eq!(
+//             snapshot.to_block_point(WrapPoint::new(1, 0)),
+//             BlockPoint::new(4, 0)
+//         );
+//         assert_eq!(
+//             snapshot.to_block_point(WrapPoint::new(3, 3)),
+//             BlockPoint::new(6, 3)
+//         );
+
+//         assert_eq!(
+//             snapshot.to_wrap_point(BlockPoint::new(0, 3)),
+//             WrapPoint::new(0, 3)
+//         );
+//         assert_eq!(
+//             snapshot.to_wrap_point(BlockPoint::new(1, 0)),
+//             WrapPoint::new(1, 0)
+//         );
+//         assert_eq!(
+//             snapshot.to_wrap_point(BlockPoint::new(3, 0)),
+//             WrapPoint::new(1, 0)
+//         );
+//         assert_eq!(
+//             snapshot.to_wrap_point(BlockPoint::new(7, 0)),
+//             WrapPoint::new(3, 3)
+//         );
+
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(1, 0), Bias::Left),
+//             BlockPoint::new(0, 3)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(1, 0), Bias::Right),
+//             BlockPoint::new(4, 0)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(1, 1), Bias::Left),
+//             BlockPoint::new(0, 3)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(1, 1), Bias::Right),
+//             BlockPoint::new(4, 0)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(4, 0), Bias::Left),
+//             BlockPoint::new(4, 0)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(4, 0), Bias::Right),
+//             BlockPoint::new(4, 0)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(6, 3), Bias::Left),
+//             BlockPoint::new(6, 3)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(6, 3), Bias::Right),
+//             BlockPoint::new(6, 3)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(7, 0), Bias::Left),
+//             BlockPoint::new(6, 3)
+//         );
+//         assert_eq!(
+//             snapshot.clip_point(BlockPoint::new(7, 0), Bias::Right),
+//             BlockPoint::new(6, 3)
+//         );
+
+//         assert_eq!(
+//             snapshot.buffer_rows(0).collect::<Vec<_>>(),
+//             &[
+//                 Some(0),
+//                 None,
+//                 None,
+//                 None,
+//                 Some(1),
+//                 Some(2),
+//                 Some(3),
+//                 None,
+//                 None,
+//                 None
+//             ]
+//         );
+
+//         // Insert a line break, separating two block decorations into separate lines.
+//         let buffer_snapshot = buffer.update(cx, |buffer, cx| {
+//             buffer.edit([(Point::new(1, 1)..Point::new(1, 1), "!!!\n")], None, cx);
+//             buffer.snapshot(cx)
+//         });
+
+//         let (inlay_snapshot, inlay_edits) =
+//             inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
+//         let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+//         let (tab_snapshot, tab_edits) =
+//             tab_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap());
+//         let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
+//             wrap_map.sync(tab_snapshot, tab_edits, cx)
+//         });
+//         let snapshot = block_map.read(wraps_snapshot, wrap_edits);
+//         assert_eq!(snapshot.text(), "aaa\n\nb!!!\n\n\nbb\nccc\nddd\n\n\n");
+//     }
+
+//     #[gpui::test]
+//     fn test_blocks_on_wrapped_lines(cx: &mut gpui::AppContext) {
+//         init_test(cx);
+
+//         let family_id = cx
+//             .font_cache()
+//             .load_family(&["Helvetica"], &Default::default())
+//             .unwrap();
+//         let font_id = cx
+//             .font_cache()
+//             .select_font(family_id, &Default::default())
+//             .unwrap();
+
+//         let text = "one two three\nfour five six\nseven eight";
+
+//         let buffer = MultiBuffer::build_simple(text, cx);
+//         let buffer_snapshot = buffer.read(cx).snapshot(cx);
+//         let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+//         let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
+//         let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
+//         let (_, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, Some(60.), cx);
+//         let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
+
+//         let mut writer = block_map.write(wraps_snapshot.clone(), Default::default());
+//         writer.insert(vec![
+//             BlockProperties {
+//                 style: BlockStyle::Fixed,
+//                 position: buffer_snapshot.anchor_after(Point::new(1, 12)),
+//                 disposition: BlockDisposition::Above,
+//                 render: Arc::new(|_| Empty::new().into_any_named("block 1")),
+//                 height: 1,
+//             },
+//             BlockProperties {
+//                 style: BlockStyle::Fixed,
+//                 position: buffer_snapshot.anchor_after(Point::new(1, 1)),
+//                 disposition: BlockDisposition::Below,
+//                 render: Arc::new(|_| Empty::new().into_any_named("block 2")),
+//                 height: 1,
+//             },
+//         ]);
+
+//         // Blocks with an 'above' disposition go above their corresponding buffer line.
+//         // Blocks with a 'below' disposition go below their corresponding buffer line.
+//         let snapshot = block_map.read(wraps_snapshot, Default::default());
+//         assert_eq!(
+//             snapshot.text(),
+//             "one two \nthree\n\nfour five \nsix\n\nseven \neight"
+//         );
+//     }
+
+//     #[gpui::test(iterations = 100)]
+//     fn test_random_blocks(cx: &mut gpui::AppContext, mut rng: StdRng) {
+//         init_test(cx);
+
+//         let operations = env::var("OPERATIONS")
+//             .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
+//             .unwrap_or(10);
+
+//         let wrap_width = if rng.gen_bool(0.2) {
+//             None
+//         } else {
+//             Some(rng.gen_range(0.0..=100.0))
+//         };
+//         let tab_size = 1.try_into().unwrap();
+//         let family_id = cx
+//             .font_cache()
+//             .load_family(&["Helvetica"], &Default::default())
+//             .unwrap();
+//         let font_id = cx
+//             .font_cache()
+//             .select_font(family_id, &Default::default())
+//             .unwrap();
+//         let font_size = 14.0;
+//         let buffer_start_header_height = rng.gen_range(1..=5);
+//         let excerpt_header_height = rng.gen_range(1..=5);
+
+//         log::info!("Wrap width: {:?}", wrap_width);
+//         log::info!("Excerpt Header Height: {:?}", excerpt_header_height);
+
+//         let buffer = if rng.gen() {
+//             let len = rng.gen_range(0..10);
+//             let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
+//             log::info!("initial buffer text: {:?}", text);
+//             MultiBuffer::build_simple(&text, cx)
+//         } else {
+//             MultiBuffer::build_random(&mut rng, cx)
+//         };
+
+//         let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
+//         let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+//         let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
+//         let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
+//         let (wrap_map, wraps_snapshot) =
+//             WrapMap::new(tab_snapshot, font_id, font_size, wrap_width, cx);
+//         let mut block_map = BlockMap::new(
+//             wraps_snapshot,
+//             buffer_start_header_height,
+//             excerpt_header_height,
+//         );
+//         let mut custom_blocks = Vec::new();
+
+//         for _ in 0..operations {
+//             let mut buffer_edits = Vec::new();
+//             match rng.gen_range(0..=100) {
+//                 0..=19 => {
+//                     let wrap_width = if rng.gen_bool(0.2) {
+//                         None
+//                     } else {
+//                         Some(rng.gen_range(0.0..=100.0))
+//                     };
+//                     log::info!("Setting wrap width to {:?}", wrap_width);
+//                     wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
+//                 }
+//                 20..=39 => {
+//                     let block_count = rng.gen_range(1..=5);
+//                     let block_properties = (0..block_count)
+//                         .map(|_| {
+//                             let buffer = buffer.read(cx).read(cx);
+//                             let position = buffer.anchor_after(
+//                                 buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Left),
+//                             );
+
+//                             let disposition = if rng.gen() {
+//                                 BlockDisposition::Above
+//                             } else {
+//                                 BlockDisposition::Below
+//                             };
+//                             let height = rng.gen_range(1..5);
+//                             log::info!(
+//                                 "inserting block {:?} {:?} with height {}",
+//                                 disposition,
+//                                 position.to_point(&buffer),
+//                                 height
+//                             );
+//                             BlockProperties {
+//                                 style: BlockStyle::Fixed,
+//                                 position,
+//                                 height,
+//                                 disposition,
+//                                 render: Arc::new(|_| Empty::new().into_any()),
+//                             }
+//                         })
+//                         .collect::<Vec<_>>();
+
+//                     let (inlay_snapshot, inlay_edits) =
+//                         inlay_map.sync(buffer_snapshot.clone(), vec![]);
+//                     let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+//                     let (tab_snapshot, tab_edits) =
+//                         tab_map.sync(fold_snapshot, fold_edits, tab_size);
+//                     let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
+//                         wrap_map.sync(tab_snapshot, tab_edits, cx)
+//                     });
+//                     let mut block_map = block_map.write(wraps_snapshot, wrap_edits);
+//                     let block_ids = block_map.insert(block_properties.clone());
+//                     for (block_id, props) in block_ids.into_iter().zip(block_properties) {
+//                         custom_blocks.push((block_id, props));
+//                     }
+//                 }
+//                 40..=59 if !custom_blocks.is_empty() => {
+//                     let block_count = rng.gen_range(1..=4.min(custom_blocks.len()));
+//                     let block_ids_to_remove = (0..block_count)
+//                         .map(|_| {
+//                             custom_blocks
+//                                 .remove(rng.gen_range(0..custom_blocks.len()))
+//                                 .0
+//                         })
+//                         .collect();
+
+//                     let (inlay_snapshot, inlay_edits) =
+//                         inlay_map.sync(buffer_snapshot.clone(), vec![]);
+//                     let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+//                     let (tab_snapshot, tab_edits) =
+//                         tab_map.sync(fold_snapshot, fold_edits, tab_size);
+//                     let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
+//                         wrap_map.sync(tab_snapshot, tab_edits, cx)
+//                     });
+//                     let mut block_map = block_map.write(wraps_snapshot, wrap_edits);
+//                     block_map.remove(block_ids_to_remove);
+//                 }
+//                 _ => {
+//                     buffer.update(cx, |buffer, cx| {
+//                         let mutation_count = rng.gen_range(1..=5);
+//                         let subscription = buffer.subscribe();
+//                         buffer.randomly_mutate(&mut rng, mutation_count, cx);
+//                         buffer_snapshot = buffer.snapshot(cx);
+//                         buffer_edits.extend(subscription.consume());
+//                         log::info!("buffer text: {:?}", buffer_snapshot.text());
+//                     });
+//                 }
+//             }
+
+//             let (inlay_snapshot, inlay_edits) =
+//                 inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
+//             let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+//             let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
+//             let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
+//                 wrap_map.sync(tab_snapshot, tab_edits, cx)
+//             });
+//             let blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits);
+//             assert_eq!(
+//                 blocks_snapshot.transforms.summary().input_rows,
+//                 wraps_snapshot.max_point().row() + 1
+//             );
+//             log::info!("blocks text: {:?}", blocks_snapshot.text());
+
+//             let mut expected_blocks = Vec::new();
+//             expected_blocks.extend(custom_blocks.iter().map(|(id, block)| {
+//                 let mut position = block.position.to_point(&buffer_snapshot);
+//                 match block.disposition {
+//                     BlockDisposition::Above => {
+//                         position.column = 0;
+//                     }
+//                     BlockDisposition::Below => {
+//                         position.column = buffer_snapshot.line_len(position.row);
+//                     }
+//                 };
+//                 let row = wraps_snapshot.make_wrap_point(position, Bias::Left).row();
+//                 (
+//                     row,
+//                     ExpectedBlock::Custom {
+//                         disposition: block.disposition,
+//                         id: *id,
+//                         height: block.height,
+//                     },
+//                 )
+//             }));
+//             expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map(
+//                 |boundary| {
+//                     let position =
+//                         wraps_snapshot.make_wrap_point(Point::new(boundary.row, 0), Bias::Left);
+//                     (
+//                         position.row(),
+//                         ExpectedBlock::ExcerptHeader {
+//                             height: if boundary.starts_new_buffer {
+//                                 buffer_start_header_height
+//                             } else {
+//                                 excerpt_header_height
+//                             },
+//                             starts_new_buffer: boundary.starts_new_buffer,
+//                         },
+//                     )
+//                 },
+//             ));
+//             expected_blocks.sort_unstable();
+//             let mut sorted_blocks_iter = expected_blocks.into_iter().peekable();
+
+//             let input_buffer_rows = buffer_snapshot.buffer_rows(0).collect::<Vec<_>>();
+//             let mut expected_buffer_rows = Vec::new();
+//             let mut expected_text = String::new();
+//             let mut expected_block_positions = Vec::new();
+//             let input_text = wraps_snapshot.text();
+//             for (row, input_line) in input_text.split('\n').enumerate() {
+//                 let row = row as u32;
+//                 if row > 0 {
+//                     expected_text.push('\n');
+//                 }
+
+//                 let buffer_row = input_buffer_rows[wraps_snapshot
+//                     .to_point(WrapPoint::new(row, 0), Bias::Left)
+//                     .row as usize];
+
+//                 while let Some((block_row, block)) = sorted_blocks_iter.peek() {
+//                     if *block_row == row && block.disposition() == BlockDisposition::Above {
+//                         let (_, block) = sorted_blocks_iter.next().unwrap();
+//                         let height = block.height() as usize;
+//                         expected_block_positions
+//                             .push((expected_text.matches('\n').count() as u32, block));
+//                         let text = "\n".repeat(height);
+//                         expected_text.push_str(&text);
+//                         for _ in 0..height {
+//                             expected_buffer_rows.push(None);
+//                         }
+//                     } else {
+//                         break;
+//                     }
+//                 }
+
+//                 let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
+//                 expected_buffer_rows.push(if soft_wrapped { None } else { buffer_row });
+//                 expected_text.push_str(input_line);
+
+//                 while let Some((block_row, block)) = sorted_blocks_iter.peek() {
+//                     if *block_row == row && block.disposition() == BlockDisposition::Below {
+//                         let (_, block) = sorted_blocks_iter.next().unwrap();
+//                         let height = block.height() as usize;
+//                         expected_block_positions
+//                             .push((expected_text.matches('\n').count() as u32 + 1, block));
+//                         let text = "\n".repeat(height);
+//                         expected_text.push_str(&text);
+//                         for _ in 0..height {
+//                             expected_buffer_rows.push(None);
+//                         }
+//                     } else {
+//                         break;
+//                     }
+//                 }
+//             }
+
+//             let expected_lines = expected_text.split('\n').collect::<Vec<_>>();
+//             let expected_row_count = expected_lines.len();
+//             for start_row in 0..expected_row_count {
+//                 let expected_text = expected_lines[start_row..].join("\n");
+//                 let actual_text = blocks_snapshot
+//                     .chunks(
+//                         start_row as u32..blocks_snapshot.max_point().row + 1,
+//                         false,
+//                         Highlights::default(),
+//                     )
+//                     .map(|chunk| chunk.text)
+//                     .collect::<String>();
+//                 assert_eq!(
+//                     actual_text, expected_text,
+//                     "incorrect text starting from row {}",
+//                     start_row
+//                 );
+//                 assert_eq!(
+//                     blocks_snapshot
+//                         .buffer_rows(start_row as u32)
+//                         .collect::<Vec<_>>(),
+//                     &expected_buffer_rows[start_row..]
+//                 );
+//             }
+
+//             assert_eq!(
+//                 blocks_snapshot
+//                     .blocks_in_range(0..(expected_row_count as u32))
+//                     .map(|(row, block)| (row, block.clone().into()))
+//                     .collect::<Vec<_>>(),
+//                 expected_block_positions
+//             );
+
+//             let mut expected_longest_rows = Vec::new();
+//             let mut longest_line_len = -1_isize;
+//             for (row, line) in expected_lines.iter().enumerate() {
+//                 let row = row as u32;
+
+//                 assert_eq!(
+//                     blocks_snapshot.line_len(row),
+//                     line.len() as u32,
+//                     "invalid line len for row {}",
+//                     row
+//                 );
+
+//                 let line_char_count = line.chars().count() as isize;
+//                 match line_char_count.cmp(&longest_line_len) {
+//                     Ordering::Less => {}
+//                     Ordering::Equal => expected_longest_rows.push(row),
+//                     Ordering::Greater => {
+//                         longest_line_len = line_char_count;
+//                         expected_longest_rows.clear();
+//                         expected_longest_rows.push(row);
+//                     }
+//                 }
+//             }
+
+//             let longest_row = blocks_snapshot.longest_row();
+//             assert!(
+//                 expected_longest_rows.contains(&longest_row),
+//                 "incorrect longest row {}. expected {:?} with length {}",
+//                 longest_row,
+//                 expected_longest_rows,
+//                 longest_line_len,
+//             );
+
+//             for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
+//                 let wrap_point = WrapPoint::new(row, 0);
+//                 let block_point = blocks_snapshot.to_block_point(wrap_point);
+//                 assert_eq!(blocks_snapshot.to_wrap_point(block_point), wrap_point);
+//             }
+
+//             let mut block_point = BlockPoint::new(0, 0);
+//             for c in expected_text.chars() {
+//                 let left_point = blocks_snapshot.clip_point(block_point, Bias::Left);
+//                 let left_buffer_point = blocks_snapshot.to_point(left_point, Bias::Left);
+//                 assert_eq!(
+//                     blocks_snapshot.to_block_point(blocks_snapshot.to_wrap_point(left_point)),
+//                     left_point
+//                 );
+//                 assert_eq!(
+//                     left_buffer_point,
+//                     buffer_snapshot.clip_point(left_buffer_point, Bias::Right),
+//                     "{:?} is not valid in buffer coordinates",
+//                     left_point
+//                 );
+
+//                 let right_point = blocks_snapshot.clip_point(block_point, Bias::Right);
+//                 let right_buffer_point = blocks_snapshot.to_point(right_point, Bias::Right);
+//                 assert_eq!(
+//                     blocks_snapshot.to_block_point(blocks_snapshot.to_wrap_point(right_point)),
+//                     right_point
+//                 );
+//                 assert_eq!(
+//                     right_buffer_point,
+//                     buffer_snapshot.clip_point(right_buffer_point, Bias::Left),
+//                     "{:?} is not valid in buffer coordinates",
+//                     right_point
+//                 );
+
+//                 if c == '\n' {
+//                     block_point.0 += Point::new(1, 0);
+//                 } else {
+//                     block_point.column += c.len_utf8() as u32;
+//                 }
+//             }
+//         }
+
+//         #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
+//         enum ExpectedBlock {
+//             ExcerptHeader {
+//                 height: u8,
+//                 starts_new_buffer: bool,
+//             },
+//             Custom {
+//                 disposition: BlockDisposition,
+//                 id: BlockId,
+//                 height: u8,
+//             },
+//         }
+
+//         impl ExpectedBlock {
+//             fn height(&self) -> u8 {
+//                 match self {
+//                     ExpectedBlock::ExcerptHeader { height, .. } => *height,
+//                     ExpectedBlock::Custom { height, .. } => *height,
+//                 }
+//             }
+
+//             fn disposition(&self) -> BlockDisposition {
+//                 match self {
+//                     ExpectedBlock::ExcerptHeader { .. } => BlockDisposition::Above,
+//                     ExpectedBlock::Custom { disposition, .. } => *disposition,
+//                 }
+//             }
+//         }
+
+//         impl From<TransformBlock> for ExpectedBlock {
+//             fn from(block: TransformBlock) -> Self {
+//                 match block {
+//                     TransformBlock::Custom(block) => ExpectedBlock::Custom {
+//                         id: block.id,
+//                         disposition: block.disposition,
+//                         height: block.height,
+//                     },
+//                     TransformBlock::ExcerptHeader {
+//                         height,
+//                         starts_new_buffer,
+//                         ..
+//                     } => ExpectedBlock::ExcerptHeader {
+//                         height,
+//                         starts_new_buffer,
+//                     },
+//                 }
+//             }
+//         }
+//     }
+
+//     fn init_test(cx: &mut gpui::AppContext) {
+//         cx.set_global(SettingsStore::test(cx));
+//         theme::init(cx);
+//     }
+
+//     impl TransformBlock {
+//         fn as_custom(&self) -> Option<&Block> {
+//             match self {
+//                 TransformBlock::Custom(block) => Some(block),
+//                 TransformBlock::ExcerptHeader { .. } => None,
+//             }
+//         }
+//     }
+
+//     impl BlockSnapshot {
+//         fn to_point(&self, point: BlockPoint, bias: Bias) -> Point {
+//             self.wrap_snapshot.to_point(self.to_wrap_point(point), bias)
+//         }
+//     }
+// }

crates/editor2/src/display_map/fold_map.rs 🔗

@@ -3,7 +3,7 @@ use super::{
     Highlights,
 };
 use crate::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset};
-use gpui::{color::Color, fonts::HighlightStyle};
+use gpui::{fonts::HighlightStyle, Hsla};
 use language::{Chunk, Edit, Point, TextSummary};
 use std::{
     any::TypeId,
@@ -174,7 +174,7 @@ impl<'a> FoldMapWriter<'a> {
 
 pub struct FoldMap {
     snapshot: FoldSnapshot,
-    ellipses_color: Option<Color>,
+    ellipses_color: Option<Hsla>,
 }
 
 impl FoldMap {

crates/editor2/src/display_map/wrap_map.rs 🔗

@@ -4,9 +4,7 @@ use super::{
     Highlights,
 };
 use crate::MultiBufferSnapshot;
-use gpui::{
-    fonts::FontId, text_layout::LineWrapper, AppContext, Entity, ModelContext, ModelHandle, Task,
-};
+use gpui::{AppContext, Entity, Model, ModelContext, Task};
 use language::{Chunk, Point};
 use lazy_static::lazy_static;
 use smol::future::yield_now;
@@ -27,10 +25,6 @@ pub struct WrapMap {
     font: (FontId, f32),
 }
 
-impl Entity for WrapMap {
-    type Event = ();
-}
-
 #[derive(Clone)]
 pub struct WrapSnapshot {
     tab_snapshot: TabSnapshot,
@@ -78,7 +72,7 @@ impl WrapMap {
         font_size: f32,
         wrap_width: Option<f32>,
         cx: &mut AppContext,
-    ) -> (ModelHandle<Self>, WrapSnapshot) {
+    ) -> (Model<Self>, WrapSnapshot) {
         let handle = cx.add_model(|cx| {
             let mut this = Self {
                 font: (font_id, font_size),
@@ -1019,337 +1013,337 @@ fn consolidate_wrap_edits(edits: &mut Vec<WrapEdit>) {
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::{
-        display_map::{fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap},
-        MultiBuffer,
-    };
-    use gpui::test::observe;
-    use rand::prelude::*;
-    use settings::SettingsStore;
-    use smol::stream::StreamExt;
-    use std::{cmp, env, num::NonZeroU32};
-    use text::Rope;
-
-    #[gpui::test(iterations = 100)]
-    async fn test_random_wraps(cx: &mut gpui::TestAppContext, mut rng: StdRng) {
-        init_test(cx);
-
-        cx.foreground().set_block_on_ticks(0..=50);
-        let operations = env::var("OPERATIONS")
-            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
-            .unwrap_or(10);
-
-        let font_cache = cx.font_cache().clone();
-        let font_system = cx.platform().fonts();
-        let mut wrap_width = if rng.gen_bool(0.1) {
-            None
-        } else {
-            Some(rng.gen_range(0.0..=1000.0))
-        };
-        let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
-        let family_id = font_cache
-            .load_family(&["Helvetica"], &Default::default())
-            .unwrap();
-        let font_id = font_cache
-            .select_font(family_id, &Default::default())
-            .unwrap();
-        let font_size = 14.0;
-
-        log::info!("Tab size: {}", tab_size);
-        log::info!("Wrap width: {:?}", wrap_width);
-
-        let buffer = cx.update(|cx| {
-            if rng.gen() {
-                MultiBuffer::build_random(&mut rng, cx)
-            } else {
-                let len = rng.gen_range(0..10);
-                let text = util::RandomCharIter::new(&mut rng)
-                    .take(len)
-                    .collect::<String>();
-                MultiBuffer::build_simple(&text, cx)
-            }
-        });
-        let mut buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
-        log::info!("Buffer text: {:?}", buffer_snapshot.text());
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
-        log::info!("InlayMap text: {:?}", inlay_snapshot.text());
-        let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
-        log::info!("FoldMap text: {:?}", fold_snapshot.text());
-        let (mut tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
-        let tabs_snapshot = tab_map.set_max_expansion_column(32);
-        log::info!("TabMap text: {:?}", tabs_snapshot.text());
-
-        let mut line_wrapper = LineWrapper::new(font_id, font_size, font_system);
-        let unwrapped_text = tabs_snapshot.text();
-        let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
-
-        let (wrap_map, _) =
-            cx.update(|cx| WrapMap::new(tabs_snapshot.clone(), font_id, font_size, wrap_width, cx));
-        let mut notifications = observe(&wrap_map, cx);
-
-        if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
-            notifications.next().await.unwrap();
-        }
-
-        let (initial_snapshot, _) = wrap_map.update(cx, |map, cx| {
-            assert!(!map.is_rewrapping());
-            map.sync(tabs_snapshot.clone(), Vec::new(), cx)
-        });
-
-        let actual_text = initial_snapshot.text();
-        assert_eq!(
-            actual_text, expected_text,
-            "unwrapped text is: {:?}",
-            unwrapped_text
-        );
-        log::info!("Wrapped text: {:?}", actual_text);
-
-        let mut next_inlay_id = 0;
-        let mut edits = Vec::new();
-        for _i in 0..operations {
-            log::info!("{} ==============================================", _i);
-
-            let mut buffer_edits = Vec::new();
-            match rng.gen_range(0..=100) {
-                0..=19 => {
-                    wrap_width = if rng.gen_bool(0.2) {
-                        None
-                    } else {
-                        Some(rng.gen_range(0.0..=1000.0))
-                    };
-                    log::info!("Setting wrap width to {:?}", wrap_width);
-                    wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
-                }
-                20..=39 => {
-                    for (fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) {
-                        let (tabs_snapshot, tab_edits) =
-                            tab_map.sync(fold_snapshot, fold_edits, tab_size);
-                        let (mut snapshot, wrap_edits) =
-                            wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
-                        snapshot.check_invariants();
-                        snapshot.verify_chunks(&mut rng);
-                        edits.push((snapshot, wrap_edits));
-                    }
-                }
-                40..=59 => {
-                    let (inlay_snapshot, inlay_edits) =
-                        inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
-                    let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
-                    let (tabs_snapshot, tab_edits) =
-                        tab_map.sync(fold_snapshot, fold_edits, tab_size);
-                    let (mut snapshot, wrap_edits) =
-                        wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
-                    snapshot.check_invariants();
-                    snapshot.verify_chunks(&mut rng);
-                    edits.push((snapshot, wrap_edits));
-                }
-                _ => {
-                    buffer.update(cx, |buffer, cx| {
-                        let subscription = buffer.subscribe();
-                        let edit_count = rng.gen_range(1..=5);
-                        buffer.randomly_mutate(&mut rng, edit_count, cx);
-                        buffer_snapshot = buffer.snapshot(cx);
-                        buffer_edits.extend(subscription.consume());
-                    });
-                }
-            }
-
-            log::info!("Buffer text: {:?}", buffer_snapshot.text());
-            let (inlay_snapshot, inlay_edits) =
-                inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
-            log::info!("InlayMap text: {:?}", inlay_snapshot.text());
-            let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
-            log::info!("FoldMap text: {:?}", fold_snapshot.text());
-            let (tabs_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
-            log::info!("TabMap text: {:?}", tabs_snapshot.text());
-
-            let unwrapped_text = tabs_snapshot.text();
-            let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
-            let (mut snapshot, wrap_edits) =
-                wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot.clone(), tab_edits, cx));
-            snapshot.check_invariants();
-            snapshot.verify_chunks(&mut rng);
-            edits.push((snapshot, wrap_edits));
-
-            if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) && rng.gen_bool(0.4) {
-                log::info!("Waiting for wrapping to finish");
-                while wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
-                    notifications.next().await.unwrap();
-                }
-                wrap_map.read_with(cx, |map, _| assert!(map.pending_edits.is_empty()));
-            }
-
-            if !wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
-                let (mut wrapped_snapshot, wrap_edits) =
-                    wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
-                let actual_text = wrapped_snapshot.text();
-                let actual_longest_row = wrapped_snapshot.longest_row();
-                log::info!("Wrapping finished: {:?}", actual_text);
-                wrapped_snapshot.check_invariants();
-                wrapped_snapshot.verify_chunks(&mut rng);
-                edits.push((wrapped_snapshot.clone(), wrap_edits));
-                assert_eq!(
-                    actual_text, expected_text,
-                    "unwrapped text is: {:?}",
-                    unwrapped_text
-                );
-
-                let mut summary = TextSummary::default();
-                for (ix, item) in wrapped_snapshot
-                    .transforms
-                    .items(&())
-                    .into_iter()
-                    .enumerate()
-                {
-                    summary += &item.summary.output;
-                    log::info!("{} summary: {:?}", ix, item.summary.output,);
-                }
-
-                if tab_size.get() == 1
-                    || !wrapped_snapshot
-                        .tab_snapshot
-                        .fold_snapshot
-                        .text()
-                        .contains('\t')
-                {
-                    let mut expected_longest_rows = Vec::new();
-                    let mut longest_line_len = -1;
-                    for (row, line) in expected_text.split('\n').enumerate() {
-                        let line_char_count = line.chars().count() as isize;
-                        if line_char_count > longest_line_len {
-                            expected_longest_rows.clear();
-                            longest_line_len = line_char_count;
-                        }
-                        if line_char_count >= longest_line_len {
-                            expected_longest_rows.push(row as u32);
-                        }
-                    }
-
-                    assert!(
-                        expected_longest_rows.contains(&actual_longest_row),
-                        "incorrect longest row {}. expected {:?} with length {}",
-                        actual_longest_row,
-                        expected_longest_rows,
-                        longest_line_len,
-                    )
-                }
-            }
-        }
-
-        let mut initial_text = Rope::from(initial_snapshot.text().as_str());
-        for (snapshot, patch) in edits {
-            let snapshot_text = Rope::from(snapshot.text().as_str());
-            for edit in &patch {
-                let old_start = initial_text.point_to_offset(Point::new(edit.new.start, 0));
-                let old_end = initial_text.point_to_offset(cmp::min(
-                    Point::new(edit.new.start + edit.old.len() as u32, 0),
-                    initial_text.max_point(),
-                ));
-                let new_start = snapshot_text.point_to_offset(Point::new(edit.new.start, 0));
-                let new_end = snapshot_text.point_to_offset(cmp::min(
-                    Point::new(edit.new.end, 0),
-                    snapshot_text.max_point(),
-                ));
-                let new_text = snapshot_text
-                    .chunks_in_range(new_start..new_end)
-                    .collect::<String>();
-
-                initial_text.replace(old_start..old_end, &new_text);
-            }
-            assert_eq!(initial_text.to_string(), snapshot_text.to_string());
-        }
-
-        if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
-            log::info!("Waiting for wrapping to finish");
-            while wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
-                notifications.next().await.unwrap();
-            }
-        }
-        wrap_map.read_with(cx, |map, _| assert!(map.pending_edits.is_empty()));
-    }
-
-    fn init_test(cx: &mut gpui::TestAppContext) {
-        cx.foreground().forbid_parking();
-        cx.update(|cx| {
-            cx.set_global(SettingsStore::test(cx));
-            theme::init((), cx);
-        });
-    }
-
-    fn wrap_text(
-        unwrapped_text: &str,
-        wrap_width: Option<f32>,
-        line_wrapper: &mut LineWrapper,
-    ) -> String {
-        if let Some(wrap_width) = wrap_width {
-            let mut wrapped_text = String::new();
-            for (row, line) in unwrapped_text.split('\n').enumerate() {
-                if row > 0 {
-                    wrapped_text.push('\n')
-                }
-
-                let mut prev_ix = 0;
-                for boundary in line_wrapper.wrap_line(line, wrap_width) {
-                    wrapped_text.push_str(&line[prev_ix..boundary.ix]);
-                    wrapped_text.push('\n');
-                    wrapped_text.push_str(&" ".repeat(boundary.next_indent as usize));
-                    prev_ix = boundary.ix;
-                }
-                wrapped_text.push_str(&line[prev_ix..]);
-            }
-            wrapped_text
-        } else {
-            unwrapped_text.to_string()
-        }
-    }
-
-    impl WrapSnapshot {
-        pub fn text(&self) -> String {
-            self.text_chunks(0).collect()
-        }
-
-        pub fn text_chunks(&self, wrap_row: u32) -> impl Iterator<Item = &str> {
-            self.chunks(
-                wrap_row..self.max_point().row() + 1,
-                false,
-                Highlights::default(),
-            )
-            .map(|h| h.text)
-        }
-
-        fn verify_chunks(&mut self, rng: &mut impl Rng) {
-            for _ in 0..5 {
-                let mut end_row = rng.gen_range(0..=self.max_point().row());
-                let start_row = rng.gen_range(0..=end_row);
-                end_row += 1;
-
-                let mut expected_text = self.text_chunks(start_row).collect::<String>();
-                if expected_text.ends_with('\n') {
-                    expected_text.push('\n');
-                }
-                let mut expected_text = expected_text
-                    .lines()
-                    .take((end_row - start_row) as usize)
-                    .collect::<Vec<_>>()
-                    .join("\n");
-                if end_row <= self.max_point().row() {
-                    expected_text.push('\n');
-                }
-
-                let actual_text = self
-                    .chunks(start_row..end_row, true, Highlights::default())
-                    .map(|c| c.text)
-                    .collect::<String>();
-                assert_eq!(
-                    expected_text,
-                    actual_text,
-                    "chunks != highlighted_chunks for rows {:?}",
-                    start_row..end_row
-                );
-            }
-        }
-    }
-}
+// #[cfg(test)]
+// mod tests {
+//     use super::*;
+//     use crate::{
+//         display_map::{fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap},
+//         MultiBuffer,
+//     };
+//     use gpui::test::observe;
+//     use rand::prelude::*;
+//     use settings::SettingsStore;
+//     use smol::stream::StreamExt;
+//     use std::{cmp, env, num::NonZeroU32};
+//     use text::Rope;
+
+//     #[gpui::test(iterations = 100)]
+//     async fn test_random_wraps(cx: &mut gpui::TestAppContext, mut rng: StdRng) {
+//         init_test(cx);
+
+//         cx.foreground().set_block_on_ticks(0..=50);
+//         let operations = env::var("OPERATIONS")
+//             .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
+//             .unwrap_or(10);
+
+//         let font_cache = cx.font_cache().clone();
+//         let font_system = cx.platform().fonts();
+//         let mut wrap_width = if rng.gen_bool(0.1) {
+//             None
+//         } else {
+//             Some(rng.gen_range(0.0..=1000.0))
+//         };
+//         let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
+//         let family_id = font_cache
+//             .load_family(&["Helvetica"], &Default::default())
+//             .unwrap();
+//         let font_id = font_cache
+//             .select_font(family_id, &Default::default())
+//             .unwrap();
+//         let font_size = 14.0;
+
+//         log::info!("Tab size: {}", tab_size);
+//         log::info!("Wrap width: {:?}", wrap_width);
+
+//         let buffer = cx.update(|cx| {
+//             if rng.gen() {
+//                 MultiBuffer::build_random(&mut rng, cx)
+//             } else {
+//                 let len = rng.gen_range(0..10);
+//                 let text = util::RandomCharIter::new(&mut rng)
+//                     .take(len)
+//                     .collect::<String>();
+//                 MultiBuffer::build_simple(&text, cx)
+//             }
+//         });
+//         let mut buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
+//         log::info!("Buffer text: {:?}", buffer_snapshot.text());
+//         let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+//         log::info!("InlayMap text: {:?}", inlay_snapshot.text());
+//         let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
+//         log::info!("FoldMap text: {:?}", fold_snapshot.text());
+//         let (mut tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
+//         let tabs_snapshot = tab_map.set_max_expansion_column(32);
+//         log::info!("TabMap text: {:?}", tabs_snapshot.text());
+
+//         let mut line_wrapper = LineWrapper::new(font_id, font_size, font_system);
+//         let unwrapped_text = tabs_snapshot.text();
+//         let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
+
+//         let (wrap_map, _) =
+//             cx.update(|cx| WrapMap::new(tabs_snapshot.clone(), font_id, font_size, wrap_width, cx));
+//         let mut notifications = observe(&wrap_map, cx);
+
+//         if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
+//             notifications.next().await.unwrap();
+//         }
+
+//         let (initial_snapshot, _) = wrap_map.update(cx, |map, cx| {
+//             assert!(!map.is_rewrapping());
+//             map.sync(tabs_snapshot.clone(), Vec::new(), cx)
+//         });
+
+//         let actual_text = initial_snapshot.text();
+//         assert_eq!(
+//             actual_text, expected_text,
+//             "unwrapped text is: {:?}",
+//             unwrapped_text
+//         );
+//         log::info!("Wrapped text: {:?}", actual_text);
+
+//         let mut next_inlay_id = 0;
+//         let mut edits = Vec::new();
+//         for _i in 0..operations {
+//             log::info!("{} ==============================================", _i);
+
+//             let mut buffer_edits = Vec::new();
+//             match rng.gen_range(0..=100) {
+//                 0..=19 => {
+//                     wrap_width = if rng.gen_bool(0.2) {
+//                         None
+//                     } else {
+//                         Some(rng.gen_range(0.0..=1000.0))
+//                     };
+//                     log::info!("Setting wrap width to {:?}", wrap_width);
+//                     wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
+//                 }
+//                 20..=39 => {
+//                     for (fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) {
+//                         let (tabs_snapshot, tab_edits) =
+//                             tab_map.sync(fold_snapshot, fold_edits, tab_size);
+//                         let (mut snapshot, wrap_edits) =
+//                             wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
+//                         snapshot.check_invariants();
+//                         snapshot.verify_chunks(&mut rng);
+//                         edits.push((snapshot, wrap_edits));
+//                     }
+//                 }
+//                 40..=59 => {
+//                     let (inlay_snapshot, inlay_edits) =
+//                         inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
+//                     let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+//                     let (tabs_snapshot, tab_edits) =
+//                         tab_map.sync(fold_snapshot, fold_edits, tab_size);
+//                     let (mut snapshot, wrap_edits) =
+//                         wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
+//                     snapshot.check_invariants();
+//                     snapshot.verify_chunks(&mut rng);
+//                     edits.push((snapshot, wrap_edits));
+//                 }
+//                 _ => {
+//                     buffer.update(cx, |buffer, cx| {
+//                         let subscription = buffer.subscribe();
+//                         let edit_count = rng.gen_range(1..=5);
+//                         buffer.randomly_mutate(&mut rng, edit_count, cx);
+//                         buffer_snapshot = buffer.snapshot(cx);
+//                         buffer_edits.extend(subscription.consume());
+//                     });
+//                 }
+//             }
+
+//             log::info!("Buffer text: {:?}", buffer_snapshot.text());
+//             let (inlay_snapshot, inlay_edits) =
+//                 inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
+//             log::info!("InlayMap text: {:?}", inlay_snapshot.text());
+//             let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+//             log::info!("FoldMap text: {:?}", fold_snapshot.text());
+//             let (tabs_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
+//             log::info!("TabMap text: {:?}", tabs_snapshot.text());
+
+//             let unwrapped_text = tabs_snapshot.text();
+//             let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
+//             let (mut snapshot, wrap_edits) =
+//                 wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot.clone(), tab_edits, cx));
+//             snapshot.check_invariants();
+//             snapshot.verify_chunks(&mut rng);
+//             edits.push((snapshot, wrap_edits));
+
+//             if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) && rng.gen_bool(0.4) {
+//                 log::info!("Waiting for wrapping to finish");
+//                 while wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
+//                     notifications.next().await.unwrap();
+//                 }
+//                 wrap_map.read_with(cx, |map, _| assert!(map.pending_edits.is_empty()));
+//             }
+
+//             if !wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
+//                 let (mut wrapped_snapshot, wrap_edits) =
+//                     wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
+//                 let actual_text = wrapped_snapshot.text();
+//                 let actual_longest_row = wrapped_snapshot.longest_row();
+//                 log::info!("Wrapping finished: {:?}", actual_text);
+//                 wrapped_snapshot.check_invariants();
+//                 wrapped_snapshot.verify_chunks(&mut rng);
+//                 edits.push((wrapped_snapshot.clone(), wrap_edits));
+//                 assert_eq!(
+//                     actual_text, expected_text,
+//                     "unwrapped text is: {:?}",
+//                     unwrapped_text
+//                 );
+
+//                 let mut summary = TextSummary::default();
+//                 for (ix, item) in wrapped_snapshot
+//                     .transforms
+//                     .items(&())
+//                     .into_iter()
+//                     .enumerate()
+//                 {
+//                     summary += &item.summary.output;
+//                     log::info!("{} summary: {:?}", ix, item.summary.output,);
+//                 }
+
+//                 if tab_size.get() == 1
+//                     || !wrapped_snapshot
+//                         .tab_snapshot
+//                         .fold_snapshot
+//                         .text()
+//                         .contains('\t')
+//                 {
+//                     let mut expected_longest_rows = Vec::new();
+//                     let mut longest_line_len = -1;
+//                     for (row, line) in expected_text.split('\n').enumerate() {
+//                         let line_char_count = line.chars().count() as isize;
+//                         if line_char_count > longest_line_len {
+//                             expected_longest_rows.clear();
+//                             longest_line_len = line_char_count;
+//                         }
+//                         if line_char_count >= longest_line_len {
+//                             expected_longest_rows.push(row as u32);
+//                         }
+//                     }
+
+//                     assert!(
+//                         expected_longest_rows.contains(&actual_longest_row),
+//                         "incorrect longest row {}. expected {:?} with length {}",
+//                         actual_longest_row,
+//                         expected_longest_rows,
+//                         longest_line_len,
+//                     )
+//                 }
+//             }
+//         }
+
+//         let mut initial_text = Rope::from(initial_snapshot.text().as_str());
+//         for (snapshot, patch) in edits {
+//             let snapshot_text = Rope::from(snapshot.text().as_str());
+//             for edit in &patch {
+//                 let old_start = initial_text.point_to_offset(Point::new(edit.new.start, 0));
+//                 let old_end = initial_text.point_to_offset(cmp::min(
+//                     Point::new(edit.new.start + edit.old.len() as u32, 0),
+//                     initial_text.max_point(),
+//                 ));
+//                 let new_start = snapshot_text.point_to_offset(Point::new(edit.new.start, 0));
+//                 let new_end = snapshot_text.point_to_offset(cmp::min(
+//                     Point::new(edit.new.end, 0),
+//                     snapshot_text.max_point(),
+//                 ));
+//                 let new_text = snapshot_text
+//                     .chunks_in_range(new_start..new_end)
+//                     .collect::<String>();
+
+//                 initial_text.replace(old_start..old_end, &new_text);
+//             }
+//             assert_eq!(initial_text.to_string(), snapshot_text.to_string());
+//         }
+
+//         if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
+//             log::info!("Waiting for wrapping to finish");
+//             while wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
+//                 notifications.next().await.unwrap();
+//             }
+//         }
+//         wrap_map.read_with(cx, |map, _| assert!(map.pending_edits.is_empty()));
+//     }
+
+//     fn init_test(cx: &mut gpui::TestAppContext) {
+//         cx.foreground().forbid_parking();
+//         cx.update(|cx| {
+//             cx.set_global(SettingsStore::test(cx));
+//             theme::init((), cx);
+//         });
+//     }
+
+//     fn wrap_text(
+//         unwrapped_text: &str,
+//         wrap_width: Option<f32>,
+//         line_wrapper: &mut LineWrapper,
+//     ) -> String {
+//         if let Some(wrap_width) = wrap_width {
+//             let mut wrapped_text = String::new();
+//             for (row, line) in unwrapped_text.split('\n').enumerate() {
+//                 if row > 0 {
+//                     wrapped_text.push('\n')
+//                 }
+
+//                 let mut prev_ix = 0;
+//                 for boundary in line_wrapper.wrap_line(line, wrap_width) {
+//                     wrapped_text.push_str(&line[prev_ix..boundary.ix]);
+//                     wrapped_text.push('\n');
+//                     wrapped_text.push_str(&" ".repeat(boundary.next_indent as usize));
+//                     prev_ix = boundary.ix;
+//                 }
+//                 wrapped_text.push_str(&line[prev_ix..]);
+//             }
+//             wrapped_text
+//         } else {
+//             unwrapped_text.to_string()
+//         }
+//     }
+
+//     impl WrapSnapshot {
+//         pub fn text(&self) -> String {
+//             self.text_chunks(0).collect()
+//         }
+
+//         pub fn text_chunks(&self, wrap_row: u32) -> impl Iterator<Item = &str> {
+//             self.chunks(
+//                 wrap_row..self.max_point().row() + 1,
+//                 false,
+//                 Highlights::default(),
+//             )
+//             .map(|h| h.text)
+//         }
+
+//         fn verify_chunks(&mut self, rng: &mut impl Rng) {
+//             for _ in 0..5 {
+//                 let mut end_row = rng.gen_range(0..=self.max_point().row());
+//                 let start_row = rng.gen_range(0..=end_row);
+//                 end_row += 1;
+
+//                 let mut expected_text = self.text_chunks(start_row).collect::<String>();
+//                 if expected_text.ends_with('\n') {
+//                     expected_text.push('\n');
+//                 }
+//                 let mut expected_text = expected_text
+//                     .lines()
+//                     .take((end_row - start_row) as usize)
+//                     .collect::<Vec<_>>()
+//                     .join("\n");
+//                 if end_row <= self.max_point().row() {
+//                     expected_text.push('\n');
+//                 }
+
+//                 let actual_text = self
+//                     .chunks(start_row..end_row, true, Highlights::default())
+//                     .map(|c| c.text)
+//                     .collect::<String>();
+//                 assert_eq!(
+//                     expected_text,
+//                     actual_text,
+//                     "chunks != highlighted_chunks for rows {:?}",
+//                     start_row..end_row
+//                 );
+//             }
+//         }
+//     }
+// }

crates/editor2/src/editor.rs 🔗

@@ -38,18 +38,9 @@ pub use element::{
 use futures::FutureExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    actions,
-    color::Color,
-    elements::*,
-    executor,
-    fonts::{self, HighlightStyle, TextStyle},
-    geometry::vector::{vec2f, Vector2F},
-    impl_actions,
-    keymap_matcher::KeymapContext,
-    platform::{CursorStyle, MouseButton},
-    serde_json, AnyElement, AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem,
-    CursorRegion, Element, Entity, ModelHandle, MouseRegion, Subscription, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle, WindowContext,
+    serde_json, AnyElement, AppContext, AsyncAppContext, ClipboardItem,
+    Element, Entity, Hsla, Model, Subscription, Task, View, ViewContext,
+    WindowContext,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HoverState};
@@ -59,8 +50,8 @@ use itertools::Itertools;
 pub use language::{char_kind, CharKind};
 use language::{
     language_settings::{self, all_language_settings, InlayHintSettings},
-    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel,
-    Completion, CursorShape, Diagnostic, DiagnosticSeverity, Documentation, File, IndentKind,
+    point_from_lsp, AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel,
+    Completion, CursorShape, Diagnostic, DiagnosticSeverity, File, IndentKind,
     IndentSize, Language, LanguageRegistry, LanguageServerName, OffsetRangeExt, OffsetUtf16, Point,
     Selection, SelectionGoal, TransactionId,
 };
@@ -551,7 +542,7 @@ pub fn init(cx: &mut AppContext) {
     cx.add_action(Editor::context_menu_last);
 
     hover_popover::init(cx);
-    scroll::actions::init(cx);
+    /scroll::actions::init(cx);
 
     workspace::register_project_item::<Editor>(cx);
     workspace::register_followable_item::<Editor>(cx);
@@ -626,8 +617,8 @@ type InlayBackgroundHighlight = (fn(&Theme) -> Color, Vec<InlayHighlight>);
 
 pub struct Editor {
     handle: WeakViewHandle<Self>,
-    buffer: ModelHandle<MultiBuffer>,
-    display_map: ModelHandle<DisplayMap>,
+    buffer: Model<MultiBuffer>,
+    display_map: Model<DisplayMap>,
     pub selections: SelectionsCollection,
     pub scroll_manager: ScrollManager,
     columnar_selection_tail: Option<Anchor>,
@@ -643,10 +634,10 @@ pub struct Editor {
     soft_wrap_mode_override: Option<language_settings::SoftWrap>,
     get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
     override_text_style: Option<Box<OverrideTextStyle>>,
-    project: Option<ModelHandle<Project>>,
+    project: Option<Model<Project>>,
     collaboration_hub: Option<Box<dyn CollaborationHub>>,
     focused: bool,
-    blink_manager: ModelHandle<BlinkManager>,
+    blink_manager: Model<BlinkManager>,
     pub show_local_selections: bool,
     mode: EditorMode,
     show_gutter: bool,
@@ -660,7 +651,7 @@ pub struct Editor {
     mouse_context_menu: ViewHandle<context_menu::ContextMenu>,
     completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
     next_completion_id: CompletionId,
-    available_code_actions: Option<(ModelHandle<Buffer>, Arc<[CodeAction]>)>,
+    available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,
     code_actions_task: Option<Task<()>>,
     document_highlights_task: Option<Task<()>>,
     pending_rename: Option<RenameState>,
@@ -678,7 +669,7 @@ pub struct Editor {
     gutter_hovered: bool,
     link_go_to_definition_state: LinkGoToDefinitionState,
     copilot_state: CopilotState,
-    inlay_hint_cache: InlayHintCache,
+    // inlay_hint_cache: InlayHintCache,
     next_inlay_id: usize,
     _subscriptions: Vec<Subscription>,
     pixel_position_of_newest_cursor: Option<Vector2F>,
@@ -851,7 +842,7 @@ enum ContextMenu {
 impl ContextMenu {
     fn select_first(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) -> bool {
         if self.visible() {
@@ -867,7 +858,7 @@ impl ContextMenu {
 
     fn select_prev(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) -> bool {
         if self.visible() {
@@ -883,7 +874,7 @@ impl ContextMenu {
 
     fn select_next(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) -> bool {
         if self.visible() {
@@ -899,7 +890,7 @@ impl ContextMenu {
 
     fn select_last(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) -> bool {
         if self.visible() {
@@ -938,7 +929,7 @@ impl ContextMenu {
 struct CompletionsMenu {
     id: CompletionId,
     initial_position: Anchor,
-    buffer: ModelHandle<Buffer>,
+    buffer: Model<Buffer>,
     completions: Arc<RwLock<Box<[Completion]>>>,
     match_candidates: Arc<[StringMatchCandidate]>,
     matches: Arc<[StringMatch]>,
@@ -949,7 +940,7 @@ struct CompletionsMenu {
 impl CompletionsMenu {
     fn select_first(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) {
         self.selected_item = 0;
@@ -960,7 +951,7 @@ impl CompletionsMenu {
 
     fn select_prev(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) {
         if self.selected_item > 0 {
@@ -975,7 +966,7 @@ impl CompletionsMenu {
 
     fn select_next(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) {
         if self.selected_item + 1 < self.matches.len() {
@@ -990,7 +981,7 @@ impl CompletionsMenu {
 
     fn select_last(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) {
         self.selected_item = self.matches.len() - 1;
@@ -1001,7 +992,7 @@ impl CompletionsMenu {
 
     fn pre_resolve_completion_documentation(
         &self,
-        project: Option<ModelHandle<Project>>,
+        project: Option<Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) {
         let settings = settings::get::<EditorSettings>(cx);
@@ -1089,7 +1080,7 @@ impl CompletionsMenu {
 
     fn attempt_resolve_selected_completion_documentation(
         &mut self,
-        project: Option<&ModelHandle<Project>>,
+        project: Option<&Model<Project>>,
         cx: &mut ViewContext<Editor>,
     ) {
         let settings = settings::get::<EditorSettings>(cx);
@@ -1519,7 +1510,7 @@ impl CompletionsMenu {
 #[derive(Clone)]
 struct CodeActionsMenu {
     actions: Arc<[CodeAction]>,
-    buffer: ModelHandle<Buffer>,
+    buffer: Model<Buffer>,
     selected_item: usize,
     list: UniformListState,
     deployed_from_indicator: bool,
@@ -1798,7347 +1789,7349 @@ impl InlayHintRefreshReason {
     }
 }
 
-impl Editor {
-    pub fn single_line(
-        field_editor_style: Option<Arc<GetFieldEditorTheme>>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
-        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
-        Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
-    }
-
-    pub fn multi_line(
-        field_editor_style: Option<Arc<GetFieldEditorTheme>>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
-        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
-        Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
-    }
-
-    pub fn auto_height(
-        max_lines: usize,
-        field_editor_style: Option<Arc<GetFieldEditorTheme>>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
-        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
-        Self::new(
-            EditorMode::AutoHeight { max_lines },
-            buffer,
-            None,
-            field_editor_style,
-            cx,
-        )
-    }
-
-    pub fn for_buffer(
-        buffer: ModelHandle<Buffer>,
-        project: Option<ModelHandle<Project>>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
-        Self::new(EditorMode::Full, buffer, project, None, cx)
-    }
-
-    pub fn for_multibuffer(
-        buffer: ModelHandle<MultiBuffer>,
-        project: Option<ModelHandle<Project>>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        Self::new(EditorMode::Full, buffer, project, None, cx)
-    }
-
-    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
-        let mut clone = Self::new(
-            self.mode,
-            self.buffer.clone(),
-            self.project.clone(),
-            self.get_field_editor_theme.clone(),
-            cx,
-        );
-        self.display_map.update(cx, |display_map, cx| {
-            let snapshot = display_map.snapshot(cx);
-            clone.display_map.update(cx, |display_map, cx| {
-                display_map.set_state(&snapshot, cx);
-            });
-        });
-        clone.selections.clone_state(&self.selections);
-        clone.scroll_manager.clone_state(&self.scroll_manager);
-        clone.searchable = self.searchable;
-        clone
-    }
-
-    fn new(
-        mode: EditorMode,
-        buffer: ModelHandle<MultiBuffer>,
-        project: Option<ModelHandle<Project>>,
-        get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        let editor_view_id = cx.view_id();
-        let display_map = cx.add_model(|cx| {
-            let settings = settings::get::<ThemeSettings>(cx);
-            let style = build_style(settings, get_field_editor_theme.as_deref(), None, cx);
-            DisplayMap::new(
-                buffer.clone(),
-                style.text.font_id,
-                style.text.font_size,
-                None,
-                2,
-                1,
-                cx,
-            )
-        });
-
-        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
-
-        let blink_manager = cx.add_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
-
-        let soft_wrap_mode_override =
-            (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
-
-        let mut project_subscriptions = Vec::new();
-        if mode == EditorMode::Full {
-            if let Some(project) = project.as_ref() {
-                if buffer.read(cx).is_singleton() {
-                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
-                        cx.emit(Event::TitleChanged);
-                    }));
-                }
-                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
-                    if let project::Event::RefreshInlayHints = event {
-                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
-                    };
-                }));
-            }
-        }
-
-        let inlay_hint_settings = inlay_hint_settings(
-            selections.newest_anchor().head(),
-            &buffer.read(cx).snapshot(cx),
-            cx,
-        );
-
-        let mut this = Self {
-            handle: cx.weak_handle(),
-            buffer: buffer.clone(),
-            display_map: display_map.clone(),
-            selections,
-            scroll_manager: ScrollManager::new(),
-            columnar_selection_tail: None,
-            add_selections_state: None,
-            select_next_state: None,
-            select_prev_state: None,
-            selection_history: Default::default(),
-            autoclose_regions: Default::default(),
-            snippet_stack: Default::default(),
-            select_larger_syntax_node_stack: Vec::new(),
-            ime_transaction: Default::default(),
-            active_diagnostics: None,
-            soft_wrap_mode_override,
-            get_field_editor_theme,
-            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
-            project,
-            focused: false,
-            blink_manager: blink_manager.clone(),
-            show_local_selections: true,
-            mode,
-            show_gutter: mode == EditorMode::Full,
-            show_wrap_guides: None,
-            placeholder_text: None,
-            highlighted_rows: None,
-            background_highlights: Default::default(),
-            inlay_background_highlights: Default::default(),
-            nav_history: None,
-            context_menu: RwLock::new(None),
-            mouse_context_menu: cx
-                .add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)),
-            completion_tasks: Default::default(),
-            next_completion_id: 0,
-            next_inlay_id: 0,
-            available_code_actions: Default::default(),
-            code_actions_task: Default::default(),
-            document_highlights_task: Default::default(),
-            pending_rename: Default::default(),
-            searchable: true,
-            override_text_style: None,
-            cursor_shape: Default::default(),
-            autoindent_mode: Some(AutoindentMode::EachLine),
-            collapse_matches: false,
-            workspace: None,
-            keymap_context_layers: Default::default(),
-            input_enabled: true,
-            read_only: false,
-            leader_peer_id: None,
-            remote_id: None,
-            hover_state: Default::default(),
-            link_go_to_definition_state: Default::default(),
-            copilot_state: Default::default(),
-            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
-            gutter_hovered: false,
-            pixel_position_of_newest_cursor: None,
-            _subscriptions: vec![
-                cx.observe(&buffer, Self::on_buffer_changed),
-                cx.subscribe(&buffer, Self::on_buffer_event),
-                cx.observe(&display_map, Self::on_display_map_changed),
-                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
-                cx.observe_global::<SettingsStore, _>(Self::settings_changed),
-                cx.observe_window_activation(|editor, active, cx| {
-                    editor.blink_manager.update(cx, |blink_manager, cx| {
-                        if active {
-                            blink_manager.enable(cx);
-                        } else {
-                            blink_manager.show_cursor(cx);
-                            blink_manager.disable(cx);
-                        }
-                    });
-                }),
-            ],
-        };
-
-        this._subscriptions.extend(project_subscriptions);
-
-        this.end_selection(cx);
-        this.scroll_manager.show_scrollbar(cx);
-
-        let editor_created_event = EditorCreated(cx.handle());
-        cx.emit_global(editor_created_event);
-
-        if mode == EditorMode::Full {
-            let should_auto_hide_scrollbars = cx.platform().should_auto_hide_scrollbars();
-            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
-        }
-
-        this.report_editor_event("open", None, cx);
-        this
-    }
-
-    pub fn new_file(
-        workspace: &mut Workspace,
-        _: &workspace::NewFile,
-        cx: &mut ViewContext<Workspace>,
-    ) {
-        let project = workspace.project().clone();
-        if project.read(cx).is_remote() {
-            cx.propagate_action();
-        } else if let Some(buffer) = project
-            .update(cx, |project, cx| project.create_buffer("", None, cx))
-            .log_err()
-        {
-            workspace.add_item(
-                Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
-                cx,
-            );
-        }
-    }
-
-    pub fn new_file_in_direction(
-        workspace: &mut Workspace,
-        action: &workspace::NewFileInDirection,
-        cx: &mut ViewContext<Workspace>,
-    ) {
-        let project = workspace.project().clone();
-        if project.read(cx).is_remote() {
-            cx.propagate_action();
-        } else if let Some(buffer) = project
-            .update(cx, |project, cx| project.create_buffer("", None, cx))
-            .log_err()
-        {
-            workspace.split_item(
-                action.0,
-                Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
-                cx,
-            );
-        }
-    }
-
-    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
-        self.buffer.read(cx).replica_id()
-    }
-
-    pub fn leader_peer_id(&self) -> Option<PeerId> {
-        self.leader_peer_id
-    }
-
-    pub fn buffer(&self) -> &ModelHandle<MultiBuffer> {
-        &self.buffer
-    }
-
-    fn workspace(&self, cx: &AppContext) -> Option<ViewHandle<Workspace>> {
-        self.workspace.as_ref()?.0.upgrade(cx)
-    }
-
-    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
-        self.buffer().read(cx).title(cx)
-    }
-
-    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
-        EditorSnapshot {
-            mode: self.mode,
-            show_gutter: self.show_gutter,
-            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
-            scroll_anchor: self.scroll_manager.anchor(),
-            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
-            placeholder_text: self.placeholder_text.clone(),
-            is_focused: self
-                .handle
-                .upgrade(cx)
-                .map_or(false, |handle| handle.is_focused(cx)),
-        }
-    }
-
-    pub fn language_at<'a, T: ToOffset>(
-        &self,
-        point: T,
-        cx: &'a AppContext,
-    ) -> Option<Arc<Language>> {
-        self.buffer.read(cx).language_at(point, cx)
-    }
-
-    pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option<Arc<dyn File>> {
-        self.buffer.read(cx).read(cx).file_at(point).cloned()
-    }
-
-    pub fn active_excerpt(
-        &self,
-        cx: &AppContext,
-    ) -> Option<(ExcerptId, ModelHandle<Buffer>, Range<text::Anchor>)> {
-        self.buffer
-            .read(cx)
-            .excerpt_containing(self.selections.newest_anchor().head(), cx)
-    }
-
-    pub fn style(&self, cx: &AppContext) -> EditorStyle {
-        build_style(
-            settings::get::<ThemeSettings>(cx),
-            self.get_field_editor_theme.as_deref(),
-            self.override_text_style.as_deref(),
-            cx,
-        )
-    }
-
-    pub fn mode(&self) -> EditorMode {
-        self.mode
-    }
-
-    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
-        self.collaboration_hub.as_deref()
-    }
-
-    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
-        self.collaboration_hub = Some(hub);
-    }
-
-    pub fn set_placeholder_text(
-        &mut self,
-        placeholder_text: impl Into<Arc<str>>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.placeholder_text = Some(placeholder_text.into());
-        cx.notify();
-    }
-
-    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
-        self.cursor_shape = cursor_shape;
-        cx.notify();
-    }
-
-    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
-        self.collapse_matches = collapse_matches;
-    }
-
-    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
-        if self.collapse_matches {
-            return range.start..range.start;
-        }
-        range.clone()
-    }
-
-    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
-        if self.display_map.read(cx).clip_at_line_ends != clip {
-            self.display_map
-                .update(cx, |map, _| map.clip_at_line_ends = clip);
-        }
-    }
-
-    pub fn set_keymap_context_layer<Tag: 'static>(
-        &mut self,
-        context: KeymapContext,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.keymap_context_layers
-            .insert(TypeId::of::<Tag>(), context);
-        cx.notify();
-    }
-
-    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
-        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
-        cx.notify();
-    }
-
-    pub fn set_input_enabled(&mut self, input_enabled: bool) {
-        self.input_enabled = input_enabled;
-    }
-
-    pub fn set_autoindent(&mut self, autoindent: bool) {
-        if autoindent {
-            self.autoindent_mode = Some(AutoindentMode::EachLine);
-        } else {
-            self.autoindent_mode = None;
-        }
-    }
-
-    pub fn read_only(&self) -> bool {
-        self.read_only
-    }
-
-    pub fn set_read_only(&mut self, read_only: bool) {
-        self.read_only = read_only;
-    }
-
-    pub fn set_field_editor_style(
-        &mut self,
-        style: Option<Arc<GetFieldEditorTheme>>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.get_field_editor_theme = style;
-        cx.notify();
-    }
-
-    fn selections_did_change(
-        &mut self,
-        local: bool,
-        old_cursor_position: &Anchor,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if self.focused && self.leader_peer_id.is_none() {
-            self.buffer.update(cx, |buffer, cx| {
-                buffer.set_active_selections(
-                    &self.selections.disjoint_anchors(),
-                    self.selections.line_mode,
-                    self.cursor_shape,
-                    cx,
-                )
-            });
-        }
-
-        let display_map = self
-            .display_map
-            .update(cx, |display_map, cx| display_map.snapshot(cx));
-        let buffer = &display_map.buffer_snapshot;
-        self.add_selections_state = None;
-        self.select_next_state = None;
-        self.select_prev_state = None;
-        self.select_larger_syntax_node_stack.clear();
-        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
-        self.snippet_stack
-            .invalidate(&self.selections.disjoint_anchors(), buffer);
-        self.take_rename(false, cx);
-
-        let new_cursor_position = self.selections.newest_anchor().head();
-
-        self.push_to_nav_history(
-            old_cursor_position.clone(),
-            Some(new_cursor_position.to_point(buffer)),
-            cx,
-        );
-
-        if local {
-            let new_cursor_position = self.selections.newest_anchor().head();
-            let mut context_menu = self.context_menu.write();
-            let completion_menu = match context_menu.as_ref() {
-                Some(ContextMenu::Completions(menu)) => Some(menu),
-
-                _ => {
-                    *context_menu = None;
-                    None
-                }
-            };
-
-            if let Some(completion_menu) = completion_menu {
-                let cursor_position = new_cursor_position.to_offset(buffer);
-                let (word_range, kind) =
-                    buffer.surrounding_word(completion_menu.initial_position.clone());
-                if kind == Some(CharKind::Word)
-                    && word_range.to_inclusive().contains(&cursor_position)
-                {
-                    let mut completion_menu = completion_menu.clone();
-                    drop(context_menu);
-
-                    let query = Self::completion_query(buffer, cursor_position);
-                    cx.spawn(move |this, mut cx| async move {
-                        completion_menu
-                            .filter(query.as_deref(), cx.background().clone())
-                            .await;
-
-                        this.update(&mut cx, |this, cx| {
-                            let mut context_menu = this.context_menu.write();
-                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
-                                return;
-                            };
-
-                            if menu.id > completion_menu.id {
-                                return;
-                            }
-
-                            *context_menu = Some(ContextMenu::Completions(completion_menu));
-                            drop(context_menu);
-                            cx.notify();
-                        })
-                    })
-                    .detach();
-
-                    self.show_completions(&ShowCompletions, cx);
-                } else {
-                    drop(context_menu);
-                    self.hide_context_menu(cx);
-                }
-            } else {
-                drop(context_menu);
-            }
-
-            hide_hover(self, cx);
-
-            if old_cursor_position.to_display_point(&display_map).row()
-                != new_cursor_position.to_display_point(&display_map).row()
-            {
-                self.available_code_actions.take();
-            }
-            self.refresh_code_actions(cx);
-            self.refresh_document_highlights(cx);
-            refresh_matching_bracket_highlights(self, cx);
-            self.discard_copilot_suggestion(cx);
-        }
-
-        self.blink_manager.update(cx, BlinkManager::pause_blinking);
-        cx.emit(Event::SelectionsChanged { local });
-        cx.notify();
-    }
-
-    pub fn change_selections<R>(
-        &mut self,
-        autoscroll: Option<Autoscroll>,
-        cx: &mut ViewContext<Self>,
-        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
-    ) -> R {
-        let old_cursor_position = self.selections.newest_anchor().head();
-        self.push_to_selection_history();
-
-        let (changed, result) = self.selections.change_with(cx, change);
-
-        if changed {
-            if let Some(autoscroll) = autoscroll {
-                self.request_autoscroll(autoscroll, cx);
-            }
-            self.selections_did_change(true, &old_cursor_position, cx);
-        }
-
-        result
-    }
-
-    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
-    where
-        I: IntoIterator<Item = (Range<S>, T)>,
-        S: ToOffset,
-        T: Into<Arc<str>>,
-    {
-        if self.read_only {
-            return;
-        }
-
-        self.buffer
-            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
-    }
-
-    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
-    where
-        I: IntoIterator<Item = (Range<S>, T)>,
-        S: ToOffset,
-        T: Into<Arc<str>>,
-    {
-        if self.read_only {
-            return;
-        }
-
-        self.buffer.update(cx, |buffer, cx| {
-            buffer.edit(edits, self.autoindent_mode.clone(), cx)
-        });
-    }
-
-    pub fn edit_with_block_indent<I, S, T>(
-        &mut self,
-        edits: I,
-        original_indent_columns: Vec<u32>,
-        cx: &mut ViewContext<Self>,
-    ) where
-        I: IntoIterator<Item = (Range<S>, T)>,
-        S: ToOffset,
-        T: Into<Arc<str>>,
-    {
-        if self.read_only {
-            return;
-        }
-
-        self.buffer.update(cx, |buffer, cx| {
-            buffer.edit(
-                edits,
-                Some(AutoindentMode::Block {
-                    original_indent_columns,
-                }),
-                cx,
-            )
-        });
-    }
-
-    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
-        self.hide_context_menu(cx);
-
-        match phase {
-            SelectPhase::Begin {
-                position,
-                add,
-                click_count,
-            } => self.begin_selection(position, add, click_count, cx),
-            SelectPhase::BeginColumnar {
-                position,
-                goal_column,
-            } => self.begin_columnar_selection(position, goal_column, cx),
-            SelectPhase::Extend {
-                position,
-                click_count,
-            } => self.extend_selection(position, click_count, cx),
-            SelectPhase::Update {
-                position,
-                goal_column,
-                scroll_position,
-            } => self.update_selection(position, goal_column, scroll_position, cx),
-            SelectPhase::End => self.end_selection(cx),
-        }
-    }
-
-    fn extend_selection(
-        &mut self,
-        position: DisplayPoint,
-        click_count: usize,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let tail = self.selections.newest::<usize>(cx).tail();
-        self.begin_selection(position, false, click_count, cx);
-
-        let position = position.to_offset(&display_map, Bias::Left);
-        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
-
-        let mut pending_selection = self
-            .selections
-            .pending_anchor()
-            .expect("extend_selection not called with pending selection");
-        if position >= tail {
-            pending_selection.start = tail_anchor;
-        } else {
-            pending_selection.end = tail_anchor;
-            pending_selection.reversed = true;
-        }
-
-        let mut pending_mode = self.selections.pending_mode().unwrap();
-        match &mut pending_mode {
-            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
-            _ => {}
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.set_pending(pending_selection, pending_mode)
-        });
-    }
-
-    fn begin_selection(
-        &mut self,
-        position: DisplayPoint,
-        add: bool,
-        click_count: usize,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if !self.focused {
-            cx.focus_self();
-        }
-
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = &display_map.buffer_snapshot;
-        let newest_selection = self.selections.newest_anchor().clone();
-        let position = display_map.clip_point(position, Bias::Left);
-
-        let start;
-        let end;
-        let mode;
-        let auto_scroll;
-        match click_count {
-            1 => {
-                start = buffer.anchor_before(position.to_point(&display_map));
-                end = start.clone();
-                mode = SelectMode::Character;
-                auto_scroll = true;
-            }
-            2 => {
-                let range = movement::surrounding_word(&display_map, position);
-                start = buffer.anchor_before(range.start.to_point(&display_map));
-                end = buffer.anchor_before(range.end.to_point(&display_map));
-                mode = SelectMode::Word(start.clone()..end.clone());
-                auto_scroll = true;
-            }
-            3 => {
-                let position = display_map
-                    .clip_point(position, Bias::Left)
-                    .to_point(&display_map);
-                let line_start = display_map.prev_line_boundary(position).0;
-                let next_line_start = buffer.clip_point(
-                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
-                    Bias::Left,
-                );
-                start = buffer.anchor_before(line_start);
-                end = buffer.anchor_before(next_line_start);
-                mode = SelectMode::Line(start.clone()..end.clone());
-                auto_scroll = true;
-            }
-            _ => {
-                start = buffer.anchor_before(0);
-                end = buffer.anchor_before(buffer.len());
-                mode = SelectMode::All;
-                auto_scroll = false;
-            }
-        }
-
-        self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
-            if !add {
-                s.clear_disjoint();
-            } else if click_count > 1 {
-                s.delete(newest_selection.id)
-            }
-
-            s.set_pending_anchor_range(start..end, mode);
-        });
-    }
-
-    fn begin_columnar_selection(
-        &mut self,
-        position: DisplayPoint,
-        goal_column: u32,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if !self.focused {
-            cx.focus_self();
-        }
-
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let tail = self.selections.newest::<Point>(cx).tail();
-        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
-
-        self.select_columns(
-            tail.to_display_point(&display_map),
-            position,
-            goal_column,
-            &display_map,
-            cx,
-        );
-    }
-
-    fn update_selection(
-        &mut self,
-        position: DisplayPoint,
-        goal_column: u32,
-        scroll_position: Vector2F,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-
-        if let Some(tail) = self.columnar_selection_tail.as_ref() {
-            let tail = tail.to_display_point(&display_map);
-            self.select_columns(tail, position, goal_column, &display_map, cx);
-        } else if let Some(mut pending) = self.selections.pending_anchor() {
-            let buffer = self.buffer.read(cx).snapshot(cx);
-            let head;
-            let tail;
-            let mode = self.selections.pending_mode().unwrap();
-            match &mode {
-                SelectMode::Character => {
-                    head = position.to_point(&display_map);
-                    tail = pending.tail().to_point(&buffer);
-                }
-                SelectMode::Word(original_range) => {
-                    let original_display_range = original_range.start.to_display_point(&display_map)
-                        ..original_range.end.to_display_point(&display_map);
-                    let original_buffer_range = original_display_range.start.to_point(&display_map)
-                        ..original_display_range.end.to_point(&display_map);
-                    if movement::is_inside_word(&display_map, position)
-                        || original_display_range.contains(&position)
-                    {
-                        let word_range = movement::surrounding_word(&display_map, position);
-                        if word_range.start < original_display_range.start {
-                            head = word_range.start.to_point(&display_map);
-                        } else {
-                            head = word_range.end.to_point(&display_map);
-                        }
-                    } else {
-                        head = position.to_point(&display_map);
-                    }
-
-                    if head <= original_buffer_range.start {
-                        tail = original_buffer_range.end;
-                    } else {
-                        tail = original_buffer_range.start;
-                    }
-                }
-                SelectMode::Line(original_range) => {
-                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
-
-                    let position = display_map
-                        .clip_point(position, Bias::Left)
-                        .to_point(&display_map);
-                    let line_start = display_map.prev_line_boundary(position).0;
-                    let next_line_start = buffer.clip_point(
-                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
-                        Bias::Left,
-                    );
-
-                    if line_start < original_range.start {
-                        head = line_start
-                    } else {
-                        head = next_line_start
-                    }
-
-                    if head <= original_range.start {
-                        tail = original_range.end;
-                    } else {
-                        tail = original_range.start;
-                    }
-                }
-                SelectMode::All => {
-                    return;
-                }
-            };
-
-            if head < tail {
-                pending.start = buffer.anchor_before(head);
-                pending.end = buffer.anchor_before(tail);
-                pending.reversed = true;
-            } else {
-                pending.start = buffer.anchor_before(tail);
-                pending.end = buffer.anchor_before(head);
-                pending.reversed = false;
-            }
-
-            self.change_selections(None, cx, |s| {
-                s.set_pending(pending, mode);
-            });
-        } else {
-            error!("update_selection dispatched with no pending selection");
-            return;
-        }
-
-        self.set_scroll_position(scroll_position, cx);
-        cx.notify();
-    }
-
-    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
-        self.columnar_selection_tail.take();
-        if self.selections.pending_anchor().is_some() {
-            let selections = self.selections.all::<usize>(cx);
-            self.change_selections(None, cx, |s| {
-                s.select(selections);
-                s.clear_pending();
-            });
-        }
-    }
-
-    fn select_columns(
-        &mut self,
-        tail: DisplayPoint,
-        head: DisplayPoint,
-        goal_column: u32,
-        display_map: &DisplaySnapshot,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let start_row = cmp::min(tail.row(), head.row());
-        let end_row = cmp::max(tail.row(), head.row());
-        let start_column = cmp::min(tail.column(), goal_column);
-        let end_column = cmp::max(tail.column(), goal_column);
-        let reversed = start_column < tail.column();
-
-        let selection_ranges = (start_row..=end_row)
-            .filter_map(|row| {
-                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
-                    let start = display_map
-                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
-                        .to_point(display_map);
-                    let end = display_map
-                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
-                        .to_point(display_map);
-                    if reversed {
-                        Some(end..start)
-                    } else {
-                        Some(start..end)
-                    }
-                } else {
-                    None
-                }
-            })
-            .collect::<Vec<_>>();
-
-        self.change_selections(None, cx, |s| {
-            s.select_ranges(selection_ranges);
-        });
-        cx.notify();
-    }
-
-    pub fn has_pending_nonempty_selection(&self) -> bool {
-        let pending_nonempty_selection = match self.selections.pending_anchor() {
-            Some(Selection { start, end, .. }) => start != end,
-            None => false,
-        };
-        pending_nonempty_selection || self.columnar_selection_tail.is_some()
-    }
-
-    pub fn has_pending_selection(&self) -> bool {
-        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
-    }
-
-    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
-        if self.take_rename(false, cx).is_some() {
-            return;
-        }
-
-        if hide_hover(self, cx) {
-            return;
-        }
-
-        if self.hide_context_menu(cx).is_some() {
-            return;
-        }
-
-        if self.discard_copilot_suggestion(cx) {
-            return;
-        }
-
-        if self.snippet_stack.pop().is_some() {
-            return;
-        }
-
-        if self.mode == EditorMode::Full {
-            if self.active_diagnostics.is_some() {
-                self.dismiss_diagnostics(cx);
-                return;
-            }
-
-            if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
-                return;
-            }
-        }
-
-        cx.propagate_action();
-    }
-
-    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
-        let text: Arc<str> = text.into();
-
-        if self.read_only {
-            return;
-        }
-
-        let selections = self.selections.all_adjusted(cx);
-        let mut brace_inserted = false;
-        let mut edits = Vec::new();
-        let mut new_selections = Vec::with_capacity(selections.len());
-        let mut new_autoclose_regions = Vec::new();
-        let snapshot = self.buffer.read(cx).read(cx);
-
-        for (selection, autoclose_region) in
-            self.selections_with_autoclose_regions(selections, &snapshot)
-        {
-            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
-                // Determine if the inserted text matches the opening or closing
-                // bracket of any of this language's bracket pairs.
-                let mut bracket_pair = None;
-                let mut is_bracket_pair_start = false;
-                if !text.is_empty() {
-                    // `text` can be empty when an user is using IME (e.g. Chinese Wubi Simplified)
-                    //  and they are removing the character that triggered IME popup.
-                    for (pair, enabled) in scope.brackets() {
-                        if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
-                            bracket_pair = Some(pair.clone());
-                            is_bracket_pair_start = true;
-                            break;
-                        } else if pair.end.as_str() == text.as_ref() {
-                            bracket_pair = Some(pair.clone());
-                            break;
-                        }
-                    }
-                }
-
-                if let Some(bracket_pair) = bracket_pair {
-                    if selection.is_empty() {
-                        if is_bracket_pair_start {
-                            let prefix_len = bracket_pair.start.len() - text.len();
-
-                            // If the inserted text is a suffix of an opening bracket and the
-                            // selection is preceded by the rest of the opening bracket, then
-                            // insert the closing bracket.
-                            let following_text_allows_autoclose = snapshot
-                                .chars_at(selection.start)
-                                .next()
-                                .map_or(true, |c| scope.should_autoclose_before(c));
-                            let preceding_text_matches_prefix = prefix_len == 0
-                                || (selection.start.column >= (prefix_len as u32)
-                                    && snapshot.contains_str_at(
-                                        Point::new(
-                                            selection.start.row,
-                                            selection.start.column - (prefix_len as u32),
-                                        ),
-                                        &bracket_pair.start[..prefix_len],
-                                    ));
-                            if following_text_allows_autoclose && preceding_text_matches_prefix {
-                                let anchor = snapshot.anchor_before(selection.end);
-                                new_selections.push((selection.map(|_| anchor), text.len()));
-                                new_autoclose_regions.push((
-                                    anchor,
-                                    text.len(),
-                                    selection.id,
-                                    bracket_pair.clone(),
-                                ));
-                                edits.push((
-                                    selection.range(),
-                                    format!("{}{}", text, bracket_pair.end).into(),
-                                ));
-                                brace_inserted = true;
-                                continue;
-                            }
-                        }
-
-                        if let Some(region) = autoclose_region {
-                            // If the selection is followed by an auto-inserted closing bracket,
-                            // then don't insert that closing bracket again; just move the selection
-                            // past the closing bracket.
-                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
-                                && text.as_ref() == region.pair.end.as_str();
-                            if should_skip {
-                                let anchor = snapshot.anchor_after(selection.end);
-                                new_selections
-                                    .push((selection.map(|_| anchor), region.pair.end.len()));
-                                continue;
-                            }
-                        }
-                    }
-                    // If an opening bracket is 1 character long and is typed while
-                    // text is selected, then surround that text with the bracket pair.
-                    else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
-                        edits.push((selection.start..selection.start, text.clone()));
-                        edits.push((
-                            selection.end..selection.end,
-                            bracket_pair.end.as_str().into(),
-                        ));
-                        brace_inserted = true;
-                        new_selections.push((
-                            Selection {
-                                id: selection.id,
-                                start: snapshot.anchor_after(selection.start),
-                                end: snapshot.anchor_before(selection.end),
-                                reversed: selection.reversed,
-                                goal: selection.goal,
-                            },
-                            0,
-                        ));
-                        continue;
-                    }
-                }
-            }
-
-            // If not handling any auto-close operation, then just replace the selected
-            // text with the given input and move the selection to the end of the
-            // newly inserted text.
-            let anchor = snapshot.anchor_after(selection.end);
-            new_selections.push((selection.map(|_| anchor), 0));
-            edits.push((selection.start..selection.end, text.clone()));
-        }
-
-        drop(snapshot);
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |buffer, cx| {
-                buffer.edit(edits, this.autoindent_mode.clone(), cx);
-            });
-
-            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
-            let new_selection_deltas = new_selections.iter().map(|e| e.1);
-            let snapshot = this.buffer.read(cx).read(cx);
-            let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
-                .zip(new_selection_deltas)
-                .map(|(selection, delta)| Selection {
-                    id: selection.id,
-                    start: selection.start + delta,
-                    end: selection.end + delta,
-                    reversed: selection.reversed,
-                    goal: SelectionGoal::None,
-                })
-                .collect::<Vec<_>>();
-
-            let mut i = 0;
-            for (position, delta, selection_id, pair) in new_autoclose_regions {
-                let position = position.to_offset(&snapshot) + delta;
-                let start = snapshot.anchor_before(position);
-                let end = snapshot.anchor_after(position);
-                while let Some(existing_state) = this.autoclose_regions.get(i) {
-                    match existing_state.range.start.cmp(&start, &snapshot) {
-                        Ordering::Less => i += 1,
-                        Ordering::Greater => break,
-                        Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
-                            Ordering::Less => i += 1,
-                            Ordering::Equal => break,
-                            Ordering::Greater => break,
-                        },
-                    }
-                }
-                this.autoclose_regions.insert(
-                    i,
-                    AutocloseRegion {
-                        selection_id,
-                        range: start..end,
-                        pair,
-                    },
-                );
-            }
-
-            drop(snapshot);
-            let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
-
-            if !brace_inserted && settings::get::<EditorSettings>(cx).use_on_type_format {
-                if let Some(on_type_format_task) =
-                    this.trigger_on_type_formatting(text.to_string(), cx)
-                {
-                    on_type_format_task.detach_and_log_err(cx);
-                }
-            }
-
-            if had_active_copilot_suggestion {
-                this.refresh_copilot_suggestions(true, cx);
-                if !this.has_active_copilot_suggestion(cx) {
-                    this.trigger_completion_on_input(&text, cx);
-                }
-            } else {
-                this.trigger_completion_on_input(&text, cx);
-                this.refresh_copilot_suggestions(true, cx);
-            }
-        });
-    }
-
-    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
-                let selections = this.selections.all::<usize>(cx);
-                let multi_buffer = this.buffer.read(cx);
-                let buffer = multi_buffer.snapshot(cx);
-                selections
-                    .iter()
-                    .map(|selection| {
-                        let start_point = selection.start.to_point(&buffer);
-                        let mut indent = buffer.indent_size_for_line(start_point.row);
-                        indent.len = cmp::min(indent.len, start_point.column);
-                        let start = selection.start;
-                        let end = selection.end;
-                        let is_cursor = start == end;
-                        let language_scope = buffer.language_scope_at(start);
-                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
-                            &language_scope
-                        {
-                            let leading_whitespace_len = buffer
-                                .reversed_chars_at(start)
-                                .take_while(|c| c.is_whitespace() && *c != '\n')
-                                .map(|c| c.len_utf8())
-                                .sum::<usize>();
-
-                            let trailing_whitespace_len = buffer
-                                .chars_at(end)
-                                .take_while(|c| c.is_whitespace() && *c != '\n')
-                                .map(|c| c.len_utf8())
-                                .sum::<usize>();
-
-                            let insert_extra_newline =
-                                language.brackets().any(|(pair, enabled)| {
-                                    let pair_start = pair.start.trim_end();
-                                    let pair_end = pair.end.trim_start();
-
-                                    enabled
-                                        && pair.newline
-                                        && buffer.contains_str_at(
-                                            end + trailing_whitespace_len,
-                                            pair_end,
-                                        )
-                                        && buffer.contains_str_at(
-                                            (start - leading_whitespace_len)
-                                                .saturating_sub(pair_start.len()),
-                                            pair_start,
-                                        )
-                                });
-                            // Comment extension on newline is allowed only for cursor selections
-                            let comment_delimiter = language.line_comment_prefix().filter(|_| {
-                                let is_comment_extension_enabled =
-                                    multi_buffer.settings_at(0, cx).extend_comment_on_newline;
-                                is_cursor && is_comment_extension_enabled
-                            });
-                            let comment_delimiter = if let Some(delimiter) = comment_delimiter {
-                                buffer
-                                    .buffer_line_for_row(start_point.row)
-                                    .is_some_and(|(snapshot, range)| {
-                                        let mut index_of_first_non_whitespace = 0;
-                                        let line_starts_with_comment = snapshot
-                                            .chars_for_range(range)
-                                            .skip_while(|c| {
-                                                let should_skip = c.is_whitespace();
-                                                if should_skip {
-                                                    index_of_first_non_whitespace += 1;
-                                                }
-                                                should_skip
-                                            })
-                                            .take(delimiter.len())
-                                            .eq(delimiter.chars());
-                                        let cursor_is_placed_after_comment_marker =
-                                            index_of_first_non_whitespace + delimiter.len()
-                                                <= start_point.column as usize;
-                                        line_starts_with_comment
-                                            && cursor_is_placed_after_comment_marker
-                                    })
-                                    .then(|| delimiter.clone())
-                            } else {
-                                None
-                            };
-                            (comment_delimiter, insert_extra_newline)
-                        } else {
-                            (None, false)
-                        };
-
-                        let capacity_for_delimiter = comment_delimiter
-                            .as_deref()
-                            .map(str::len)
-                            .unwrap_or_default();
-                        let mut new_text =
-                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
-                        new_text.push_str("\n");
-                        new_text.extend(indent.chars());
-                        if let Some(delimiter) = &comment_delimiter {
-                            new_text.push_str(&delimiter);
-                        }
-                        if insert_extra_newline {
-                            new_text = new_text.repeat(2);
-                        }
-
-                        let anchor = buffer.anchor_after(end);
-                        let new_selection = selection.map(|_| anchor);
-                        (
-                            (start..end, new_text),
-                            (insert_extra_newline, new_selection),
-                        )
-                    })
-                    .unzip()
-            };
-
-            this.edit_with_autoindent(edits, cx);
-            let buffer = this.buffer.read(cx).snapshot(cx);
-            let new_selections = selection_fixup_info
-                .into_iter()
-                .map(|(extra_newline_inserted, new_selection)| {
-                    let mut cursor = new_selection.end.to_point(&buffer);
-                    if extra_newline_inserted {
-                        cursor.row -= 1;
-                        cursor.column = buffer.line_len(cursor.row);
-                    }
-                    new_selection.map(|_| cursor)
-                })
-                .collect();
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
-            this.refresh_copilot_suggestions(true, cx);
-        });
-    }
-
-    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
-        let buffer = self.buffer.read(cx);
-        let snapshot = buffer.snapshot(cx);
-
-        let mut edits = Vec::new();
-        let mut rows = Vec::new();
-        let mut rows_inserted = 0;
-
-        for selection in self.selections.all_adjusted(cx) {
-            let cursor = selection.head();
-            let row = cursor.row;
-
-            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
-
-            let newline = "\n".to_string();
-            edits.push((start_of_line..start_of_line, newline));
-
-            rows.push(row + rows_inserted);
-            rows_inserted += 1;
-        }
-
-        self.transact(cx, |editor, cx| {
-            editor.edit(edits, cx);
-
-            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let mut index = 0;
-                s.move_cursors_with(|map, _, _| {
-                    let row = rows[index];
-                    index += 1;
-
-                    let point = Point::new(row, 0);
-                    let boundary = map.next_line_boundary(point).1;
-                    let clipped = map.clip_point(boundary, Bias::Left);
-
-                    (clipped, SelectionGoal::None)
-                });
-            });
-
-            let mut indent_edits = Vec::new();
-            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
-            for row in rows {
-                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
-                for (row, indent) in indents {
-                    if indent.len == 0 {
-                        continue;
-                    }
-
-                    let text = match indent.kind {
-                        IndentKind::Space => " ".repeat(indent.len as usize),
-                        IndentKind::Tab => "\t".repeat(indent.len as usize),
-                    };
-                    let point = Point::new(row, 0);
-                    indent_edits.push((point..point, text));
-                }
-            }
-            editor.edit(indent_edits, cx);
-        });
-    }
-
-    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
-        let buffer = self.buffer.read(cx);
-        let snapshot = buffer.snapshot(cx);
-
-        let mut edits = Vec::new();
-        let mut rows = Vec::new();
-        let mut rows_inserted = 0;
-
-        for selection in self.selections.all_adjusted(cx) {
-            let cursor = selection.head();
-            let row = cursor.row;
-
-            let point = Point::new(row + 1, 0);
-            let start_of_line = snapshot.clip_point(point, Bias::Left);
-
-            let newline = "\n".to_string();
-            edits.push((start_of_line..start_of_line, newline));
-
-            rows_inserted += 1;
-            rows.push(row + rows_inserted);
-        }
-
-        self.transact(cx, |editor, cx| {
-            editor.edit(edits, cx);
-
-            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let mut index = 0;
-                s.move_cursors_with(|map, _, _| {
-                    let row = rows[index];
-                    index += 1;
-
-                    let point = Point::new(row, 0);
-                    let boundary = map.next_line_boundary(point).1;
-                    let clipped = map.clip_point(boundary, Bias::Left);
-
-                    (clipped, SelectionGoal::None)
-                });
-            });
-
-            let mut indent_edits = Vec::new();
-            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
-            for row in rows {
-                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
-                for (row, indent) in indents {
-                    if indent.len == 0 {
-                        continue;
-                    }
-
-                    let text = match indent.kind {
-                        IndentKind::Space => " ".repeat(indent.len as usize),
-                        IndentKind::Tab => "\t".repeat(indent.len as usize),
-                    };
-                    let point = Point::new(row, 0);
-                    indent_edits.push((point..point, text));
-                }
-            }
-            editor.edit(indent_edits, cx);
-        });
-    }
-
-    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
-        self.insert_with_autoindent_mode(
-            text,
-            Some(AutoindentMode::Block {
-                original_indent_columns: Vec::new(),
-            }),
-            cx,
-        );
-    }
-
-    fn insert_with_autoindent_mode(
-        &mut self,
-        text: &str,
-        autoindent_mode: Option<AutoindentMode>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if self.read_only {
-            return;
-        }
-
-        let text: Arc<str> = text.into();
-        self.transact(cx, |this, cx| {
-            let old_selections = this.selections.all_adjusted(cx);
-            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
-                let anchors = {
-                    let snapshot = buffer.read(cx);
-                    old_selections
-                        .iter()
-                        .map(|s| {
-                            let anchor = snapshot.anchor_after(s.head());
-                            s.map(|_| anchor)
-                        })
-                        .collect::<Vec<_>>()
-                };
-                buffer.edit(
-                    old_selections
-                        .iter()
-                        .map(|s| (s.start..s.end, text.clone())),
-                    autoindent_mode,
-                    cx,
-                );
-                anchors
-            });
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select_anchors(selection_anchors);
-            })
-        });
-    }
-
-    fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
-        if !settings::get::<EditorSettings>(cx).show_completions_on_input {
-            return;
-        }
-
-        let selection = self.selections.newest_anchor();
-        if self
-            .buffer
-            .read(cx)
-            .is_completion_trigger(selection.head(), text, cx)
-        {
-            self.show_completions(&ShowCompletions, cx);
-        } else {
-            self.hide_context_menu(cx);
-        }
-    }
-
-    /// If any empty selections is touching the start of its innermost containing autoclose
-    /// region, expand it to select the brackets.
-    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
-        let selections = self.selections.all::<usize>(cx);
-        let buffer = self.buffer.read(cx).read(cx);
-        let mut new_selections = Vec::new();
-        for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
-            if let (Some(region), true) = (region, selection.is_empty()) {
-                let mut range = region.range.to_offset(&buffer);
-                if selection.start == range.start {
-                    if range.start >= region.pair.start.len() {
-                        range.start -= region.pair.start.len();
-                        if buffer.contains_str_at(range.start, &region.pair.start) {
-                            if buffer.contains_str_at(range.end, &region.pair.end) {
-                                range.end += region.pair.end.len();
-                                selection.start = range.start;
-                                selection.end = range.end;
-                            }
-                        }
-                    }
-                }
-            }
-            new_selections.push(selection);
-        }
-
-        drop(buffer);
-        self.change_selections(None, cx, |selections| selections.select(new_selections));
-    }
-
-    /// Iterate the given selections, and for each one, find the smallest surrounding
-    /// autoclose region. This uses the ordering of the selections and the autoclose
-    /// regions to avoid repeated comparisons.
-    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
-        &'a self,
-        selections: impl IntoIterator<Item = Selection<D>>,
-        buffer: &'a MultiBufferSnapshot,
-    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
-        let mut i = 0;
-        let mut regions = self.autoclose_regions.as_slice();
-        selections.into_iter().map(move |selection| {
-            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
-
-            let mut enclosing = None;
-            while let Some(pair_state) = regions.get(i) {
-                if pair_state.range.end.to_offset(buffer) < range.start {
-                    regions = &regions[i + 1..];
-                    i = 0;
-                } else if pair_state.range.start.to_offset(buffer) > range.end {
-                    break;
-                } else {
-                    if pair_state.selection_id == selection.id {
-                        enclosing = Some(pair_state);
-                    }
-                    i += 1;
-                }
-            }
-
-            (selection.clone(), enclosing)
-        })
-    }
-
-    /// Remove any autoclose regions that no longer contain their selection.
-    fn invalidate_autoclose_regions(
-        &mut self,
-        mut selections: &[Selection<Anchor>],
-        buffer: &MultiBufferSnapshot,
-    ) {
-        self.autoclose_regions.retain(|state| {
-            let mut i = 0;
-            while let Some(selection) = selections.get(i) {
-                if selection.end.cmp(&state.range.start, buffer).is_lt() {
-                    selections = &selections[1..];
-                    continue;
-                }
-                if selection.start.cmp(&state.range.end, buffer).is_gt() {
-                    break;
-                }
-                if selection.id == state.selection_id {
-                    return true;
-                } else {
-                    i += 1;
-                }
-            }
-            false
-        });
-    }
-
-    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
-        let offset = position.to_offset(buffer);
-        let (word_range, kind) = buffer.surrounding_word(offset);
-        if offset > word_range.start && kind == Some(CharKind::Word) {
-            Some(
-                buffer
-                    .text_for_range(word_range.start..offset)
-                    .collect::<String>(),
-            )
-        } else {
-            None
-        }
-    }
-
-    pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
-        self.refresh_inlay_hints(
-            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
-            cx,
-        );
-    }
-
-    pub fn inlay_hints_enabled(&self) -> bool {
-        self.inlay_hint_cache.enabled
-    }
-
-    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
-        if self.project.is_none() || self.mode != EditorMode::Full {
-            return;
-        }
-
-        let reason_description = reason.description();
-        let (invalidate_cache, required_languages) = match reason {
-            InlayHintRefreshReason::Toggle(enabled) => {
-                self.inlay_hint_cache.enabled = enabled;
-                if enabled {
-                    (InvalidationStrategy::RefreshRequested, None)
-                } else {
-                    self.inlay_hint_cache.clear();
-                    self.splice_inlay_hints(
-                        self.visible_inlay_hints(cx)
-                            .iter()
-                            .map(|inlay| inlay.id)
-                            .collect(),
-                        Vec::new(),
-                        cx,
-                    );
-                    return;
-                }
-            }
-            InlayHintRefreshReason::SettingsChange(new_settings) => {
-                match self.inlay_hint_cache.update_settings(
-                    &self.buffer,
-                    new_settings,
-                    self.visible_inlay_hints(cx),
-                    cx,
-                ) {
-                    ControlFlow::Break(Some(InlaySplice {
-                        to_remove,
-                        to_insert,
-                    })) => {
-                        self.splice_inlay_hints(to_remove, to_insert, cx);
-                        return;
-                    }
-                    ControlFlow::Break(None) => return,
-                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
-                }
-            }
-            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
-                if let Some(InlaySplice {
-                    to_remove,
-                    to_insert,
-                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
-                {
-                    self.splice_inlay_hints(to_remove, to_insert, cx);
-                }
-                return;
-            }
-            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
-            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
-                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
-            }
-            InlayHintRefreshReason::RefreshRequested => {
-                (InvalidationStrategy::RefreshRequested, None)
-            }
-        };
-
-        if let Some(InlaySplice {
-            to_remove,
-            to_insert,
-        }) = self.inlay_hint_cache.spawn_hint_refresh(
-            reason_description,
-            self.excerpt_visible_offsets(required_languages.as_ref(), cx),
-            invalidate_cache,
-            cx,
-        ) {
-            self.splice_inlay_hints(to_remove, to_insert, cx);
-        }
-    }
-
-    fn visible_inlay_hints(&self, cx: &ViewContext<'_, '_, Editor>) -> Vec<Inlay> {
-        self.display_map
-            .read(cx)
-            .current_inlays()
-            .filter(move |inlay| {
-                Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id)
-            })
-            .cloned()
-            .collect()
-    }
-
-    pub fn excerpt_visible_offsets(
-        &self,
-        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
-        cx: &mut ViewContext<'_, '_, Editor>,
-    ) -> HashMap<ExcerptId, (ModelHandle<Buffer>, Global, Range<usize>)> {
-        let multi_buffer = self.buffer().read(cx);
-        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
-        let multi_buffer_visible_start = self
-            .scroll_manager
-            .anchor()
-            .anchor
-            .to_point(&multi_buffer_snapshot);
-        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
-            multi_buffer_visible_start
-                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
-            Bias::Left,
-        );
-        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
-        multi_buffer
-            .range_to_buffer_ranges(multi_buffer_visible_range, cx)
-            .into_iter()
-            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
-            .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
-                let buffer = buffer_handle.read(cx);
-                let language = buffer.language()?;
-                if let Some(restrict_to_languages) = restrict_to_languages {
-                    if !restrict_to_languages.contains(language) {
-                        return None;
-                    }
-                }
-                Some((
-                    excerpt_id,
-                    (
-                        buffer_handle,
-                        buffer.version().clone(),
-                        excerpt_visible_range,
-                    ),
-                ))
-            })
-            .collect()
-    }
-
-    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
-        TextLayoutDetails {
-            font_cache: cx.font_cache().clone(),
-            text_layout_cache: cx.text_layout_cache().clone(),
-            editor_style: self.style(cx),
-        }
-    }
-
-    fn splice_inlay_hints(
-        &self,
-        to_remove: Vec<InlayId>,
-        to_insert: Vec<Inlay>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.display_map.update(cx, |display_map, cx| {
-            display_map.splice_inlays(to_remove, to_insert, cx);
-        });
-        cx.notify();
-    }
-
-    fn trigger_on_type_formatting(
-        &self,
-        input: String,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<Task<Result<()>>> {
-        if input.len() != 1 {
-            return None;
-        }
-
-        let project = self.project.as_ref()?;
-        let position = self.selections.newest_anchor().head();
-        let (buffer, buffer_position) = self
-            .buffer
-            .read(cx)
-            .text_anchor_for_position(position.clone(), cx)?;
-
-        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
-        // hence we do LSP request & edit on host side only — add formats to host's history.
-        let push_to_lsp_host_history = true;
-        // If this is not the host, append its history with new edits.
-        let push_to_client_history = project.read(cx).is_remote();
-
-        let on_type_formatting = project.update(cx, |project, cx| {
-            project.on_type_format(
-                buffer.clone(),
-                buffer_position,
-                input,
-                push_to_lsp_host_history,
-                cx,
-            )
-        });
-        Some(cx.spawn(|editor, mut cx| async move {
-            if let Some(transaction) = on_type_formatting.await? {
-                if push_to_client_history {
-                    buffer.update(&mut cx, |buffer, _| {
-                        buffer.push_transaction(transaction, Instant::now());
-                    });
-                }
-                editor.update(&mut cx, |editor, cx| {
-                    editor.refresh_document_highlights(cx);
-                })?;
-            }
-            Ok(())
-        }))
-    }
-
-    fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
-        if self.pending_rename.is_some() {
-            return;
-        }
-
-        let project = if let Some(project) = self.project.clone() {
-            project
-        } else {
-            return;
-        };
-
-        let position = self.selections.newest_anchor().head();
-        let (buffer, buffer_position) = if let Some(output) = self
-            .buffer
-            .read(cx)
-            .text_anchor_for_position(position.clone(), cx)
-        {
-            output
-        } else {
-            return;
-        };
-
-        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
-        let completions = project.update(cx, |project, cx| {
-            project.completions(&buffer, buffer_position, cx)
-        });
-
-        let id = post_inc(&mut self.next_completion_id);
-        let task = cx.spawn(|this, mut cx| {
-            async move {
-                let menu = if let Some(completions) = completions.await.log_err() {
-                    let mut menu = CompletionsMenu {
-                        id,
-                        initial_position: position,
-                        match_candidates: completions
-                            .iter()
-                            .enumerate()
-                            .map(|(id, completion)| {
-                                StringMatchCandidate::new(
-                                    id,
-                                    completion.label.text[completion.label.filter_range.clone()]
-                                        .into(),
-                                )
-                            })
-                            .collect(),
-                        buffer,
-                        completions: Arc::new(RwLock::new(completions.into())),
-                        matches: Vec::new().into(),
-                        selected_item: 0,
-                        list: Default::default(),
-                    };
-                    menu.filter(query.as_deref(), cx.background()).await;
-                    if menu.matches.is_empty() {
-                        None
-                    } else {
-                        _ = this.update(&mut cx, |editor, cx| {
-                            menu.pre_resolve_completion_documentation(editor.project.clone(), cx);
-                        });
-                        Some(menu)
-                    }
-                } else {
-                    None
-                };
-
-                this.update(&mut cx, |this, cx| {
-                    this.completion_tasks.retain(|(task_id, _)| *task_id > id);
-
-                    let mut context_menu = this.context_menu.write();
-                    match context_menu.as_ref() {
-                        None => {}
-
-                        Some(ContextMenu::Completions(prev_menu)) => {
-                            if prev_menu.id > id {
-                                return;
-                            }
-                        }
-
-                        _ => return,
-                    }
-
-                    if this.focused && menu.is_some() {
-                        let menu = menu.unwrap();
-                        *context_menu = Some(ContextMenu::Completions(menu));
-                        drop(context_menu);
-                        this.discard_copilot_suggestion(cx);
-                        cx.notify();
-                    } else if this.completion_tasks.is_empty() {
-                        // If there are no more completion tasks and the last menu was
-                        // empty, we should hide it. If it was already hidden, we should
-                        // also show the copilot suggestion when available.
-                        drop(context_menu);
-                        if this.hide_context_menu(cx).is_none() {
-                            this.update_visible_copilot_suggestion(cx);
-                        }
-                    }
-                })?;
-
-                Ok::<_, anyhow::Error>(())
-            }
-            .log_err()
-        });
-        self.completion_tasks.push((id, task));
-    }
-
-    pub fn confirm_completion(
-        &mut self,
-        action: &ConfirmCompletion,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<Task<Result<()>>> {
-        use language::ToOffset as _;
-
-        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
-            menu
-        } else {
-            return None;
-        };
-
-        let mat = completions_menu
-            .matches
-            .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
-        let buffer_handle = completions_menu.buffer;
-        let completions = completions_menu.completions.read();
-        let completion = completions.get(mat.candidate_id)?;
-
-        let snippet;
-        let text;
-        if completion.is_snippet() {
-            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
-            text = snippet.as_ref().unwrap().text.clone();
-        } else {
-            snippet = None;
-            text = completion.new_text.clone();
-        };
-        let selections = self.selections.all::<usize>(cx);
-        let buffer = buffer_handle.read(cx);
-        let old_range = completion.old_range.to_offset(buffer);
-        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
-
-        let newest_selection = self.selections.newest_anchor();
-        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
-            return None;
-        }
-
-        let lookbehind = newest_selection
-            .start
-            .text_anchor
-            .to_offset(buffer)
-            .saturating_sub(old_range.start);
-        let lookahead = old_range
-            .end
-            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
-        let mut common_prefix_len = old_text
-            .bytes()
-            .zip(text.bytes())
-            .take_while(|(a, b)| a == b)
-            .count();
-
-        let snapshot = self.buffer.read(cx).snapshot(cx);
-        let mut range_to_replace: Option<Range<isize>> = None;
-        let mut ranges = Vec::new();
-        for selection in &selections {
-            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
-                let start = selection.start.saturating_sub(lookbehind);
-                let end = selection.end + lookahead;
-                if selection.id == newest_selection.id {
-                    range_to_replace = Some(
-                        ((start + common_prefix_len) as isize - selection.start as isize)
-                            ..(end as isize - selection.start as isize),
-                    );
-                }
-                ranges.push(start + common_prefix_len..end);
-            } else {
-                common_prefix_len = 0;
-                ranges.clear();
-                ranges.extend(selections.iter().map(|s| {
-                    if s.id == newest_selection.id {
-                        range_to_replace = Some(
-                            old_range.start.to_offset_utf16(&snapshot).0 as isize
-                                - selection.start as isize
-                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
-                                    - selection.start as isize,
-                        );
-                        old_range.clone()
-                    } else {
-                        s.start..s.end
-                    }
-                }));
-                break;
-            }
-        }
-        let text = &text[common_prefix_len..];
-
-        cx.emit(Event::InputHandled {
-            utf16_range_to_replace: range_to_replace,
-            text: text.into(),
-        });
-
-        self.transact(cx, |this, cx| {
-            if let Some(mut snippet) = snippet {
-                snippet.text = text.to_string();
-                for tabstop in snippet.tabstops.iter_mut().flatten() {
-                    tabstop.start -= common_prefix_len as isize;
-                    tabstop.end -= common_prefix_len as isize;
-                }
-
-                this.insert_snippet(&ranges, snippet, cx).log_err();
-            } else {
-                this.buffer.update(cx, |buffer, cx| {
-                    buffer.edit(
-                        ranges.iter().map(|range| (range.clone(), text)),
-                        this.autoindent_mode.clone(),
-                        cx,
-                    );
-                });
-            }
-
-            this.refresh_copilot_suggestions(true, cx);
-        });
-
-        let project = self.project.clone()?;
-        let apply_edits = project.update(cx, |project, cx| {
-            project.apply_additional_edits_for_completion(
-                buffer_handle,
-                completion.clone(),
-                true,
-                cx,
-            )
-        });
-        Some(cx.foreground().spawn(async move {
-            apply_edits.await?;
-            Ok(())
-        }))
-    }
-
-    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
-        let mut context_menu = self.context_menu.write();
-        if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
-            *context_menu = None;
-            cx.notify();
-            return;
-        }
-        drop(context_menu);
-
-        let deployed_from_indicator = action.deployed_from_indicator;
-        let mut task = self.code_actions_task.take();
-        cx.spawn(|this, mut cx| async move {
-            while let Some(prev_task) = task {
-                prev_task.await;
-                task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
-            }
-
-            this.update(&mut cx, |this, cx| {
-                if this.focused {
-                    if let Some((buffer, actions)) = this.available_code_actions.clone() {
-                        this.completion_tasks.clear();
-                        this.discard_copilot_suggestion(cx);
-                        *this.context_menu.write() =
-                            Some(ContextMenu::CodeActions(CodeActionsMenu {
-                                buffer,
-                                actions,
-                                selected_item: Default::default(),
-                                list: Default::default(),
-                                deployed_from_indicator,
-                            }));
-                    }
-                }
-            })?;
-
-            Ok::<_, anyhow::Error>(())
-        })
-        .detach_and_log_err(cx);
-    }
-
-    pub fn confirm_code_action(
-        workspace: &mut Workspace,
-        action: &ConfirmCodeAction,
-        cx: &mut ViewContext<Workspace>,
-    ) -> Option<Task<Result<()>>> {
-        let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
-        let actions_menu = if let ContextMenu::CodeActions(menu) =
-            editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
-        {
-            menu
-        } else {
-            return None;
-        };
-        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
-        let action = actions_menu.actions.get(action_ix)?.clone();
-        let title = action.lsp_action.title.clone();
-        let buffer = actions_menu.buffer;
-
-        let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
-            project.apply_code_action(buffer, action, true, cx)
-        });
-        let editor = editor.downgrade();
-        Some(cx.spawn(|workspace, cx| async move {
-            let project_transaction = apply_code_actions.await?;
-            Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
-        }))
-    }
-
-    async fn open_project_transaction(
-        this: &WeakViewHandle<Editor>,
-        workspace: WeakViewHandle<Workspace>,
-        transaction: ProjectTransaction,
-        title: String,
-        mut cx: AsyncAppContext,
-    ) -> Result<()> {
-        let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx))?;
-
-        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
-        entries.sort_unstable_by_key(|(buffer, _)| {
-            buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
-        });
-
-        // If the project transaction's edits are all contained within this editor, then
-        // avoid opening a new editor to display them.
-
-        if let Some((buffer, transaction)) = entries.first() {
-            if entries.len() == 1 {
-                let excerpt = this.read_with(&cx, |editor, cx| {
-                    editor
-                        .buffer()
-                        .read(cx)
-                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
-                })?;
-                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
-                    if excerpted_buffer == *buffer {
-                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
-                            let excerpt_range = excerpt_range.to_offset(buffer);
-                            buffer
-                                .edited_ranges_for_transaction::<usize>(transaction)
-                                .all(|range| {
-                                    excerpt_range.start <= range.start
-                                        && excerpt_range.end >= range.end
-                                })
-                        });
-
-                        if all_edits_within_excerpt {
-                            return Ok(());
-                        }
-                    }
-                }
-            }
-        } else {
-            return Ok(());
-        }
-
-        let mut ranges_to_highlight = Vec::new();
-        let excerpt_buffer = cx.add_model(|cx| {
-            let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
-            for (buffer_handle, transaction) in &entries {
-                let buffer = buffer_handle.read(cx);
-                ranges_to_highlight.extend(
-                    multibuffer.push_excerpts_with_context_lines(
-                        buffer_handle.clone(),
-                        buffer
-                            .edited_ranges_for_transaction::<usize>(transaction)
-                            .collect(),
-                        1,
-                        cx,
-                    ),
-                );
-            }
-            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
-            multibuffer
-        });
-
-        workspace.update(&mut cx, |workspace, cx| {
-            let project = workspace.project().clone();
-            let editor =
-                cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
-            workspace.add_item(Box::new(editor.clone()), cx);
-            editor.update(cx, |editor, cx| {
-                editor.highlight_background::<Self>(
-                    ranges_to_highlight,
-                    |theme| theme.editor.highlighted_line_background,
-                    cx,
-                );
-            });
-        })?;
-
-        Ok(())
-    }
-
-    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
-        let project = self.project.clone()?;
-        let buffer = self.buffer.read(cx);
-        let newest_selection = self.selections.newest_anchor().clone();
-        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
-        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
-        if start_buffer != end_buffer {
-            return None;
-        }
-
-        self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
-            cx.background().timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT).await;
-
-            let actions = project
-                .update(&mut cx, |project, cx| {
-                    project.code_actions(&start_buffer, start..end, cx)
-                })
-                .await;
-
-            this.update(&mut cx, |this, cx| {
-                this.available_code_actions = actions.log_err().and_then(|actions| {
-                    if actions.is_empty() {
-                        None
-                    } else {
-                        Some((start_buffer, actions.into()))
-                    }
-                });
-                cx.notify();
-            })
-            .log_err();
-        }));
-        None
-    }
-
-    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
-        if self.pending_rename.is_some() {
-            return None;
-        }
-
-        let project = self.project.clone()?;
-        let buffer = self.buffer.read(cx);
-        let newest_selection = self.selections.newest_anchor().clone();
-        let cursor_position = newest_selection.head();
-        let (cursor_buffer, cursor_buffer_position) =
-            buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
-        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
-        if cursor_buffer != tail_buffer {
-            return None;
-        }
-
-        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
-            cx.background()
-                .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
-                .await;
-
-            let highlights = project
-                .update(&mut cx, |project, cx| {
-                    project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
-                })
-                .await
-                .log_err();
-
-            if let Some(highlights) = highlights {
-                this.update(&mut cx, |this, cx| {
-                    if this.pending_rename.is_some() {
-                        return;
-                    }
-
-                    let buffer_id = cursor_position.buffer_id;
-                    let buffer = this.buffer.read(cx);
-                    if !buffer
-                        .text_anchor_for_position(cursor_position, cx)
-                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
-                    {
-                        return;
-                    }
-
-                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
-                    let mut write_ranges = Vec::new();
-                    let mut read_ranges = Vec::new();
-                    for highlight in highlights {
-                        for (excerpt_id, excerpt_range) in
-                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
-                        {
-                            let start = highlight
-                                .range
-                                .start
-                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
-                            let end = highlight
-                                .range
-                                .end
-                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
-                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
-                                continue;
-                            }
-
-                            let range = Anchor {
-                                buffer_id,
-                                excerpt_id: excerpt_id.clone(),
-                                text_anchor: start,
-                            }..Anchor {
-                                buffer_id,
-                                excerpt_id,
-                                text_anchor: end,
-                            };
-                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
-                                write_ranges.push(range);
-                            } else {
-                                read_ranges.push(range);
-                            }
-                        }
-                    }
-
-                    this.highlight_background::<DocumentHighlightRead>(
-                        read_ranges,
-                        |theme| theme.editor.document_highlight_read_background,
-                        cx,
-                    );
-                    this.highlight_background::<DocumentHighlightWrite>(
-                        write_ranges,
-                        |theme| theme.editor.document_highlight_write_background,
-                        cx,
-                    );
-                    cx.notify();
-                })
-                .log_err();
-            }
-        }));
-        None
-    }
-
-    fn refresh_copilot_suggestions(
-        &mut self,
-        debounce: bool,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<()> {
-        let copilot = Copilot::global(cx)?;
-        if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
-            self.clear_copilot_suggestions(cx);
-            return None;
-        }
-        self.update_visible_copilot_suggestion(cx);
-
-        let snapshot = self.buffer.read(cx).snapshot(cx);
-        let cursor = self.selections.newest_anchor().head();
-        if !self.is_copilot_enabled_at(cursor, &snapshot, cx) {
-            self.clear_copilot_suggestions(cx);
-            return None;
-        }
-
-        let (buffer, buffer_position) =
-            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
-        self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move {
-            if debounce {
-                cx.background().timer(COPILOT_DEBOUNCE_TIMEOUT).await;
-            }
-
-            let completions = copilot
-                .update(&mut cx, |copilot, cx| {
-                    copilot.completions(&buffer, buffer_position, cx)
-                })
-                .await
-                .log_err()
-                .into_iter()
-                .flatten()
-                .collect_vec();
-
-            this.update(&mut cx, |this, cx| {
-                if !completions.is_empty() {
-                    this.copilot_state.cycled = false;
-                    this.copilot_state.pending_cycling_refresh = Task::ready(None);
-                    this.copilot_state.completions.clear();
-                    this.copilot_state.active_completion_index = 0;
-                    this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
-                    for completion in completions {
-                        this.copilot_state.push_completion(completion);
-                    }
-                    this.update_visible_copilot_suggestion(cx);
-                }
-            })
-            .log_err()?;
-            Some(())
-        });
-
-        Some(())
-    }
-
-    fn cycle_copilot_suggestions(
-        &mut self,
-        direction: Direction,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<()> {
-        let copilot = Copilot::global(cx)?;
-        if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
-            return None;
-        }
-
-        if self.copilot_state.cycled {
-            self.copilot_state.cycle_completions(direction);
-            self.update_visible_copilot_suggestion(cx);
-        } else {
-            let cursor = self.selections.newest_anchor().head();
-            let (buffer, buffer_position) =
-                self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
-            self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move {
-                let completions = copilot
-                    .update(&mut cx, |copilot, cx| {
-                        copilot.completions_cycling(&buffer, buffer_position, cx)
-                    })
-                    .await;
-
-                this.update(&mut cx, |this, cx| {
-                    this.copilot_state.cycled = true;
-                    for completion in completions.log_err().into_iter().flatten() {
-                        this.copilot_state.push_completion(completion);
-                    }
-                    this.copilot_state.cycle_completions(direction);
-                    this.update_visible_copilot_suggestion(cx);
-                })
-                .log_err()?;
-
-                Some(())
-            });
-        }
-
-        Some(())
-    }
-
-    fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext<Self>) {
-        if !self.has_active_copilot_suggestion(cx) {
-            self.refresh_copilot_suggestions(false, cx);
-            return;
-        }
-
-        self.update_visible_copilot_suggestion(cx);
-    }
-
-    fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
-        if self.has_active_copilot_suggestion(cx) {
-            self.cycle_copilot_suggestions(Direction::Next, cx);
-        } else {
-            let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
-            if is_copilot_disabled {
-                cx.propagate_action();
-            }
-        }
-    }
-
-    fn previous_copilot_suggestion(
-        &mut self,
-        _: &copilot::PreviousSuggestion,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if self.has_active_copilot_suggestion(cx) {
-            self.cycle_copilot_suggestions(Direction::Prev, cx);
-        } else {
-            let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
-            if is_copilot_disabled {
-                cx.propagate_action();
-            }
-        }
-    }
-
-    fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
-        if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
-            if let Some((copilot, completion)) =
-                Copilot::global(cx).zip(self.copilot_state.active_completion())
-            {
-                copilot
-                    .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
-                    .detach_and_log_err(cx);
-
-                self.report_copilot_event(Some(completion.uuid.clone()), true, cx)
-            }
-            cx.emit(Event::InputHandled {
-                utf16_range_to_replace: None,
-                text: suggestion.text.to_string().into(),
-            });
-            self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
-            cx.notify();
-            true
-        } else {
-            false
-        }
-    }
-
-    fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
-        if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
-            if let Some(copilot) = Copilot::global(cx) {
-                copilot
-                    .update(cx, |copilot, cx| {
-                        copilot.discard_completions(&self.copilot_state.completions, cx)
-                    })
-                    .detach_and_log_err(cx);
-
-                self.report_copilot_event(None, false, cx)
-            }
-
-            self.display_map.update(cx, |map, cx| {
-                map.splice_inlays(vec![suggestion.id], Vec::new(), cx)
-            });
-            cx.notify();
-            true
-        } else {
-            false
-        }
-    }
-
-    fn is_copilot_enabled_at(
-        &self,
-        location: Anchor,
-        snapshot: &MultiBufferSnapshot,
-        cx: &mut ViewContext<Self>,
-    ) -> bool {
-        let file = snapshot.file_at(location);
-        let language = snapshot.language_at(location);
-        let settings = all_language_settings(file, cx);
-        settings.copilot_enabled(language, file.map(|f| f.path().as_ref()))
-    }
-
-    fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
-        if let Some(suggestion) = self.copilot_state.suggestion.as_ref() {
-            let buffer = self.buffer.read(cx).read(cx);
-            suggestion.position.is_valid(&buffer)
-        } else {
-            false
-        }
-    }
-
-    fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> Option<Inlay> {
-        let suggestion = self.copilot_state.suggestion.take()?;
-        self.display_map.update(cx, |map, cx| {
-            map.splice_inlays(vec![suggestion.id], Default::default(), cx);
-        });
-        let buffer = self.buffer.read(cx).read(cx);
-
-        if suggestion.position.is_valid(&buffer) {
-            Some(suggestion)
-        } else {
-            None
-        }
-    }
-
-    fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
-        let snapshot = self.buffer.read(cx).snapshot(cx);
-        let selection = self.selections.newest_anchor();
-        let cursor = selection.head();
-
-        if self.context_menu.read().is_some()
-            || !self.completion_tasks.is_empty()
-            || selection.start != selection.end
-        {
-            self.discard_copilot_suggestion(cx);
-        } else if let Some(text) = self
-            .copilot_state
-            .text_for_active_completion(cursor, &snapshot)
-        {
-            let text = Rope::from(text);
-            let mut to_remove = Vec::new();
-            if let Some(suggestion) = self.copilot_state.suggestion.take() {
-                to_remove.push(suggestion.id);
-            }
-
-            let suggestion_inlay =
-                Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
-            self.copilot_state.suggestion = Some(suggestion_inlay.clone());
-            self.display_map.update(cx, move |map, cx| {
-                map.splice_inlays(to_remove, vec![suggestion_inlay], cx)
-            });
-            cx.notify();
-        } else {
-            self.discard_copilot_suggestion(cx);
-        }
-    }
-
-    fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) {
-        self.copilot_state = Default::default();
-        self.discard_copilot_suggestion(cx);
-    }
-
-    pub fn render_code_actions_indicator(
-        &self,
-        style: &EditorStyle,
-        is_active: bool,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<AnyElement<Self>> {
-        if self.available_code_actions.is_some() {
-            enum CodeActions {}
-            Some(
-                MouseEventHandler::new::<CodeActions, _>(0, cx, |state, _| {
-                    Svg::new("icons/bolt.svg").with_color(
-                        style
-                            .code_actions
-                            .indicator
-                            .in_state(is_active)
-                            .style_for(state)
-                            .color,
-                    )
-                })
-                .with_cursor_style(CursorStyle::PointingHand)
-                .with_padding(Padding::uniform(3.))
-                .on_down(MouseButton::Left, |_, this, cx| {
-                    this.toggle_code_actions(
-                        &ToggleCodeActions {
-                            deployed_from_indicator: true,
-                        },
-                        cx,
-                    );
-                })
-                .into_any(),
-            )
-        } else {
-            None
-        }
-    }
-
-    pub fn render_fold_indicators(
-        &self,
-        fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
-        style: &EditorStyle,
-        gutter_hovered: bool,
-        line_height: f32,
-        gutter_margin: f32,
-        cx: &mut ViewContext<Self>,
-    ) -> Vec<Option<AnyElement<Self>>> {
-        enum FoldIndicators {}
-
-        let style = style.folds.clone();
-
-        fold_data
-            .iter()
-            .enumerate()
-            .map(|(ix, fold_data)| {
-                fold_data
-                    .map(|(fold_status, buffer_row, active)| {
-                        (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
-                            MouseEventHandler::new::<FoldIndicators, _>(
-                                ix as usize,
-                                cx,
-                                |mouse_state, _| {
-                                    Svg::new(match fold_status {
-                                        FoldStatus::Folded => style.folded_icon.clone(),
-                                        FoldStatus::Foldable => style.foldable_icon.clone(),
-                                    })
-                                    .with_color(
-                                        style
-                                            .indicator
-                                            .in_state(fold_status == FoldStatus::Folded)
-                                            .style_for(mouse_state)
-                                            .color,
-                                    )
-                                    .constrained()
-                                    .with_width(gutter_margin * style.icon_margin_scale)
-                                    .aligned()
-                                    .constrained()
-                                    .with_height(line_height)
-                                    .with_width(gutter_margin)
-                                    .aligned()
-                                },
-                            )
-                            .with_cursor_style(CursorStyle::PointingHand)
-                            .with_padding(Padding::uniform(3.))
-                            .on_click(MouseButton::Left, {
-                                move |_, editor, cx| match fold_status {
-                                    FoldStatus::Folded => {
-                                        editor.unfold_at(&UnfoldAt { buffer_row }, cx);
-                                    }
-                                    FoldStatus::Foldable => {
-                                        editor.fold_at(&FoldAt { buffer_row }, cx);
-                                    }
-                                }
-                            })
-                            .into_any()
-                        })
-                    })
-                    .flatten()
-            })
-            .collect()
-    }
-
-    pub fn context_menu_visible(&self) -> bool {
-        self.context_menu
-            .read()
-            .as_ref()
-            .map_or(false, |menu| menu.visible())
-    }
-
-    pub fn render_context_menu(
-        &self,
-        cursor_position: DisplayPoint,
-        style: EditorStyle,
-        cx: &mut ViewContext<Editor>,
-    ) -> Option<(DisplayPoint, AnyElement<Editor>)> {
-        self.context_menu.read().as_ref().map(|menu| {
-            menu.render(
-                cursor_position,
-                style,
-                self.workspace.as_ref().map(|(w, _)| w.clone()),
-                cx,
-            )
-        })
-    }
-
-    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
-        cx.notify();
-        self.completion_tasks.clear();
-        let context_menu = self.context_menu.write().take();
-        if context_menu.is_some() {
-            self.update_visible_copilot_suggestion(cx);
-        }
-        context_menu
-    }
-
-    pub fn insert_snippet(
-        &mut self,
-        insertion_ranges: &[Range<usize>],
-        snippet: Snippet,
-        cx: &mut ViewContext<Self>,
-    ) -> Result<()> {
-        let tabstops = self.buffer.update(cx, |buffer, cx| {
-            let snippet_text: Arc<str> = snippet.text.clone().into();
-            buffer.edit(
-                insertion_ranges
-                    .iter()
-                    .cloned()
-                    .map(|range| (range, snippet_text.clone())),
-                Some(AutoindentMode::EachLine),
-                cx,
-            );
-
-            let snapshot = &*buffer.read(cx);
-            let snippet = &snippet;
-            snippet
-                .tabstops
-                .iter()
-                .map(|tabstop| {
-                    let mut tabstop_ranges = tabstop
-                        .iter()
-                        .flat_map(|tabstop_range| {
-                            let mut delta = 0_isize;
-                            insertion_ranges.iter().map(move |insertion_range| {
-                                let insertion_start = insertion_range.start as isize + delta;
-                                delta +=
-                                    snippet.text.len() as isize - insertion_range.len() as isize;
-
-                                let start = snapshot.anchor_before(
-                                    (insertion_start + tabstop_range.start) as usize,
-                                );
-                                let end = snapshot
-                                    .anchor_after((insertion_start + tabstop_range.end) as usize);
-                                start..end
-                            })
-                        })
-                        .collect::<Vec<_>>();
-                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
-                    tabstop_ranges
-                })
-                .collect::<Vec<_>>()
-        });
-
-        if let Some(tabstop) = tabstops.first() {
-            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select_ranges(tabstop.iter().cloned());
-            });
-            self.snippet_stack.push(SnippetState {
-                active_index: 0,
-                ranges: tabstops,
-            });
-        }
-
-        Ok(())
-    }
-
-    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
-        self.move_to_snippet_tabstop(Bias::Right, cx)
-    }
-
-    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
-        self.move_to_snippet_tabstop(Bias::Left, cx)
-    }
-
-    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
-        if let Some(mut snippet) = self.snippet_stack.pop() {
-            match bias {
-                Bias::Left => {
-                    if snippet.active_index > 0 {
-                        snippet.active_index -= 1;
-                    } else {
-                        self.snippet_stack.push(snippet);
-                        return false;
-                    }
-                }
-                Bias::Right => {
-                    if snippet.active_index + 1 < snippet.ranges.len() {
-                        snippet.active_index += 1;
-                    } else {
-                        self.snippet_stack.push(snippet);
-                        return false;
-                    }
-                }
-            }
-            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
-                self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                    s.select_anchor_ranges(current_ranges.iter().cloned())
-                });
-                // If snippet state is not at the last tabstop, push it back on the stack
-                if snippet.active_index + 1 < snippet.ranges.len() {
-                    self.snippet_stack.push(snippet);
-                }
-                return true;
-            }
-        }
-
-        false
-    }
-
-    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.select_all(&SelectAll, cx);
-            this.insert("", cx);
-        });
-    }
-
-    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.select_autoclose_pair(cx);
-            let mut selections = this.selections.all::<Point>(cx);
-            if !this.selections.line_mode {
-                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
-                for selection in &mut selections {
-                    if selection.is_empty() {
-                        let old_head = selection.head();
-                        let mut new_head =
-                            movement::left(&display_map, old_head.to_display_point(&display_map))
-                                .to_point(&display_map);
-                        if let Some((buffer, line_buffer_range)) = display_map
-                            .buffer_snapshot
-                            .buffer_line_for_row(old_head.row)
-                        {
-                            let indent_size =
-                                buffer.indent_size_for_line(line_buffer_range.start.row);
-                            let indent_len = match indent_size.kind {
-                                IndentKind::Space => {
-                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
-                                }
-                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
-                            };
-                            if old_head.column <= indent_size.len && old_head.column > 0 {
-                                let indent_len = indent_len.get();
-                                new_head = cmp::min(
-                                    new_head,
-                                    Point::new(
-                                        old_head.row,
-                                        ((old_head.column - 1) / indent_len) * indent_len,
-                                    ),
-                                );
-                            }
-                        }
-
-                        selection.set_head(new_head, SelectionGoal::None);
-                    }
-                }
-            }
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
-            this.insert("", cx);
-            this.refresh_copilot_suggestions(true, cx);
-        });
-    }
-
-    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let line_mode = s.line_mode;
-                s.move_with(|map, selection| {
-                    if selection.is_empty() && !line_mode {
-                        let cursor = movement::right(map, selection.head());
-                        selection.end = cursor;
-                        selection.reversed = true;
-                        selection.goal = SelectionGoal::None;
-                    }
-                })
-            });
-            this.insert("", cx);
-            this.refresh_copilot_suggestions(true, cx);
-        });
-    }
-
-    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
-        if self.move_to_prev_snippet_tabstop(cx) {
-            return;
-        }
-
-        self.outdent(&Outdent, cx);
-    }
-
-    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
-        if self.move_to_next_snippet_tabstop(cx) {
-            return;
-        }
-
-        let mut selections = self.selections.all_adjusted(cx);
-        let buffer = self.buffer.read(cx);
-        let snapshot = buffer.snapshot(cx);
-        let rows_iter = selections.iter().map(|s| s.head().row);
-        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
-
-        let mut edits = Vec::new();
-        let mut prev_edited_row = 0;
-        let mut row_delta = 0;
-        for selection in &mut selections {
-            if selection.start.row != prev_edited_row {
-                row_delta = 0;
-            }
-            prev_edited_row = selection.end.row;
-
-            // If the selection is non-empty, then increase the indentation of the selected lines.
-            if !selection.is_empty() {
-                row_delta =
-                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
-                continue;
-            }
-
-            // If the selection is empty and the cursor is in the leading whitespace before the
-            // suggested indentation, then auto-indent the line.
-            let cursor = selection.head();
-            let current_indent = snapshot.indent_size_for_line(cursor.row);
-            if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
-                if cursor.column < suggested_indent.len
-                    && cursor.column <= current_indent.len
-                    && current_indent.len <= suggested_indent.len
-                {
-                    selection.start = Point::new(cursor.row, suggested_indent.len);
-                    selection.end = selection.start;
-                    if row_delta == 0 {
-                        edits.extend(Buffer::edit_for_indent_size_adjustment(
-                            cursor.row,
-                            current_indent,
-                            suggested_indent,
-                        ));
-                        row_delta = suggested_indent.len - current_indent.len;
-                    }
-                    continue;
-                }
-            }
-
-            // Accept copilot suggestion if there is only one selection and the cursor is not
-            // in the leading whitespace.
-            if self.selections.count() == 1
-                && cursor.column >= current_indent.len
-                && self.has_active_copilot_suggestion(cx)
-            {
-                self.accept_copilot_suggestion(cx);
-                return;
-            }
-
-            // Otherwise, insert a hard or soft tab.
-            let settings = buffer.settings_at(cursor, cx);
-            let tab_size = if settings.hard_tabs {
-                IndentSize::tab()
-            } else {
-                let tab_size = settings.tab_size.get();
-                let char_column = snapshot
-                    .text_for_range(Point::new(cursor.row, 0)..cursor)
-                    .flat_map(str::chars)
-                    .count()
-                    + row_delta as usize;
-                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
-                IndentSize::spaces(chars_to_next_tab_stop)
-            };
-            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
-            selection.end = selection.start;
-            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
-            row_delta += tab_size.len;
-        }
-
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
-            this.refresh_copilot_suggestions(true, cx);
-        });
-    }
-
-    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
-        let mut selections = self.selections.all::<Point>(cx);
-        let mut prev_edited_row = 0;
-        let mut row_delta = 0;
-        let mut edits = Vec::new();
-        let buffer = self.buffer.read(cx);
-        let snapshot = buffer.snapshot(cx);
-        for selection in &mut selections {
-            if selection.start.row != prev_edited_row {
-                row_delta = 0;
-            }
-            prev_edited_row = selection.end.row;
-
-            row_delta =
-                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
-        }
-
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
-        });
-    }
-
-    fn indent_selection(
-        buffer: &MultiBuffer,
-        snapshot: &MultiBufferSnapshot,
-        selection: &mut Selection<Point>,
-        edits: &mut Vec<(Range<Point>, String)>,
-        delta_for_start_row: u32,
-        cx: &AppContext,
-    ) -> u32 {
-        let settings = buffer.settings_at(selection.start, cx);
-        let tab_size = settings.tab_size.get();
-        let indent_kind = if settings.hard_tabs {
-            IndentKind::Tab
-        } else {
-            IndentKind::Space
-        };
-        let mut start_row = selection.start.row;
-        let mut end_row = selection.end.row + 1;
-
-        // If a selection ends at the beginning of a line, don't indent
-        // that last line.
-        if selection.end.column == 0 {
-            end_row -= 1;
-        }
-
-        // Avoid re-indenting a row that has already been indented by a
-        // previous selection, but still update this selection's column
-        // to reflect that indentation.
-        if delta_for_start_row > 0 {
-            start_row += 1;
-            selection.start.column += delta_for_start_row;
-            if selection.end.row == selection.start.row {
-                selection.end.column += delta_for_start_row;
-            }
-        }
-
-        let mut delta_for_end_row = 0;
-        for row in start_row..end_row {
-            let current_indent = snapshot.indent_size_for_line(row);
-            let indent_delta = match (current_indent.kind, indent_kind) {
-                (IndentKind::Space, IndentKind::Space) => {
-                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
-                    IndentSize::spaces(columns_to_next_tab_stop)
-                }
-                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
-                (_, IndentKind::Tab) => IndentSize::tab(),
-            };
-
-            let row_start = Point::new(row, 0);
-            edits.push((
-                row_start..row_start,
-                indent_delta.chars().collect::<String>(),
-            ));
-
-            // Update this selection's endpoints to reflect the indentation.
-            if row == selection.start.row {
-                selection.start.column += indent_delta.len;
-            }
-            if row == selection.end.row {
-                selection.end.column += indent_delta.len;
-                delta_for_end_row = indent_delta.len;
-            }
-        }
-
-        if selection.start.row == selection.end.row {
-            delta_for_start_row + delta_for_end_row
-        } else {
-            delta_for_end_row
-        }
-    }
-
-    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let selections = self.selections.all::<Point>(cx);
-        let mut deletion_ranges = Vec::new();
-        let mut last_outdent = None;
-        {
-            let buffer = self.buffer.read(cx);
-            let snapshot = buffer.snapshot(cx);
-            for selection in &selections {
-                let settings = buffer.settings_at(selection.start, cx);
-                let tab_size = settings.tab_size.get();
-                let mut rows = selection.spanned_rows(false, &display_map);
-
-                // Avoid re-outdenting a row that has already been outdented by a
-                // previous selection.
-                if let Some(last_row) = last_outdent {
-                    if last_row == rows.start {
-                        rows.start += 1;
-                    }
-                }
-
-                for row in rows {
-                    let indent_size = snapshot.indent_size_for_line(row);
-                    if indent_size.len > 0 {
-                        let deletion_len = match indent_size.kind {
-                            IndentKind::Space => {
-                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
-                                if columns_to_prev_tab_stop == 0 {
-                                    tab_size
-                                } else {
-                                    columns_to_prev_tab_stop
-                                }
-                            }
-                            IndentKind::Tab => 1,
-                        };
-                        deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
-                        last_outdent = Some(row);
-                    }
-                }
-            }
-        }
-
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |buffer, cx| {
-                let empty_str: Arc<str> = "".into();
-                buffer.edit(
-                    deletion_ranges
-                        .into_iter()
-                        .map(|range| (range, empty_str.clone())),
-                    None,
-                    cx,
-                );
-            });
-            let selections = this.selections.all::<usize>(cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
-        });
-    }
-
-    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let selections = self.selections.all::<Point>(cx);
-
-        let mut new_cursors = Vec::new();
-        let mut edit_ranges = Vec::new();
-        let mut selections = selections.iter().peekable();
-        while let Some(selection) = selections.next() {
-            let mut rows = selection.spanned_rows(false, &display_map);
-            let goal_display_column = selection.head().to_display_point(&display_map).column();
-
-            // Accumulate contiguous regions of rows that we want to delete.
-            while let Some(next_selection) = selections.peek() {
-                let next_rows = next_selection.spanned_rows(false, &display_map);
-                if next_rows.start <= rows.end {
-                    rows.end = next_rows.end;
-                    selections.next().unwrap();
-                } else {
-                    break;
-                }
-            }
-
-            let buffer = &display_map.buffer_snapshot;
-            let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
-            let edit_end;
-            let cursor_buffer_row;
-            if buffer.max_point().row >= rows.end {
-                // If there's a line after the range, delete the \n from the end of the row range
-                // and position the cursor on the next line.
-                edit_end = Point::new(rows.end, 0).to_offset(buffer);
-                cursor_buffer_row = rows.end;
-            } else {
-                // If there isn't a line after the range, delete the \n from the line before the
-                // start of the row range and position the cursor there.
-                edit_start = edit_start.saturating_sub(1);
-                edit_end = buffer.len();
-                cursor_buffer_row = rows.start.saturating_sub(1);
-            }
-
-            let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
-            *cursor.column_mut() =
-                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
-
-            new_cursors.push((
-                selection.id,
-                buffer.anchor_after(cursor.to_point(&display_map)),
-            ));
-            edit_ranges.push(edit_start..edit_end);
-        }
-
-        self.transact(cx, |this, cx| {
-            let buffer = this.buffer.update(cx, |buffer, cx| {
-                let empty_str: Arc<str> = "".into();
-                buffer.edit(
-                    edit_ranges
-                        .into_iter()
-                        .map(|range| (range, empty_str.clone())),
-                    None,
-                    cx,
-                );
-                buffer.snapshot(cx)
-            });
-            let new_selections = new_cursors
-                .into_iter()
-                .map(|(id, cursor)| {
-                    let cursor = cursor.to_point(&buffer);
-                    Selection {
-                        id,
-                        start: cursor,
-                        end: cursor,
-                        reversed: false,
-                        goal: SelectionGoal::None,
-                    }
-                })
-                .collect();
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(new_selections);
-            });
-        });
-    }
-
-    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
-        let mut row_ranges = Vec::<Range<u32>>::new();
-        for selection in self.selections.all::<Point>(cx) {
-            let start = selection.start.row;
-            let end = if selection.start.row == selection.end.row {
-                selection.start.row + 1
-            } else {
-                selection.end.row
-            };
-
-            if let Some(last_row_range) = row_ranges.last_mut() {
-                if start <= last_row_range.end {
-                    last_row_range.end = end;
-                    continue;
-                }
-            }
-            row_ranges.push(start..end);
-        }
-
-        let snapshot = self.buffer.read(cx).snapshot(cx);
-        let mut cursor_positions = Vec::new();
-        for row_range in &row_ranges {
-            let anchor = snapshot.anchor_before(Point::new(
-                row_range.end - 1,
-                snapshot.line_len(row_range.end - 1),
-            ));
-            cursor_positions.push(anchor.clone()..anchor);
-        }
-
-        self.transact(cx, |this, cx| {
-            for row_range in row_ranges.into_iter().rev() {
-                for row in row_range.rev() {
-                    let end_of_line = Point::new(row, snapshot.line_len(row));
-                    let indent = snapshot.indent_size_for_line(row + 1);
-                    let start_of_next_line = Point::new(row + 1, indent.len);
-
-                    let replace = if snapshot.line_len(row + 1) > indent.len {
-                        " "
-                    } else {
-                        ""
-                    };
-
-                    this.buffer.update(cx, |buffer, cx| {
-                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
-                    });
-                }
-            }
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select_anchor_ranges(cursor_positions)
-            });
-        });
-    }
-
-    pub fn sort_lines_case_sensitive(
-        &mut self,
-        _: &SortLinesCaseSensitive,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.manipulate_lines(cx, |lines| lines.sort())
-    }
-
-    pub fn sort_lines_case_insensitive(
-        &mut self,
-        _: &SortLinesCaseInsensitive,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
-    }
-
-    pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
-        self.manipulate_lines(cx, |lines| lines.reverse())
-    }
-
-    pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
-        self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
-    }
-
-    fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
-    where
-        Fn: FnMut(&mut [&str]),
-    {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx).snapshot(cx);
-
-        let mut edits = Vec::new();
-
-        let selections = self.selections.all::<Point>(cx);
-        let mut selections = selections.iter().peekable();
-        let mut contiguous_row_selections = Vec::new();
-        let mut new_selections = Vec::new();
-
-        while let Some(selection) = selections.next() {
-            let (start_row, end_row) = consume_contiguous_rows(
-                &mut contiguous_row_selections,
-                selection,
-                &display_map,
-                &mut selections,
-            );
-
-            let start_point = Point::new(start_row, 0);
-            let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1));
-            let text = buffer
-                .text_for_range(start_point..end_point)
-                .collect::<String>();
-            let mut lines = text.split("\n").collect_vec();
-
-            let lines_len = lines.len();
-            callback(&mut lines);
-
-            // This is a current limitation with selections.
-            // If we wanted to support removing or adding lines, we'd need to fix the logic associated with selections.
-            debug_assert!(
-                lines.len() == lines_len,
-                "callback should not change the number of lines"
-            );
-
-            edits.push((start_point..end_point, lines.join("\n")));
-            let start_anchor = buffer.anchor_after(start_point);
-            let end_anchor = buffer.anchor_before(end_point);
-
-            // Make selection and push
-            new_selections.push(Selection {
-                id: selection.id,
-                start: start_anchor.to_offset(&buffer),
-                end: end_anchor.to_offset(&buffer),
-                goal: SelectionGoal::None,
-                reversed: selection.reversed,
-            });
-        }
-
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |buffer, cx| {
-                buffer.edit(edits, None, cx);
-            });
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(new_selections);
-            });
-
-            this.request_autoscroll(Autoscroll::fit(), cx);
-        });
-    }
-
-    pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
-        self.manipulate_text(cx, |text| text.to_uppercase())
-    }
-
-    pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
-        self.manipulate_text(cx, |text| text.to_lowercase())
-    }
-
-    pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
-        self.manipulate_text(cx, |text| {
-            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
-            // https://github.com/rutrum/convert-case/issues/16
-            text.split("\n")
-                .map(|line| line.to_case(Case::Title))
-                .join("\n")
-        })
-    }
-
-    pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
-        self.manipulate_text(cx, |text| text.to_case(Case::Snake))
-    }
-
-    pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
-        self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
-    }
-
-    pub fn convert_to_upper_camel_case(
-        &mut self,
-        _: &ConvertToUpperCamelCase,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.manipulate_text(cx, |text| {
-            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
-            // https://github.com/rutrum/convert-case/issues/16
-            text.split("\n")
-                .map(|line| line.to_case(Case::UpperCamel))
-                .join("\n")
-        })
-    }
-
-    pub fn convert_to_lower_camel_case(
-        &mut self,
-        _: &ConvertToLowerCamelCase,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.manipulate_text(cx, |text| text.to_case(Case::Camel))
-    }
-
-    fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
-    where
-        Fn: FnMut(&str) -> String,
-    {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx).snapshot(cx);
-
-        let mut new_selections = Vec::new();
-        let mut edits = Vec::new();
-        let mut selection_adjustment = 0i32;
-
-        for selection in self.selections.all::<usize>(cx) {
-            let selection_is_empty = selection.is_empty();
-
-            let (start, end) = if selection_is_empty {
-                let word_range = movement::surrounding_word(
-                    &display_map,
-                    selection.start.to_display_point(&display_map),
-                );
-                let start = word_range.start.to_offset(&display_map, Bias::Left);
-                let end = word_range.end.to_offset(&display_map, Bias::Left);
-                (start, end)
-            } else {
-                (selection.start, selection.end)
-            };
-
-            let text = buffer.text_for_range(start..end).collect::<String>();
-            let old_length = text.len() as i32;
-            let text = callback(&text);
-
-            new_selections.push(Selection {
-                start: (start as i32 - selection_adjustment) as usize,
-                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
-                goal: SelectionGoal::None,
-                ..selection
-            });
-
-            selection_adjustment += old_length - text.len() as i32;
-
-            edits.push((start..end, text));
-        }
-
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |buffer, cx| {
-                buffer.edit(edits, None, cx);
-            });
-
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(new_selections);
-            });
-
-            this.request_autoscroll(Autoscroll::fit(), cx);
-        });
-    }
-
-    pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = &display_map.buffer_snapshot;
-        let selections = self.selections.all::<Point>(cx);
-
-        let mut edits = Vec::new();
-        let mut selections_iter = selections.iter().peekable();
-        while let Some(selection) = selections_iter.next() {
-            // Avoid duplicating the same lines twice.
-            let mut rows = selection.spanned_rows(false, &display_map);
-
-            while let Some(next_selection) = selections_iter.peek() {
-                let next_rows = next_selection.spanned_rows(false, &display_map);
-                if next_rows.start < rows.end {
-                    rows.end = next_rows.end;
-                    selections_iter.next().unwrap();
-                } else {
-                    break;
-                }
-            }
-
-            // Copy the text from the selected row region and splice it at the start of the region.
-            let start = Point::new(rows.start, 0);
-            let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
-            let text = buffer
-                .text_for_range(start..end)
-                .chain(Some("\n"))
-                .collect::<String>();
-            edits.push((start..start, text));
-        }
-
-        self.transact(cx, |this, cx| {
-            this.buffer.update(cx, |buffer, cx| {
-                buffer.edit(edits, None, cx);
-            });
-
-            this.request_autoscroll(Autoscroll::fit(), cx);
-        });
-    }
-
-    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx).snapshot(cx);
-
-        let mut edits = Vec::new();
-        let mut unfold_ranges = Vec::new();
-        let mut refold_ranges = Vec::new();
-
-        let selections = self.selections.all::<Point>(cx);
-        let mut selections = selections.iter().peekable();
-        let mut contiguous_row_selections = Vec::new();
-        let mut new_selections = Vec::new();
-
-        while let Some(selection) = selections.next() {
-            // Find all the selections that span a contiguous row range
-            let (start_row, end_row) = consume_contiguous_rows(
-                &mut contiguous_row_selections,
-                selection,
-                &display_map,
-                &mut selections,
-            );
-
-            // Move the text spanned by the row range to be before the line preceding the row range
-            if start_row > 0 {
-                let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
-                    ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
-                let insertion_point = display_map
-                    .prev_line_boundary(Point::new(start_row - 1, 0))
-                    .0;
-
-                // Don't move lines across excerpts
-                if buffer
-                    .excerpt_boundaries_in_range((
-                        Bound::Excluded(insertion_point),
-                        Bound::Included(range_to_move.end),
-                    ))
-                    .next()
-                    .is_none()
-                {
-                    let text = buffer
-                        .text_for_range(range_to_move.clone())
-                        .flat_map(|s| s.chars())
-                        .skip(1)
-                        .chain(['\n'])
-                        .collect::<String>();
-
-                    edits.push((
-                        buffer.anchor_after(range_to_move.start)
-                            ..buffer.anchor_before(range_to_move.end),
-                        String::new(),
-                    ));
-                    let insertion_anchor = buffer.anchor_after(insertion_point);
-                    edits.push((insertion_anchor..insertion_anchor, text));
-
-                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
-
-                    // Move selections up
-                    new_selections.extend(contiguous_row_selections.drain(..).map(
-                        |mut selection| {
-                            selection.start.row -= row_delta;
-                            selection.end.row -= row_delta;
-                            selection
-                        },
-                    ));
-
-                    // Move folds up
-                    unfold_ranges.push(range_to_move.clone());
-                    for fold in display_map.folds_in_range(
-                        buffer.anchor_before(range_to_move.start)
-                            ..buffer.anchor_after(range_to_move.end),
-                    ) {
-                        let mut start = fold.start.to_point(&buffer);
-                        let mut end = fold.end.to_point(&buffer);
-                        start.row -= row_delta;
-                        end.row -= row_delta;
-                        refold_ranges.push(start..end);
-                    }
-                }
-            }
-
-            // If we didn't move line(s), preserve the existing selections
-            new_selections.append(&mut contiguous_row_selections);
-        }
-
-        self.transact(cx, |this, cx| {
-            this.unfold_ranges(unfold_ranges, true, true, cx);
-            this.buffer.update(cx, |buffer, cx| {
-                for (range, text) in edits {
-                    buffer.edit([(range, text)], None, cx);
-                }
-            });
-            this.fold_ranges(refold_ranges, true, cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(new_selections);
-            })
-        });
-    }
-
-    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx).snapshot(cx);
-
-        let mut edits = Vec::new();
-        let mut unfold_ranges = Vec::new();
-        let mut refold_ranges = Vec::new();
-
-        let selections = self.selections.all::<Point>(cx);
-        let mut selections = selections.iter().peekable();
-        let mut contiguous_row_selections = Vec::new();
-        let mut new_selections = Vec::new();
-
-        while let Some(selection) = selections.next() {
-            // Find all the selections that span a contiguous row range
-            let (start_row, end_row) = consume_contiguous_rows(
-                &mut contiguous_row_selections,
-                selection,
-                &display_map,
-                &mut selections,
-            );
-
-            // Move the text spanned by the row range to be after the last line of the row range
-            if end_row <= buffer.max_point().row {
-                let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
-                let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
-
-                // Don't move lines across excerpt boundaries
-                if buffer
-                    .excerpt_boundaries_in_range((
-                        Bound::Excluded(range_to_move.start),
-                        Bound::Included(insertion_point),
-                    ))
-                    .next()
-                    .is_none()
-                {
-                    let mut text = String::from("\n");
-                    text.extend(buffer.text_for_range(range_to_move.clone()));
-                    text.pop(); // Drop trailing newline
-                    edits.push((
-                        buffer.anchor_after(range_to_move.start)
-                            ..buffer.anchor_before(range_to_move.end),
-                        String::new(),
-                    ));
-                    let insertion_anchor = buffer.anchor_after(insertion_point);
-                    edits.push((insertion_anchor..insertion_anchor, text));
-
-                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
-
-                    // Move selections down
-                    new_selections.extend(contiguous_row_selections.drain(..).map(
-                        |mut selection| {
-                            selection.start.row += row_delta;
-                            selection.end.row += row_delta;
-                            selection
-                        },
-                    ));
-
-                    // Move folds down
-                    unfold_ranges.push(range_to_move.clone());
-                    for fold in display_map.folds_in_range(
-                        buffer.anchor_before(range_to_move.start)
-                            ..buffer.anchor_after(range_to_move.end),
-                    ) {
-                        let mut start = fold.start.to_point(&buffer);
-                        let mut end = fold.end.to_point(&buffer);
-                        start.row += row_delta;
-                        end.row += row_delta;
-                        refold_ranges.push(start..end);
-                    }
-                }
-            }
-
-            // If we didn't move line(s), preserve the existing selections
-            new_selections.append(&mut contiguous_row_selections);
-        }
-
-        self.transact(cx, |this, cx| {
-            this.unfold_ranges(unfold_ranges, true, true, cx);
-            this.buffer.update(cx, |buffer, cx| {
-                for (range, text) in edits {
-                    buffer.edit([(range, text)], None, cx);
-                }
-            });
-            this.fold_ranges(refold_ranges, true, cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
-        });
-    }
-
-    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
-        let text_layout_details = &self.text_layout_details(cx);
-        self.transact(cx, |this, cx| {
-            let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let mut edits: Vec<(Range<usize>, String)> = Default::default();
-                let line_mode = s.line_mode;
-                s.move_with(|display_map, selection| {
-                    if !selection.is_empty() || line_mode {
-                        return;
-                    }
-
-                    let mut head = selection.head();
-                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
-                    if head.column() == display_map.line_len(head.row()) {
-                        transpose_offset = display_map
-                            .buffer_snapshot
-                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
-                    }
-
-                    if transpose_offset == 0 {
-                        return;
-                    }
-
-                    *head.column_mut() += 1;
-                    head = display_map.clip_point(head, Bias::Right);
-                    let goal = SelectionGoal::HorizontalPosition(
-                        display_map.x_for_point(head, &text_layout_details),
-                    );
-                    selection.collapse_to(head, goal);
-
-                    let transpose_start = display_map
-                        .buffer_snapshot
-                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
-                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
-                        let transpose_end = display_map
-                            .buffer_snapshot
-                            .clip_offset(transpose_offset + 1, Bias::Right);
-                        if let Some(ch) =
-                            display_map.buffer_snapshot.chars_at(transpose_start).next()
-                        {
-                            edits.push((transpose_start..transpose_offset, String::new()));
-                            edits.push((transpose_end..transpose_end, ch.to_string()));
-                        }
-                    }
-                });
-                edits
-            });
-            this.buffer
-                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
-            let selections = this.selections.all::<usize>(cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(selections);
-            });
-        });
-    }
-
-    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
-        let mut text = String::new();
-        let buffer = self.buffer.read(cx).snapshot(cx);
-        let mut selections = self.selections.all::<Point>(cx);
-        let mut clipboard_selections = Vec::with_capacity(selections.len());
-        {
-            let max_point = buffer.max_point();
-            let mut is_first = true;
-            for selection in &mut selections {
-                let is_entire_line = selection.is_empty() || self.selections.line_mode;
-                if is_entire_line {
-                    selection.start = Point::new(selection.start.row, 0);
-                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
-                    selection.goal = SelectionGoal::None;
-                }
-                if is_first {
-                    is_first = false;
-                } else {
-                    text += "\n";
-                }
-                let mut len = 0;
-                for chunk in buffer.text_for_range(selection.start..selection.end) {
-                    text.push_str(chunk);
-                    len += chunk.len();
-                }
-                clipboard_selections.push(ClipboardSelection {
-                    len,
-                    is_entire_line,
-                    first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
-                });
-            }
-        }
-
-        self.transact(cx, |this, cx| {
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(selections);
-            });
-            this.insert("", cx);
-            cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
-        });
-    }
-
-    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
-        let selections = self.selections.all::<Point>(cx);
-        let buffer = self.buffer.read(cx).read(cx);
-        let mut text = String::new();
-
-        let mut clipboard_selections = Vec::with_capacity(selections.len());
-        {
-            let max_point = buffer.max_point();
-            let mut is_first = true;
-            for selection in selections.iter() {
-                let mut start = selection.start;
-                let mut end = selection.end;
-                let is_entire_line = selection.is_empty() || self.selections.line_mode;
-                if is_entire_line {
-                    start = Point::new(start.row, 0);
-                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
-                }
-                if is_first {
-                    is_first = false;
-                } else {
-                    text += "\n";
-                }
-                let mut len = 0;
-                for chunk in buffer.text_for_range(start..end) {
-                    text.push_str(chunk);
-                    len += chunk.len();
-                }
-                clipboard_selections.push(ClipboardSelection {
-                    len,
-                    is_entire_line,
-                    first_line_indent: buffer.indent_size_for_line(start.row).len,
-                });
-            }
-        }
-
-        cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
-    }
-
-    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            if let Some(item) = cx.read_from_clipboard() {
-                let clipboard_text = Cow::Borrowed(item.text());
-                if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
-                    let old_selections = this.selections.all::<usize>(cx);
-                    let all_selections_were_entire_line =
-                        clipboard_selections.iter().all(|s| s.is_entire_line);
-                    let first_selection_indent_column =
-                        clipboard_selections.first().map(|s| s.first_line_indent);
-                    if clipboard_selections.len() != old_selections.len() {
-                        clipboard_selections.drain(..);
-                    }
-
-                    this.buffer.update(cx, |buffer, cx| {
-                        let snapshot = buffer.read(cx);
-                        let mut start_offset = 0;
-                        let mut edits = Vec::new();
-                        let mut original_indent_columns = Vec::new();
-                        let line_mode = this.selections.line_mode;
-                        for (ix, selection) in old_selections.iter().enumerate() {
-                            let to_insert;
-                            let entire_line;
-                            let original_indent_column;
-                            if let Some(clipboard_selection) = clipboard_selections.get(ix) {
-                                let end_offset = start_offset + clipboard_selection.len;
-                                to_insert = &clipboard_text[start_offset..end_offset];
-                                entire_line = clipboard_selection.is_entire_line;
-                                start_offset = end_offset + 1;
-                                original_indent_column =
-                                    Some(clipboard_selection.first_line_indent);
-                            } else {
-                                to_insert = clipboard_text.as_str();
-                                entire_line = all_selections_were_entire_line;
-                                original_indent_column = first_selection_indent_column
-                            }
-
-                            // If the corresponding selection was empty when this slice of the
-                            // clipboard text was written, then the entire line containing the
-                            // selection was copied. If this selection is also currently empty,
-                            // then paste the line before the current line of the buffer.
-                            let range = if selection.is_empty() && !line_mode && entire_line {
-                                let column = selection.start.to_point(&snapshot).column as usize;
-                                let line_start = selection.start - column;
-                                line_start..line_start
-                            } else {
-                                selection.range()
-                            };
-
-                            edits.push((range, to_insert));
-                            original_indent_columns.extend(original_indent_column);
-                        }
-                        drop(snapshot);
-
-                        buffer.edit(
-                            edits,
-                            Some(AutoindentMode::Block {
-                                original_indent_columns,
-                            }),
-                            cx,
-                        );
-                    });
-
-                    let selections = this.selections.all::<usize>(cx);
-                    this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
-                } else {
-                    this.insert(&clipboard_text, cx);
-                }
-            }
-        });
-    }
-
-    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
-        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
-            if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
-                self.change_selections(None, cx, |s| {
-                    s.select_anchors(selections.to_vec());
-                });
-            }
-            self.request_autoscroll(Autoscroll::fit(), cx);
-            self.unmark_text(cx);
-            self.refresh_copilot_suggestions(true, cx);
-            cx.emit(Event::Edited);
-        }
-    }
-
-    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
-        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
-            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
-            {
-                self.change_selections(None, cx, |s| {
-                    s.select_anchors(selections.to_vec());
-                });
-            }
-            self.request_autoscroll(Autoscroll::fit(), cx);
-            self.unmark_text(cx);
-            self.refresh_copilot_suggestions(true, cx);
-            cx.emit(Event::Edited);
-        }
-    }
-
-    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
-        self.buffer
-            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
-    }
-
-    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            let line_mode = s.line_mode;
-            s.move_with(|map, selection| {
-                let cursor = if selection.is_empty() && !line_mode {
-                    movement::left(map, selection.start)
-                } else {
-                    selection.start
-                };
-                selection.collapse_to(cursor, SelectionGoal::None);
-            });
-        })
-    }
-
-    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
-        })
-    }
-
-    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            let line_mode = s.line_mode;
-            s.move_with(|map, selection| {
-                let cursor = if selection.is_empty() && !line_mode {
-                    movement::right(map, selection.end)
-                } else {
-                    selection.end
-                };
-                selection.collapse_to(cursor, SelectionGoal::None)
-            });
-        })
-    }
-
-    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
-        })
-    }
-
-    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
-        if self.take_rename(true, cx).is_some() {
-            return;
-        }
-
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        let text_layout_details = &self.text_layout_details(cx);
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            let line_mode = s.line_mode;
-            s.move_with(|map, selection| {
-                if !selection.is_empty() && !line_mode {
-                    selection.goal = SelectionGoal::None;
-                }
-                let (cursor, goal) = movement::up(
-                    map,
-                    selection.start,
-                    selection.goal,
-                    false,
-                    &text_layout_details,
-                );
-                selection.collapse_to(cursor, goal);
-            });
-        })
-    }
-
-    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
-        if self.take_rename(true, cx).is_some() {
-            return;
-        }
-
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        let row_count = if let Some(row_count) = self.visible_line_count() {
-            row_count as u32 - 1
-        } else {
-            return;
-        };
-
-        let autoscroll = if action.center_cursor {
-            Autoscroll::center()
-        } else {
-            Autoscroll::fit()
-        };
-
-        let text_layout_details = &self.text_layout_details(cx);
-
-        self.change_selections(Some(autoscroll), cx, |s| {
-            let line_mode = s.line_mode;
-            s.move_with(|map, selection| {
-                if !selection.is_empty() && !line_mode {
-                    selection.goal = SelectionGoal::None;
-                }
-                let (cursor, goal) = movement::up_by_rows(
-                    map,
-                    selection.end,
-                    row_count,
-                    selection.goal,
-                    false,
-                    &text_layout_details,
-                );
-                selection.collapse_to(cursor, goal);
-            });
-        });
-    }
-
-    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
-        let text_layout_details = &self.text_layout_details(cx);
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, goal| {
-                movement::up(map, head, goal, false, &text_layout_details)
-            })
-        })
-    }
-
-    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
-        self.take_rename(true, cx);
-
-        if self.mode == EditorMode::SingleLine {
-            cx.propagate_action();
-            return;
-        }
-
-        let text_layout_details = &self.text_layout_details(cx);
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            let line_mode = s.line_mode;
-            s.move_with(|map, selection| {
-                if !selection.is_empty() && !line_mode {
-                    selection.goal = SelectionGoal::None;
-                }
-                let (cursor, goal) = movement::down(
-                    map,
-                    selection.end,
-                    selection.goal,
-                    false,
-                    &text_layout_details,
-                );
-                selection.collapse_to(cursor, goal);
-            });
-        });
-    }
-
-    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
-        if self.take_rename(true, cx).is_some() {
-            return;
-        }
-
-        if self
-            .context_menu
-            .write()
-            .as_mut()
-            .map(|menu| menu.select_last(self.project.as_ref(), cx))
-            .unwrap_or(false)
-        {
-            return;
-        }
-
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        let row_count = if let Some(row_count) = self.visible_line_count() {
-            row_count as u32 - 1
-        } else {
-            return;
-        };
-
-        let autoscroll = if action.center_cursor {
-            Autoscroll::center()
-        } else {
-            Autoscroll::fit()
-        };
-
-        let text_layout_details = &self.text_layout_details(cx);
-        self.change_selections(Some(autoscroll), cx, |s| {
-            let line_mode = s.line_mode;
-            s.move_with(|map, selection| {
-                if !selection.is_empty() && !line_mode {
-                    selection.goal = SelectionGoal::None;
-                }
-                let (cursor, goal) = movement::down_by_rows(
-                    map,
-                    selection.end,
-                    row_count,
-                    selection.goal,
-                    false,
-                    &text_layout_details,
-                );
-                selection.collapse_to(cursor, goal);
-            });
-        });
-    }
-
-    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
-        let text_layout_details = &self.text_layout_details(cx);
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, goal| {
-                movement::down(map, head, goal, false, &text_layout_details)
-            })
-        });
-    }
-
-    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
-        if let Some(context_menu) = self.context_menu.write().as_mut() {
-            context_menu.select_first(self.project.as_ref(), cx);
-        }
-    }
-
-    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
-        if let Some(context_menu) = self.context_menu.write().as_mut() {
-            context_menu.select_prev(self.project.as_ref(), cx);
-        }
-    }
-
-    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
-        if let Some(context_menu) = self.context_menu.write().as_mut() {
-            context_menu.select_next(self.project.as_ref(), cx);
-        }
-    }
-
-    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
-        if let Some(context_menu) = self.context_menu.write().as_mut() {
-            context_menu.select_last(self.project.as_ref(), cx);
-        }
-    }
-
-    pub fn move_to_previous_word_start(
-        &mut self,
-        _: &MoveToPreviousWordStart,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_cursors_with(|map, head, _| {
-                (
-                    movement::previous_word_start(map, head),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn move_to_previous_subword_start(
-        &mut self,
-        _: &MoveToPreviousSubwordStart,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_cursors_with(|map, head, _| {
-                (
-                    movement::previous_subword_start(map, head),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn select_to_previous_word_start(
-        &mut self,
-        _: &SelectToPreviousWordStart,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (
-                    movement::previous_word_start(map, head),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn select_to_previous_subword_start(
-        &mut self,
-        _: &SelectToPreviousSubwordStart,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (
-                    movement::previous_subword_start(map, head),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn delete_to_previous_word_start(
-        &mut self,
-        _: &DeleteToPreviousWordStart,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.transact(cx, |this, cx| {
-            this.select_autoclose_pair(cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let line_mode = s.line_mode;
-                s.move_with(|map, selection| {
-                    if selection.is_empty() && !line_mode {
-                        let cursor = movement::previous_word_start(map, selection.head());
-                        selection.set_head(cursor, SelectionGoal::None);
-                    }
-                });
-            });
-            this.insert("", cx);
-        });
-    }
-
-    pub fn delete_to_previous_subword_start(
-        &mut self,
-        _: &DeleteToPreviousSubwordStart,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.transact(cx, |this, cx| {
-            this.select_autoclose_pair(cx);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let line_mode = s.line_mode;
-                s.move_with(|map, selection| {
-                    if selection.is_empty() && !line_mode {
-                        let cursor = movement::previous_subword_start(map, selection.head());
-                        selection.set_head(cursor, SelectionGoal::None);
-                    }
-                });
-            });
-            this.insert("", cx);
-        });
-    }
-
-    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_cursors_with(|map, head, _| {
-                (movement::next_word_end(map, head), SelectionGoal::None)
-            });
-        })
-    }
-
-    pub fn move_to_next_subword_end(
-        &mut self,
-        _: &MoveToNextSubwordEnd,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_cursors_with(|map, head, _| {
-                (movement::next_subword_end(map, head), SelectionGoal::None)
-            });
-        })
-    }
-
-    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (movement::next_word_end(map, head), SelectionGoal::None)
-            });
-        })
-    }
-
-    pub fn select_to_next_subword_end(
-        &mut self,
-        _: &SelectToNextSubwordEnd,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (movement::next_subword_end(map, head), SelectionGoal::None)
-            });
-        })
-    }
-
-    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let line_mode = s.line_mode;
-                s.move_with(|map, selection| {
-                    if selection.is_empty() && !line_mode {
-                        let cursor = movement::next_word_end(map, selection.head());
-                        selection.set_head(cursor, SelectionGoal::None);
-                    }
-                });
-            });
-            this.insert("", cx);
-        });
-    }
-
-    pub fn delete_to_next_subword_end(
-        &mut self,
-        _: &DeleteToNextSubwordEnd,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.transact(cx, |this, cx| {
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.move_with(|map, selection| {
-                    if selection.is_empty() {
-                        let cursor = movement::next_subword_end(map, selection.head());
-                        selection.set_head(cursor, SelectionGoal::None);
-                    }
-                });
-            });
-            this.insert("", cx);
-        });
-    }
-
-    pub fn move_to_beginning_of_line(
-        &mut self,
-        _: &MoveToBeginningOfLine,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_cursors_with(|map, head, _| {
-                (
-                    movement::indented_line_beginning(map, head, true),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn select_to_beginning_of_line(
-        &mut self,
-        action: &SelectToBeginningOfLine,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (
-                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
-                    SelectionGoal::None,
-                )
-            });
-        });
-    }
-
-    pub fn delete_to_beginning_of_line(
-        &mut self,
-        _: &DeleteToBeginningOfLine,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.transact(cx, |this, cx| {
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.move_with(|_, selection| {
-                    selection.reversed = true;
-                });
-            });
-
-            this.select_to_beginning_of_line(
-                &SelectToBeginningOfLine {
-                    stop_at_soft_wraps: false,
-                },
-                cx,
-            );
-            this.backspace(&Backspace, cx);
-        });
-    }
-
-    pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_cursors_with(|map, head, _| {
-                (movement::line_end(map, head, true), SelectionGoal::None)
-            });
-        })
-    }
-
-    pub fn select_to_end_of_line(
-        &mut self,
-        action: &SelectToEndOfLine,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (
-                    movement::line_end(map, head, action.stop_at_soft_wraps),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.select_to_end_of_line(
-                &SelectToEndOfLine {
-                    stop_at_soft_wraps: false,
-                },
-                cx,
-            );
-            this.delete(&Delete, cx);
-        });
-    }
-
-    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.select_to_end_of_line(
-                &SelectToEndOfLine {
-                    stop_at_soft_wraps: false,
-                },
-                cx,
-            );
-            this.cut(&Cut, cx);
-        });
-    }
-
-    pub fn move_to_start_of_paragraph(
-        &mut self,
-        _: &MoveToStartOfParagraph,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_with(|map, selection| {
-                selection.collapse_to(
-                    movement::start_of_paragraph(map, selection.head(), 1),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn move_to_end_of_paragraph(
-        &mut self,
-        _: &MoveToEndOfParagraph,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_with(|map, selection| {
-                selection.collapse_to(
-                    movement::end_of_paragraph(map, selection.head(), 1),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn select_to_start_of_paragraph(
-        &mut self,
-        _: &SelectToStartOfParagraph,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (
-                    movement::start_of_paragraph(map, head, 1),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn select_to_end_of_paragraph(
-        &mut self,
-        _: &SelectToEndOfParagraph,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_heads_with(|map, head, _| {
-                (
-                    movement::end_of_paragraph(map, head, 1),
-                    SelectionGoal::None,
-                )
-            });
-        })
-    }
-
-    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select_ranges(vec![0..0]);
-        });
-    }
-
-    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
-        let mut selection = self.selections.last::<Point>(cx);
-        selection.set_head(Point::zero(), SelectionGoal::None);
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select(vec![selection]);
-        });
-    }
-
-    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return;
-        }
-
-        let cursor = self.buffer.read(cx).read(cx).len();
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select_ranges(vec![cursor..cursor])
-        });
-    }
-
-    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
-        self.nav_history = nav_history;
-    }
-
-    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
-        self.nav_history.as_ref()
-    }
-
-    fn push_to_nav_history(
-        &mut self,
-        cursor_anchor: Anchor,
-        new_position: Option<Point>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if let Some(nav_history) = self.nav_history.as_mut() {
-            let buffer = self.buffer.read(cx).read(cx);
-            let cursor_position = cursor_anchor.to_point(&buffer);
-            let scroll_state = self.scroll_manager.anchor();
-            let scroll_top_row = scroll_state.top_row(&buffer);
-            drop(buffer);
-
-            if let Some(new_position) = new_position {
-                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
-                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
-                    return;
-                }
-            }
-
-            nav_history.push(
-                Some(NavigationData {
-                    cursor_anchor,
-                    cursor_position,
-                    scroll_anchor: scroll_state,
-                    scroll_top_row,
-                }),
-                cx,
-            );
-        }
-    }
-
-    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
-        let buffer = self.buffer.read(cx).snapshot(cx);
-        let mut selection = self.selections.first::<usize>(cx);
-        selection.set_head(buffer.len(), SelectionGoal::None);
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select(vec![selection]);
-        });
-    }
-
-    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
-        let end = self.buffer.read(cx).read(cx).len();
-        self.change_selections(None, cx, |s| {
-            s.select_ranges(vec![0..end]);
-        });
-    }
-
-    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections.all::<Point>(cx);
-        let max_point = display_map.buffer_snapshot.max_point();
-        for selection in &mut selections {
-            let rows = selection.spanned_rows(true, &display_map);
-            selection.start = Point::new(rows.start, 0);
-            selection.end = cmp::min(max_point, Point::new(rows.end, 0));
-            selection.reversed = false;
-        }
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select(selections);
-        });
-    }
-
-    pub fn split_selection_into_lines(
-        &mut self,
-        _: &SplitSelectionIntoLines,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let mut to_unfold = Vec::new();
-        let mut new_selection_ranges = Vec::new();
-        {
-            let selections = self.selections.all::<Point>(cx);
-            let buffer = self.buffer.read(cx).read(cx);
-            for selection in selections {
-                for row in selection.start.row..selection.end.row {
-                    let cursor = Point::new(row, buffer.line_len(row));
-                    new_selection_ranges.push(cursor..cursor);
-                }
-                new_selection_ranges.push(selection.end..selection.end);
-                to_unfold.push(selection.start..selection.end);
-            }
-        }
-        self.unfold_ranges(to_unfold, true, true, cx);
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select_ranges(new_selection_ranges);
-        });
-    }
-
-    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
-        self.add_selection(true, cx);
-    }
-
-    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
-        self.add_selection(false, cx);
-    }
-
-    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections.all::<Point>(cx);
-        let text_layout_details = self.text_layout_details(cx);
-        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
-            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
-            let range = oldest_selection.display_range(&display_map).sorted();
-
-            let start_x = display_map.x_for_point(range.start, &text_layout_details);
-            let end_x = display_map.x_for_point(range.end, &text_layout_details);
-            let positions = start_x.min(end_x)..start_x.max(end_x);
-
-            selections.clear();
-            let mut stack = Vec::new();
-            for row in range.start.row()..=range.end.row() {
-                if let Some(selection) = self.selections.build_columnar_selection(
-                    &display_map,
-                    row,
-                    &positions,
-                    oldest_selection.reversed,
-                    &text_layout_details,
-                ) {
-                    stack.push(selection.id);
-                    selections.push(selection);
-                }
-            }
-
-            if above {
-                stack.reverse();
-            }
-
-            AddSelectionsState { above, stack }
-        });
-
-        let last_added_selection = *state.stack.last().unwrap();
-        let mut new_selections = Vec::new();
-        if above == state.above {
-            let end_row = if above {
-                0
-            } else {
-                display_map.max_point().row()
-            };
-
-            'outer: for selection in selections {
-                if selection.id == last_added_selection {
-                    let range = selection.display_range(&display_map).sorted();
-                    debug_assert_eq!(range.start.row(), range.end.row());
-                    let mut row = range.start.row();
-                    let positions = if let SelectionGoal::HorizontalRange { start, end } =
-                        selection.goal
-                    {
-                        start..end
-                    } else {
-                        let start_x = display_map.x_for_point(range.start, &text_layout_details);
-                        let end_x = display_map.x_for_point(range.end, &text_layout_details);
-
-                        start_x.min(end_x)..start_x.max(end_x)
-                    };
-
-                    while row != end_row {
-                        if above {
-                            row -= 1;
-                        } else {
-                            row += 1;
-                        }
-
-                        if let Some(new_selection) = self.selections.build_columnar_selection(
-                            &display_map,
-                            row,
-                            &positions,
-                            selection.reversed,
-                            &text_layout_details,
-                        ) {
-                            state.stack.push(new_selection.id);
-                            if above {
-                                new_selections.push(new_selection);
-                                new_selections.push(selection);
-                            } else {
-                                new_selections.push(selection);
-                                new_selections.push(new_selection);
-                            }
-
-                            continue 'outer;
-                        }
-                    }
-                }
-
-                new_selections.push(selection);
-            }
-        } else {
-            new_selections = selections;
-            new_selections.retain(|s| s.id != last_added_selection);
-            state.stack.pop();
-        }
-
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.select(new_selections);
-        });
-        if state.stack.len() > 1 {
-            self.add_selections_state = Some(state);
-        }
-    }
-
-    pub fn select_next_match_internal(
-        &mut self,
-        display_map: &DisplaySnapshot,
-        replace_newest: bool,
-        autoscroll: Option<Autoscroll>,
-        cx: &mut ViewContext<Self>,
-    ) -> Result<()> {
-        fn select_next_match_ranges(
-            this: &mut Editor,
-            range: Range<usize>,
-            replace_newest: bool,
-            auto_scroll: Option<Autoscroll>,
-            cx: &mut ViewContext<Editor>,
-        ) {
-            this.unfold_ranges([range.clone()], false, true, cx);
-            this.change_selections(auto_scroll, cx, |s| {
-                if replace_newest {
-                    s.delete(s.newest_anchor().id);
-                }
-                s.insert_range(range.clone());
-            });
-        }
-
-        let buffer = &display_map.buffer_snapshot;
-        let mut selections = self.selections.all::<usize>(cx);
-        if let Some(mut select_next_state) = self.select_next_state.take() {
-            let query = &select_next_state.query;
-            if !select_next_state.done {
-                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
-                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
-                let mut next_selected_range = None;
-
-                let bytes_after_last_selection =
-                    buffer.bytes_in_range(last_selection.end..buffer.len());
-                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
-                let query_matches = query
-                    .stream_find_iter(bytes_after_last_selection)
-                    .map(|result| (last_selection.end, result))
-                    .chain(
-                        query
-                            .stream_find_iter(bytes_before_first_selection)
-                            .map(|result| (0, result)),
-                    );
-
-                for (start_offset, query_match) in query_matches {
-                    let query_match = query_match.unwrap(); // can only fail due to I/O
-                    let offset_range =
-                        start_offset + query_match.start()..start_offset + query_match.end();
-                    let display_range = offset_range.start.to_display_point(&display_map)
-                        ..offset_range.end.to_display_point(&display_map);
-
-                    if !select_next_state.wordwise
-                        || (!movement::is_inside_word(&display_map, display_range.start)
-                            && !movement::is_inside_word(&display_map, display_range.end))
-                    {
-                        if selections
-                            .iter()
-                            .find(|selection| selection.range().overlaps(&offset_range))
-                            .is_none()
-                        {
-                            next_selected_range = Some(offset_range);
-                            break;
-                        }
-                    }
-                }
-
-                if let Some(next_selected_range) = next_selected_range {
-                    select_next_match_ranges(
-                        self,
-                        next_selected_range,
-                        replace_newest,
-                        autoscroll,
-                        cx,
-                    );
-                } else {
-                    select_next_state.done = true;
-                }
-            }
-
-            self.select_next_state = Some(select_next_state);
-        } else if selections.len() == 1 {
-            let selection = selections.last_mut().unwrap();
-            if selection.start == selection.end {
-                let word_range = movement::surrounding_word(
-                    &display_map,
-                    selection.start.to_display_point(&display_map),
-                );
-                selection.start = word_range.start.to_offset(&display_map, Bias::Left);
-                selection.end = word_range.end.to_offset(&display_map, Bias::Left);
-                selection.goal = SelectionGoal::None;
-                selection.reversed = false;
-
-                let query = buffer
-                    .text_for_range(selection.start..selection.end)
-                    .collect::<String>();
-
-                let is_empty = query.is_empty();
-                let select_state = SelectNextState {
-                    query: AhoCorasick::new(&[query])?,
-                    wordwise: true,
-                    done: is_empty,
-                };
-                select_next_match_ranges(
-                    self,
-                    selection.start..selection.end,
-                    replace_newest,
-                    autoscroll,
-                    cx,
-                );
-                self.select_next_state = Some(select_state);
-            } else {
-                let query = buffer
-                    .text_for_range(selection.start..selection.end)
-                    .collect::<String>();
-                self.select_next_state = Some(SelectNextState {
-                    query: AhoCorasick::new(&[query])?,
-                    wordwise: false,
-                    done: false,
-                });
-                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
-            }
-        }
-        Ok(())
-    }
-
-    pub fn select_all_matches(
-        &mut self,
-        action: &SelectAllMatches,
-        cx: &mut ViewContext<Self>,
-    ) -> Result<()> {
-        self.push_to_selection_history();
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-
-        loop {
-            self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?;
-
-            if self
-                .select_next_state
-                .as_ref()
-                .map(|selection_state| selection_state.done)
-                .unwrap_or(true)
-            {
-                break;
-            }
-        }
-
-        Ok(())
-    }
-
-    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
-        self.push_to_selection_history();
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        self.select_next_match_internal(
-            &display_map,
-            action.replace_newest,
-            Some(Autoscroll::newest()),
-            cx,
-        )?;
-        Ok(())
-    }
-
-    pub fn select_previous(
-        &mut self,
-        action: &SelectPrevious,
-        cx: &mut ViewContext<Self>,
-    ) -> Result<()> {
-        self.push_to_selection_history();
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = &display_map.buffer_snapshot;
-        let mut selections = self.selections.all::<usize>(cx);
-        if let Some(mut select_prev_state) = self.select_prev_state.take() {
-            let query = &select_prev_state.query;
-            if !select_prev_state.done {
-                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
-                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
-                let mut next_selected_range = None;
-                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
-                let bytes_before_last_selection =
-                    buffer.reversed_bytes_in_range(0..last_selection.start);
-                let bytes_after_first_selection =
-                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
-                let query_matches = query
-                    .stream_find_iter(bytes_before_last_selection)
-                    .map(|result| (last_selection.start, result))
-                    .chain(
-                        query
-                            .stream_find_iter(bytes_after_first_selection)
-                            .map(|result| (buffer.len(), result)),
-                    );
-                for (end_offset, query_match) in query_matches {
-                    let query_match = query_match.unwrap(); // can only fail due to I/O
-                    let offset_range =
-                        end_offset - query_match.end()..end_offset - query_match.start();
-                    let display_range = offset_range.start.to_display_point(&display_map)
-                        ..offset_range.end.to_display_point(&display_map);
-
-                    if !select_prev_state.wordwise
-                        || (!movement::is_inside_word(&display_map, display_range.start)
-                            && !movement::is_inside_word(&display_map, display_range.end))
-                    {
-                        next_selected_range = Some(offset_range);
-                        break;
-                    }
-                }
-
-                if let Some(next_selected_range) = next_selected_range {
-                    self.unfold_ranges([next_selected_range.clone()], false, true, cx);
-                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
-                        if action.replace_newest {
-                            s.delete(s.newest_anchor().id);
-                        }
-                        s.insert_range(next_selected_range);
-                    });
-                } else {
-                    select_prev_state.done = true;
-                }
-            }
-
-            self.select_prev_state = Some(select_prev_state);
-        } else if selections.len() == 1 {
-            let selection = selections.last_mut().unwrap();
-            if selection.start == selection.end {
-                let word_range = movement::surrounding_word(
-                    &display_map,
-                    selection.start.to_display_point(&display_map),
-                );
-                selection.start = word_range.start.to_offset(&display_map, Bias::Left);
-                selection.end = word_range.end.to_offset(&display_map, Bias::Left);
-                selection.goal = SelectionGoal::None;
-                selection.reversed = false;
-
-                let query = buffer
-                    .text_for_range(selection.start..selection.end)
-                    .collect::<String>();
-                let query = query.chars().rev().collect::<String>();
-                let select_state = SelectNextState {
-                    query: AhoCorasick::new(&[query])?,
-                    wordwise: true,
-                    done: false,
-                };
-                self.unfold_ranges([selection.start..selection.end], false, true, cx);
-                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
-                    s.select(selections);
-                });
-                self.select_prev_state = Some(select_state);
-            } else {
-                let query = buffer
-                    .text_for_range(selection.start..selection.end)
-                    .collect::<String>();
-                let query = query.chars().rev().collect::<String>();
-                self.select_prev_state = Some(SelectNextState {
-                    query: AhoCorasick::new(&[query])?,
-                    wordwise: false,
-                    done: false,
-                });
-                self.select_previous(action, cx)?;
-            }
-        }
-        Ok(())
-    }
-
-    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
-        let text_layout_details = &self.text_layout_details(cx);
-        self.transact(cx, |this, cx| {
-            let mut selections = this.selections.all::<Point>(cx);
-            let mut edits = Vec::new();
-            let mut selection_edit_ranges = Vec::new();
-            let mut last_toggled_row = None;
-            let snapshot = this.buffer.read(cx).read(cx);
-            let empty_str: Arc<str> = "".into();
-            let mut suffixes_inserted = Vec::new();
-
-            fn comment_prefix_range(
-                snapshot: &MultiBufferSnapshot,
-                row: u32,
-                comment_prefix: &str,
-                comment_prefix_whitespace: &str,
-            ) -> Range<Point> {
-                let start = Point::new(row, snapshot.indent_size_for_line(row).len);
-
-                let mut line_bytes = snapshot
-                    .bytes_in_range(start..snapshot.max_point())
-                    .flatten()
-                    .copied();
-
-                // If this line currently begins with the line comment prefix, then record
-                // the range containing the prefix.
-                if line_bytes
-                    .by_ref()
-                    .take(comment_prefix.len())
-                    .eq(comment_prefix.bytes())
-                {
-                    // Include any whitespace that matches the comment prefix.
-                    let matching_whitespace_len = line_bytes
-                        .zip(comment_prefix_whitespace.bytes())
-                        .take_while(|(a, b)| a == b)
-                        .count() as u32;
-                    let end = Point::new(
-                        start.row,
-                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
-                    );
-                    start..end
-                } else {
-                    start..start
-                }
-            }
-
-            fn comment_suffix_range(
-                snapshot: &MultiBufferSnapshot,
-                row: u32,
-                comment_suffix: &str,
-                comment_suffix_has_leading_space: bool,
-            ) -> Range<Point> {
-                let end = Point::new(row, snapshot.line_len(row));
-                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
-
-                let mut line_end_bytes = snapshot
-                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
-                    .flatten()
-                    .copied();
-
-                let leading_space_len = if suffix_start_column > 0
-                    && line_end_bytes.next() == Some(b' ')
-                    && comment_suffix_has_leading_space
-                {
-                    1
-                } else {
-                    0
-                };
-
-                // If this line currently begins with the line comment prefix, then record
-                // the range containing the prefix.
-                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
-                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
-                    start..end
-                } else {
-                    end..end
-                }
-            }
-
-            // TODO: Handle selections that cross excerpts
-            for selection in &mut selections {
-                let start_column = snapshot.indent_size_for_line(selection.start.row).len;
-                let language = if let Some(language) =
-                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
-                {
-                    language
-                } else {
-                    continue;
-                };
-
-                selection_edit_ranges.clear();
-
-                // If multiple selections contain a given row, avoid processing that
-                // row more than once.
-                let mut start_row = selection.start.row;
-                if last_toggled_row == Some(start_row) {
-                    start_row += 1;
-                }
-                let end_row =
-                    if selection.end.row > selection.start.row && selection.end.column == 0 {
-                        selection.end.row - 1
-                    } else {
-                        selection.end.row
-                    };
-                last_toggled_row = Some(end_row);
-
-                if start_row > end_row {
-                    continue;
-                }
-
-                // If the language has line comments, toggle those.
-                if let Some(full_comment_prefix) = language.line_comment_prefix() {
-                    // Split the comment prefix's trailing whitespace into a separate string,
-                    // as that portion won't be used for detecting if a line is a comment.
-                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
-                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
-                    let mut all_selection_lines_are_comments = true;
-
-                    for row in start_row..=end_row {
-                        if snapshot.is_line_blank(row) && start_row < end_row {
-                            continue;
-                        }
-
-                        let prefix_range = comment_prefix_range(
-                            snapshot.deref(),
-                            row,
-                            comment_prefix,
-                            comment_prefix_whitespace,
-                        );
-                        if prefix_range.is_empty() {
-                            all_selection_lines_are_comments = false;
-                        }
-                        selection_edit_ranges.push(prefix_range);
-                    }
-
-                    if all_selection_lines_are_comments {
-                        edits.extend(
-                            selection_edit_ranges
-                                .iter()
-                                .cloned()
-                                .map(|range| (range, empty_str.clone())),
-                        );
-                    } else {
-                        let min_column = selection_edit_ranges
-                            .iter()
-                            .map(|r| r.start.column)
-                            .min()
-                            .unwrap_or(0);
-                        edits.extend(selection_edit_ranges.iter().map(|range| {
-                            let position = Point::new(range.start.row, min_column);
-                            (position..position, full_comment_prefix.clone())
-                        }));
-                    }
-                } else if let Some((full_comment_prefix, comment_suffix)) =
-                    language.block_comment_delimiters()
-                {
-                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
-                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
-                    let prefix_range = comment_prefix_range(
-                        snapshot.deref(),
-                        start_row,
-                        comment_prefix,
-                        comment_prefix_whitespace,
-                    );
-                    let suffix_range = comment_suffix_range(
-                        snapshot.deref(),
-                        end_row,
-                        comment_suffix.trim_start_matches(' '),
-                        comment_suffix.starts_with(' '),
-                    );
-
-                    if prefix_range.is_empty() || suffix_range.is_empty() {
-                        edits.push((
-                            prefix_range.start..prefix_range.start,
-                            full_comment_prefix.clone(),
-                        ));
-                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
-                        suffixes_inserted.push((end_row, comment_suffix.len()));
-                    } else {
-                        edits.push((prefix_range, empty_str.clone()));
-                        edits.push((suffix_range, empty_str.clone()));
-                    }
-                } else {
-                    continue;
-                }
-            }
-
-            drop(snapshot);
-            this.buffer.update(cx, |buffer, cx| {
-                buffer.edit(edits, None, cx);
-            });
-
-            // Adjust selections so that they end before any comment suffixes that
-            // were inserted.
-            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
-            let mut selections = this.selections.all::<Point>(cx);
-            let snapshot = this.buffer.read(cx).read(cx);
-            for selection in &mut selections {
-                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
-                    match row.cmp(&selection.end.row) {
-                        Ordering::Less => {
-                            suffixes_inserted.next();
-                            continue;
-                        }
-                        Ordering::Greater => break,
-                        Ordering::Equal => {
-                            if selection.end.column == snapshot.line_len(row) {
-                                if selection.is_empty() {
-                                    selection.start.column -= suffix_len as u32;
-                                }
-                                selection.end.column -= suffix_len as u32;
-                            }
-                            break;
-                        }
-                    }
-                }
-            }
-
-            drop(snapshot);
-            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
-
-            let selections = this.selections.all::<Point>(cx);
-            let selections_on_single_row = selections.windows(2).all(|selections| {
-                selections[0].start.row == selections[1].start.row
-                    && selections[0].end.row == selections[1].end.row
-                    && selections[0].start.row == selections[0].end.row
-            });
-            let selections_selecting = selections
-                .iter()
-                .any(|selection| selection.start != selection.end);
-            let advance_downwards = action.advance_downwards
-                && selections_on_single_row
-                && !selections_selecting
-                && this.mode != EditorMode::SingleLine;
-
-            if advance_downwards {
-                let snapshot = this.buffer.read(cx).snapshot(cx);
-
-                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                    s.move_cursors_with(|display_snapshot, display_point, _| {
-                        let mut point = display_point.to_point(display_snapshot);
-                        point.row += 1;
-                        point = snapshot.clip_point(point, Bias::Left);
-                        let display_point = point.to_display_point(display_snapshot);
-                        let goal = SelectionGoal::HorizontalPosition(
-                            display_snapshot.x_for_point(display_point, &text_layout_details),
-                        );
-                        (display_point, goal)
-                    })
-                });
-            }
-        });
-    }
-
-    pub fn select_larger_syntax_node(
-        &mut self,
-        _: &SelectLargerSyntaxNode,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx).snapshot(cx);
-        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
-
-        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
-        let mut selected_larger_node = false;
-        let new_selections = old_selections
-            .iter()
-            .map(|selection| {
-                let old_range = selection.start..selection.end;
-                let mut new_range = old_range.clone();
-                while let Some(containing_range) =
-                    buffer.range_for_syntax_ancestor(new_range.clone())
-                {
-                    new_range = containing_range;
-                    if !display_map.intersects_fold(new_range.start)
-                        && !display_map.intersects_fold(new_range.end)
-                    {
-                        break;
-                    }
-                }
-
-                selected_larger_node |= new_range != old_range;
-                Selection {
-                    id: selection.id,
-                    start: new_range.start,
-                    end: new_range.end,
-                    goal: SelectionGoal::None,
-                    reversed: selection.reversed,
-                }
-            })
-            .collect::<Vec<_>>();
-
-        if selected_larger_node {
-            stack.push(old_selections);
-            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(new_selections);
-            });
-        }
-        self.select_larger_syntax_node_stack = stack;
-    }
-
-    pub fn select_smaller_syntax_node(
-        &mut self,
-        _: &SelectSmallerSyntaxNode,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
-        if let Some(selections) = stack.pop() {
-            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                s.select(selections.to_vec());
-            });
-        }
-        self.select_larger_syntax_node_stack = stack;
-    }
-
-    pub fn move_to_enclosing_bracket(
-        &mut self,
-        _: &MoveToEnclosingBracket,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-            s.move_offsets_with(|snapshot, selection| {
-                let Some(enclosing_bracket_ranges) =
-                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
-                else {
-                    return;
-                };
-
-                let mut best_length = usize::MAX;
-                let mut best_inside = false;
-                let mut best_in_bracket_range = false;
-                let mut best_destination = None;
-                for (open, close) in enclosing_bracket_ranges {
-                    let close = close.to_inclusive();
-                    let length = close.end() - open.start;
-                    let inside = selection.start >= open.end && selection.end <= *close.start();
-                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
-                        || close.contains(&selection.head());
-
-                    // If best is next to a bracket and current isn't, skip
-                    if !in_bracket_range && best_in_bracket_range {
-                        continue;
-                    }
-
-                    // Prefer smaller lengths unless best is inside and current isn't
-                    if length > best_length && (best_inside || !inside) {
-                        continue;
-                    }
-
-                    best_length = length;
-                    best_inside = inside;
-                    best_in_bracket_range = in_bracket_range;
-                    best_destination = Some(
-                        if close.contains(&selection.start) && close.contains(&selection.end) {
-                            if inside {
-                                open.end
-                            } else {
-                                open.start
-                            }
-                        } else {
-                            if inside {
-                                *close.start()
-                            } else {
-                                *close.end()
-                            }
-                        },
-                    );
-                }
-
-                if let Some(destination) = best_destination {
-                    selection.collapse_to(destination, SelectionGoal::None);
-                }
-            })
-        });
-    }
-
-    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
-        self.end_selection(cx);
-        self.selection_history.mode = SelectionHistoryMode::Undoing;
-        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
-            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
-            self.select_next_state = entry.select_next_state;
-            self.select_prev_state = entry.select_prev_state;
-            self.add_selections_state = entry.add_selections_state;
-            self.request_autoscroll(Autoscroll::newest(), cx);
-        }
-        self.selection_history.mode = SelectionHistoryMode::Normal;
-    }
-
-    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
-        self.end_selection(cx);
-        self.selection_history.mode = SelectionHistoryMode::Redoing;
-        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
-            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
-            self.select_next_state = entry.select_next_state;
-            self.select_prev_state = entry.select_prev_state;
-            self.add_selections_state = entry.add_selections_state;
-            self.request_autoscroll(Autoscroll::newest(), cx);
-        }
-        self.selection_history.mode = SelectionHistoryMode::Normal;
-    }
-
-    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
-        self.go_to_diagnostic_impl(Direction::Next, cx)
-    }
-
-    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
-        self.go_to_diagnostic_impl(Direction::Prev, cx)
-    }
-
-    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
-        let buffer = self.buffer.read(cx).snapshot(cx);
-        let selection = self.selections.newest::<usize>(cx);
-
-        // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
-        if direction == Direction::Next {
-            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
-                let (group_id, jump_to) = popover.activation_info();
-                if self.activate_diagnostics(group_id, cx) {
-                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                        let mut new_selection = s.newest_anchor().clone();
-                        new_selection.collapse_to(jump_to, SelectionGoal::None);
-                        s.select_anchors(vec![new_selection.clone()]);
-                    });
-                }
-                return;
-            }
-        }
-
-        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
-            active_diagnostics
-                .primary_range
-                .to_offset(&buffer)
-                .to_inclusive()
-        });
-        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
-            if active_primary_range.contains(&selection.head()) {
-                *active_primary_range.end()
-            } else {
-                selection.head()
-            }
-        } else {
-            selection.head()
-        };
-
-        loop {
-            let mut diagnostics = if direction == Direction::Prev {
-                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
-            } else {
-                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
-            };
-            let group = diagnostics.find_map(|entry| {
-                if entry.diagnostic.is_primary
-                    && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
-                    && !entry.range.is_empty()
-                    && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
-                    && !entry.range.contains(&search_start)
-                {
-                    Some((entry.range, entry.diagnostic.group_id))
-                } else {
-                    None
-                }
-            });
-
-            if let Some((primary_range, group_id)) = group {
-                if self.activate_diagnostics(group_id, cx) {
-                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                        s.select(vec![Selection {
-                            id: selection.id,
-                            start: primary_range.start,
-                            end: primary_range.start,
-                            reversed: false,
-                            goal: SelectionGoal::None,
-                        }]);
-                    });
-                }
-                break;
-            } else {
-                // Cycle around to the start of the buffer, potentially moving back to the start of
-                // the currently active diagnostic.
-                active_primary_range.take();
-                if direction == Direction::Prev {
-                    if search_start == buffer.len() {
-                        break;
-                    } else {
-                        search_start = buffer.len();
-                    }
-                } else if search_start == 0 {
-                    break;
-                } else {
-                    search_start = 0;
-                }
-            }
-        }
-    }
-
-    fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
-        let snapshot = self
-            .display_map
-            .update(cx, |display_map, cx| display_map.snapshot(cx));
-        let selection = self.selections.newest::<Point>(cx);
-
-        if !self.seek_in_direction(
-            &snapshot,
-            selection.head(),
-            false,
-            snapshot
-                .buffer_snapshot
-                .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
-            cx,
-        ) {
-            let wrapped_point = Point::zero();
-            self.seek_in_direction(
-                &snapshot,
-                wrapped_point,
-                true,
-                snapshot
-                    .buffer_snapshot
-                    .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
-                cx,
-            );
-        }
-    }
-
-    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
-        let snapshot = self
-            .display_map
-            .update(cx, |display_map, cx| display_map.snapshot(cx));
-        let selection = self.selections.newest::<Point>(cx);
-
-        if !self.seek_in_direction(
-            &snapshot,
-            selection.head(),
-            false,
-            snapshot
-                .buffer_snapshot
-                .git_diff_hunks_in_range_rev(0..selection.head().row),
-            cx,
-        ) {
-            let wrapped_point = snapshot.buffer_snapshot.max_point();
-            self.seek_in_direction(
-                &snapshot,
-                wrapped_point,
-                true,
-                snapshot
-                    .buffer_snapshot
-                    .git_diff_hunks_in_range_rev(0..wrapped_point.row),
-                cx,
-            );
-        }
-    }
-
-    fn seek_in_direction(
-        &mut self,
-        snapshot: &DisplaySnapshot,
-        initial_point: Point,
-        is_wrapped: bool,
-        hunks: impl Iterator<Item = DiffHunk<u32>>,
-        cx: &mut ViewContext<Editor>,
-    ) -> bool {
-        let display_point = initial_point.to_display_point(snapshot);
-        let mut hunks = hunks
-            .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
-            .filter(|hunk| {
-                if is_wrapped {
-                    true
-                } else {
-                    !hunk.contains_display_row(display_point.row())
-                }
-            })
-            .dedup();
-
-        if let Some(hunk) = hunks.next() {
-            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                let row = hunk.start_display_row();
-                let point = DisplayPoint::new(row, 0);
-                s.select_display_ranges([point..point]);
-            });
-
-            true
-        } else {
-            false
-        }
-    }
-
-    pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
-        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
-    }
-
-    pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
-        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
-    }
-
-    pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext<Self>) {
-        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx);
-    }
-
-    pub fn go_to_type_definition_split(
-        &mut self,
-        _: &GoToTypeDefinitionSplit,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx);
-    }
-
-    fn go_to_definition_of_kind(
-        &mut self,
-        kind: GotoDefinitionKind,
-        split: bool,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let Some(workspace) = self.workspace(cx) else {
-            return;
-        };
-        let buffer = self.buffer.read(cx);
-        let head = self.selections.newest::<usize>(cx).head();
-        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
-            text_anchor
-        } else {
-            return;
-        };
-
-        let project = workspace.read(cx).project().clone();
-        let definitions = project.update(cx, |project, cx| match kind {
-            GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
-            GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
-        });
-
-        cx.spawn_labeled("Fetching Definition...", |editor, mut cx| async move {
-            let definitions = definitions.await?;
-            editor.update(&mut cx, |editor, cx| {
-                editor.navigate_to_definitions(
-                    definitions
-                        .into_iter()
-                        .map(GoToDefinitionLink::Text)
-                        .collect(),
-                    split,
-                    cx,
-                );
-            })?;
-            Ok::<(), anyhow::Error>(())
-        })
-        .detach_and_log_err(cx);
-    }
-
-    pub fn navigate_to_definitions(
-        &mut self,
-        mut definitions: Vec<GoToDefinitionLink>,
-        split: bool,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let Some(workspace) = self.workspace(cx) else {
-            return;
-        };
-        let pane = workspace.read(cx).active_pane().clone();
-        // If there is one definition, just open it directly
-        if definitions.len() == 1 {
-            let definition = definitions.pop().unwrap();
-            let target_task = match definition {
-                GoToDefinitionLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
-                GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
-                    self.compute_target_location(lsp_location, server_id, cx)
-                }
-            };
-            cx.spawn(|editor, mut cx| async move {
-                let target = target_task.await.context("target resolution task")?;
-                if let Some(target) = target {
-                    editor.update(&mut cx, |editor, cx| {
-                        let range = target.range.to_offset(target.buffer.read(cx));
-                        let range = editor.range_for_match(&range);
-                        if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
-                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
-                                s.select_ranges([range]);
-                            });
-                        } else {
-                            cx.window_context().defer(move |cx| {
-                                let target_editor: ViewHandle<Self> =
-                                    workspace.update(cx, |workspace, cx| {
-                                        if split {
-                                            workspace.split_project_item(target.buffer.clone(), cx)
-                                        } else {
-                                            workspace.open_project_item(target.buffer.clone(), cx)
-                                        }
-                                    });
-                                target_editor.update(cx, |target_editor, cx| {
-                                    // When selecting a definition in a different buffer, disable the nav history
-                                    // to avoid creating a history entry at the previous cursor location.
-                                    pane.update(cx, |pane, _| pane.disable_history());
-                                    target_editor.change_selections(
-                                        Some(Autoscroll::fit()),
-                                        cx,
-                                        |s| {
-                                            s.select_ranges([range]);
-                                        },
-                                    );
-                                    pane.update(cx, |pane, _| pane.enable_history());
-                                });
-                            });
-                        }
-                    })
-                } else {
-                    Ok(())
-                }
-            })
-            .detach_and_log_err(cx);
-        } else if !definitions.is_empty() {
-            let replica_id = self.replica_id(cx);
-            cx.spawn(|editor, mut cx| async move {
-                let (title, location_tasks) = editor
-                    .update(&mut cx, |editor, cx| {
-                        let title = definitions
-                            .iter()
-                            .find_map(|definition| match definition {
-                                GoToDefinitionLink::Text(link) => {
-                                    link.origin.as_ref().map(|origin| {
-                                        let buffer = origin.buffer.read(cx);
-                                        format!(
-                                            "Definitions for {}",
-                                            buffer
-                                                .text_for_range(origin.range.clone())
-                                                .collect::<String>()
-                                        )
-                                    })
-                                }
-                                GoToDefinitionLink::InlayHint(_, _) => None,
-                            })
-                            .unwrap_or("Definitions".to_string());
-                        let location_tasks = definitions
-                            .into_iter()
-                            .map(|definition| match definition {
-                                GoToDefinitionLink::Text(link) => {
-                                    Task::Ready(Some(Ok(Some(link.target))))
-                                }
-                                GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
-                                    editor.compute_target_location(lsp_location, server_id, cx)
-                                }
-                            })
-                            .collect::<Vec<_>>();
-                        (title, location_tasks)
-                    })
-                    .context("location tasks preparation")?;
-
-                let locations = futures::future::join_all(location_tasks)
-                    .await
-                    .into_iter()
-                    .filter_map(|location| location.transpose())
-                    .collect::<Result<_>>()
-                    .context("location tasks")?;
-                workspace.update(&mut cx, |workspace, cx| {
-                    Self::open_locations_in_multibuffer(
-                        workspace, locations, replica_id, title, split, cx,
-                    )
-                });
-
-                anyhow::Ok(())
-            })
-            .detach_and_log_err(cx);
-        }
-    }
-
-    fn compute_target_location(
-        &self,
-        lsp_location: lsp::Location,
-        server_id: LanguageServerId,
-        cx: &mut ViewContext<Editor>,
-    ) -> Task<anyhow::Result<Option<Location>>> {
-        let Some(project) = self.project.clone() else {
-            return Task::Ready(Some(Ok(None)));
-        };
-
-        cx.spawn(move |editor, mut cx| async move {
-            let location_task = editor.update(&mut cx, |editor, cx| {
-                project.update(cx, |project, cx| {
-                    let language_server_name =
-                        editor.buffer.read(cx).as_singleton().and_then(|buffer| {
-                            project
-                                .language_server_for_buffer(buffer.read(cx), server_id, cx)
-                                .map(|(_, lsp_adapter)| {
-                                    LanguageServerName(Arc::from(lsp_adapter.name()))
-                                })
-                        });
-                    language_server_name.map(|language_server_name| {
-                        project.open_local_buffer_via_lsp(
-                            lsp_location.uri.clone(),
-                            server_id,
-                            language_server_name,
-                            cx,
-                        )
-                    })
-                })
-            })?;
-            let location = match location_task {
-                Some(task) => Some({
-                    let target_buffer_handle = task.await.context("open local buffer")?;
-                    let range = {
-                        target_buffer_handle.update(&mut cx, |target_buffer, _| {
-                            let target_start = target_buffer.clip_point_utf16(
-                                point_from_lsp(lsp_location.range.start),
-                                Bias::Left,
-                            );
-                            let target_end = target_buffer.clip_point_utf16(
-                                point_from_lsp(lsp_location.range.end),
-                                Bias::Left,
-                            );
-                            target_buffer.anchor_after(target_start)
-                                ..target_buffer.anchor_before(target_end)
-                        })
-                    };
-                    Location {
-                        buffer: target_buffer_handle,
-                        range,
-                    }
-                }),
-                None => None,
-            };
-            Ok(location)
-        })
-    }
-
-    pub fn find_all_references(
-        workspace: &mut Workspace,
-        _: &FindAllReferences,
-        cx: &mut ViewContext<Workspace>,
-    ) -> Option<Task<Result<()>>> {
-        let active_item = workspace.active_item(cx)?;
-        let editor_handle = active_item.act_as::<Self>(cx)?;
-
-        let editor = editor_handle.read(cx);
-        let buffer = editor.buffer.read(cx);
-        let head = editor.selections.newest::<usize>(cx).head();
-        let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
-        let replica_id = editor.replica_id(cx);
-
-        let project = workspace.project().clone();
-        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
-        Some(cx.spawn_labeled(
-            "Finding All References...",
-            |workspace, mut cx| async move {
-                let locations = references.await?;
-                if locations.is_empty() {
-                    return Ok(());
-                }
-
-                workspace.update(&mut cx, |workspace, cx| {
-                    let title = locations
-                        .first()
-                        .as_ref()
-                        .map(|location| {
-                            let buffer = location.buffer.read(cx);
-                            format!(
-                                "References to `{}`",
-                                buffer
-                                    .text_for_range(location.range.clone())
-                                    .collect::<String>()
-                            )
-                        })
-                        .unwrap();
-                    Self::open_locations_in_multibuffer(
-                        workspace, locations, replica_id, title, false, cx,
-                    );
-                })?;
-
-                Ok(())
-            },
-        ))
-    }
-
-    /// Opens a multibuffer with the given project locations in it
-    pub fn open_locations_in_multibuffer(
-        workspace: &mut Workspace,
-        mut locations: Vec<Location>,
-        replica_id: ReplicaId,
-        title: String,
-        split: bool,
-        cx: &mut ViewContext<Workspace>,
-    ) {
-        // If there are multiple definitions, open them in a multibuffer
-        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
-        let mut locations = locations.into_iter().peekable();
-        let mut ranges_to_highlight = Vec::new();
-
-        let excerpt_buffer = cx.add_model(|cx| {
-            let mut multibuffer = MultiBuffer::new(replica_id);
-            while let Some(location) = locations.next() {
-                let buffer = location.buffer.read(cx);
-                let mut ranges_for_buffer = Vec::new();
-                let range = location.range.to_offset(buffer);
-                ranges_for_buffer.push(range.clone());
-
-                while let Some(next_location) = locations.peek() {
-                    if next_location.buffer == location.buffer {
-                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
-                        locations.next();
-                    } else {
-                        break;
-                    }
-                }
-
-                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
-                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
-                    location.buffer.clone(),
-                    ranges_for_buffer,
-                    1,
-                    cx,
-                ))
-            }
-
-            multibuffer.with_title(title)
-        });
-
-        let editor = cx.add_view(|cx| {
-            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
-        });
-        editor.update(cx, |editor, cx| {
-            editor.highlight_background::<Self>(
-                ranges_to_highlight,
-                |theme| theme.editor.highlighted_line_background,
-                cx,
-            );
-        });
-        if split {
-            workspace.split_item(SplitDirection::Right, Box::new(editor), cx);
-        } else {
-            workspace.add_item(Box::new(editor), cx);
-        }
-    }
-
-    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
-        use language::ToOffset as _;
-
-        let project = self.project.clone()?;
-        let selection = self.selections.newest_anchor().clone();
-        let (cursor_buffer, cursor_buffer_position) = self
-            .buffer
-            .read(cx)
-            .text_anchor_for_position(selection.head(), cx)?;
-        let (tail_buffer, _) = self
-            .buffer
-            .read(cx)
-            .text_anchor_for_position(selection.tail(), cx)?;
-        if tail_buffer != cursor_buffer {
-            return None;
-        }
-
-        let snapshot = cursor_buffer.read(cx).snapshot();
-        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
-        let prepare_rename = project.update(cx, |project, cx| {
-            project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
-        });
-
-        Some(cx.spawn(|this, mut cx| async move {
-            let rename_range = if let Some(range) = prepare_rename.await? {
-                Some(range)
-            } else {
-                this.update(&mut cx, |this, cx| {
-                    let buffer = this.buffer.read(cx).snapshot(cx);
-                    let mut buffer_highlights = this
-                        .document_highlights_for_position(selection.head(), &buffer)
-                        .filter(|highlight| {
-                            highlight.start.excerpt_id == selection.head().excerpt_id
-                                && highlight.end.excerpt_id == selection.head().excerpt_id
-                        });
-                    buffer_highlights
-                        .next()
-                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
-                })?
-            };
-            if let Some(rename_range) = rename_range {
-                let rename_buffer_range = rename_range.to_offset(&snapshot);
-                let cursor_offset_in_rename_range =
-                    cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
-
-                this.update(&mut cx, |this, cx| {
-                    this.take_rename(false, cx);
-                    let style = this.style(cx);
-                    let buffer = this.buffer.read(cx).read(cx);
-                    let cursor_offset = selection.head().to_offset(&buffer);
-                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
-                    let rename_end = rename_start + rename_buffer_range.len();
-                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
-                    let mut old_highlight_id = None;
-                    let old_name: Arc<str> = buffer
-                        .chunks(rename_start..rename_end, true)
-                        .map(|chunk| {
-                            if old_highlight_id.is_none() {
-                                old_highlight_id = chunk.syntax_highlight_id;
-                            }
-                            chunk.text
-                        })
-                        .collect::<String>()
-                        .into();
-
-                    drop(buffer);
-
-                    // Position the selection in the rename editor so that it matches the current selection.
-                    this.show_local_selections = false;
-                    let rename_editor = cx.add_view(|cx| {
-                        let mut editor = Editor::single_line(None, cx);
-                        if let Some(old_highlight_id) = old_highlight_id {
-                            editor.override_text_style =
-                                Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
-                        }
-                        editor.buffer.update(cx, |buffer, cx| {
-                            buffer.edit([(0..0, old_name.clone())], None, cx)
-                        });
-                        editor.select_all(&SelectAll, cx);
-                        editor
-                    });
-
-                    let ranges = this
-                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
-                        .into_iter()
-                        .flat_map(|(_, ranges)| ranges.into_iter())
-                        .chain(
-                            this.clear_background_highlights::<DocumentHighlightRead>(cx)
-                                .into_iter()
-                                .flat_map(|(_, ranges)| ranges.into_iter()),
-                        )
-                        .collect();
-
-                    this.highlight_text::<Rename>(
-                        ranges,
-                        HighlightStyle {
-                            fade_out: Some(style.rename_fade),
-                            ..Default::default()
-                        },
-                        cx,
-                    );
-                    cx.focus(&rename_editor);
-                    let block_id = this.insert_blocks(
-                        [BlockProperties {
-                            style: BlockStyle::Flex,
-                            position: range.start.clone(),
-                            height: 1,
-                            render: Arc::new({
-                                let editor = rename_editor.clone();
-                                move |cx: &mut BlockContext| {
-                                    ChildView::new(&editor, cx)
-                                        .contained()
-                                        .with_padding_left(cx.anchor_x)
-                                        .into_any()
-                                }
-                            }),
-                            disposition: BlockDisposition::Below,
-                        }],
-                        Some(Autoscroll::fit()),
-                        cx,
-                    )[0];
-                    this.pending_rename = Some(RenameState {
-                        range,
-                        old_name,
-                        editor: rename_editor,
-                        block_id,
-                    });
-                })?;
-            }
-
-            Ok(())
-        }))
-    }
-
-    pub fn confirm_rename(
-        workspace: &mut Workspace,
-        _: &ConfirmRename,
-        cx: &mut ViewContext<Workspace>,
-    ) -> Option<Task<Result<()>>> {
-        let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
-
-        let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
-            let rename = editor.take_rename(false, cx)?;
-            let buffer = editor.buffer.read(cx);
-            let (start_buffer, start) =
-                buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
-            let (end_buffer, end) =
-                buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
-            if start_buffer == end_buffer {
-                let new_name = rename.editor.read(cx).text(cx);
-                Some((start_buffer, start..end, rename.old_name, new_name))
-            } else {
-                None
-            }
-        })?;
-
-        let rename = workspace.project().clone().update(cx, |project, cx| {
-            project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
-        });
-
-        let editor = editor.downgrade();
-        Some(cx.spawn(|workspace, mut cx| async move {
-            let project_transaction = rename.await?;
-            Self::open_project_transaction(
-                &editor,
-                workspace,
-                project_transaction,
-                format!("Rename: {} → {}", old_name, new_name),
-                cx.clone(),
-            )
-            .await?;
-
-            editor.update(&mut cx, |editor, cx| {
-                editor.refresh_document_highlights(cx);
-            })?;
-            Ok(())
-        }))
-    }
-
-    fn take_rename(
-        &mut self,
-        moving_cursor: bool,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<RenameState> {
-        let rename = self.pending_rename.take()?;
-        self.remove_blocks(
-            [rename.block_id].into_iter().collect(),
-            Some(Autoscroll::fit()),
-            cx,
-        );
-        self.clear_highlights::<Rename>(cx);
-        self.show_local_selections = true;
-
-        if moving_cursor {
-            let rename_editor = rename.editor.read(cx);
-            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
-
-            // Update the selection to match the position of the selection inside
-            // the rename editor.
-            let snapshot = self.buffer.read(cx).read(cx);
-            let rename_range = rename.range.to_offset(&snapshot);
-            let cursor_in_editor = snapshot
-                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
-                .min(rename_range.end);
-            drop(snapshot);
-
-            self.change_selections(None, cx, |s| {
-                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
-            });
-        } else {
-            self.refresh_document_highlights(cx);
-        }
-
-        Some(rename)
-    }
-
-    #[cfg(any(test, feature = "test-support"))]
-    pub fn pending_rename(&self) -> Option<&RenameState> {
-        self.pending_rename.as_ref()
-    }
-
-    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
-        let project = match &self.project {
-            Some(project) => project.clone(),
-            None => return None,
-        };
-
-        Some(self.perform_format(project, FormatTrigger::Manual, cx))
-    }
-
-    fn perform_format(
-        &mut self,
-        project: ModelHandle<Project>,
-        trigger: FormatTrigger,
-        cx: &mut ViewContext<Self>,
-    ) -> Task<Result<()>> {
-        let buffer = self.buffer().clone();
-        let buffers = buffer.read(cx).all_buffers();
-
-        let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
-        let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
-
-        cx.spawn(|_, mut cx| async move {
-            let transaction = futures::select_biased! {
-                _ = timeout => {
-                    log::warn!("timed out waiting for formatting");
-                    None
-                }
-                transaction = format.log_err().fuse() => transaction,
-            };
-
-            buffer.update(&mut cx, |buffer, cx| {
-                if let Some(transaction) = transaction {
-                    if !buffer.is_singleton() {
-                        buffer.push_transaction(&transaction.0, cx);
-                    }
-                }
-
-                cx.notify();
-            });
-
-            Ok(())
-        })
-    }
-
-    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
-        if let Some(project) = self.project.clone() {
-            self.buffer.update(cx, |multi_buffer, cx| {
-                project.update(cx, |project, cx| {
-                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
-                });
-            })
-        }
-    }
-
-    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
-        cx.show_character_palette();
-    }
-
-    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
-        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
-            let buffer = self.buffer.read(cx).snapshot(cx);
-            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
-            let is_valid = buffer
-                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
-                .any(|entry| {
-                    entry.diagnostic.is_primary
-                        && !entry.range.is_empty()
-                        && entry.range.start == primary_range_start
-                        && entry.diagnostic.message == active_diagnostics.primary_message
-                });
-
-            if is_valid != active_diagnostics.is_valid {
-                active_diagnostics.is_valid = is_valid;
-                let mut new_styles = HashMap::default();
-                for (block_id, diagnostic) in &active_diagnostics.blocks {
-                    new_styles.insert(
-                        *block_id,
-                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
-                    );
-                }
-                self.display_map
-                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
-            }
-        }
-    }
-
-    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
-        self.dismiss_diagnostics(cx);
-        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
-            let buffer = self.buffer.read(cx).snapshot(cx);
-
-            let mut primary_range = None;
-            let mut primary_message = None;
-            let mut group_end = Point::zero();
-            let diagnostic_group = buffer
-                .diagnostic_group::<Point>(group_id)
-                .map(|entry| {
-                    if entry.range.end > group_end {
-                        group_end = entry.range.end;
-                    }
-                    if entry.diagnostic.is_primary {
-                        primary_range = Some(entry.range.clone());
-                        primary_message = Some(entry.diagnostic.message.clone());
-                    }
-                    entry
-                })
-                .collect::<Vec<_>>();
-            let primary_range = primary_range?;
-            let primary_message = primary_message?;
-            let primary_range =
-                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
-
-            let blocks = display_map
-                .insert_blocks(
-                    diagnostic_group.iter().map(|entry| {
-                        let diagnostic = entry.diagnostic.clone();
-                        let message_height = diagnostic.message.lines().count() as u8;
-                        BlockProperties {
-                            style: BlockStyle::Fixed,
-                            position: buffer.anchor_after(entry.range.start),
-                            height: message_height,
-                            render: diagnostic_block_renderer(diagnostic, true),
-                            disposition: BlockDisposition::Below,
-                        }
-                    }),
-                    cx,
-                )
-                .into_iter()
-                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
-                .collect();
-
-            Some(ActiveDiagnosticGroup {
-                primary_range,
-                primary_message,
-                blocks,
-                is_valid: true,
-            })
-        });
-        self.active_diagnostics.is_some()
-    }
-
-    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
-        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
-            self.display_map.update(cx, |display_map, cx| {
-                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
-            });
-            cx.notify();
-        }
-    }
-
-    pub fn set_selections_from_remote(
-        &mut self,
-        selections: Vec<Selection<Anchor>>,
-        pending_selection: Option<Selection<Anchor>>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let old_cursor_position = self.selections.newest_anchor().head();
-        self.selections.change_with(cx, |s| {
-            s.select_anchors(selections);
-            if let Some(pending_selection) = pending_selection {
-                s.set_pending(pending_selection, SelectMode::Character);
-            } else {
-                s.clear_pending();
-            }
-        });
-        self.selections_did_change(false, &old_cursor_position, cx);
-    }
-
-    fn push_to_selection_history(&mut self) {
-        self.selection_history.push(SelectionHistoryEntry {
-            selections: self.selections.disjoint_anchors(),
-            select_next_state: self.select_next_state.clone(),
-            select_prev_state: self.select_prev_state.clone(),
-            add_selections_state: self.add_selections_state.clone(),
-        });
-    }
-
-    pub fn transact(
-        &mut self,
-        cx: &mut ViewContext<Self>,
-        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
-    ) -> Option<TransactionId> {
-        self.start_transaction_at(Instant::now(), cx);
-        update(self, cx);
-        self.end_transaction_at(Instant::now(), cx)
-    }
-
-    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
-        self.end_selection(cx);
-        if let Some(tx_id) = self
-            .buffer
-            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
-        {
-            self.selection_history
-                .insert_transaction(tx_id, self.selections.disjoint_anchors());
-        }
-    }
-
-    fn end_transaction_at(
-        &mut self,
-        now: Instant,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<TransactionId> {
-        if let Some(tx_id) = self
-            .buffer
-            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
-        {
-            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
-                *end_selections = Some(self.selections.disjoint_anchors());
-            } else {
-                error!("unexpectedly ended a transaction that wasn't started by this editor");
-            }
-
-            cx.emit(Event::Edited);
-            Some(tx_id)
-        } else {
-            None
-        }
-    }
-
-    pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
-        let mut fold_ranges = Vec::new();
-
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-
-        let selections = self.selections.all_adjusted(cx);
-        for selection in selections {
-            let range = selection.range().sorted();
-            let buffer_start_row = range.start.row;
-
-            for row in (0..=range.end.row).rev() {
-                let fold_range = display_map.foldable_range(row);
-
-                if let Some(fold_range) = fold_range {
-                    if fold_range.end.row >= buffer_start_row {
-                        fold_ranges.push(fold_range);
-                        if row <= range.start.row {
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        self.fold_ranges(fold_ranges, true, cx);
-    }
-
-    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
-        let buffer_row = fold_at.buffer_row;
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-
-        if let Some(fold_range) = display_map.foldable_range(buffer_row) {
-            let autoscroll = self
-                .selections
-                .all::<Point>(cx)
-                .iter()
-                .any(|selection| fold_range.overlaps(&selection.range()));
-
-            self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
-        }
-    }
-
-    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = &display_map.buffer_snapshot;
-        let selections = self.selections.all::<Point>(cx);
-        let ranges = selections
-            .iter()
-            .map(|s| {
-                let range = s.display_range(&display_map).sorted();
-                let mut start = range.start.to_point(&display_map);
-                let mut end = range.end.to_point(&display_map);
-                start.column = 0;
-                end.column = buffer.line_len(end.row);
-                start..end
-            })
-            .collect::<Vec<_>>();
-
-        self.unfold_ranges(ranges, true, true, cx);
-    }
-
-    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-
-        let intersection_range = Point::new(unfold_at.buffer_row, 0)
-            ..Point::new(
-                unfold_at.buffer_row,
-                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
-            );
-
-        let autoscroll = self
-            .selections
-            .all::<Point>(cx)
-            .iter()
-            .any(|selection| selection.range().overlaps(&intersection_range));
-
-        self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
-    }
-
-    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
-        let selections = self.selections.all::<Point>(cx);
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let line_mode = self.selections.line_mode;
-        let ranges = selections.into_iter().map(|s| {
-            if line_mode {
-                let start = Point::new(s.start.row, 0);
-                let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
-                start..end
-            } else {
-                s.start..s.end
-            }
-        });
-        self.fold_ranges(ranges, true, cx);
-    }
-
-    pub fn fold_ranges<T: ToOffset + Clone>(
-        &mut self,
-        ranges: impl IntoIterator<Item = Range<T>>,
-        auto_scroll: bool,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let mut ranges = ranges.into_iter().peekable();
-        if ranges.peek().is_some() {
-            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
-
-            if auto_scroll {
-                self.request_autoscroll(Autoscroll::fit(), cx);
-            }
-
-            cx.notify();
-        }
-    }
-
-    pub fn unfold_ranges<T: ToOffset + Clone>(
-        &mut self,
-        ranges: impl IntoIterator<Item = Range<T>>,
-        inclusive: bool,
-        auto_scroll: bool,
-        cx: &mut ViewContext<Self>,
-    ) {
-        let mut ranges = ranges.into_iter().peekable();
-        if ranges.peek().is_some() {
-            self.display_map
-                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
-            if auto_scroll {
-                self.request_autoscroll(Autoscroll::fit(), cx);
-            }
-
-            cx.notify();
-        }
-    }
-
-    pub fn gutter_hover(
-        &mut self,
-        GutterHover { hovered }: &GutterHover,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.gutter_hovered = *hovered;
-        cx.notify();
-    }
-
-    pub fn insert_blocks(
-        &mut self,
-        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
-        autoscroll: Option<Autoscroll>,
-        cx: &mut ViewContext<Self>,
-    ) -> Vec<BlockId> {
-        let blocks = self
-            .display_map
-            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
-        if let Some(autoscroll) = autoscroll {
-            self.request_autoscroll(autoscroll, cx);
-        }
-        blocks
-    }
-
-    pub fn replace_blocks(
-        &mut self,
-        blocks: HashMap<BlockId, RenderBlock>,
-        autoscroll: Option<Autoscroll>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.display_map
-            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
-        if let Some(autoscroll) = autoscroll {
-            self.request_autoscroll(autoscroll, cx);
-        }
-    }
-
-    pub fn remove_blocks(
-        &mut self,
-        block_ids: HashSet<BlockId>,
-        autoscroll: Option<Autoscroll>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.display_map.update(cx, |display_map, cx| {
-            display_map.remove_blocks(block_ids, cx)
-        });
-        if let Some(autoscroll) = autoscroll {
-            self.request_autoscroll(autoscroll, cx);
-        }
-    }
-
-    pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
-        self.display_map
-            .update(cx, |map, cx| map.snapshot(cx))
-            .longest_row()
-    }
-
-    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
-        self.display_map
-            .update(cx, |map, cx| map.snapshot(cx))
-            .max_point()
-    }
-
-    pub fn text(&self, cx: &AppContext) -> String {
-        self.buffer.read(cx).read(cx).text()
-    }
-
-    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
-        self.transact(cx, |this, cx| {
-            this.buffer
-                .read(cx)
-                .as_singleton()
-                .expect("you can only call set_text on editors for singleton buffers")
-                .update(cx, |buffer, cx| buffer.set_text(text, cx));
-        });
-    }
-
-    pub fn display_text(&self, cx: &mut AppContext) -> String {
-        self.display_map
-            .update(cx, |map, cx| map.snapshot(cx))
-            .text()
-    }
-
-    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
-        let mut wrap_guides = smallvec::smallvec![];
-
-        if self.show_wrap_guides == Some(false) {
-            return wrap_guides;
-        }
-
-        let settings = self.buffer.read(cx).settings_at(0, cx);
-        if settings.show_wrap_guides {
-            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
-                wrap_guides.push((soft_wrap as usize, true));
-            }
-            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
-        }
-
-        wrap_guides
-    }
-
-    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
-        let settings = self.buffer.read(cx).settings_at(0, cx);
-        let mode = self
-            .soft_wrap_mode_override
-            .unwrap_or_else(|| settings.soft_wrap);
-        match mode {
-            language_settings::SoftWrap::None => SoftWrap::None,
-            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
-            language_settings::SoftWrap::PreferredLineLength => {
-                SoftWrap::Column(settings.preferred_line_length)
-            }
-        }
-    }
-
-    pub fn set_soft_wrap_mode(
-        &mut self,
-        mode: language_settings::SoftWrap,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.soft_wrap_mode_override = Some(mode);
-        cx.notify();
-    }
-
-    pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut AppContext) -> bool {
-        self.display_map
-            .update(cx, |map, cx| map.set_wrap_width(width, cx))
-    }
-
-    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
-        if self.soft_wrap_mode_override.is_some() {
-            self.soft_wrap_mode_override.take();
-        } else {
-            let soft_wrap = match self.soft_wrap_mode(cx) {
-                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
-                SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None,
-            };
-            self.soft_wrap_mode_override = Some(soft_wrap);
-        }
-        cx.notify();
-    }
-
-    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
-        self.show_gutter = show_gutter;
-        cx.notify();
-    }
-
-    pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
-        self.show_wrap_guides = Some(show_gutter);
-        cx.notify();
-    }
-
-    pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
-        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
-            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
-                cx.reveal_path(&file.abs_path(cx));
-            }
-        }
-    }
-
-    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
-        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
-            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
-                if let Some(path) = file.abs_path(cx).to_str() {
-                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
-                }
-            }
-        }
-    }
-
-    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
-        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
-            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
-                if let Some(path) = file.path().to_str() {
-                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
-                }
-            }
-        }
-    }
-
-    pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
-        self.highlighted_rows = rows;
-    }
-
-    pub fn highlighted_rows(&self) -> Option<Range<u32>> {
-        self.highlighted_rows.clone()
-    }
-
-    pub fn highlight_background<T: 'static>(
-        &mut self,
-        ranges: Vec<Range<Anchor>>,
-        color_fetcher: fn(&Theme) -> Color,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.background_highlights
-            .insert(TypeId::of::<T>(), (color_fetcher, ranges));
-        cx.notify();
-    }
-
-    pub fn highlight_inlay_background<T: 'static>(
-        &mut self,
-        ranges: Vec<InlayHighlight>,
-        color_fetcher: fn(&Theme) -> Color,
-        cx: &mut ViewContext<Self>,
-    ) {
-        // TODO: no actual highlights happen for inlays currently, find a way to do that
-        self.inlay_background_highlights
-            .insert(Some(TypeId::of::<T>()), (color_fetcher, ranges));
-        cx.notify();
-    }
-
-    pub fn clear_background_highlights<T: 'static>(
-        &mut self,
-        cx: &mut ViewContext<Self>,
-    ) -> Option<BackgroundHighlight> {
-        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>());
-        let inlay_highlights = self
-            .inlay_background_highlights
-            .remove(&Some(TypeId::of::<T>()));
-        if text_highlights.is_some() || inlay_highlights.is_some() {
-            cx.notify();
-        }
-        text_highlights
-    }
-
-    #[cfg(feature = "test-support")]
-    pub fn all_text_background_highlights(
-        &mut self,
-        cx: &mut ViewContext<Self>,
-    ) -> Vec<(Range<DisplayPoint>, Color)> {
-        let snapshot = self.snapshot(cx);
-        let buffer = &snapshot.buffer_snapshot;
-        let start = buffer.anchor_before(0);
-        let end = buffer.anchor_after(buffer.len());
-        let theme = theme::current(cx);
-        self.background_highlights_in_range(start..end, &snapshot, theme.as_ref())
-    }
-
-    fn document_highlights_for_position<'a>(
-        &'a self,
-        position: Anchor,
-        buffer: &'a MultiBufferSnapshot,
-    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
-        let read_highlights = self
-            .background_highlights
-            .get(&TypeId::of::<DocumentHighlightRead>())
-            .map(|h| &h.1);
-        let write_highlights = self
-            .background_highlights
-            .get(&TypeId::of::<DocumentHighlightWrite>())
-            .map(|h| &h.1);
-        let left_position = position.bias_left(buffer);
-        let right_position = position.bias_right(buffer);
-        read_highlights
-            .into_iter()
-            .chain(write_highlights)
-            .flat_map(move |ranges| {
-                let start_ix = match ranges.binary_search_by(|probe| {
-                    let cmp = probe.end.cmp(&left_position, buffer);
-                    if cmp.is_ge() {
-                        Ordering::Greater
-                    } else {
-                        Ordering::Less
-                    }
-                }) {
-                    Ok(i) | Err(i) => i,
-                };
-
-                let right_position = right_position.clone();
-                ranges[start_ix..]
-                    .iter()
-                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
-            })
-    }
-
-    pub fn background_highlights_in_range(
-        &self,
-        search_range: Range<Anchor>,
-        display_snapshot: &DisplaySnapshot,
-        theme: &Theme,
-    ) -> Vec<(Range<DisplayPoint>, Color)> {
-        let mut results = Vec::new();
-        for (color_fetcher, ranges) in self.background_highlights.values() {
-            let color = color_fetcher(theme);
-            let start_ix = match ranges.binary_search_by(|probe| {
-                let cmp = probe
-                    .end
-                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
-                if cmp.is_gt() {
-                    Ordering::Greater
-                } else {
-                    Ordering::Less
-                }
-            }) {
-                Ok(i) | Err(i) => i,
-            };
-            for range in &ranges[start_ix..] {
-                if range
-                    .start
-                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
-                    .is_ge()
-                {
-                    break;
-                }
-
-                let start = range.start.to_display_point(&display_snapshot);
-                let end = range.end.to_display_point(&display_snapshot);
-                results.push((start..end, color))
-            }
-        }
-        results
-    }
-
-    pub fn background_highlight_row_ranges<T: 'static>(
-        &self,
-        search_range: Range<Anchor>,
-        display_snapshot: &DisplaySnapshot,
-        count: usize,
-    ) -> Vec<RangeInclusive<DisplayPoint>> {
-        let mut results = Vec::new();
-        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
-            return vec![];
-        };
-
-        let start_ix = match ranges.binary_search_by(|probe| {
-            let cmp = probe
-                .end
-                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
-            if cmp.is_gt() {
-                Ordering::Greater
-            } else {
-                Ordering::Less
-            }
-        }) {
-            Ok(i) | Err(i) => i,
-        };
-        let mut push_region = |start: Option<Point>, end: Option<Point>| {
-            if let (Some(start_display), Some(end_display)) = (start, end) {
-                results.push(
-                    start_display.to_display_point(display_snapshot)
-                        ..=end_display.to_display_point(display_snapshot),
-                );
-            }
-        };
-        let mut start_row: Option<Point> = None;
-        let mut end_row: Option<Point> = None;
-        if ranges.len() > count {
-            return Vec::new();
-        }
-        for range in &ranges[start_ix..] {
-            if range
-                .start
-                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
-                .is_ge()
-            {
-                break;
-            }
-            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
-            if let Some(current_row) = &end_row {
-                if end.row == current_row.row {
-                    continue;
-                }
-            }
-            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
-            if start_row.is_none() {
-                assert_eq!(end_row, None);
-                start_row = Some(start);
-                end_row = Some(end);
-                continue;
-            }
-            if let Some(current_end) = end_row.as_mut() {
-                if start.row > current_end.row + 1 {
-                    push_region(start_row, end_row);
-                    start_row = Some(start);
-                    end_row = Some(end);
-                } else {
-                    // Merge two hunks.
-                    *current_end = end;
-                }
-            } else {
-                unreachable!();
-            }
-        }
-        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
-        push_region(start_row, end_row);
-        results
-    }
-
-    pub fn highlight_text<T: 'static>(
-        &mut self,
-        ranges: Vec<Range<Anchor>>,
-        style: HighlightStyle,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.display_map.update(cx, |map, _| {
-            map.highlight_text(TypeId::of::<T>(), ranges, style)
-        });
-        cx.notify();
-    }
-
-    pub fn highlight_inlays<T: 'static>(
-        &mut self,
-        highlights: Vec<InlayHighlight>,
-        style: HighlightStyle,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.display_map.update(cx, |map, _| {
-            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
-        });
-        cx.notify();
-    }
-
-    pub fn text_highlights<'a, T: 'static>(
-        &'a self,
-        cx: &'a AppContext,
-    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
-        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
-    }
-
-    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
-        let cleared = self
-            .display_map
-            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
-        if cleared {
-            cx.notify();
-        }
-    }
-
-    pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
-        self.blink_manager.read(cx).visible() && self.focused
-    }
-
-    fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
-        cx.notify();
-    }
-
-    fn on_buffer_event(
-        &mut self,
-        multibuffer: ModelHandle<MultiBuffer>,
-        event: &multi_buffer::Event,
-        cx: &mut ViewContext<Self>,
-    ) {
-        match event {
-            multi_buffer::Event::Edited {
-                sigleton_buffer_edited,
-            } => {
-                self.refresh_active_diagnostics(cx);
-                self.refresh_code_actions(cx);
-                if self.has_active_copilot_suggestion(cx) {
-                    self.update_visible_copilot_suggestion(cx);
-                }
-                cx.emit(Event::BufferEdited);
-
-                if *sigleton_buffer_edited {
-                    if let Some(project) = &self.project {
-                        let project = project.read(cx);
-                        let languages_affected = multibuffer
-                            .read(cx)
-                            .all_buffers()
-                            .into_iter()
-                            .filter_map(|buffer| {
-                                let buffer = buffer.read(cx);
-                                let language = buffer.language()?;
-                                if project.is_local()
-                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
-                                {
-                                    None
-                                } else {
-                                    Some(language)
-                                }
-                            })
-                            .cloned()
-                            .collect::<HashSet<_>>();
-                        if !languages_affected.is_empty() {
-                            self.refresh_inlay_hints(
-                                InlayHintRefreshReason::BufferEdited(languages_affected),
-                                cx,
-                            );
-                        }
-                    }
-                }
-            }
-            multi_buffer::Event::ExcerptsAdded {
-                buffer,
-                predecessor,
-                excerpts,
-            } => {
-                cx.emit(Event::ExcerptsAdded {
-                    buffer: buffer.clone(),
-                    predecessor: *predecessor,
-                    excerpts: excerpts.clone(),
-                });
-                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
-            }
-            multi_buffer::Event::ExcerptsRemoved { ids } => {
-                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
-                cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
-            }
-            multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
-            multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
-            multi_buffer::Event::Saved => cx.emit(Event::Saved),
-            multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
-            multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
-            multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged),
-            multi_buffer::Event::Closed => cx.emit(Event::Closed),
-            multi_buffer::Event::DiagnosticsUpdated => {
-                self.refresh_active_diagnostics(cx);
-            }
-            _ => {}
-        };
-    }
-
-    fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
-        cx.notify();
-    }
-
-    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
-        self.refresh_copilot_suggestions(true, cx);
-        self.refresh_inlay_hints(
-            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
-                self.selections.newest_anchor().head(),
-                &self.buffer.read(cx).snapshot(cx),
-                cx,
-            )),
-            cx,
-        );
-    }
-
-    pub fn set_searchable(&mut self, searchable: bool) {
-        self.searchable = searchable;
-    }
-
-    pub fn searchable(&self) -> bool {
-        self.searchable
-    }
-
-    fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
-        let active_item = workspace.active_item(cx);
-        let editor_handle = if let Some(editor) = active_item
-            .as_ref()
-            .and_then(|item| item.act_as::<Self>(cx))
-        {
-            editor
-        } else {
-            cx.propagate_action();
-            return;
-        };
-
-        let editor = editor_handle.read(cx);
-        let buffer = editor.buffer.read(cx);
-        if buffer.is_singleton() {
-            cx.propagate_action();
-            return;
-        }
-
-        let mut new_selections_by_buffer = HashMap::default();
-        for selection in editor.selections.all::<usize>(cx) {
-            for (buffer, mut range, _) in
-                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
-            {
-                if selection.reversed {
-                    mem::swap(&mut range.start, &mut range.end);
-                }
-                new_selections_by_buffer
-                    .entry(buffer)
-                    .or_insert(Vec::new())
-                    .push(range)
-            }
-        }
-
-        editor_handle.update(cx, |editor, cx| {
-            editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
-        });
-        let pane = workspace.active_pane().clone();
-        pane.update(cx, |pane, _| pane.disable_history());
-
-        // We defer the pane interaction because we ourselves are a workspace item
-        // and activating a new item causes the pane to call a method on us reentrantly,
-        // which panics if we're on the stack.
-        cx.defer(move |workspace, cx| {
-            for (buffer, ranges) in new_selections_by_buffer.into_iter() {
-                let editor = workspace.open_project_item::<Self>(buffer, cx);
-                editor.update(cx, |editor, cx| {
-                    editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
-                        s.select_ranges(ranges);
-                    });
-                });
-            }
-
-            pane.update(cx, |pane, _| pane.enable_history());
-        });
-    }
-
-    fn jump(
-        workspace: &mut Workspace,
-        path: ProjectPath,
-        position: Point,
-        anchor: language::Anchor,
-        cx: &mut ViewContext<Workspace>,
-    ) {
-        let editor = workspace.open_path(path, None, true, cx);
-        cx.spawn(|_, mut cx| async move {
-            let editor = editor
-                .await?
-                .downcast::<Editor>()
-                .ok_or_else(|| anyhow!("opened item was not an editor"))?
-                .downgrade();
-            editor.update(&mut cx, |editor, cx| {
-                let buffer = editor
-                    .buffer()
-                    .read(cx)
-                    .as_singleton()
-                    .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
-                let buffer = buffer.read(cx);
-                let cursor = if buffer.can_resolve(&anchor) {
-                    language::ToPoint::to_point(&anchor, buffer)
-                } else {
-                    buffer.clip_point(position, Bias::Left)
-                };
-
-                let nav_history = editor.nav_history.take();
-                editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
-                    s.select_ranges([cursor..cursor]);
-                });
-                editor.nav_history = nav_history;
-
-                anyhow::Ok(())
-            })??;
-
-            anyhow::Ok(())
-        })
-        .detach_and_log_err(cx);
-    }
-
-    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
-        let snapshot = self.buffer.read(cx).read(cx);
-        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
-        Some(
-            ranges
-                .iter()
-                .map(move |range| {
-                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
-                })
-                .collect(),
-        )
-    }
-
-    fn selection_replacement_ranges(
-        &self,
-        range: Range<OffsetUtf16>,
-        cx: &AppContext,
-    ) -> Vec<Range<OffsetUtf16>> {
-        let selections = self.selections.all::<OffsetUtf16>(cx);
-        let newest_selection = selections
-            .iter()
-            .max_by_key(|selection| selection.id)
-            .unwrap();
-        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
-        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
-        let snapshot = self.buffer.read(cx).read(cx);
-        selections
-            .into_iter()
-            .map(|mut selection| {
-                selection.start.0 =
-                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
-                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
-                snapshot.clip_offset_utf16(selection.start, Bias::Left)
-                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
-            })
-            .collect()
-    }
-
-    fn report_copilot_event(
-        &self,
-        suggestion_id: Option<String>,
-        suggestion_accepted: bool,
-        cx: &AppContext,
-    ) {
-        let Some(project) = &self.project else { return };
-
-        // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension
-        let file_extension = self
-            .buffer
-            .read(cx)
-            .as_singleton()
-            .and_then(|b| b.read(cx).file())
-            .and_then(|file| Path::new(file.file_name(cx)).extension())
-            .and_then(|e| e.to_str())
-            .map(|a| a.to_string());
-
-        let telemetry = project.read(cx).client().telemetry().clone();
-        let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
-
-        let event = ClickhouseEvent::Copilot {
-            suggestion_id,
-            suggestion_accepted,
-            file_extension,
-        };
-        telemetry.report_clickhouse_event(event, telemetry_settings);
-    }
-
-    #[cfg(any(test, feature = "test-support"))]
-    fn report_editor_event(
-        &self,
-        _operation: &'static str,
-        _file_extension: Option<String>,
-        _cx: &AppContext,
-    ) {
-    }
-
-    #[cfg(not(any(test, feature = "test-support")))]
-    fn report_editor_event(
-        &self,
-        operation: &'static str,
-        file_extension: Option<String>,
-        cx: &AppContext,
-    ) {
-        let Some(project) = &self.project else { return };
-
-        // If None, we are in a file without an extension
-        let file = self
-            .buffer
-            .read(cx)
-            .as_singleton()
-            .and_then(|b| b.read(cx).file());
-        let file_extension = file_extension.or(file
-            .as_ref()
-            .and_then(|file| Path::new(file.file_name(cx)).extension())
-            .and_then(|e| e.to_str())
-            .map(|a| a.to_string()));
-
-        let vim_mode = cx
-            .global::<SettingsStore>()
-            .raw_user_settings()
-            .get("vim_mode")
-            == Some(&serde_json::Value::Bool(true));
-        let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
-        let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None);
-        let copilot_enabled_for_language = self
-            .buffer
-            .read(cx)
-            .settings_at(0, cx)
-            .show_copilot_suggestions;
-
-        let telemetry = project.read(cx).client().telemetry().clone();
-        let event = ClickhouseEvent::Editor {
-            file_extension,
-            vim_mode,
-            operation,
-            copilot_enabled,
-            copilot_enabled_for_language,
-        };
-        telemetry.report_clickhouse_event(event, telemetry_settings)
-    }
-
-    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
-    /// with each line being an array of {text, highlight} objects.
-    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
-        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
-            return;
-        };
-
-        #[derive(Serialize)]
-        struct Chunk<'a> {
-            text: String,
-            highlight: Option<&'a str>,
-        }
-
-        let snapshot = buffer.read(cx).snapshot();
-        let range = self
-            .selected_text_range(cx)
-            .and_then(|selected_range| {
-                if selected_range.is_empty() {
-                    None
-                } else {
-                    Some(selected_range)
-                }
-            })
-            .unwrap_or_else(|| 0..snapshot.len());
-
-        let chunks = snapshot.chunks(range, true);
-        let mut lines = Vec::new();
-        let mut line: VecDeque<Chunk> = VecDeque::new();
-
-        let theme = &theme::current(cx).editor.syntax;
-
-        for chunk in chunks {
-            let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme));
-            let mut chunk_lines = chunk.text.split("\n").peekable();
-            while let Some(text) = chunk_lines.next() {
-                let mut merged_with_last_token = false;
-                if let Some(last_token) = line.back_mut() {
-                    if last_token.highlight == highlight {
-                        last_token.text.push_str(text);
-                        merged_with_last_token = true;
-                    }
-                }
-
-                if !merged_with_last_token {
-                    line.push_back(Chunk {
-                        text: text.into(),
-                        highlight,
-                    });
-                }
-
-                if chunk_lines.peek().is_some() {
-                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
-                        line.pop_front();
-                    }
-                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
-                        line.pop_back();
-                    }
-
-                    lines.push(mem::take(&mut line));
-                }
-            }
-        }
-
-        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
-            return;
-        };
-        cx.write_to_clipboard(ClipboardItem::new(lines));
-    }
-
-    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
-        &self.inlay_hint_cache
-    }
-
-    pub fn replay_insert_event(
-        &mut self,
-        text: &str,
-        relative_utf16_range: Option<Range<isize>>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if !self.input_enabled {
-            cx.emit(Event::InputIgnored { text: text.into() });
-            return;
-        }
-        if let Some(relative_utf16_range) = relative_utf16_range {
-            let selections = self.selections.all::<OffsetUtf16>(cx);
-            self.change_selections(None, cx, |s| {
-                let new_ranges = selections.into_iter().map(|range| {
-                    let start = OffsetUtf16(
-                        range
-                            .head()
-                            .0
-                            .saturating_add_signed(relative_utf16_range.start),
-                    );
-                    let end = OffsetUtf16(
-                        range
-                            .head()
-                            .0
-                            .saturating_add_signed(relative_utf16_range.end),
-                    );
-                    start..end
-                });
-                s.select_ranges(new_ranges);
-            });
-        }
-
-        self.handle_input(text, cx);
-    }
-
-    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
-        let Some(project) = self.project.as_ref() else {
-            return false;
-        };
-        let project = project.read(cx);
-
-        let mut supports = false;
-        self.buffer().read(cx).for_each_buffer(|buffer| {
-            if !supports {
-                supports = project
-                    .language_servers_for_buffer(buffer.read(cx), cx)
-                    .any(
-                        |(_, server)| match server.capabilities().inlay_hint_provider {
-                            Some(lsp::OneOf::Left(enabled)) => enabled,
-                            Some(lsp::OneOf::Right(_)) => true,
-                            None => false,
-                        },
-                    )
-            }
-        });
-        supports
-    }
-}
+// impl Editor {
+//     pub fn single_line(
+//         field_editor_style: Option<Arc<GetFieldEditorTheme>>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Self {
+//         let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
+//         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
+//         Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
+//     }
+
+//     pub fn multi_line(
+//         field_editor_style: Option<Arc<GetFieldEditorTheme>>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Self {
+//         let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
+//         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
+//         Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
+//     }
+
+//     pub fn auto_height(
+//         max_lines: usize,
+//         field_editor_style: Option<Arc<GetFieldEditorTheme>>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Self {
+//         let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
+//         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
+//         Self::new(
+//             EditorMode::AutoHeight { max_lines },
+//             buffer,
+//             None,
+//             field_editor_style,
+//             cx,
+//         )
+//     }
+
+//     pub fn for_buffer(
+//         buffer: Model<Buffer>,
+//         project: Option<Model<Project>>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Self {
+//         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
+//         Self::new(EditorMode::Full, buffer, project, None, cx)
+//     }
+
+//     pub fn for_multibuffer(
+//         buffer: Model<MultiBuffer>,
+//         project: Option<Model<Project>>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Self {
+//         Self::new(EditorMode::Full, buffer, project, None, cx)
+//     }
+
+//     pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
+//         let mut clone = Self::new(
+//             self.mode,
+//             self.buffer.clone(),
+//             self.project.clone(),
+//             self.get_field_editor_theme.clone(),
+//             cx,
+//         );
+//         self.display_map.update(cx, |display_map, cx| {
+//             let snapshot = display_map.snapshot(cx);
+//             clone.display_map.update(cx, |display_map, cx| {
+//                 display_map.set_state(&snapshot, cx);
+//             });
+//         });
+//         clone.selections.clone_state(&self.selections);
+//         clone.scroll_manager.clone_state(&self.scroll_manager);
+//         clone.searchable = self.searchable;
+//         clone
+//     }
+
+//     fn new(
+//         mode: EditorMode,
+//         buffer: Model<MultiBuffer>,
+//         project: Option<Model<Project>>,
+//         get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Self {
+//         let editor_view_id = cx.view_id();
+//         let display_map = cx.add_model(|cx| {
+//             let settings = settings::get::<ThemeSettings>(cx);
+//             let style = build_style(settings, get_field_editor_theme.as_deref(), None, cx);
+//             DisplayMap::new(
+//                 buffer.clone(),
+//                 style.text.font_id,
+//                 style.text.font_size,
+//                 None,
+//                 2,
+//                 1,
+//                 cx,
+//             )
+//         });
+
+//         let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
+
+//         let blink_manager = cx.add_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
+
+//         let soft_wrap_mode_override =
+//             (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
+
+//         let mut project_subscriptions = Vec::new();
+//         if mode == EditorMode::Full {
+//             if let Some(project) = project.as_ref() {
+//                 if buffer.read(cx).is_singleton() {
+//                     project_subscriptions.push(cx.observe(project, |_, _, cx| {
+//                         cx.emit(Event::TitleChanged);
+//                     }));
+//                 }
+//                 project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
+//                     if let project::Event::RefreshInlayHints = event {
+//                         editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
+//                     };
+//                 }));
+//             }
+//         }
+
+//         let inlay_hint_settings = inlay_hint_settings(
+//             selections.newest_anchor().head(),
+//             &buffer.read(cx).snapshot(cx),
+//             cx,
+//         );
+
+//         let mut this = Self {
+//             handle: cx.weak_handle(),
+//             buffer: buffer.clone(),
+//             display_map: display_map.clone(),
+//             selections,
+//             scroll_manager: ScrollManager::new(),
+//             columnar_selection_tail: None,
+//             add_selections_state: None,
+//             select_next_state: None,
+//             select_prev_state: None,
+//             selection_history: Default::default(),
+//             autoclose_regions: Default::default(),
+//             snippet_stack: Default::default(),
+//             select_larger_syntax_node_stack: Vec::new(),
+//             ime_transaction: Default::default(),
+//             active_diagnostics: None,
+//             soft_wrap_mode_override,
+//             get_field_editor_theme,
+//             collaboration_hub: project.clone().map(|project| Box::new(project) as _),
+//             project,
+//             focused: false,
+//             blink_manager: blink_manager.clone(),
+//             show_local_selections: true,
+//             mode,
+//             show_gutter: mode == EditorMode::Full,
+//             show_wrap_guides: None,
+//             placeholder_text: None,
+//             highlighted_rows: None,
+//             background_highlights: Default::default(),
+//             inlay_background_highlights: Default::default(),
+//             nav_history: None,
+//             context_menu: RwLock::new(None),
+//             mouse_context_menu: cx
+//                 .add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)),
+//             completion_tasks: Default::default(),
+//             next_completion_id: 0,
+//             next_inlay_id: 0,
+//             available_code_actions: Default::default(),
+//             code_actions_task: Default::default(),
+//             document_highlights_task: Default::default(),
+//             pending_rename: Default::default(),
+//             searchable: true,
+//             override_text_style: None,
+//             cursor_shape: Default::default(),
+//             autoindent_mode: Some(AutoindentMode::EachLine),
+//             collapse_matches: false,
+//             workspace: None,
+//             keymap_context_layers: Default::default(),
+//             input_enabled: true,
+//             read_only: false,
+//             leader_peer_id: None,
+//             remote_id: None,
+//             hover_state: Default::default(),
+//             link_go_to_definition_state: Default::default(),
+//             copilot_state: Default::default(),
+//             // inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
+//             gutter_hovered: false,
+//             pixel_position_of_newest_cursor: None,
+//             _subscriptions: vec![
+//                 cx.observe(&buffer, Self::on_buffer_changed),
+//                 cx.subscribe(&buffer, Self::on_buffer_event),
+//                 cx.observe(&display_map, Self::on_display_map_changed),
+//                 cx.observe(&blink_manager, |_, _, cx| cx.notify()),
+//                 cx.observe_global::<SettingsStore, _>(Self::settings_changed),
+//                 cx.observe_window_activation(|editor, active, cx| {
+//                     editor.blink_manager.update(cx, |blink_manager, cx| {
+//                         if active {
+//                             blink_manager.enable(cx);
+//                         } else {
+//                             blink_manager.show_cursor(cx);
+//                             blink_manager.disable(cx);
+//                         }
+//                     });
+//                 }),
+//             ],
+//         };
+
+//         this._subscriptions.extend(project_subscriptions);
+
+//         this.end_selection(cx);
+//         this.scroll_manager.show_scrollbar(cx);
+
+//         let editor_created_event = EditorCreated(cx.handle());
+//         cx.emit_global(editor_created_event);
+
+//         if mode == EditorMode::Full {
+//             let should_auto_hide_scrollbars = cx.platform().should_auto_hide_scrollbars();
+//             cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
+//         }
+
+//         this.report_editor_event("open", None, cx);
+//         this
+//     }
+
+//     pub fn new_file(
+//         workspace: &mut Workspace,
+//         _: &workspace::NewFile,
+//         cx: &mut ViewContext<Workspace>,
+//     ) {
+//         let project = workspace.project().clone();
+//         if project.read(cx).is_remote() {
+//             cx.propagate_action();
+//         } else if let Some(buffer) = project
+//             .update(cx, |project, cx| project.create_buffer("", None, cx))
+//             .log_err()
+//         {
+//             workspace.add_item(
+//                 Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
+//                 cx,
+//             );
+//         }
+//     }
+
+//     pub fn new_file_in_direction(
+//         workspace: &mut Workspace,
+//         action: &workspace::NewFileInDirection,
+//         cx: &mut ViewContext<Workspace>,
+//     ) {
+//         let project = workspace.project().clone();
+//         if project.read(cx).is_remote() {
+//             cx.propagate_action();
+//         } else if let Some(buffer) = project
+//             .update(cx, |project, cx| project.create_buffer("", None, cx))
+//             .log_err()
+//         {
+//             workspace.split_item(
+//                 action.0,
+//                 Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
+//                 cx,
+//             );
+//         }
+//     }
+
+//     pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
+//         self.buffer.read(cx).replica_id()
+//     }
+
+//     pub fn leader_peer_id(&self) -> Option<PeerId> {
+//         self.leader_peer_id
+//     }
+
+//     pub fn buffer(&self) -> &Model<MultiBuffer> {
+//         &self.buffer
+//     }
+
+//     fn workspace(&self, cx: &AppContext) -> Option<ViewHandle<Workspace>> {
+//         self.workspace.as_ref()?.0.upgrade(cx)
+//     }
+
+//     pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
+//         self.buffer().read(cx).title(cx)
+//     }
+
+//     pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
+//         EditorSnapshot {
+//             mode: self.mode,
+//             show_gutter: self.show_gutter,
+//             display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
+//             scroll_anchor: self.scroll_manager.anchor(),
+//             ongoing_scroll: self.scroll_manager.ongoing_scroll(),
+//             placeholder_text: self.placeholder_text.clone(),
+//             is_focused: self
+//                 .handle
+//                 .upgrade(cx)
+//                 .map_or(false, |handle| handle.is_focused(cx)),
+//         }
+//     }
+
+//     pub fn language_at<'a, T: ToOffset>(
+//         &self,
+//         point: T,
+//         cx: &'a AppContext,
+//     ) -> Option<Arc<Language>> {
+//         self.buffer.read(cx).language_at(point, cx)
+//     }
+
+//     pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option<Arc<dyn File>> {
+//         self.buffer.read(cx).read(cx).file_at(point).cloned()
+//     }
+
+//     pub fn active_excerpt(
+//         &self,
+//         cx: &AppContext,
+//     ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
+//         self.buffer
+//             .read(cx)
+//             .excerpt_containing(self.selections.newest_anchor().head(), cx)
+//     }
+
+//     pub fn style(&self, cx: &AppContext) -> EditorStyle {
+//         build_style(
+//             settings::get::<ThemeSettings>(cx),
+//             self.get_field_editor_theme.as_deref(),
+//             self.override_text_style.as_deref(),
+//             cx,
+//         )
+//     }
+
+//     pub fn mode(&self) -> EditorMode {
+//         self.mode
+//     }
+
+//     pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
+//         self.collaboration_hub.as_deref()
+//     }
+
+//     pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
+//         self.collaboration_hub = Some(hub);
+//     }
+
+//     pub fn set_placeholder_text(
+//         &mut self,
+//         placeholder_text: impl Into<Arc<str>>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.placeholder_text = Some(placeholder_text.into());
+//         cx.notify();
+//     }
+
+//     pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
+//         self.cursor_shape = cursor_shape;
+//         cx.notify();
+//     }
+
+//     pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
+//         self.collapse_matches = collapse_matches;
+//     }
+
+//     pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
+//         if self.collapse_matches {
+//             return range.start..range.start;
+//         }
+//         range.clone()
+//     }
+
+//     pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
+//         if self.display_map.read(cx).clip_at_line_ends != clip {
+//             self.display_map
+//                 .update(cx, |map, _| map.clip_at_line_ends = clip);
+//         }
+//     }
+
+//     pub fn set_keymap_context_layer<Tag: 'static>(
+//         &mut self,
+//         context: KeymapContext,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.keymap_context_layers
+//             .insert(TypeId::of::<Tag>(), context);
+//         cx.notify();
+//     }
+
+//     pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
+//         self.keymap_context_layers.remove(&TypeId::of::<Tag>());
+//         cx.notify();
+//     }
+
+//     pub fn set_input_enabled(&mut self, input_enabled: bool) {
+//         self.input_enabled = input_enabled;
+//     }
+
+//     pub fn set_autoindent(&mut self, autoindent: bool) {
+//         if autoindent {
+//             self.autoindent_mode = Some(AutoindentMode::EachLine);
+//         } else {
+//             self.autoindent_mode = None;
+//         }
+//     }
+
+//     pub fn read_only(&self) -> bool {
+//         self.read_only
+//     }
+
+//     pub fn set_read_only(&mut self, read_only: bool) {
+//         self.read_only = read_only;
+//     }
+
+//     pub fn set_field_editor_style(
+//         &mut self,
+//         style: Option<Arc<GetFieldEditorTheme>>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.get_field_editor_theme = style;
+//         cx.notify();
+//     }
+
+//     fn selections_did_change(
+//         &mut self,
+//         local: bool,
+//         old_cursor_position: &Anchor,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if self.focused && self.leader_peer_id.is_none() {
+//             self.buffer.update(cx, |buffer, cx| {
+//                 buffer.set_active_selections(
+//                     &self.selections.disjoint_anchors(),
+//                     self.selections.line_mode,
+//                     self.cursor_shape,
+//                     cx,
+//                 )
+//             });
+//         }
+
+//         let display_map = self
+//             .display_map
+//             .update(cx, |display_map, cx| display_map.snapshot(cx));
+//         let buffer = &display_map.buffer_snapshot;
+//         self.add_selections_state = None;
+//         self.select_next_state = None;
+//         self.select_prev_state = None;
+//         self.select_larger_syntax_node_stack.clear();
+//         self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
+//         self.snippet_stack
+//             .invalidate(&self.selections.disjoint_anchors(), buffer);
+//         self.take_rename(false, cx);
+
+//         let new_cursor_position = self.selections.newest_anchor().head();
+
+//         self.push_to_nav_history(
+//             old_cursor_position.clone(),
+//             Some(new_cursor_position.to_point(buffer)),
+//             cx,
+//         );
+
+//         if local {
+//             let new_cursor_position = self.selections.newest_anchor().head();
+//             let mut context_menu = self.context_menu.write();
+//             let completion_menu = match context_menu.as_ref() {
+//                 Some(ContextMenu::Completions(menu)) => Some(menu),
+
+//                 _ => {
+//                     *context_menu = None;
+//                     None
+//                 }
+//             };
+
+//             if let Some(completion_menu) = completion_menu {
+//                 let cursor_position = new_cursor_position.to_offset(buffer);
+//                 let (word_range, kind) =
+//                     buffer.surrounding_word(completion_menu.initial_position.clone());
+//                 if kind == Some(CharKind::Word)
+//                     && word_range.to_inclusive().contains(&cursor_position)
+//                 {
+//                     let mut completion_menu = completion_menu.clone();
+//                     drop(context_menu);
+
+//                     let query = Self::completion_query(buffer, cursor_position);
+//                     cx.spawn(move |this, mut cx| async move {
+//                         completion_menu
+//                             .filter(query.as_deref(), cx.background().clone())
+//                             .await;
+
+//                         this.update(&mut cx, |this, cx| {
+//                             let mut context_menu = this.context_menu.write();
+//                             let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
+//                                 return;
+//                             };
+
+//                             if menu.id > completion_menu.id {
+//                                 return;
+//                             }
+
+//                             *context_menu = Some(ContextMenu::Completions(completion_menu));
+//                             drop(context_menu);
+//                             cx.notify();
+//                         })
+//                     })
+//                     .detach();
+
+//                     self.show_completions(&ShowCompletions, cx);
+//                 } else {
+//                     drop(context_menu);
+//                     self.hide_context_menu(cx);
+//                 }
+//             } else {
+//                 drop(context_menu);
+//             }
+
+//             hide_hover(self, cx);
+
+//             if old_cursor_position.to_display_point(&display_map).row()
+//                 != new_cursor_position.to_display_point(&display_map).row()
+//             {
+//                 self.available_code_actions.take();
+//             }
+//             self.refresh_code_actions(cx);
+//             self.refresh_document_highlights(cx);
+//             refresh_matching_bracket_highlights(self, cx);
+//             self.discard_copilot_suggestion(cx);
+//         }
+
+//         self.blink_manager.update(cx, BlinkManager::pause_blinking);
+//         cx.emit(Event::SelectionsChanged { local });
+//         cx.notify();
+//     }
+
+//     pub fn change_selections<R>(
+//         &mut self,
+//         autoscroll: Option<Autoscroll>,
+//         cx: &mut ViewContext<Self>,
+//         change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
+//     ) -> R {
+//         let old_cursor_position = self.selections.newest_anchor().head();
+//         self.push_to_selection_history();
+
+//         let (changed, result) = self.selections.change_with(cx, change);
+
+//         if changed {
+//             if let Some(autoscroll) = autoscroll {
+//                 self.request_autoscroll(autoscroll, cx);
+//             }
+//             self.selections_did_change(true, &old_cursor_position, cx);
+//         }
+
+//         result
+//     }
+
+//     pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
+//     where
+//         I: IntoIterator<Item = (Range<S>, T)>,
+//         S: ToOffset,
+//         T: Into<Arc<str>>,
+//     {
+//         if self.read_only {
+//             return;
+//         }
+
+//         self.buffer
+//             .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
+//     }
+
+//     pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
+//     where
+//         I: IntoIterator<Item = (Range<S>, T)>,
+//         S: ToOffset,
+//         T: Into<Arc<str>>,
+//     {
+//         if self.read_only {
+//             return;
+//         }
+
+//         self.buffer.update(cx, |buffer, cx| {
+//             buffer.edit(edits, self.autoindent_mode.clone(), cx)
+//         });
+//     }
+
+//     pub fn edit_with_block_indent<I, S, T>(
+//         &mut self,
+//         edits: I,
+//         original_indent_columns: Vec<u32>,
+//         cx: &mut ViewContext<Self>,
+//     ) where
+//         I: IntoIterator<Item = (Range<S>, T)>,
+//         S: ToOffset,
+//         T: Into<Arc<str>>,
+//     {
+//         if self.read_only {
+//             return;
+//         }
+
+//         self.buffer.update(cx, |buffer, cx| {
+//             buffer.edit(
+//                 edits,
+//                 Some(AutoindentMode::Block {
+//                     original_indent_columns,
+//                 }),
+//                 cx,
+//             )
+//         });
+//     }
+
+//     fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
+//         self.hide_context_menu(cx);
+
+//         match phase {
+//             SelectPhase::Begin {
+//                 position,
+//                 add,
+//                 click_count,
+//             } => self.begin_selection(position, add, click_count, cx),
+//             SelectPhase::BeginColumnar {
+//                 position,
+//                 goal_column,
+//             } => self.begin_columnar_selection(position, goal_column, cx),
+//             SelectPhase::Extend {
+//                 position,
+//                 click_count,
+//             } => self.extend_selection(position, click_count, cx),
+//             SelectPhase::Update {
+//                 position,
+//                 goal_column,
+//                 scroll_position,
+//             } => self.update_selection(position, goal_column, scroll_position, cx),
+//             SelectPhase::End => self.end_selection(cx),
+//         }
+//     }
+
+//     fn extend_selection(
+//         &mut self,
+//         position: DisplayPoint,
+//         click_count: usize,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let tail = self.selections.newest::<usize>(cx).tail();
+//         self.begin_selection(position, false, click_count, cx);
+
+//         let position = position.to_offset(&display_map, Bias::Left);
+//         let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
+
+//         let mut pending_selection = self
+//             .selections
+//             .pending_anchor()
+//             .expect("extend_selection not called with pending selection");
+//         if position >= tail {
+//             pending_selection.start = tail_anchor;
+//         } else {
+//             pending_selection.end = tail_anchor;
+//             pending_selection.reversed = true;
+//         }
+
+//         let mut pending_mode = self.selections.pending_mode().unwrap();
+//         match &mut pending_mode {
+//             SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
+//             _ => {}
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.set_pending(pending_selection, pending_mode)
+//         });
+//     }
+
+//     fn begin_selection(
+//         &mut self,
+//         position: DisplayPoint,
+//         add: bool,
+//         click_count: usize,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if !self.focused {
+//             cx.focus_self();
+//         }
+
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = &display_map.buffer_snapshot;
+//         let newest_selection = self.selections.newest_anchor().clone();
+//         let position = display_map.clip_point(position, Bias::Left);
+
+//         let start;
+//         let end;
+//         let mode;
+//         let auto_scroll;
+//         match click_count {
+//             1 => {
+//                 start = buffer.anchor_before(position.to_point(&display_map));
+//                 end = start.clone();
+//                 mode = SelectMode::Character;
+//                 auto_scroll = true;
+//             }
+//             2 => {
+//                 let range = movement::surrounding_word(&display_map, position);
+//                 start = buffer.anchor_before(range.start.to_point(&display_map));
+//                 end = buffer.anchor_before(range.end.to_point(&display_map));
+//                 mode = SelectMode::Word(start.clone()..end.clone());
+//                 auto_scroll = true;
+//             }
+//             3 => {
+//                 let position = display_map
+//                     .clip_point(position, Bias::Left)
+//                     .to_point(&display_map);
+//                 let line_start = display_map.prev_line_boundary(position).0;
+//                 let next_line_start = buffer.clip_point(
+//                     display_map.next_line_boundary(position).0 + Point::new(1, 0),
+//                     Bias::Left,
+//                 );
+//                 start = buffer.anchor_before(line_start);
+//                 end = buffer.anchor_before(next_line_start);
+//                 mode = SelectMode::Line(start.clone()..end.clone());
+//                 auto_scroll = true;
+//             }
+//             _ => {
+//                 start = buffer.anchor_before(0);
+//                 end = buffer.anchor_before(buffer.len());
+//                 mode = SelectMode::All;
+//                 auto_scroll = false;
+//             }
+//         }
+
+//         self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
+//             if !add {
+//                 s.clear_disjoint();
+//             } else if click_count > 1 {
+//                 s.delete(newest_selection.id)
+//             }
+
+//             s.set_pending_anchor_range(start..end, mode);
+//         });
+//     }
+
+//     fn begin_columnar_selection(
+//         &mut self,
+//         position: DisplayPoint,
+//         goal_column: u32,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if !self.focused {
+//             cx.focus_self();
+//         }
+
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let tail = self.selections.newest::<Point>(cx).tail();
+//         self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
+
+//         self.select_columns(
+//             tail.to_display_point(&display_map),
+//             position,
+//             goal_column,
+//             &display_map,
+//             cx,
+//         );
+//     }
+
+//     fn update_selection(
+//         &mut self,
+//         position: DisplayPoint,
+//         goal_column: u32,
+//         scroll_position: Vector2F,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+//         if let Some(tail) = self.columnar_selection_tail.as_ref() {
+//             let tail = tail.to_display_point(&display_map);
+//             self.select_columns(tail, position, goal_column, &display_map, cx);
+//         } else if let Some(mut pending) = self.selections.pending_anchor() {
+//             let buffer = self.buffer.read(cx).snapshot(cx);
+//             let head;
+//             let tail;
+//             let mode = self.selections.pending_mode().unwrap();
+//             match &mode {
+//                 SelectMode::Character => {
+//                     head = position.to_point(&display_map);
+//                     tail = pending.tail().to_point(&buffer);
+//                 }
+//                 SelectMode::Word(original_range) => {
+//                     let original_display_range = original_range.start.to_display_point(&display_map)
+//                         ..original_range.end.to_display_point(&display_map);
+//                     let original_buffer_range = original_display_range.start.to_point(&display_map)
+//                         ..original_display_range.end.to_point(&display_map);
+//                     if movement::is_inside_word(&display_map, position)
+//                         || original_display_range.contains(&position)
+//                     {
+//                         let word_range = movement::surrounding_word(&display_map, position);
+//                         if word_range.start < original_display_range.start {
+//                             head = word_range.start.to_point(&display_map);
+//                         } else {
+//                             head = word_range.end.to_point(&display_map);
+//                         }
+//                     } else {
+//                         head = position.to_point(&display_map);
+//                     }
+
+//                     if head <= original_buffer_range.start {
+//                         tail = original_buffer_range.end;
+//                     } else {
+//                         tail = original_buffer_range.start;
+//                     }
+//                 }
+//                 SelectMode::Line(original_range) => {
+//                     let original_range = original_range.to_point(&display_map.buffer_snapshot);
+
+//                     let position = display_map
+//                         .clip_point(position, Bias::Left)
+//                         .to_point(&display_map);
+//                     let line_start = display_map.prev_line_boundary(position).0;
+//                     let next_line_start = buffer.clip_point(
+//                         display_map.next_line_boundary(position).0 + Point::new(1, 0),
+//                         Bias::Left,
+//                     );
+
+//                     if line_start < original_range.start {
+//                         head = line_start
+//                     } else {
+//                         head = next_line_start
+//                     }
+
+//                     if head <= original_range.start {
+//                         tail = original_range.end;
+//                     } else {
+//                         tail = original_range.start;
+//                     }
+//                 }
+//                 SelectMode::All => {
+//                     return;
+//                 }
+//             };
+
+//             if head < tail {
+//                 pending.start = buffer.anchor_before(head);
+//                 pending.end = buffer.anchor_before(tail);
+//                 pending.reversed = true;
+//             } else {
+//                 pending.start = buffer.anchor_before(tail);
+//                 pending.end = buffer.anchor_before(head);
+//                 pending.reversed = false;
+//             }
+
+//             self.change_selections(None, cx, |s| {
+//                 s.set_pending(pending, mode);
+//             });
+//         } else {
+//             error!("update_selection dispatched with no pending selection");
+//             return;
+//         }
+
+//         self.set_scroll_position(scroll_position, cx);
+//         cx.notify();
+//     }
+
+//     fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
+//         self.columnar_selection_tail.take();
+//         if self.selections.pending_anchor().is_some() {
+//             let selections = self.selections.all::<usize>(cx);
+//             self.change_selections(None, cx, |s| {
+//                 s.select(selections);
+//                 s.clear_pending();
+//             });
+//         }
+//     }
+
+//     fn select_columns(
+//         &mut self,
+//         tail: DisplayPoint,
+//         head: DisplayPoint,
+//         goal_column: u32,
+//         display_map: &DisplaySnapshot,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let start_row = cmp::min(tail.row(), head.row());
+//         let end_row = cmp::max(tail.row(), head.row());
+//         let start_column = cmp::min(tail.column(), goal_column);
+//         let end_column = cmp::max(tail.column(), goal_column);
+//         let reversed = start_column < tail.column();
+
+//         let selection_ranges = (start_row..=end_row)
+//             .filter_map(|row| {
+//                 if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
+//                     let start = display_map
+//                         .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
+//                         .to_point(display_map);
+//                     let end = display_map
+//                         .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
+//                         .to_point(display_map);
+//                     if reversed {
+//                         Some(end..start)
+//                     } else {
+//                         Some(start..end)
+//                     }
+//                 } else {
+//                     None
+//                 }
+//             })
+//             .collect::<Vec<_>>();
+
+//         self.change_selections(None, cx, |s| {
+//             s.select_ranges(selection_ranges);
+//         });
+//         cx.notify();
+//     }
+
+//     pub fn has_pending_nonempty_selection(&self) -> bool {
+//         let pending_nonempty_selection = match self.selections.pending_anchor() {
+//             Some(Selection { start, end, .. }) => start != end,
+//             None => false,
+//         };
+//         pending_nonempty_selection || self.columnar_selection_tail.is_some()
+//     }
+
+//     pub fn has_pending_selection(&self) -> bool {
+//         self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
+//     }
+
+//     pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
+//         if self.take_rename(false, cx).is_some() {
+//             return;
+//         }
+
+//         if hide_hover(self, cx) {
+//             return;
+//         }
+
+//         if self.hide_context_menu(cx).is_some() {
+//             return;
+//         }
+
+//         if self.discard_copilot_suggestion(cx) {
+//             return;
+//         }
+
+//         if self.snippet_stack.pop().is_some() {
+//             return;
+//         }
+
+//         if self.mode == EditorMode::Full {
+//             if self.active_diagnostics.is_some() {
+//                 self.dismiss_diagnostics(cx);
+//                 return;
+//             }
+
+//             if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
+//                 return;
+//             }
+//         }
+
+//         cx.propagate_action();
+//     }
+
+//     pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
+//         let text: Arc<str> = text.into();
+
+//         if self.read_only {
+//             return;
+//         }
+
+//         let selections = self.selections.all_adjusted(cx);
+//         let mut brace_inserted = false;
+//         let mut edits = Vec::new();
+//         let mut new_selections = Vec::with_capacity(selections.len());
+//         let mut new_autoclose_regions = Vec::new();
+//         let snapshot = self.buffer.read(cx).read(cx);
+
+//         for (selection, autoclose_region) in
+//             self.selections_with_autoclose_regions(selections, &snapshot)
+//         {
+//             if let Some(scope) = snapshot.language_scope_at(selection.head()) {
+//                 // Determine if the inserted text matches the opening or closing
+//                 // bracket of any of this language's bracket pairs.
+//                 let mut bracket_pair = None;
+//                 let mut is_bracket_pair_start = false;
+//                 if !text.is_empty() {
+//                     // `text` can be empty when an user is using IME (e.g. Chinese Wubi Simplified)
+//                     //  and they are removing the character that triggered IME popup.
+//                     for (pair, enabled) in scope.brackets() {
+//                         if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
+//                             bracket_pair = Some(pair.clone());
+//                             is_bracket_pair_start = true;
+//                             break;
+//                         } else if pair.end.as_str() == text.as_ref() {
+//                             bracket_pair = Some(pair.clone());
+//                             break;
+//                         }
+//                     }
+//                 }
+
+//                 if let Some(bracket_pair) = bracket_pair {
+//                     if selection.is_empty() {
+//                         if is_bracket_pair_start {
+//                             let prefix_len = bracket_pair.start.len() - text.len();
+
+//                             // If the inserted text is a suffix of an opening bracket and the
+//                             // selection is preceded by the rest of the opening bracket, then
+//                             // insert the closing bracket.
+//                             let following_text_allows_autoclose = snapshot
+//                                 .chars_at(selection.start)
+//                                 .next()
+//                                 .map_or(true, |c| scope.should_autoclose_before(c));
+//                             let preceding_text_matches_prefix = prefix_len == 0
+//                                 || (selection.start.column >= (prefix_len as u32)
+//                                     && snapshot.contains_str_at(
+//                                         Point::new(
+//                                             selection.start.row,
+//                                             selection.start.column - (prefix_len as u32),
+//                                         ),
+//                                         &bracket_pair.start[..prefix_len],
+//                                     ));
+//                             if following_text_allows_autoclose && preceding_text_matches_prefix {
+//                                 let anchor = snapshot.anchor_before(selection.end);
+//                                 new_selections.push((selection.map(|_| anchor), text.len()));
+//                                 new_autoclose_regions.push((
+//                                     anchor,
+//                                     text.len(),
+//                                     selection.id,
+//                                     bracket_pair.clone(),
+//                                 ));
+//                                 edits.push((
+//                                     selection.range(),
+//                                     format!("{}{}", text, bracket_pair.end).into(),
+//                                 ));
+//                                 brace_inserted = true;
+//                                 continue;
+//                             }
+//                         }
+
+//                         if let Some(region) = autoclose_region {
+//                             // If the selection is followed by an auto-inserted closing bracket,
+//                             // then don't insert that closing bracket again; just move the selection
+//                             // past the closing bracket.
+//                             let should_skip = selection.end == region.range.end.to_point(&snapshot)
+//                                 && text.as_ref() == region.pair.end.as_str();
+//                             if should_skip {
+//                                 let anchor = snapshot.anchor_after(selection.end);
+//                                 new_selections
+//                                     .push((selection.map(|_| anchor), region.pair.end.len()));
+//                                 continue;
+//                             }
+//                         }
+//                     }
+//                     // If an opening bracket is 1 character long and is typed while
+//                     // text is selected, then surround that text with the bracket pair.
+//                     else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
+//                         edits.push((selection.start..selection.start, text.clone()));
+//                         edits.push((
+//                             selection.end..selection.end,
+//                             bracket_pair.end.as_str().into(),
+//                         ));
+//                         brace_inserted = true;
+//                         new_selections.push((
+//                             Selection {
+//                                 id: selection.id,
+//                                 start: snapshot.anchor_after(selection.start),
+//                                 end: snapshot.anchor_before(selection.end),
+//                                 reversed: selection.reversed,
+//                                 goal: selection.goal,
+//                             },
+//                             0,
+//                         ));
+//                         continue;
+//                     }
+//                 }
+//             }
+
+//             // If not handling any auto-close operation, then just replace the selected
+//             // text with the given input and move the selection to the end of the
+//             // newly inserted text.
+//             let anchor = snapshot.anchor_after(selection.end);
+//             new_selections.push((selection.map(|_| anchor), 0));
+//             edits.push((selection.start..selection.end, text.clone()));
+//         }
+
+//         drop(snapshot);
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |buffer, cx| {
+//                 buffer.edit(edits, this.autoindent_mode.clone(), cx);
+//             });
+
+//             let new_anchor_selections = new_selections.iter().map(|e| &e.0);
+//             let new_selection_deltas = new_selections.iter().map(|e| e.1);
+//             let snapshot = this.buffer.read(cx).read(cx);
+//             let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
+//                 .zip(new_selection_deltas)
+//                 .map(|(selection, delta)| Selection {
+//                     id: selection.id,
+//                     start: selection.start + delta,
+//                     end: selection.end + delta,
+//                     reversed: selection.reversed,
+//                     goal: SelectionGoal::None,
+//                 })
+//                 .collect::<Vec<_>>();
+
+//             let mut i = 0;
+//             for (position, delta, selection_id, pair) in new_autoclose_regions {
+//                 let position = position.to_offset(&snapshot) + delta;
+//                 let start = snapshot.anchor_before(position);
+//                 let end = snapshot.anchor_after(position);
+//                 while let Some(existing_state) = this.autoclose_regions.get(i) {
+//                     match existing_state.range.start.cmp(&start, &snapshot) {
+//                         Ordering::Less => i += 1,
+//                         Ordering::Greater => break,
+//                         Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
+//                             Ordering::Less => i += 1,
+//                             Ordering::Equal => break,
+//                             Ordering::Greater => break,
+//                         },
+//                     }
+//                 }
+//                 this.autoclose_regions.insert(
+//                     i,
+//                     AutocloseRegion {
+//                         selection_id,
+//                         range: start..end,
+//                         pair,
+//                     },
+//                 );
+//             }
+
+//             drop(snapshot);
+//             let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
+
+//             if !brace_inserted && settings::get::<EditorSettings>(cx).use_on_type_format {
+//                 if let Some(on_type_format_task) =
+//                     this.trigger_on_type_formatting(text.to_string(), cx)
+//                 {
+//                     on_type_format_task.detach_and_log_err(cx);
+//                 }
+//             }
+
+//             if had_active_copilot_suggestion {
+//                 this.refresh_copilot_suggestions(true, cx);
+//                 if !this.has_active_copilot_suggestion(cx) {
+//                     this.trigger_completion_on_input(&text, cx);
+//                 }
+//             } else {
+//                 this.trigger_completion_on_input(&text, cx);
+//                 this.refresh_copilot_suggestions(true, cx);
+//             }
+//         });
+//     }
+
+//     pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
+//                 let selections = this.selections.all::<usize>(cx);
+//                 let multi_buffer = this.buffer.read(cx);
+//                 let buffer = multi_buffer.snapshot(cx);
+//                 selections
+//                     .iter()
+//                     .map(|selection| {
+//                         let start_point = selection.start.to_point(&buffer);
+//                         let mut indent = buffer.indent_size_for_line(start_point.row);
+//                         indent.len = cmp::min(indent.len, start_point.column);
+//                         let start = selection.start;
+//                         let end = selection.end;
+//                         let is_cursor = start == end;
+//                         let language_scope = buffer.language_scope_at(start);
+//                         let (comment_delimiter, insert_extra_newline) = if let Some(language) =
+//                             &language_scope
+//                         {
+//                             let leading_whitespace_len = buffer
+//                                 .reversed_chars_at(start)
+//                                 .take_while(|c| c.is_whitespace() && *c != '\n')
+//                                 .map(|c| c.len_utf8())
+//                                 .sum::<usize>();
+
+//                             let trailing_whitespace_len = buffer
+//                                 .chars_at(end)
+//                                 .take_while(|c| c.is_whitespace() && *c != '\n')
+//                                 .map(|c| c.len_utf8())
+//                                 .sum::<usize>();
+
+//                             let insert_extra_newline =
+//                                 language.brackets().any(|(pair, enabled)| {
+//                                     let pair_start = pair.start.trim_end();
+//                                     let pair_end = pair.end.trim_start();
+
+//                                     enabled
+//                                         && pair.newline
+//                                         && buffer.contains_str_at(
+//                                             end + trailing_whitespace_len,
+//                                             pair_end,
+//                                         )
+//                                         && buffer.contains_str_at(
+//                                             (start - leading_whitespace_len)
+//                                                 .saturating_sub(pair_start.len()),
+//                                             pair_start,
+//                                         )
+//                                 });
+//                             // Comment extension on newline is allowed only for cursor selections
+//                             let comment_delimiter = language.line_comment_prefix().filter(|_| {
+//                                 let is_comment_extension_enabled =
+//                                     multi_buffer.settings_at(0, cx).extend_comment_on_newline;
+//                                 is_cursor && is_comment_extension_enabled
+//                             });
+//                             let comment_delimiter = if let Some(delimiter) = comment_delimiter {
+//                                 buffer
+//                                     .buffer_line_for_row(start_point.row)
+//                                     .is_some_and(|(snapshot, range)| {
+//                                         let mut index_of_first_non_whitespace = 0;
+//                                         let line_starts_with_comment = snapshot
+//                                             .chars_for_range(range)
+//                                             .skip_while(|c| {
+//                                                 let should_skip = c.is_whitespace();
+//                                                 if should_skip {
+//                                                     index_of_first_non_whitespace += 1;
+//                                                 }
+//                                                 should_skip
+//                                             })
+//                                             .take(delimiter.len())
+//                                             .eq(delimiter.chars());
+//                                         let cursor_is_placed_after_comment_marker =
+//                                             index_of_first_non_whitespace + delimiter.len()
+//                                                 <= start_point.column as usize;
+//                                         line_starts_with_comment
+//                                             && cursor_is_placed_after_comment_marker
+//                                     })
+//                                     .then(|| delimiter.clone())
+//                             } else {
+//                                 None
+//                             };
+//                             (comment_delimiter, insert_extra_newline)
+//                         } else {
+//                             (None, false)
+//                         };
+
+//                         let capacity_for_delimiter = comment_delimiter
+//                             .as_deref()
+//                             .map(str::len)
+//                             .unwrap_or_default();
+//                         let mut new_text =
+//                             String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
+//                         new_text.push_str("\n");
+//                         new_text.extend(indent.chars());
+//                         if let Some(delimiter) = &comment_delimiter {
+//                             new_text.push_str(&delimiter);
+//                         }
+//                         if insert_extra_newline {
+//                             new_text = new_text.repeat(2);
+//                         }
+
+//                         let anchor = buffer.anchor_after(end);
+//                         let new_selection = selection.map(|_| anchor);
+//                         (
+//                             (start..end, new_text),
+//                             (insert_extra_newline, new_selection),
+//                         )
+//                     })
+//                     .unzip()
+//             };
+
+//             this.edit_with_autoindent(edits, cx);
+//             let buffer = this.buffer.read(cx).snapshot(cx);
+//             let new_selections = selection_fixup_info
+//                 .into_iter()
+//                 .map(|(extra_newline_inserted, new_selection)| {
+//                     let mut cursor = new_selection.end.to_point(&buffer);
+//                     if extra_newline_inserted {
+//                         cursor.row -= 1;
+//                         cursor.column = buffer.line_len(cursor.row);
+//                     }
+//                     new_selection.map(|_| cursor)
+//                 })
+//                 .collect();
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
+//             this.refresh_copilot_suggestions(true, cx);
+//         });
+//     }
+
+//     pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
+//         let buffer = self.buffer.read(cx);
+//         let snapshot = buffer.snapshot(cx);
+
+//         let mut edits = Vec::new();
+//         let mut rows = Vec::new();
+//         let mut rows_inserted = 0;
+
+//         for selection in self.selections.all_adjusted(cx) {
+//             let cursor = selection.head();
+//             let row = cursor.row;
+
+//             let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
+
+//             let newline = "\n".to_string();
+//             edits.push((start_of_line..start_of_line, newline));
+
+//             rows.push(row + rows_inserted);
+//             rows_inserted += 1;
+//         }
+
+//         self.transact(cx, |editor, cx| {
+//             editor.edit(edits, cx);
+
+//             editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let mut index = 0;
+//                 s.move_cursors_with(|map, _, _| {
+//                     let row = rows[index];
+//                     index += 1;
+
+//                     let point = Point::new(row, 0);
+//                     let boundary = map.next_line_boundary(point).1;
+//                     let clipped = map.clip_point(boundary, Bias::Left);
+
+//                     (clipped, SelectionGoal::None)
+//                 });
+//             });
+
+//             let mut indent_edits = Vec::new();
+//             let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
+//             for row in rows {
+//                 let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
+//                 for (row, indent) in indents {
+//                     if indent.len == 0 {
+//                         continue;
+//                     }
+
+//                     let text = match indent.kind {
+//                         IndentKind::Space => " ".repeat(indent.len as usize),
+//                         IndentKind::Tab => "\t".repeat(indent.len as usize),
+//                     };
+//                     let point = Point::new(row, 0);
+//                     indent_edits.push((point..point, text));
+//                 }
+//             }
+//             editor.edit(indent_edits, cx);
+//         });
+//     }
+
+//     pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
+//         let buffer = self.buffer.read(cx);
+//         let snapshot = buffer.snapshot(cx);
+
+//         let mut edits = Vec::new();
+//         let mut rows = Vec::new();
+//         let mut rows_inserted = 0;
+
+//         for selection in self.selections.all_adjusted(cx) {
+//             let cursor = selection.head();
+//             let row = cursor.row;
+
+//             let point = Point::new(row + 1, 0);
+//             let start_of_line = snapshot.clip_point(point, Bias::Left);
+
+//             let newline = "\n".to_string();
+//             edits.push((start_of_line..start_of_line, newline));
+
+//             rows_inserted += 1;
+//             rows.push(row + rows_inserted);
+//         }
+
+//         self.transact(cx, |editor, cx| {
+//             editor.edit(edits, cx);
+
+//             editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let mut index = 0;
+//                 s.move_cursors_with(|map, _, _| {
+//                     let row = rows[index];
+//                     index += 1;
+
+//                     let point = Point::new(row, 0);
+//                     let boundary = map.next_line_boundary(point).1;
+//                     let clipped = map.clip_point(boundary, Bias::Left);
+
+//                     (clipped, SelectionGoal::None)
+//                 });
+//             });
+
+//             let mut indent_edits = Vec::new();
+//             let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
+//             for row in rows {
+//                 let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
+//                 for (row, indent) in indents {
+//                     if indent.len == 0 {
+//                         continue;
+//                     }
+
+//                     let text = match indent.kind {
+//                         IndentKind::Space => " ".repeat(indent.len as usize),
+//                         IndentKind::Tab => "\t".repeat(indent.len as usize),
+//                     };
+//                     let point = Point::new(row, 0);
+//                     indent_edits.push((point..point, text));
+//                 }
+//             }
+//             editor.edit(indent_edits, cx);
+//         });
+//     }
+
+//     pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
+//         self.insert_with_autoindent_mode(
+//             text,
+//             Some(AutoindentMode::Block {
+//                 original_indent_columns: Vec::new(),
+//             }),
+//             cx,
+//         );
+//     }
+
+//     fn insert_with_autoindent_mode(
+//         &mut self,
+//         text: &str,
+//         autoindent_mode: Option<AutoindentMode>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if self.read_only {
+//             return;
+//         }
+
+//         let text: Arc<str> = text.into();
+//         self.transact(cx, |this, cx| {
+//             let old_selections = this.selections.all_adjusted(cx);
+//             let selection_anchors = this.buffer.update(cx, |buffer, cx| {
+//                 let anchors = {
+//                     let snapshot = buffer.read(cx);
+//                     old_selections
+//                         .iter()
+//                         .map(|s| {
+//                             let anchor = snapshot.anchor_after(s.head());
+//                             s.map(|_| anchor)
+//                         })
+//                         .collect::<Vec<_>>()
+//                 };
+//                 buffer.edit(
+//                     old_selections
+//                         .iter()
+//                         .map(|s| (s.start..s.end, text.clone())),
+//                     autoindent_mode,
+//                     cx,
+//                 );
+//                 anchors
+//             });
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select_anchors(selection_anchors);
+//             })
+//         });
+//     }
+
+//     fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
+//         if !settings::get::<EditorSettings>(cx).show_completions_on_input {
+//             return;
+//         }
+
+//         let selection = self.selections.newest_anchor();
+//         if self
+//             .buffer
+//             .read(cx)
+//             .is_completion_trigger(selection.head(), text, cx)
+//         {
+//             self.show_completions(&ShowCompletions, cx);
+//         } else {
+//             self.hide_context_menu(cx);
+//         }
+//     }
+
+//     /// If any empty selections is touching the start of its innermost containing autoclose
+//     /// region, expand it to select the brackets.
+//     fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
+//         let selections = self.selections.all::<usize>(cx);
+//         let buffer = self.buffer.read(cx).read(cx);
+//         let mut new_selections = Vec::new();
+//         for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
+//             if let (Some(region), true) = (region, selection.is_empty()) {
+//                 let mut range = region.range.to_offset(&buffer);
+//                 if selection.start == range.start {
+//                     if range.start >= region.pair.start.len() {
+//                         range.start -= region.pair.start.len();
+//                         if buffer.contains_str_at(range.start, &region.pair.start) {
+//                             if buffer.contains_str_at(range.end, &region.pair.end) {
+//                                 range.end += region.pair.end.len();
+//                                 selection.start = range.start;
+//                                 selection.end = range.end;
+//                             }
+//                         }
+//                     }
+//                 }
+//             }
+//             new_selections.push(selection);
+//         }
+
+//         drop(buffer);
+//         self.change_selections(None, cx, |selections| selections.select(new_selections));
+//     }
+
+//     /// Iterate the given selections, and for each one, find the smallest surrounding
+//     /// autoclose region. This uses the ordering of the selections and the autoclose
+//     /// regions to avoid repeated comparisons.
+//     fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
+//         &'a self,
+//         selections: impl IntoIterator<Item = Selection<D>>,
+//         buffer: &'a MultiBufferSnapshot,
+//     ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
+//         let mut i = 0;
+//         let mut regions = self.autoclose_regions.as_slice();
+//         selections.into_iter().map(move |selection| {
+//             let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
+
+//             let mut enclosing = None;
+//             while let Some(pair_state) = regions.get(i) {
+//                 if pair_state.range.end.to_offset(buffer) < range.start {
+//                     regions = &regions[i + 1..];
+//                     i = 0;
+//                 } else if pair_state.range.start.to_offset(buffer) > range.end {
+//                     break;
+//                 } else {
+//                     if pair_state.selection_id == selection.id {
+//                         enclosing = Some(pair_state);
+//                     }
+//                     i += 1;
+//                 }
+//             }
+
+//             (selection.clone(), enclosing)
+//         })
+//     }
+
+//     /// Remove any autoclose regions that no longer contain their selection.
+//     fn invalidate_autoclose_regions(
+//         &mut self,
+//         mut selections: &[Selection<Anchor>],
+//         buffer: &MultiBufferSnapshot,
+//     ) {
+//         self.autoclose_regions.retain(|state| {
+//             let mut i = 0;
+//             while let Some(selection) = selections.get(i) {
+//                 if selection.end.cmp(&state.range.start, buffer).is_lt() {
+//                     selections = &selections[1..];
+//                     continue;
+//                 }
+//                 if selection.start.cmp(&state.range.end, buffer).is_gt() {
+//                     break;
+//                 }
+//                 if selection.id == state.selection_id {
+//                     return true;
+//                 } else {
+//                     i += 1;
+//                 }
+//             }
+//             false
+//         });
+//     }
+
+//     fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
+//         let offset = position.to_offset(buffer);
+//         let (word_range, kind) = buffer.surrounding_word(offset);
+//         if offset > word_range.start && kind == Some(CharKind::Word) {
+//             Some(
+//                 buffer
+//                     .text_for_range(word_range.start..offset)
+//                     .collect::<String>(),
+//             )
+//         } else {
+//             None
+//         }
+//     }
+
+//     pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
+//         todo!();
+//         // self.refresh_inlay_hints(
+//         //     InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
+//         //     cx,
+//         // );
+//     }
+
+//     pub fn inlay_hints_enabled(&self) -> bool {
+//         todo!();
+//         self.inlay_hint_cache.enabled
+//     }
+
+//     fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
+//         if self.project.is_none() || self.mode != EditorMode::Full {
+//             return;
+//         }
+
+//         let reason_description = reason.description();
+//         let (invalidate_cache, required_languages) = match reason {
+//             InlayHintRefreshReason::Toggle(enabled) => {
+//                 self.inlay_hint_cache.enabled = enabled;
+//                 if enabled {
+//                     (InvalidationStrategy::RefreshRequested, None)
+//                 } else {
+//                     self.inlay_hint_cache.clear();
+//                     self.splice_inlay_hints(
+//                         self.visible_inlay_hints(cx)
+//                             .iter()
+//                             .map(|inlay| inlay.id)
+//                             .collect(),
+//                         Vec::new(),
+//                         cx,
+//                     );
+//                     return;
+//                 }
+//             }
+//             InlayHintRefreshReason::SettingsChange(new_settings) => {
+//                 match self.inlay_hint_cache.update_settings(
+//                     &self.buffer,
+//                     new_settings,
+//                     self.visible_inlay_hints(cx),
+//                     cx,
+//                 ) {
+//                     ControlFlow::Break(Some(InlaySplice {
+//                         to_remove,
+//                         to_insert,
+//                     })) => {
+//                         self.splice_inlay_hints(to_remove, to_insert, cx);
+//                         return;
+//                     }
+//                     ControlFlow::Break(None) => return,
+//                     ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
+//                 }
+//             }
+//             InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
+//                 if let Some(InlaySplice {
+//                     to_remove,
+//                     to_insert,
+//                 }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
+//                 {
+//                     self.splice_inlay_hints(to_remove, to_insert, cx);
+//                 }
+//                 return;
+//             }
+//             InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
+//             InlayHintRefreshReason::BufferEdited(buffer_languages) => {
+//                 (InvalidationStrategy::BufferEdited, Some(buffer_languages))
+//             }
+//             InlayHintRefreshReason::RefreshRequested => {
+//                 (InvalidationStrategy::RefreshRequested, None)
+//             }
+//         };
+
+//         if let Some(InlaySplice {
+//             to_remove,
+//             to_insert,
+//         }) = self.inlay_hint_cache.spawn_hint_refresh(
+//             reason_description,
+//             self.excerpt_visible_offsets(required_languages.as_ref(), cx),
+//             invalidate_cache,
+//             cx,
+//         ) {
+//             self.splice_inlay_hints(to_remove, to_insert, cx);
+//         }
+//     }
+
+//     fn visible_inlay_hints(&self, cx: &ViewContext<'_, '_, Editor>) -> Vec<Inlay> {
+//         self.display_map
+//             .read(cx)
+//             .current_inlays()
+//             .filter(move |inlay| {
+//                 Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id)
+//             })
+//             .cloned()
+//             .collect()
+//     }
+
+//     pub fn excerpt_visible_offsets(
+//         &self,
+//         restrict_to_languages: Option<&HashSet<Arc<Language>>>,
+//         cx: &mut ViewContext<'_, '_, Editor>,
+//     ) -> HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)> {
+//         let multi_buffer = self.buffer().read(cx);
+//         let multi_buffer_snapshot = multi_buffer.snapshot(cx);
+//         let multi_buffer_visible_start = self
+//             .scroll_manager
+//             .anchor()
+//             .anchor
+//             .to_point(&multi_buffer_snapshot);
+//         let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
+//             multi_buffer_visible_start
+//                 + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
+//             Bias::Left,
+//         );
+//         let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
+//         multi_buffer
+//             .range_to_buffer_ranges(multi_buffer_visible_range, cx)
+//             .into_iter()
+//             .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
+//             .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
+//                 let buffer = buffer_handle.read(cx);
+//                 let language = buffer.language()?;
+//                 if let Some(restrict_to_languages) = restrict_to_languages {
+//                     if !restrict_to_languages.contains(language) {
+//                         return None;
+//                     }
+//                 }
+//                 Some((
+//                     excerpt_id,
+//                     (
+//                         buffer_handle,
+//                         buffer.version().clone(),
+//                         excerpt_visible_range,
+//                     ),
+//                 ))
+//             })
+//             .collect()
+//     }
+
+//     pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
+//         TextLayoutDetails {
+//             font_cache: cx.font_cache().clone(),
+//             text_layout_cache: cx.text_layout_cache().clone(),
+//             editor_style: self.style(cx),
+//         }
+//     }
+
+//     fn splice_inlay_hints(
+//         &self,
+//         to_remove: Vec<InlayId>,
+//         to_insert: Vec<Inlay>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.display_map.update(cx, |display_map, cx| {
+//             display_map.splice_inlays(to_remove, to_insert, cx);
+//         });
+//         cx.notify();
+//     }
+
+//     fn trigger_on_type_formatting(
+//         &self,
+//         input: String,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<Task<Result<()>>> {
+//         if input.len() != 1 {
+//             return None;
+//         }
+
+//         let project = self.project.as_ref()?;
+//         let position = self.selections.newest_anchor().head();
+//         let (buffer, buffer_position) = self
+//             .buffer
+//             .read(cx)
+//             .text_anchor_for_position(position.clone(), cx)?;
+
+//         // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
+//         // hence we do LSP request & edit on host side only — add formats to host's history.
+//         let push_to_lsp_host_history = true;
+//         // If this is not the host, append its history with new edits.
+//         let push_to_client_history = project.read(cx).is_remote();
+
+//         let on_type_formatting = project.update(cx, |project, cx| {
+//             project.on_type_format(
+//                 buffer.clone(),
+//                 buffer_position,
+//                 input,
+//                 push_to_lsp_host_history,
+//                 cx,
+//             )
+//         });
+//         Some(cx.spawn(|editor, mut cx| async move {
+//             if let Some(transaction) = on_type_formatting.await? {
+//                 if push_to_client_history {
+//                     buffer.update(&mut cx, |buffer, _| {
+//                         buffer.push_transaction(transaction, Instant::now());
+//                     });
+//                 }
+//                 editor.update(&mut cx, |editor, cx| {
+//                     editor.refresh_document_highlights(cx);
+//                 })?;
+//             }
+//             Ok(())
+//         }))
+//     }
+
+//     fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
+//         if self.pending_rename.is_some() {
+//             return;
+//         }
+
+//         let project = if let Some(project) = self.project.clone() {
+//             project
+//         } else {
+//             return;
+//         };
+
+//         let position = self.selections.newest_anchor().head();
+//         let (buffer, buffer_position) = if let Some(output) = self
+//             .buffer
+//             .read(cx)
+//             .text_anchor_for_position(position.clone(), cx)
+//         {
+//             output
+//         } else {
+//             return;
+//         };
+
+//         let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
+//         let completions = project.update(cx, |project, cx| {
+//             project.completions(&buffer, buffer_position, cx)
+//         });
+
+//         let id = post_inc(&mut self.next_completion_id);
+//         let task = cx.spawn(|this, mut cx| {
+//             async move {
+//                 let menu = if let Some(completions) = completions.await.log_err() {
+//                     let mut menu = CompletionsMenu {
+//                         id,
+//                         initial_position: position,
+//                         match_candidates: completions
+//                             .iter()
+//                             .enumerate()
+//                             .map(|(id, completion)| {
+//                                 StringMatchCandidate::new(
+//                                     id,
+//                                     completion.label.text[completion.label.filter_range.clone()]
+//                                         .into(),
+//                                 )
+//                             })
+//                             .collect(),
+//                         buffer,
+//                         completions: Arc::new(RwLock::new(completions.into())),
+//                         matches: Vec::new().into(),
+//                         selected_item: 0,
+//                         list: Default::default(),
+//                     };
+//                     menu.filter(query.as_deref(), cx.background()).await;
+//                     if menu.matches.is_empty() {
+//                         None
+//                     } else {
+//                         _ = this.update(&mut cx, |editor, cx| {
+//                             menu.pre_resolve_completion_documentation(editor.project.clone(), cx);
+//                         });
+//                         Some(menu)
+//                     }
+//                 } else {
+//                     None
+//                 };
+
+//                 this.update(&mut cx, |this, cx| {
+//                     this.completion_tasks.retain(|(task_id, _)| *task_id > id);
+
+//                     let mut context_menu = this.context_menu.write();
+//                     match context_menu.as_ref() {
+//                         None => {}
+
+//                         Some(ContextMenu::Completions(prev_menu)) => {
+//                             if prev_menu.id > id {
+//                                 return;
+//                             }
+//                         }
+
+//                         _ => return,
+//                     }
+
+//                     if this.focused && menu.is_some() {
+//                         let menu = menu.unwrap();
+//                         *context_menu = Some(ContextMenu::Completions(menu));
+//                         drop(context_menu);
+//                         this.discard_copilot_suggestion(cx);
+//                         cx.notify();
+//                     } else if this.completion_tasks.is_empty() {
+//                         // If there are no more completion tasks and the last menu was
+//                         // empty, we should hide it. If it was already hidden, we should
+//                         // also show the copilot suggestion when available.
+//                         drop(context_menu);
+//                         if this.hide_context_menu(cx).is_none() {
+//                             this.update_visible_copilot_suggestion(cx);
+//                         }
+//                     }
+//                 })?;
+
+//                 Ok::<_, anyhow::Error>(())
+//             }
+//             .log_err()
+//         });
+//         self.completion_tasks.push((id, task));
+//     }
+
+//     pub fn confirm_completion(
+//         &mut self,
+//         action: &ConfirmCompletion,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<Task<Result<()>>> {
+//         use language::ToOffset as _;
+
+//         let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
+//             menu
+//         } else {
+//             return None;
+//         };
+
+//         let mat = completions_menu
+//             .matches
+//             .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
+//         let buffer_handle = completions_menu.buffer;
+//         let completions = completions_menu.completions.read();
+//         let completion = completions.get(mat.candidate_id)?;
+
+//         let snippet;
+//         let text;
+//         if completion.is_snippet() {
+//             snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
+//             text = snippet.as_ref().unwrap().text.clone();
+//         } else {
+//             snippet = None;
+//             text = completion.new_text.clone();
+//         };
+//         let selections = self.selections.all::<usize>(cx);
+//         let buffer = buffer_handle.read(cx);
+//         let old_range = completion.old_range.to_offset(buffer);
+//         let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
+
+//         let newest_selection = self.selections.newest_anchor();
+//         if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
+//             return None;
+//         }
+
+//         let lookbehind = newest_selection
+//             .start
+//             .text_anchor
+//             .to_offset(buffer)
+//             .saturating_sub(old_range.start);
+//         let lookahead = old_range
+//             .end
+//             .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
+//         let mut common_prefix_len = old_text
+//             .bytes()
+//             .zip(text.bytes())
+//             .take_while(|(a, b)| a == b)
+//             .count();
+
+//         let snapshot = self.buffer.read(cx).snapshot(cx);
+//         let mut range_to_replace: Option<Range<isize>> = None;
+//         let mut ranges = Vec::new();
+//         for selection in &selections {
+//             if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
+//                 let start = selection.start.saturating_sub(lookbehind);
+//                 let end = selection.end + lookahead;
+//                 if selection.id == newest_selection.id {
+//                     range_to_replace = Some(
+//                         ((start + common_prefix_len) as isize - selection.start as isize)
+//                             ..(end as isize - selection.start as isize),
+//                     );
+//                 }
+//                 ranges.push(start + common_prefix_len..end);
+//             } else {
+//                 common_prefix_len = 0;
+//                 ranges.clear();
+//                 ranges.extend(selections.iter().map(|s| {
+//                     if s.id == newest_selection.id {
+//                         range_to_replace = Some(
+//                             old_range.start.to_offset_utf16(&snapshot).0 as isize
+//                                 - selection.start as isize
+//                                 ..old_range.end.to_offset_utf16(&snapshot).0 as isize
+//                                     - selection.start as isize,
+//                         );
+//                         old_range.clone()
+//                     } else {
+//                         s.start..s.end
+//                     }
+//                 }));
+//                 break;
+//             }
+//         }
+//         let text = &text[common_prefix_len..];
+
+//         cx.emit(Event::InputHandled {
+//             utf16_range_to_replace: range_to_replace,
+//             text: text.into(),
+//         });
+
+//         self.transact(cx, |this, cx| {
+//             if let Some(mut snippet) = snippet {
+//                 snippet.text = text.to_string();
+//                 for tabstop in snippet.tabstops.iter_mut().flatten() {
+//                     tabstop.start -= common_prefix_len as isize;
+//                     tabstop.end -= common_prefix_len as isize;
+//                 }
+
+//                 this.insert_snippet(&ranges, snippet, cx).log_err();
+//             } else {
+//                 this.buffer.update(cx, |buffer, cx| {
+//                     buffer.edit(
+//                         ranges.iter().map(|range| (range.clone(), text)),
+//                         this.autoindent_mode.clone(),
+//                         cx,
+//                     );
+//                 });
+//             }
+
+//             this.refresh_copilot_suggestions(true, cx);
+//         });
+
+//         let project = self.project.clone()?;
+//         let apply_edits = project.update(cx, |project, cx| {
+//             project.apply_additional_edits_for_completion(
+//                 buffer_handle,
+//                 completion.clone(),
+//                 true,
+//                 cx,
+//             )
+//         });
+//         Some(cx.foreground().spawn(async move {
+//             apply_edits.await?;
+//             Ok(())
+//         }))
+//     }
+
+//     pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
+//         let mut context_menu = self.context_menu.write();
+//         if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
+//             *context_menu = None;
+//             cx.notify();
+//             return;
+//         }
+//         drop(context_menu);
+
+//         let deployed_from_indicator = action.deployed_from_indicator;
+//         let mut task = self.code_actions_task.take();
+//         cx.spawn(|this, mut cx| async move {
+//             while let Some(prev_task) = task {
+//                 prev_task.await;
+//                 task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
+//             }
+
+//             this.update(&mut cx, |this, cx| {
+//                 if this.focused {
+//                     if let Some((buffer, actions)) = this.available_code_actions.clone() {
+//                         this.completion_tasks.clear();
+//                         this.discard_copilot_suggestion(cx);
+//                         *this.context_menu.write() =
+//                             Some(ContextMenu::CodeActions(CodeActionsMenu {
+//                                 buffer,
+//                                 actions,
+//                                 selected_item: Default::default(),
+//                                 list: Default::default(),
+//                                 deployed_from_indicator,
+//                             }));
+//                     }
+//                 }
+//             })?;
+
+//             Ok::<_, anyhow::Error>(())
+//         })
+//         .detach_and_log_err(cx);
+//     }
+
+//     pub fn confirm_code_action(
+//         workspace: &mut Workspace,
+//         action: &ConfirmCodeAction,
+//         cx: &mut ViewContext<Workspace>,
+//     ) -> Option<Task<Result<()>>> {
+//         let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
+//         let actions_menu = if let ContextMenu::CodeActions(menu) =
+//             editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
+//         {
+//             menu
+//         } else {
+//             return None;
+//         };
+//         let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
+//         let action = actions_menu.actions.get(action_ix)?.clone();
+//         let title = action.lsp_action.title.clone();
+//         let buffer = actions_menu.buffer;
+
+//         let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
+//             project.apply_code_action(buffer, action, true, cx)
+//         });
+//         let editor = editor.downgrade();
+//         Some(cx.spawn(|workspace, cx| async move {
+//             let project_transaction = apply_code_actions.await?;
+//             Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
+//         }))
+//     }
+
+//     async fn open_project_transaction(
+//         this: &WeakViewHandle<Editor>,
+//         workspace: WeakViewHandle<Workspace>,
+//         transaction: ProjectTransaction,
+//         title: String,
+//         mut cx: AsyncAppContext,
+//     ) -> Result<()> {
+//         let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx))?;
+
+//         let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
+//         entries.sort_unstable_by_key(|(buffer, _)| {
+//             buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
+//         });
+
+//         // If the project transaction's edits are all contained within this editor, then
+//         // avoid opening a new editor to display them.
+
+//         if let Some((buffer, transaction)) = entries.first() {
+//             if entries.len() == 1 {
+//                 let excerpt = this.read_with(&cx, |editor, cx| {
+//                     editor
+//                         .buffer()
+//                         .read(cx)
+//                         .excerpt_containing(editor.selections.newest_anchor().head(), cx)
+//                 })?;
+//                 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
+//                     if excerpted_buffer == *buffer {
+//                         let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
+//                             let excerpt_range = excerpt_range.to_offset(buffer);
+//                             buffer
+//                                 .edited_ranges_for_transaction::<usize>(transaction)
+//                                 .all(|range| {
+//                                     excerpt_range.start <= range.start
+//                                         && excerpt_range.end >= range.end
+//                                 })
+//                         });
+
+//                         if all_edits_within_excerpt {
+//                             return Ok(());
+//                         }
+//                     }
+//                 }
+//             }
+//         } else {
+//             return Ok(());
+//         }
+
+//         let mut ranges_to_highlight = Vec::new();
+//         let excerpt_buffer = cx.add_model(|cx| {
+//             let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
+//             for (buffer_handle, transaction) in &entries {
+//                 let buffer = buffer_handle.read(cx);
+//                 ranges_to_highlight.extend(
+//                     multibuffer.push_excerpts_with_context_lines(
+//                         buffer_handle.clone(),
+//                         buffer
+//                             .edited_ranges_for_transaction::<usize>(transaction)
+//                             .collect(),
+//                         1,
+//                         cx,
+//                     ),
+//                 );
+//             }
+//             multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
+//             multibuffer
+//         });
+
+//         workspace.update(&mut cx, |workspace, cx| {
+//             let project = workspace.project().clone();
+//             let editor =
+//                 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
+//             workspace.add_item(Box::new(editor.clone()), cx);
+//             editor.update(cx, |editor, cx| {
+//                 editor.highlight_background::<Self>(
+//                     ranges_to_highlight,
+//                     |theme| theme.editor.highlighted_line_background,
+//                     cx,
+//                 );
+//             });
+//         })?;
+
+//         Ok(())
+//     }
+
+//     fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
+//         let project = self.project.clone()?;
+//         let buffer = self.buffer.read(cx);
+//         let newest_selection = self.selections.newest_anchor().clone();
+//         let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
+//         let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
+//         if start_buffer != end_buffer {
+//             return None;
+//         }
+
+//         self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
+//             cx.background().timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT).await;
+
+//             let actions = project
+//                 .update(&mut cx, |project, cx| {
+//                     project.code_actions(&start_buffer, start..end, cx)
+//                 })
+//                 .await;
+
+//             this.update(&mut cx, |this, cx| {
+//                 this.available_code_actions = actions.log_err().and_then(|actions| {
+//                     if actions.is_empty() {
+//                         None
+//                     } else {
+//                         Some((start_buffer, actions.into()))
+//                     }
+//                 });
+//                 cx.notify();
+//             })
+//             .log_err();
+//         }));
+//         None
+//     }
+
+//     fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
+//         if self.pending_rename.is_some() {
+//             return None;
+//         }
+
+//         let project = self.project.clone()?;
+//         let buffer = self.buffer.read(cx);
+//         let newest_selection = self.selections.newest_anchor().clone();
+//         let cursor_position = newest_selection.head();
+//         let (cursor_buffer, cursor_buffer_position) =
+//             buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
+//         let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
+//         if cursor_buffer != tail_buffer {
+//             return None;
+//         }
+
+//         self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
+//             cx.background()
+//                 .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
+//                 .await;
+
+//             let highlights = project
+//                 .update(&mut cx, |project, cx| {
+//                     project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
+//                 })
+//                 .await
+//                 .log_err();
+
+//             if let Some(highlights) = highlights {
+//                 this.update(&mut cx, |this, cx| {
+//                     if this.pending_rename.is_some() {
+//                         return;
+//                     }
+
+//                     let buffer_id = cursor_position.buffer_id;
+//                     let buffer = this.buffer.read(cx);
+//                     if !buffer
+//                         .text_anchor_for_position(cursor_position, cx)
+//                         .map_or(false, |(buffer, _)| buffer == cursor_buffer)
+//                     {
+//                         return;
+//                     }
+
+//                     let cursor_buffer_snapshot = cursor_buffer.read(cx);
+//                     let mut write_ranges = Vec::new();
+//                     let mut read_ranges = Vec::new();
+//                     for highlight in highlights {
+//                         for (excerpt_id, excerpt_range) in
+//                             buffer.excerpts_for_buffer(&cursor_buffer, cx)
+//                         {
+//                             let start = highlight
+//                                 .range
+//                                 .start
+//                                 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
+//                             let end = highlight
+//                                 .range
+//                                 .end
+//                                 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
+//                             if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
+//                                 continue;
+//                             }
+
+//                             let range = Anchor {
+//                                 buffer_id,
+//                                 excerpt_id: excerpt_id.clone(),
+//                                 text_anchor: start,
+//                             }..Anchor {
+//                                 buffer_id,
+//                                 excerpt_id,
+//                                 text_anchor: end,
+//                             };
+//                             if highlight.kind == lsp::DocumentHighlightKind::WRITE {
+//                                 write_ranges.push(range);
+//                             } else {
+//                                 read_ranges.push(range);
+//                             }
+//                         }
+//                     }
+
+//                     this.highlight_background::<DocumentHighlightRead>(
+//                         read_ranges,
+//                         |theme| theme.editor.document_highlight_read_background,
+//                         cx,
+//                     );
+//                     this.highlight_background::<DocumentHighlightWrite>(
+//                         write_ranges,
+//                         |theme| theme.editor.document_highlight_write_background,
+//                         cx,
+//                     );
+//                     cx.notify();
+//                 })
+//                 .log_err();
+//             }
+//         }));
+//         None
+//     }
+
+//     fn refresh_copilot_suggestions(
+//         &mut self,
+//         debounce: bool,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<()> {
+//         let copilot = Copilot::global(cx)?;
+//         if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
+//             self.clear_copilot_suggestions(cx);
+//             return None;
+//         }
+//         self.update_visible_copilot_suggestion(cx);
+
+//         let snapshot = self.buffer.read(cx).snapshot(cx);
+//         let cursor = self.selections.newest_anchor().head();
+//         if !self.is_copilot_enabled_at(cursor, &snapshot, cx) {
+//             self.clear_copilot_suggestions(cx);
+//             return None;
+//         }
+
+//         let (buffer, buffer_position) =
+//             self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
+//         self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move {
+//             if debounce {
+//                 cx.background().timer(COPILOT_DEBOUNCE_TIMEOUT).await;
+//             }
+
+//             let completions = copilot
+//                 .update(&mut cx, |copilot, cx| {
+//                     copilot.completions(&buffer, buffer_position, cx)
+//                 })
+//                 .await
+//                 .log_err()
+//                 .into_iter()
+//                 .flatten()
+//                 .collect_vec();
+
+//             this.update(&mut cx, |this, cx| {
+//                 if !completions.is_empty() {
+//                     this.copilot_state.cycled = false;
+//                     this.copilot_state.pending_cycling_refresh = Task::ready(None);
+//                     this.copilot_state.completions.clear();
+//                     this.copilot_state.active_completion_index = 0;
+//                     this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
+//                     for completion in completions {
+//                         this.copilot_state.push_completion(completion);
+//                     }
+//                     this.update_visible_copilot_suggestion(cx);
+//                 }
+//             })
+//             .log_err()?;
+//             Some(())
+//         });
+
+//         Some(())
+//     }
+
+//     fn cycle_copilot_suggestions(
+//         &mut self,
+//         direction: Direction,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<()> {
+//         let copilot = Copilot::global(cx)?;
+//         if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
+//             return None;
+//         }
+
+//         if self.copilot_state.cycled {
+//             self.copilot_state.cycle_completions(direction);
+//             self.update_visible_copilot_suggestion(cx);
+//         } else {
+//             let cursor = self.selections.newest_anchor().head();
+//             let (buffer, buffer_position) =
+//                 self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
+//             self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move {
+//                 let completions = copilot
+//                     .update(&mut cx, |copilot, cx| {
+//                         copilot.completions_cycling(&buffer, buffer_position, cx)
+//                     })
+//                     .await;
+
+//                 this.update(&mut cx, |this, cx| {
+//                     this.copilot_state.cycled = true;
+//                     for completion in completions.log_err().into_iter().flatten() {
+//                         this.copilot_state.push_completion(completion);
+//                     }
+//                     this.copilot_state.cycle_completions(direction);
+//                     this.update_visible_copilot_suggestion(cx);
+//                 })
+//                 .log_err()?;
+
+//                 Some(())
+//             });
+//         }
+
+//         Some(())
+//     }
+
+//     fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext<Self>) {
+//         if !self.has_active_copilot_suggestion(cx) {
+//             self.refresh_copilot_suggestions(false, cx);
+//             return;
+//         }
+
+//         self.update_visible_copilot_suggestion(cx);
+//     }
+
+//     fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
+//         if self.has_active_copilot_suggestion(cx) {
+//             self.cycle_copilot_suggestions(Direction::Next, cx);
+//         } else {
+//             let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
+//             if is_copilot_disabled {
+//                 cx.propagate_action();
+//             }
+//         }
+//     }
+
+//     fn previous_copilot_suggestion(
+//         &mut self,
+//         _: &copilot::PreviousSuggestion,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if self.has_active_copilot_suggestion(cx) {
+//             self.cycle_copilot_suggestions(Direction::Prev, cx);
+//         } else {
+//             let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
+//             if is_copilot_disabled {
+//                 cx.propagate_action();
+//             }
+//         }
+//     }
+
+//     fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
+//         if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
+//             if let Some((copilot, completion)) =
+//                 Copilot::global(cx).zip(self.copilot_state.active_completion())
+//             {
+//                 copilot
+//                     .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
+//                     .detach_and_log_err(cx);
+
+//                 self.report_copilot_event(Some(completion.uuid.clone()), true, cx)
+//             }
+//             cx.emit(Event::InputHandled {
+//                 utf16_range_to_replace: None,
+//                 text: suggestion.text.to_string().into(),
+//             });
+//             self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
+//             cx.notify();
+//             true
+//         } else {
+//             false
+//         }
+//     }
+
+//     fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
+//         if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
+//             if let Some(copilot) = Copilot::global(cx) {
+//                 copilot
+//                     .update(cx, |copilot, cx| {
+//                         copilot.discard_completions(&self.copilot_state.completions, cx)
+//                     })
+//                     .detach_and_log_err(cx);
+
+//                 self.report_copilot_event(None, false, cx)
+//             }
+
+//             self.display_map.update(cx, |map, cx| {
+//                 map.splice_inlays(vec![suggestion.id], Vec::new(), cx)
+//             });
+//             cx.notify();
+//             true
+//         } else {
+//             false
+//         }
+//     }
+
+//     fn is_copilot_enabled_at(
+//         &self,
+//         location: Anchor,
+//         snapshot: &MultiBufferSnapshot,
+//         cx: &mut ViewContext<Self>,
+//     ) -> bool {
+//         let file = snapshot.file_at(location);
+//         let language = snapshot.language_at(location);
+//         let settings = all_language_settings(file, cx);
+//         settings.copilot_enabled(language, file.map(|f| f.path().as_ref()))
+//     }
+
+//     fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
+//         if let Some(suggestion) = self.copilot_state.suggestion.as_ref() {
+//             let buffer = self.buffer.read(cx).read(cx);
+//             suggestion.position.is_valid(&buffer)
+//         } else {
+//             false
+//         }
+//     }
+
+//     fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> Option<Inlay> {
+//         let suggestion = self.copilot_state.suggestion.take()?;
+//         self.display_map.update(cx, |map, cx| {
+//             map.splice_inlays(vec![suggestion.id], Default::default(), cx);
+//         });
+//         let buffer = self.buffer.read(cx).read(cx);
+
+//         if suggestion.position.is_valid(&buffer) {
+//             Some(suggestion)
+//         } else {
+//             None
+//         }
+//     }
+
+//     fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
+//         let snapshot = self.buffer.read(cx).snapshot(cx);
+//         let selection = self.selections.newest_anchor();
+//         let cursor = selection.head();
+
+//         if self.context_menu.read().is_some()
+//             || !self.completion_tasks.is_empty()
+//             || selection.start != selection.end
+//         {
+//             self.discard_copilot_suggestion(cx);
+//         } else if let Some(text) = self
+//             .copilot_state
+//             .text_for_active_completion(cursor, &snapshot)
+//         {
+//             let text = Rope::from(text);
+//             let mut to_remove = Vec::new();
+//             if let Some(suggestion) = self.copilot_state.suggestion.take() {
+//                 to_remove.push(suggestion.id);
+//             }
+
+//             let suggestion_inlay =
+//                 Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
+//             self.copilot_state.suggestion = Some(suggestion_inlay.clone());
+//             self.display_map.update(cx, move |map, cx| {
+//                 map.splice_inlays(to_remove, vec![suggestion_inlay], cx)
+//             });
+//             cx.notify();
+//         } else {
+//             self.discard_copilot_suggestion(cx);
+//         }
+//     }
+
+//     fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) {
+//         self.copilot_state = Default::default();
+//         self.discard_copilot_suggestion(cx);
+//     }
+
+//     pub fn render_code_actions_indicator(
+//         &self,
+//         style: &EditorStyle,
+//         is_active: bool,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<AnyElement<Self>> {
+//         if self.available_code_actions.is_some() {
+//             enum CodeActions {}
+//             Some(
+//                 MouseEventHandler::new::<CodeActions, _>(0, cx, |state, _| {
+//                     Svg::new("icons/bolt.svg").with_color(
+//                         style
+//                             .code_actions
+//                             .indicator
+//                             .in_state(is_active)
+//                             .style_for(state)
+//                             .color,
+//                     )
+//                 })
+//                 .with_cursor_style(CursorStyle::PointingHand)
+//                 .with_padding(Padding::uniform(3.))
+//                 .on_down(MouseButton::Left, |_, this, cx| {
+//                     this.toggle_code_actions(
+//                         &ToggleCodeActions {
+//                             deployed_from_indicator: true,
+//                         },
+//                         cx,
+//                     );
+//                 })
+//                 .into_any(),
+//             )
+//         } else {
+//             None
+//         }
+//     }
+
+//     pub fn render_fold_indicators(
+//         &self,
+//         fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
+//         style: &EditorStyle,
+//         gutter_hovered: bool,
+//         line_height: f32,
+//         gutter_margin: f32,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Vec<Option<AnyElement<Self>>> {
+//         enum FoldIndicators {}
+
+//         let style = style.folds.clone();
+
+//         fold_data
+//             .iter()
+//             .enumerate()
+//             .map(|(ix, fold_data)| {
+//                 fold_data
+//                     .map(|(fold_status, buffer_row, active)| {
+//                         (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
+//                             MouseEventHandler::new::<FoldIndicators, _>(
+//                                 ix as usize,
+//                                 cx,
+//                                 |mouse_state, _| {
+//                                     Svg::new(match fold_status {
+//                                         FoldStatus::Folded => style.folded_icon.clone(),
+//                                         FoldStatus::Foldable => style.foldable_icon.clone(),
+//                                     })
+//                                     .with_color(
+//                                         style
+//                                             .indicator
+//                                             .in_state(fold_status == FoldStatus::Folded)
+//                                             .style_for(mouse_state)
+//                                             .color,
+//                                     )
+//                                     .constrained()
+//                                     .with_width(gutter_margin * style.icon_margin_scale)
+//                                     .aligned()
+//                                     .constrained()
+//                                     .with_height(line_height)
+//                                     .with_width(gutter_margin)
+//                                     .aligned()
+//                                 },
+//                             )
+//                             .with_cursor_style(CursorStyle::PointingHand)
+//                             .with_padding(Padding::uniform(3.))
+//                             .on_click(MouseButton::Left, {
+//                                 move |_, editor, cx| match fold_status {
+//                                     FoldStatus::Folded => {
+//                                         editor.unfold_at(&UnfoldAt { buffer_row }, cx);
+//                                     }
+//                                     FoldStatus::Foldable => {
+//                                         editor.fold_at(&FoldAt { buffer_row }, cx);
+//                                     }
+//                                 }
+//                             })
+//                             .into_any()
+//                         })
+//                     })
+//                     .flatten()
+//             })
+//             .collect()
+//     }
+
+//     pub fn context_menu_visible(&self) -> bool {
+//         self.context_menu
+//             .read()
+//             .as_ref()
+//             .map_or(false, |menu| menu.visible())
+//     }
+
+//     pub fn render_context_menu(
+//         &self,
+//         cursor_position: DisplayPoint,
+//         style: EditorStyle,
+//         cx: &mut ViewContext<Editor>,
+//     ) -> Option<(DisplayPoint, AnyElement<Editor>)> {
+//         self.context_menu.read().as_ref().map(|menu| {
+//             menu.render(
+//                 cursor_position,
+//                 style,
+//                 self.workspace.as_ref().map(|(w, _)| w.clone()),
+//                 cx,
+//             )
+//         })
+//     }
+
+//     fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
+//         cx.notify();
+//         self.completion_tasks.clear();
+//         let context_menu = self.context_menu.write().take();
+//         if context_menu.is_some() {
+//             self.update_visible_copilot_suggestion(cx);
+//         }
+//         context_menu
+//     }
+
+//     pub fn insert_snippet(
+//         &mut self,
+//         insertion_ranges: &[Range<usize>],
+//         snippet: Snippet,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Result<()> {
+//         let tabstops = self.buffer.update(cx, |buffer, cx| {
+//             let snippet_text: Arc<str> = snippet.text.clone().into();
+//             buffer.edit(
+//                 insertion_ranges
+//                     .iter()
+//                     .cloned()
+//                     .map(|range| (range, snippet_text.clone())),
+//                 Some(AutoindentMode::EachLine),
+//                 cx,
+//             );
+
+//             let snapshot = &*buffer.read(cx);
+//             let snippet = &snippet;
+//             snippet
+//                 .tabstops
+//                 .iter()
+//                 .map(|tabstop| {
+//                     let mut tabstop_ranges = tabstop
+//                         .iter()
+//                         .flat_map(|tabstop_range| {
+//                             let mut delta = 0_isize;
+//                             insertion_ranges.iter().map(move |insertion_range| {
+//                                 let insertion_start = insertion_range.start as isize + delta;
+//                                 delta +=
+//                                     snippet.text.len() as isize - insertion_range.len() as isize;
+
+//                                 let start = snapshot.anchor_before(
+//                                     (insertion_start + tabstop_range.start) as usize,
+//                                 );
+//                                 let end = snapshot
+//                                     .anchor_after((insertion_start + tabstop_range.end) as usize);
+//                                 start..end
+//                             })
+//                         })
+//                         .collect::<Vec<_>>();
+//                     tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
+//                     tabstop_ranges
+//                 })
+//                 .collect::<Vec<_>>()
+//         });
+
+//         if let Some(tabstop) = tabstops.first() {
+//             self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select_ranges(tabstop.iter().cloned());
+//             });
+//             self.snippet_stack.push(SnippetState {
+//                 active_index: 0,
+//                 ranges: tabstops,
+//             });
+//         }
+
+//         Ok(())
+//     }
+
+//     pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
+//         self.move_to_snippet_tabstop(Bias::Right, cx)
+//     }
+
+//     pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
+//         self.move_to_snippet_tabstop(Bias::Left, cx)
+//     }
+
+//     pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
+//         if let Some(mut snippet) = self.snippet_stack.pop() {
+//             match bias {
+//                 Bias::Left => {
+//                     if snippet.active_index > 0 {
+//                         snippet.active_index -= 1;
+//                     } else {
+//                         self.snippet_stack.push(snippet);
+//                         return false;
+//                     }
+//                 }
+//                 Bias::Right => {
+//                     if snippet.active_index + 1 < snippet.ranges.len() {
+//                         snippet.active_index += 1;
+//                     } else {
+//                         self.snippet_stack.push(snippet);
+//                         return false;
+//                     }
+//                 }
+//             }
+//             if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
+//                 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                     s.select_anchor_ranges(current_ranges.iter().cloned())
+//                 });
+//                 // If snippet state is not at the last tabstop, push it back on the stack
+//                 if snippet.active_index + 1 < snippet.ranges.len() {
+//                     self.snippet_stack.push(snippet);
+//                 }
+//                 return true;
+//             }
+//         }
+
+//         false
+//     }
+
+//     pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.select_all(&SelectAll, cx);
+//             this.insert("", cx);
+//         });
+//     }
+
+//     pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.select_autoclose_pair(cx);
+//             let mut selections = this.selections.all::<Point>(cx);
+//             if !this.selections.line_mode {
+//                 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
+//                 for selection in &mut selections {
+//                     if selection.is_empty() {
+//                         let old_head = selection.head();
+//                         let mut new_head =
+//                             movement::left(&display_map, old_head.to_display_point(&display_map))
+//                                 .to_point(&display_map);
+//                         if let Some((buffer, line_buffer_range)) = display_map
+//                             .buffer_snapshot
+//                             .buffer_line_for_row(old_head.row)
+//                         {
+//                             let indent_size =
+//                                 buffer.indent_size_for_line(line_buffer_range.start.row);
+//                             let indent_len = match indent_size.kind {
+//                                 IndentKind::Space => {
+//                                     buffer.settings_at(line_buffer_range.start, cx).tab_size
+//                                 }
+//                                 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
+//                             };
+//                             if old_head.column <= indent_size.len && old_head.column > 0 {
+//                                 let indent_len = indent_len.get();
+//                                 new_head = cmp::min(
+//                                     new_head,
+//                                     Point::new(
+//                                         old_head.row,
+//                                         ((old_head.column - 1) / indent_len) * indent_len,
+//                                     ),
+//                                 );
+//                             }
+//                         }
+
+//                         selection.set_head(new_head, SelectionGoal::None);
+//                     }
+//                 }
+//             }
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
+//             this.insert("", cx);
+//             this.refresh_copilot_suggestions(true, cx);
+//         });
+//     }
+
+//     pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let line_mode = s.line_mode;
+//                 s.move_with(|map, selection| {
+//                     if selection.is_empty() && !line_mode {
+//                         let cursor = movement::right(map, selection.head());
+//                         selection.end = cursor;
+//                         selection.reversed = true;
+//                         selection.goal = SelectionGoal::None;
+//                     }
+//                 })
+//             });
+//             this.insert("", cx);
+//             this.refresh_copilot_suggestions(true, cx);
+//         });
+//     }
+
+//     pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
+//         if self.move_to_prev_snippet_tabstop(cx) {
+//             return;
+//         }
+
+//         self.outdent(&Outdent, cx);
+//     }
+
+//     pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
+//         if self.move_to_next_snippet_tabstop(cx) {
+//             return;
+//         }
+
+//         let mut selections = self.selections.all_adjusted(cx);
+//         let buffer = self.buffer.read(cx);
+//         let snapshot = buffer.snapshot(cx);
+//         let rows_iter = selections.iter().map(|s| s.head().row);
+//         let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
+
+//         let mut edits = Vec::new();
+//         let mut prev_edited_row = 0;
+//         let mut row_delta = 0;
+//         for selection in &mut selections {
+//             if selection.start.row != prev_edited_row {
+//                 row_delta = 0;
+//             }
+//             prev_edited_row = selection.end.row;
+
+//             // If the selection is non-empty, then increase the indentation of the selected lines.
+//             if !selection.is_empty() {
+//                 row_delta =
+//                     Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
+//                 continue;
+//             }
+
+//             // If the selection is empty and the cursor is in the leading whitespace before the
+//             // suggested indentation, then auto-indent the line.
+//             let cursor = selection.head();
+//             let current_indent = snapshot.indent_size_for_line(cursor.row);
+//             if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
+//                 if cursor.column < suggested_indent.len
+//                     && cursor.column <= current_indent.len
+//                     && current_indent.len <= suggested_indent.len
+//                 {
+//                     selection.start = Point::new(cursor.row, suggested_indent.len);
+//                     selection.end = selection.start;
+//                     if row_delta == 0 {
+//                         edits.extend(Buffer::edit_for_indent_size_adjustment(
+//                             cursor.row,
+//                             current_indent,
+//                             suggested_indent,
+//                         ));
+//                         row_delta = suggested_indent.len - current_indent.len;
+//                     }
+//                     continue;
+//                 }
+//             }
+
+//             // Accept copilot suggestion if there is only one selection and the cursor is not
+//             // in the leading whitespace.
+//             if self.selections.count() == 1
+//                 && cursor.column >= current_indent.len
+//                 && self.has_active_copilot_suggestion(cx)
+//             {
+//                 self.accept_copilot_suggestion(cx);
+//                 return;
+//             }
+
+//             // Otherwise, insert a hard or soft tab.
+//             let settings = buffer.settings_at(cursor, cx);
+//             let tab_size = if settings.hard_tabs {
+//                 IndentSize::tab()
+//             } else {
+//                 let tab_size = settings.tab_size.get();
+//                 let char_column = snapshot
+//                     .text_for_range(Point::new(cursor.row, 0)..cursor)
+//                     .flat_map(str::chars)
+//                     .count()
+//                     + row_delta as usize;
+//                 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
+//                 IndentSize::spaces(chars_to_next_tab_stop)
+//             };
+//             selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
+//             selection.end = selection.start;
+//             edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
+//             row_delta += tab_size.len;
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
+//             this.refresh_copilot_suggestions(true, cx);
+//         });
+//     }
+
+//     pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
+//         let mut selections = self.selections.all::<Point>(cx);
+//         let mut prev_edited_row = 0;
+//         let mut row_delta = 0;
+//         let mut edits = Vec::new();
+//         let buffer = self.buffer.read(cx);
+//         let snapshot = buffer.snapshot(cx);
+//         for selection in &mut selections {
+//             if selection.start.row != prev_edited_row {
+//                 row_delta = 0;
+//             }
+//             prev_edited_row = selection.end.row;
+
+//             row_delta =
+//                 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
+//         });
+//     }
+
+//     fn indent_selection(
+//         buffer: &MultiBuffer,
+//         snapshot: &MultiBufferSnapshot,
+//         selection: &mut Selection<Point>,
+//         edits: &mut Vec<(Range<Point>, String)>,
+//         delta_for_start_row: u32,
+//         cx: &AppContext,
+//     ) -> u32 {
+//         let settings = buffer.settings_at(selection.start, cx);
+//         let tab_size = settings.tab_size.get();
+//         let indent_kind = if settings.hard_tabs {
+//             IndentKind::Tab
+//         } else {
+//             IndentKind::Space
+//         };
+//         let mut start_row = selection.start.row;
+//         let mut end_row = selection.end.row + 1;
+
+//         // If a selection ends at the beginning of a line, don't indent
+//         // that last line.
+//         if selection.end.column == 0 {
+//             end_row -= 1;
+//         }
+
+//         // Avoid re-indenting a row that has already been indented by a
+//         // previous selection, but still update this selection's column
+//         // to reflect that indentation.
+//         if delta_for_start_row > 0 {
+//             start_row += 1;
+//             selection.start.column += delta_for_start_row;
+//             if selection.end.row == selection.start.row {
+//                 selection.end.column += delta_for_start_row;
+//             }
+//         }
+
+//         let mut delta_for_end_row = 0;
+//         for row in start_row..end_row {
+//             let current_indent = snapshot.indent_size_for_line(row);
+//             let indent_delta = match (current_indent.kind, indent_kind) {
+//                 (IndentKind::Space, IndentKind::Space) => {
+//                     let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
+//                     IndentSize::spaces(columns_to_next_tab_stop)
+//                 }
+//                 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
+//                 (_, IndentKind::Tab) => IndentSize::tab(),
+//             };
+
+//             let row_start = Point::new(row, 0);
+//             edits.push((
+//                 row_start..row_start,
+//                 indent_delta.chars().collect::<String>(),
+//             ));
+
+//             // Update this selection's endpoints to reflect the indentation.
+//             if row == selection.start.row {
+//                 selection.start.column += indent_delta.len;
+//             }
+//             if row == selection.end.row {
+//                 selection.end.column += indent_delta.len;
+//                 delta_for_end_row = indent_delta.len;
+//             }
+//         }
+
+//         if selection.start.row == selection.end.row {
+//             delta_for_start_row + delta_for_end_row
+//         } else {
+//             delta_for_end_row
+//         }
+//     }
+
+//     pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let selections = self.selections.all::<Point>(cx);
+//         let mut deletion_ranges = Vec::new();
+//         let mut last_outdent = None;
+//         {
+//             let buffer = self.buffer.read(cx);
+//             let snapshot = buffer.snapshot(cx);
+//             for selection in &selections {
+//                 let settings = buffer.settings_at(selection.start, cx);
+//                 let tab_size = settings.tab_size.get();
+//                 let mut rows = selection.spanned_rows(false, &display_map);
+
+//                 // Avoid re-outdenting a row that has already been outdented by a
+//                 // previous selection.
+//                 if let Some(last_row) = last_outdent {
+//                     if last_row == rows.start {
+//                         rows.start += 1;
+//                     }
+//                 }
+
+//                 for row in rows {
+//                     let indent_size = snapshot.indent_size_for_line(row);
+//                     if indent_size.len > 0 {
+//                         let deletion_len = match indent_size.kind {
+//                             IndentKind::Space => {
+//                                 let columns_to_prev_tab_stop = indent_size.len % tab_size;
+//                                 if columns_to_prev_tab_stop == 0 {
+//                                     tab_size
+//                                 } else {
+//                                     columns_to_prev_tab_stop
+//                                 }
+//                             }
+//                             IndentKind::Tab => 1,
+//                         };
+//                         deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
+//                         last_outdent = Some(row);
+//                     }
+//                 }
+//             }
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |buffer, cx| {
+//                 let empty_str: Arc<str> = "".into();
+//                 buffer.edit(
+//                     deletion_ranges
+//                         .into_iter()
+//                         .map(|range| (range, empty_str.clone())),
+//                     None,
+//                     cx,
+//                 );
+//             });
+//             let selections = this.selections.all::<usize>(cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
+//         });
+//     }
+
+//     pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let selections = self.selections.all::<Point>(cx);
+
+//         let mut new_cursors = Vec::new();
+//         let mut edit_ranges = Vec::new();
+//         let mut selections = selections.iter().peekable();
+//         while let Some(selection) = selections.next() {
+//             let mut rows = selection.spanned_rows(false, &display_map);
+//             let goal_display_column = selection.head().to_display_point(&display_map).column();
+
+//             // Accumulate contiguous regions of rows that we want to delete.
+//             while let Some(next_selection) = selections.peek() {
+//                 let next_rows = next_selection.spanned_rows(false, &display_map);
+//                 if next_rows.start <= rows.end {
+//                     rows.end = next_rows.end;
+//                     selections.next().unwrap();
+//                 } else {
+//                     break;
+//                 }
+//             }
+
+//             let buffer = &display_map.buffer_snapshot;
+//             let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
+//             let edit_end;
+//             let cursor_buffer_row;
+//             if buffer.max_point().row >= rows.end {
+//                 // If there's a line after the range, delete the \n from the end of the row range
+//                 // and position the cursor on the next line.
+//                 edit_end = Point::new(rows.end, 0).to_offset(buffer);
+//                 cursor_buffer_row = rows.end;
+//             } else {
+//                 // If there isn't a line after the range, delete the \n from the line before the
+//                 // start of the row range and position the cursor there.
+//                 edit_start = edit_start.saturating_sub(1);
+//                 edit_end = buffer.len();
+//                 cursor_buffer_row = rows.start.saturating_sub(1);
+//             }
+
+//             let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
+//             *cursor.column_mut() =
+//                 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
+
+//             new_cursors.push((
+//                 selection.id,
+//                 buffer.anchor_after(cursor.to_point(&display_map)),
+//             ));
+//             edit_ranges.push(edit_start..edit_end);
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             let buffer = this.buffer.update(cx, |buffer, cx| {
+//                 let empty_str: Arc<str> = "".into();
+//                 buffer.edit(
+//                     edit_ranges
+//                         .into_iter()
+//                         .map(|range| (range, empty_str.clone())),
+//                     None,
+//                     cx,
+//                 );
+//                 buffer.snapshot(cx)
+//             });
+//             let new_selections = new_cursors
+//                 .into_iter()
+//                 .map(|(id, cursor)| {
+//                     let cursor = cursor.to_point(&buffer);
+//                     Selection {
+//                         id,
+//                         start: cursor,
+//                         end: cursor,
+//                         reversed: false,
+//                         goal: SelectionGoal::None,
+//                     }
+//                 })
+//                 .collect();
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(new_selections);
+//             });
+//         });
+//     }
+
+//     pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
+//         let mut row_ranges = Vec::<Range<u32>>::new();
+//         for selection in self.selections.all::<Point>(cx) {
+//             let start = selection.start.row;
+//             let end = if selection.start.row == selection.end.row {
+//                 selection.start.row + 1
+//             } else {
+//                 selection.end.row
+//             };
+
+//             if let Some(last_row_range) = row_ranges.last_mut() {
+//                 if start <= last_row_range.end {
+//                     last_row_range.end = end;
+//                     continue;
+//                 }
+//             }
+//             row_ranges.push(start..end);
+//         }
+
+//         let snapshot = self.buffer.read(cx).snapshot(cx);
+//         let mut cursor_positions = Vec::new();
+//         for row_range in &row_ranges {
+//             let anchor = snapshot.anchor_before(Point::new(
+//                 row_range.end - 1,
+//                 snapshot.line_len(row_range.end - 1),
+//             ));
+//             cursor_positions.push(anchor.clone()..anchor);
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             for row_range in row_ranges.into_iter().rev() {
+//                 for row in row_range.rev() {
+//                     let end_of_line = Point::new(row, snapshot.line_len(row));
+//                     let indent = snapshot.indent_size_for_line(row + 1);
+//                     let start_of_next_line = Point::new(row + 1, indent.len);
+
+//                     let replace = if snapshot.line_len(row + 1) > indent.len {
+//                         " "
+//                     } else {
+//                         ""
+//                     };
+
+//                     this.buffer.update(cx, |buffer, cx| {
+//                         buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
+//                     });
+//                 }
+//             }
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select_anchor_ranges(cursor_positions)
+//             });
+//         });
+//     }
+
+//     pub fn sort_lines_case_sensitive(
+//         &mut self,
+//         _: &SortLinesCaseSensitive,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.manipulate_lines(cx, |lines| lines.sort())
+//     }
+
+//     pub fn sort_lines_case_insensitive(
+//         &mut self,
+//         _: &SortLinesCaseInsensitive,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
+//     }
+
+//     pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
+//         self.manipulate_lines(cx, |lines| lines.reverse())
+//     }
+
+//     pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
+//         self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
+//     }
+
+//     fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
+//     where
+//         Fn: FnMut(&mut [&str]),
+//     {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+
+//         let mut edits = Vec::new();
+
+//         let selections = self.selections.all::<Point>(cx);
+//         let mut selections = selections.iter().peekable();
+//         let mut contiguous_row_selections = Vec::new();
+//         let mut new_selections = Vec::new();
+
+//         while let Some(selection) = selections.next() {
+//             let (start_row, end_row) = consume_contiguous_rows(
+//                 &mut contiguous_row_selections,
+//                 selection,
+//                 &display_map,
+//                 &mut selections,
+//             );
+
+//             let start_point = Point::new(start_row, 0);
+//             let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1));
+//             let text = buffer
+//                 .text_for_range(start_point..end_point)
+//                 .collect::<String>();
+//             let mut lines = text.split("\n").collect_vec();
+
+//             let lines_len = lines.len();
+//             callback(&mut lines);
+
+//             // This is a current limitation with selections.
+//             // If we wanted to support removing or adding lines, we'd need to fix the logic associated with selections.
+//             debug_assert!(
+//                 lines.len() == lines_len,
+//                 "callback should not change the number of lines"
+//             );
+
+//             edits.push((start_point..end_point, lines.join("\n")));
+//             let start_anchor = buffer.anchor_after(start_point);
+//             let end_anchor = buffer.anchor_before(end_point);
+
+//             // Make selection and push
+//             new_selections.push(Selection {
+//                 id: selection.id,
+//                 start: start_anchor.to_offset(&buffer),
+//                 end: end_anchor.to_offset(&buffer),
+//                 goal: SelectionGoal::None,
+//                 reversed: selection.reversed,
+//             });
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |buffer, cx| {
+//                 buffer.edit(edits, None, cx);
+//             });
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(new_selections);
+//             });
+
+//             this.request_autoscroll(Autoscroll::fit(), cx);
+//         });
+//     }
+
+//     pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
+//         self.manipulate_text(cx, |text| text.to_uppercase())
+//     }
+
+//     pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
+//         self.manipulate_text(cx, |text| text.to_lowercase())
+//     }
+
+//     pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
+//         self.manipulate_text(cx, |text| {
+//             // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
+//             // https://github.com/rutrum/convert-case/issues/16
+//             text.split("\n")
+//                 .map(|line| line.to_case(Case::Title))
+//                 .join("\n")
+//         })
+//     }
+
+//     pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
+//         self.manipulate_text(cx, |text| text.to_case(Case::Snake))
+//     }
+
+//     pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
+//         self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
+//     }
+
+//     pub fn convert_to_upper_camel_case(
+//         &mut self,
+//         _: &ConvertToUpperCamelCase,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.manipulate_text(cx, |text| {
+//             // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
+//             // https://github.com/rutrum/convert-case/issues/16
+//             text.split("\n")
+//                 .map(|line| line.to_case(Case::UpperCamel))
+//                 .join("\n")
+//         })
+//     }
+
+//     pub fn convert_to_lower_camel_case(
+//         &mut self,
+//         _: &ConvertToLowerCamelCase,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.manipulate_text(cx, |text| text.to_case(Case::Camel))
+//     }
+
+//     fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
+//     where
+//         Fn: FnMut(&str) -> String,
+//     {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+
+//         let mut new_selections = Vec::new();
+//         let mut edits = Vec::new();
+//         let mut selection_adjustment = 0i32;
+
+//         for selection in self.selections.all::<usize>(cx) {
+//             let selection_is_empty = selection.is_empty();
+
+//             let (start, end) = if selection_is_empty {
+//                 let word_range = movement::surrounding_word(
+//                     &display_map,
+//                     selection.start.to_display_point(&display_map),
+//                 );
+//                 let start = word_range.start.to_offset(&display_map, Bias::Left);
+//                 let end = word_range.end.to_offset(&display_map, Bias::Left);
+//                 (start, end)
+//             } else {
+//                 (selection.start, selection.end)
+//             };
+
+//             let text = buffer.text_for_range(start..end).collect::<String>();
+//             let old_length = text.len() as i32;
+//             let text = callback(&text);
+
+//             new_selections.push(Selection {
+//                 start: (start as i32 - selection_adjustment) as usize,
+//                 end: ((start + text.len()) as i32 - selection_adjustment) as usize,
+//                 goal: SelectionGoal::None,
+//                 ..selection
+//             });
+
+//             selection_adjustment += old_length - text.len() as i32;
+
+//             edits.push((start..end, text));
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |buffer, cx| {
+//                 buffer.edit(edits, None, cx);
+//             });
+
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(new_selections);
+//             });
+
+//             this.request_autoscroll(Autoscroll::fit(), cx);
+//         });
+//     }
+
+//     pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = &display_map.buffer_snapshot;
+//         let selections = self.selections.all::<Point>(cx);
+
+//         let mut edits = Vec::new();
+//         let mut selections_iter = selections.iter().peekable();
+//         while let Some(selection) = selections_iter.next() {
+//             // Avoid duplicating the same lines twice.
+//             let mut rows = selection.spanned_rows(false, &display_map);
+
+//             while let Some(next_selection) = selections_iter.peek() {
+//                 let next_rows = next_selection.spanned_rows(false, &display_map);
+//                 if next_rows.start < rows.end {
+//                     rows.end = next_rows.end;
+//                     selections_iter.next().unwrap();
+//                 } else {
+//                     break;
+//                 }
+//             }
+
+//             // Copy the text from the selected row region and splice it at the start of the region.
+//             let start = Point::new(rows.start, 0);
+//             let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
+//             let text = buffer
+//                 .text_for_range(start..end)
+//                 .chain(Some("\n"))
+//                 .collect::<String>();
+//             edits.push((start..start, text));
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.buffer.update(cx, |buffer, cx| {
+//                 buffer.edit(edits, None, cx);
+//             });
+
+//             this.request_autoscroll(Autoscroll::fit(), cx);
+//         });
+//     }
+
+//     pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+
+//         let mut edits = Vec::new();
+//         let mut unfold_ranges = Vec::new();
+//         let mut refold_ranges = Vec::new();
+
+//         let selections = self.selections.all::<Point>(cx);
+//         let mut selections = selections.iter().peekable();
+//         let mut contiguous_row_selections = Vec::new();
+//         let mut new_selections = Vec::new();
+
+//         while let Some(selection) = selections.next() {
+//             // Find all the selections that span a contiguous row range
+//             let (start_row, end_row) = consume_contiguous_rows(
+//                 &mut contiguous_row_selections,
+//                 selection,
+//                 &display_map,
+//                 &mut selections,
+//             );
+
+//             // Move the text spanned by the row range to be before the line preceding the row range
+//             if start_row > 0 {
+//                 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
+//                     ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
+//                 let insertion_point = display_map
+//                     .prev_line_boundary(Point::new(start_row - 1, 0))
+//                     .0;
+
+//                 // Don't move lines across excerpts
+//                 if buffer
+//                     .excerpt_boundaries_in_range((
+//                         Bound::Excluded(insertion_point),
+//                         Bound::Included(range_to_move.end),
+//                     ))
+//                     .next()
+//                     .is_none()
+//                 {
+//                     let text = buffer
+//                         .text_for_range(range_to_move.clone())
+//                         .flat_map(|s| s.chars())
+//                         .skip(1)
+//                         .chain(['\n'])
+//                         .collect::<String>();
+
+//                     edits.push((
+//                         buffer.anchor_after(range_to_move.start)
+//                             ..buffer.anchor_before(range_to_move.end),
+//                         String::new(),
+//                     ));
+//                     let insertion_anchor = buffer.anchor_after(insertion_point);
+//                     edits.push((insertion_anchor..insertion_anchor, text));
+
+//                     let row_delta = range_to_move.start.row - insertion_point.row + 1;
+
+//                     // Move selections up
+//                     new_selections.extend(contiguous_row_selections.drain(..).map(
+//                         |mut selection| {
+//                             selection.start.row -= row_delta;
+//                             selection.end.row -= row_delta;
+//                             selection
+//                         },
+//                     ));
+
+//                     // Move folds up
+//                     unfold_ranges.push(range_to_move.clone());
+//                     for fold in display_map.folds_in_range(
+//                         buffer.anchor_before(range_to_move.start)
+//                             ..buffer.anchor_after(range_to_move.end),
+//                     ) {
+//                         let mut start = fold.start.to_point(&buffer);
+//                         let mut end = fold.end.to_point(&buffer);
+//                         start.row -= row_delta;
+//                         end.row -= row_delta;
+//                         refold_ranges.push(start..end);
+//                     }
+//                 }
+//             }
+
+//             // If we didn't move line(s), preserve the existing selections
+//             new_selections.append(&mut contiguous_row_selections);
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.unfold_ranges(unfold_ranges, true, true, cx);
+//             this.buffer.update(cx, |buffer, cx| {
+//                 for (range, text) in edits {
+//                     buffer.edit([(range, text)], None, cx);
+//                 }
+//             });
+//             this.fold_ranges(refold_ranges, true, cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(new_selections);
+//             })
+//         });
+//     }
+
+//     pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+
+//         let mut edits = Vec::new();
+//         let mut unfold_ranges = Vec::new();
+//         let mut refold_ranges = Vec::new();
+
+//         let selections = self.selections.all::<Point>(cx);
+//         let mut selections = selections.iter().peekable();
+//         let mut contiguous_row_selections = Vec::new();
+//         let mut new_selections = Vec::new();
+
+//         while let Some(selection) = selections.next() {
+//             // Find all the selections that span a contiguous row range
+//             let (start_row, end_row) = consume_contiguous_rows(
+//                 &mut contiguous_row_selections,
+//                 selection,
+//                 &display_map,
+//                 &mut selections,
+//             );
+
+//             // Move the text spanned by the row range to be after the last line of the row range
+//             if end_row <= buffer.max_point().row {
+//                 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
+//                 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
+
+//                 // Don't move lines across excerpt boundaries
+//                 if buffer
+//                     .excerpt_boundaries_in_range((
+//                         Bound::Excluded(range_to_move.start),
+//                         Bound::Included(insertion_point),
+//                     ))
+//                     .next()
+//                     .is_none()
+//                 {
+//                     let mut text = String::from("\n");
+//                     text.extend(buffer.text_for_range(range_to_move.clone()));
+//                     text.pop(); // Drop trailing newline
+//                     edits.push((
+//                         buffer.anchor_after(range_to_move.start)
+//                             ..buffer.anchor_before(range_to_move.end),
+//                         String::new(),
+//                     ));
+//                     let insertion_anchor = buffer.anchor_after(insertion_point);
+//                     edits.push((insertion_anchor..insertion_anchor, text));
+
+//                     let row_delta = insertion_point.row - range_to_move.end.row + 1;
+
+//                     // Move selections down
+//                     new_selections.extend(contiguous_row_selections.drain(..).map(
+//                         |mut selection| {
+//                             selection.start.row += row_delta;
+//                             selection.end.row += row_delta;
+//                             selection
+//                         },
+//                     ));
+
+//                     // Move folds down
+//                     unfold_ranges.push(range_to_move.clone());
+//                     for fold in display_map.folds_in_range(
+//                         buffer.anchor_before(range_to_move.start)
+//                             ..buffer.anchor_after(range_to_move.end),
+//                     ) {
+//                         let mut start = fold.start.to_point(&buffer);
+//                         let mut end = fold.end.to_point(&buffer);
+//                         start.row += row_delta;
+//                         end.row += row_delta;
+//                         refold_ranges.push(start..end);
+//                     }
+//                 }
+//             }
+
+//             // If we didn't move line(s), preserve the existing selections
+//             new_selections.append(&mut contiguous_row_selections);
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.unfold_ranges(unfold_ranges, true, true, cx);
+//             this.buffer.update(cx, |buffer, cx| {
+//                 for (range, text) in edits {
+//                     buffer.edit([(range, text)], None, cx);
+//                 }
+//             });
+//             this.fold_ranges(refold_ranges, true, cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
+//         });
+//     }
+
+//     pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
+//         let text_layout_details = &self.text_layout_details(cx);
+//         self.transact(cx, |this, cx| {
+//             let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let mut edits: Vec<(Range<usize>, String)> = Default::default();
+//                 let line_mode = s.line_mode;
+//                 s.move_with(|display_map, selection| {
+//                     if !selection.is_empty() || line_mode {
+//                         return;
+//                     }
+
+//                     let mut head = selection.head();
+//                     let mut transpose_offset = head.to_offset(display_map, Bias::Right);
+//                     if head.column() == display_map.line_len(head.row()) {
+//                         transpose_offset = display_map
+//                             .buffer_snapshot
+//                             .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
+//                     }
+
+//                     if transpose_offset == 0 {
+//                         return;
+//                     }
+
+//                     *head.column_mut() += 1;
+//                     head = display_map.clip_point(head, Bias::Right);
+//                     let goal = SelectionGoal::HorizontalPosition(
+//                         display_map.x_for_point(head, &text_layout_details),
+//                     );
+//                     selection.collapse_to(head, goal);
+
+//                     let transpose_start = display_map
+//                         .buffer_snapshot
+//                         .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
+//                     if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
+//                         let transpose_end = display_map
+//                             .buffer_snapshot
+//                             .clip_offset(transpose_offset + 1, Bias::Right);
+//                         if let Some(ch) =
+//                             display_map.buffer_snapshot.chars_at(transpose_start).next()
+//                         {
+//                             edits.push((transpose_start..transpose_offset, String::new()));
+//                             edits.push((transpose_end..transpose_end, ch.to_string()));
+//                         }
+//                     }
+//                 });
+//                 edits
+//             });
+//             this.buffer
+//                 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
+//             let selections = this.selections.all::<usize>(cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(selections);
+//             });
+//         });
+//     }
+
+//     pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
+//         let mut text = String::new();
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+//         let mut selections = self.selections.all::<Point>(cx);
+//         let mut clipboard_selections = Vec::with_capacity(selections.len());
+//         {
+//             let max_point = buffer.max_point();
+//             let mut is_first = true;
+//             for selection in &mut selections {
+//                 let is_entire_line = selection.is_empty() || self.selections.line_mode;
+//                 if is_entire_line {
+//                     selection.start = Point::new(selection.start.row, 0);
+//                     selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
+//                     selection.goal = SelectionGoal::None;
+//                 }
+//                 if is_first {
+//                     is_first = false;
+//                 } else {
+//                     text += "\n";
+//                 }
+//                 let mut len = 0;
+//                 for chunk in buffer.text_for_range(selection.start..selection.end) {
+//                     text.push_str(chunk);
+//                     len += chunk.len();
+//                 }
+//                 clipboard_selections.push(ClipboardSelection {
+//                     len,
+//                     is_entire_line,
+//                     first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
+//                 });
+//             }
+//         }
+
+//         self.transact(cx, |this, cx| {
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(selections);
+//             });
+//             this.insert("", cx);
+//             cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
+//         });
+//     }
+
+//     pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
+//         let selections = self.selections.all::<Point>(cx);
+//         let buffer = self.buffer.read(cx).read(cx);
+//         let mut text = String::new();
+
+//         let mut clipboard_selections = Vec::with_capacity(selections.len());
+//         {
+//             let max_point = buffer.max_point();
+//             let mut is_first = true;
+//             for selection in selections.iter() {
+//                 let mut start = selection.start;
+//                 let mut end = selection.end;
+//                 let is_entire_line = selection.is_empty() || self.selections.line_mode;
+//                 if is_entire_line {
+//                     start = Point::new(start.row, 0);
+//                     end = cmp::min(max_point, Point::new(end.row + 1, 0));
+//                 }
+//                 if is_first {
+//                     is_first = false;
+//                 } else {
+//                     text += "\n";
+//                 }
+//                 let mut len = 0;
+//                 for chunk in buffer.text_for_range(start..end) {
+//                     text.push_str(chunk);
+//                     len += chunk.len();
+//                 }
+//                 clipboard_selections.push(ClipboardSelection {
+//                     len,
+//                     is_entire_line,
+//                     first_line_indent: buffer.indent_size_for_line(start.row).len,
+//                 });
+//             }
+//         }
+
+//         cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
+//     }
+
+//     pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             if let Some(item) = cx.read_from_clipboard() {
+//                 let clipboard_text = Cow::Borrowed(item.text());
+//                 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
+//                     let old_selections = this.selections.all::<usize>(cx);
+//                     let all_selections_were_entire_line =
+//                         clipboard_selections.iter().all(|s| s.is_entire_line);
+//                     let first_selection_indent_column =
+//                         clipboard_selections.first().map(|s| s.first_line_indent);
+//                     if clipboard_selections.len() != old_selections.len() {
+//                         clipboard_selections.drain(..);
+//                     }
+
+//                     this.buffer.update(cx, |buffer, cx| {
+//                         let snapshot = buffer.read(cx);
+//                         let mut start_offset = 0;
+//                         let mut edits = Vec::new();
+//                         let mut original_indent_columns = Vec::new();
+//                         let line_mode = this.selections.line_mode;
+//                         for (ix, selection) in old_selections.iter().enumerate() {
+//                             let to_insert;
+//                             let entire_line;
+//                             let original_indent_column;
+//                             if let Some(clipboard_selection) = clipboard_selections.get(ix) {
+//                                 let end_offset = start_offset + clipboard_selection.len;
+//                                 to_insert = &clipboard_text[start_offset..end_offset];
+//                                 entire_line = clipboard_selection.is_entire_line;
+//                                 start_offset = end_offset + 1;
+//                                 original_indent_column =
+//                                     Some(clipboard_selection.first_line_indent);
+//                             } else {
+//                                 to_insert = clipboard_text.as_str();
+//                                 entire_line = all_selections_were_entire_line;
+//                                 original_indent_column = first_selection_indent_column
+//                             }
+
+//                             // If the corresponding selection was empty when this slice of the
+//                             // clipboard text was written, then the entire line containing the
+//                             // selection was copied. If this selection is also currently empty,
+//                             // then paste the line before the current line of the buffer.
+//                             let range = if selection.is_empty() && !line_mode && entire_line {
+//                                 let column = selection.start.to_point(&snapshot).column as usize;
+//                                 let line_start = selection.start - column;
+//                                 line_start..line_start
+//                             } else {
+//                                 selection.range()
+//                             };
+
+//                             edits.push((range, to_insert));
+//                             original_indent_columns.extend(original_indent_column);
+//                         }
+//                         drop(snapshot);
+
+//                         buffer.edit(
+//                             edits,
+//                             Some(AutoindentMode::Block {
+//                                 original_indent_columns,
+//                             }),
+//                             cx,
+//                         );
+//                     });
+
+//                     let selections = this.selections.all::<usize>(cx);
+//                     this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
+//                 } else {
+//                     this.insert(&clipboard_text, cx);
+//                 }
+//             }
+//         });
+//     }
+
+//     pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
+//         if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
+//             if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
+//                 self.change_selections(None, cx, |s| {
+//                     s.select_anchors(selections.to_vec());
+//                 });
+//             }
+//             self.request_autoscroll(Autoscroll::fit(), cx);
+//             self.unmark_text(cx);
+//             self.refresh_copilot_suggestions(true, cx);
+//             cx.emit(Event::Edited);
+//         }
+//     }
+
+//     pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
+//         if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
+//             if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
+//             {
+//                 self.change_selections(None, cx, |s| {
+//                     s.select_anchors(selections.to_vec());
+//                 });
+//             }
+//             self.request_autoscroll(Autoscroll::fit(), cx);
+//             self.unmark_text(cx);
+//             self.refresh_copilot_suggestions(true, cx);
+//             cx.emit(Event::Edited);
+//         }
+//     }
+
+//     pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
+//         self.buffer
+//             .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
+//     }
+
+//     pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             let line_mode = s.line_mode;
+//             s.move_with(|map, selection| {
+//                 let cursor = if selection.is_empty() && !line_mode {
+//                     movement::left(map, selection.start)
+//                 } else {
+//                     selection.start
+//                 };
+//                 selection.collapse_to(cursor, SelectionGoal::None);
+//             });
+//         })
+//     }
+
+//     pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
+//         })
+//     }
+
+//     pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             let line_mode = s.line_mode;
+//             s.move_with(|map, selection| {
+//                 let cursor = if selection.is_empty() && !line_mode {
+//                     movement::right(map, selection.end)
+//                 } else {
+//                     selection.end
+//                 };
+//                 selection.collapse_to(cursor, SelectionGoal::None)
+//             });
+//         })
+//     }
+
+//     pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
+//         })
+//     }
+
+//     pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
+//         if self.take_rename(true, cx).is_some() {
+//             return;
+//         }
+
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         let text_layout_details = &self.text_layout_details(cx);
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             let line_mode = s.line_mode;
+//             s.move_with(|map, selection| {
+//                 if !selection.is_empty() && !line_mode {
+//                     selection.goal = SelectionGoal::None;
+//                 }
+//                 let (cursor, goal) = movement::up(
+//                     map,
+//                     selection.start,
+//                     selection.goal,
+//                     false,
+//                     &text_layout_details,
+//                 );
+//                 selection.collapse_to(cursor, goal);
+//             });
+//         })
+//     }
+
+//     pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
+//         if self.take_rename(true, cx).is_some() {
+//             return;
+//         }
+
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         let row_count = if let Some(row_count) = self.visible_line_count() {
+//             row_count as u32 - 1
+//         } else {
+//             return;
+//         };
+
+//         let autoscroll = if action.center_cursor {
+//             Autoscroll::center()
+//         } else {
+//             Autoscroll::fit()
+//         };
+
+//         let text_layout_details = &self.text_layout_details(cx);
+
+//         self.change_selections(Some(autoscroll), cx, |s| {
+//             let line_mode = s.line_mode;
+//             s.move_with(|map, selection| {
+//                 if !selection.is_empty() && !line_mode {
+//                     selection.goal = SelectionGoal::None;
+//                 }
+//                 let (cursor, goal) = movement::up_by_rows(
+//                     map,
+//                     selection.end,
+//                     row_count,
+//                     selection.goal,
+//                     false,
+//                     &text_layout_details,
+//                 );
+//                 selection.collapse_to(cursor, goal);
+//             });
+//         });
+//     }
+
+//     pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
+//         let text_layout_details = &self.text_layout_details(cx);
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, goal| {
+//                 movement::up(map, head, goal, false, &text_layout_details)
+//             })
+//         })
+//     }
+
+//     pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
+//         self.take_rename(true, cx);
+
+//         if self.mode == EditorMode::SingleLine {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         let text_layout_details = &self.text_layout_details(cx);
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             let line_mode = s.line_mode;
+//             s.move_with(|map, selection| {
+//                 if !selection.is_empty() && !line_mode {
+//                     selection.goal = SelectionGoal::None;
+//                 }
+//                 let (cursor, goal) = movement::down(
+//                     map,
+//                     selection.end,
+//                     selection.goal,
+//                     false,
+//                     &text_layout_details,
+//                 );
+//                 selection.collapse_to(cursor, goal);
+//             });
+//         });
+//     }
+
+//     pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
+//         if self.take_rename(true, cx).is_some() {
+//             return;
+//         }
+
+//         if self
+//             .context_menu
+//             .write()
+//             .as_mut()
+//             .map(|menu| menu.select_last(self.project.as_ref(), cx))
+//             .unwrap_or(false)
+//         {
+//             return;
+//         }
+
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         let row_count = if let Some(row_count) = self.visible_line_count() {
+//             row_count as u32 - 1
+//         } else {
+//             return;
+//         };
+
+//         let autoscroll = if action.center_cursor {
+//             Autoscroll::center()
+//         } else {
+//             Autoscroll::fit()
+//         };
+
+//         let text_layout_details = &self.text_layout_details(cx);
+//         self.change_selections(Some(autoscroll), cx, |s| {
+//             let line_mode = s.line_mode;
+//             s.move_with(|map, selection| {
+//                 if !selection.is_empty() && !line_mode {
+//                     selection.goal = SelectionGoal::None;
+//                 }
+//                 let (cursor, goal) = movement::down_by_rows(
+//                     map,
+//                     selection.end,
+//                     row_count,
+//                     selection.goal,
+//                     false,
+//                     &text_layout_details,
+//                 );
+//                 selection.collapse_to(cursor, goal);
+//             });
+//         });
+//     }
+
+//     pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
+//         let text_layout_details = &self.text_layout_details(cx);
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, goal| {
+//                 movement::down(map, head, goal, false, &text_layout_details)
+//             })
+//         });
+//     }
+
+//     pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
+//         if let Some(context_menu) = self.context_menu.write().as_mut() {
+//             context_menu.select_first(self.project.as_ref(), cx);
+//         }
+//     }
+
+//     pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
+//         if let Some(context_menu) = self.context_menu.write().as_mut() {
+//             context_menu.select_prev(self.project.as_ref(), cx);
+//         }
+//     }
+
+//     pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
+//         if let Some(context_menu) = self.context_menu.write().as_mut() {
+//             context_menu.select_next(self.project.as_ref(), cx);
+//         }
+//     }
+
+//     pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
+//         if let Some(context_menu) = self.context_menu.write().as_mut() {
+//             context_menu.select_last(self.project.as_ref(), cx);
+//         }
+//     }
+
+//     pub fn move_to_previous_word_start(
+//         &mut self,
+//         _: &MoveToPreviousWordStart,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_cursors_with(|map, head, _| {
+//                 (
+//                     movement::previous_word_start(map, head),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn move_to_previous_subword_start(
+//         &mut self,
+//         _: &MoveToPreviousSubwordStart,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_cursors_with(|map, head, _| {
+//                 (
+//                     movement::previous_subword_start(map, head),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn select_to_previous_word_start(
+//         &mut self,
+//         _: &SelectToPreviousWordStart,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (
+//                     movement::previous_word_start(map, head),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn select_to_previous_subword_start(
+//         &mut self,
+//         _: &SelectToPreviousSubwordStart,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (
+//                     movement::previous_subword_start(map, head),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn delete_to_previous_word_start(
+//         &mut self,
+//         _: &DeleteToPreviousWordStart,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.transact(cx, |this, cx| {
+//             this.select_autoclose_pair(cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let line_mode = s.line_mode;
+//                 s.move_with(|map, selection| {
+//                     if selection.is_empty() && !line_mode {
+//                         let cursor = movement::previous_word_start(map, selection.head());
+//                         selection.set_head(cursor, SelectionGoal::None);
+//                     }
+//                 });
+//             });
+//             this.insert("", cx);
+//         });
+//     }
+
+//     pub fn delete_to_previous_subword_start(
+//         &mut self,
+//         _: &DeleteToPreviousSubwordStart,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.transact(cx, |this, cx| {
+//             this.select_autoclose_pair(cx);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let line_mode = s.line_mode;
+//                 s.move_with(|map, selection| {
+//                     if selection.is_empty() && !line_mode {
+//                         let cursor = movement::previous_subword_start(map, selection.head());
+//                         selection.set_head(cursor, SelectionGoal::None);
+//                     }
+//                 });
+//             });
+//             this.insert("", cx);
+//         });
+//     }
+
+//     pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_cursors_with(|map, head, _| {
+//                 (movement::next_word_end(map, head), SelectionGoal::None)
+//             });
+//         })
+//     }
+
+//     pub fn move_to_next_subword_end(
+//         &mut self,
+//         _: &MoveToNextSubwordEnd,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_cursors_with(|map, head, _| {
+//                 (movement::next_subword_end(map, head), SelectionGoal::None)
+//             });
+//         })
+//     }
+
+//     pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (movement::next_word_end(map, head), SelectionGoal::None)
+//             });
+//         })
+//     }
+
+//     pub fn select_to_next_subword_end(
+//         &mut self,
+//         _: &SelectToNextSubwordEnd,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (movement::next_subword_end(map, head), SelectionGoal::None)
+//             });
+//         })
+//     }
+
+//     pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let line_mode = s.line_mode;
+//                 s.move_with(|map, selection| {
+//                     if selection.is_empty() && !line_mode {
+//                         let cursor = movement::next_word_end(map, selection.head());
+//                         selection.set_head(cursor, SelectionGoal::None);
+//                     }
+//                 });
+//             });
+//             this.insert("", cx);
+//         });
+//     }
+
+//     pub fn delete_to_next_subword_end(
+//         &mut self,
+//         _: &DeleteToNextSubwordEnd,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.transact(cx, |this, cx| {
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.move_with(|map, selection| {
+//                     if selection.is_empty() {
+//                         let cursor = movement::next_subword_end(map, selection.head());
+//                         selection.set_head(cursor, SelectionGoal::None);
+//                     }
+//                 });
+//             });
+//             this.insert("", cx);
+//         });
+//     }
+
+//     pub fn move_to_beginning_of_line(
+//         &mut self,
+//         _: &MoveToBeginningOfLine,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_cursors_with(|map, head, _| {
+//                 (
+//                     movement::indented_line_beginning(map, head, true),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn select_to_beginning_of_line(
+//         &mut self,
+//         action: &SelectToBeginningOfLine,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (
+//                     movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         });
+//     }
+
+//     pub fn delete_to_beginning_of_line(
+//         &mut self,
+//         _: &DeleteToBeginningOfLine,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.transact(cx, |this, cx| {
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.move_with(|_, selection| {
+//                     selection.reversed = true;
+//                 });
+//             });
+
+//             this.select_to_beginning_of_line(
+//                 &SelectToBeginningOfLine {
+//                     stop_at_soft_wraps: false,
+//                 },
+//                 cx,
+//             );
+//             this.backspace(&Backspace, cx);
+//         });
+//     }
+
+//     pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_cursors_with(|map, head, _| {
+//                 (movement::line_end(map, head, true), SelectionGoal::None)
+//             });
+//         })
+//     }
+
+//     pub fn select_to_end_of_line(
+//         &mut self,
+//         action: &SelectToEndOfLine,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (
+//                     movement::line_end(map, head, action.stop_at_soft_wraps),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.select_to_end_of_line(
+//                 &SelectToEndOfLine {
+//                     stop_at_soft_wraps: false,
+//                 },
+//                 cx,
+//             );
+//             this.delete(&Delete, cx);
+//         });
+//     }
+
+//     pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.select_to_end_of_line(
+//                 &SelectToEndOfLine {
+//                     stop_at_soft_wraps: false,
+//                 },
+//                 cx,
+//             );
+//             this.cut(&Cut, cx);
+//         });
+//     }
+
+//     pub fn move_to_start_of_paragraph(
+//         &mut self,
+//         _: &MoveToStartOfParagraph,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_with(|map, selection| {
+//                 selection.collapse_to(
+//                     movement::start_of_paragraph(map, selection.head(), 1),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn move_to_end_of_paragraph(
+//         &mut self,
+//         _: &MoveToEndOfParagraph,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_with(|map, selection| {
+//                 selection.collapse_to(
+//                     movement::end_of_paragraph(map, selection.head(), 1),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn select_to_start_of_paragraph(
+//         &mut self,
+//         _: &SelectToStartOfParagraph,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (
+//                     movement::start_of_paragraph(map, head, 1),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn select_to_end_of_paragraph(
+//         &mut self,
+//         _: &SelectToEndOfParagraph,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_heads_with(|map, head, _| {
+//                 (
+//                     movement::end_of_paragraph(map, head, 1),
+//                     SelectionGoal::None,
+//                 )
+//             });
+//         })
+//     }
+
+//     pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select_ranges(vec![0..0]);
+//         });
+//     }
+
+//     pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
+//         let mut selection = self.selections.last::<Point>(cx);
+//         selection.set_head(Point::zero(), SelectionGoal::None);
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select(vec![selection]);
+//         });
+//     }
+
+//     pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         let cursor = self.buffer.read(cx).read(cx).len();
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select_ranges(vec![cursor..cursor])
+//         });
+//     }
+
+//     pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
+//         self.nav_history = nav_history;
+//     }
+
+//     pub fn nav_history(&self) -> Option<&ItemNavHistory> {
+//         self.nav_history.as_ref()
+//     }
+
+//     fn push_to_nav_history(
+//         &mut self,
+//         cursor_anchor: Anchor,
+//         new_position: Option<Point>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if let Some(nav_history) = self.nav_history.as_mut() {
+//             let buffer = self.buffer.read(cx).read(cx);
+//             let cursor_position = cursor_anchor.to_point(&buffer);
+//             let scroll_state = self.scroll_manager.anchor();
+//             let scroll_top_row = scroll_state.top_row(&buffer);
+//             drop(buffer);
+
+//             if let Some(new_position) = new_position {
+//                 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
+//                 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
+//                     return;
+//                 }
+//             }
+
+//             nav_history.push(
+//                 Some(NavigationData {
+//                     cursor_anchor,
+//                     cursor_position,
+//                     scroll_anchor: scroll_state,
+//                     scroll_top_row,
+//                 }),
+//                 cx,
+//             );
+//         }
+//     }
+
+//     pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+//         let mut selection = self.selections.first::<usize>(cx);
+//         selection.set_head(buffer.len(), SelectionGoal::None);
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select(vec![selection]);
+//         });
+//     }
+
+//     pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
+//         let end = self.buffer.read(cx).read(cx).len();
+//         self.change_selections(None, cx, |s| {
+//             s.select_ranges(vec![0..end]);
+//         });
+//     }
+
+//     pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let mut selections = self.selections.all::<Point>(cx);
+//         let max_point = display_map.buffer_snapshot.max_point();
+//         for selection in &mut selections {
+//             let rows = selection.spanned_rows(true, &display_map);
+//             selection.start = Point::new(rows.start, 0);
+//             selection.end = cmp::min(max_point, Point::new(rows.end, 0));
+//             selection.reversed = false;
+//         }
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select(selections);
+//         });
+//     }
+
+//     pub fn split_selection_into_lines(
+//         &mut self,
+//         _: &SplitSelectionIntoLines,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let mut to_unfold = Vec::new();
+//         let mut new_selection_ranges = Vec::new();
+//         {
+//             let selections = self.selections.all::<Point>(cx);
+//             let buffer = self.buffer.read(cx).read(cx);
+//             for selection in selections {
+//                 for row in selection.start.row..selection.end.row {
+//                     let cursor = Point::new(row, buffer.line_len(row));
+//                     new_selection_ranges.push(cursor..cursor);
+//                 }
+//                 new_selection_ranges.push(selection.end..selection.end);
+//                 to_unfold.push(selection.start..selection.end);
+//             }
+//         }
+//         self.unfold_ranges(to_unfold, true, true, cx);
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select_ranges(new_selection_ranges);
+//         });
+//     }
+
+//     pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
+//         self.add_selection(true, cx);
+//     }
+
+//     pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
+//         self.add_selection(false, cx);
+//     }
+
+//     fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let mut selections = self.selections.all::<Point>(cx);
+//         let text_layout_details = self.text_layout_details(cx);
+//         let mut state = self.add_selections_state.take().unwrap_or_else(|| {
+//             let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
+//             let range = oldest_selection.display_range(&display_map).sorted();
+
+//             let start_x = display_map.x_for_point(range.start, &text_layout_details);
+//             let end_x = display_map.x_for_point(range.end, &text_layout_details);
+//             let positions = start_x.min(end_x)..start_x.max(end_x);
+
+//             selections.clear();
+//             let mut stack = Vec::new();
+//             for row in range.start.row()..=range.end.row() {
+//                 if let Some(selection) = self.selections.build_columnar_selection(
+//                     &display_map,
+//                     row,
+//                     &positions,
+//                     oldest_selection.reversed,
+//                     &text_layout_details,
+//                 ) {
+//                     stack.push(selection.id);
+//                     selections.push(selection);
+//                 }
+//             }
+
+//             if above {
+//                 stack.reverse();
+//             }
+
+//             AddSelectionsState { above, stack }
+//         });
+
+//         let last_added_selection = *state.stack.last().unwrap();
+//         let mut new_selections = Vec::new();
+//         if above == state.above {
+//             let end_row = if above {
+//                 0
+//             } else {
+//                 display_map.max_point().row()
+//             };
+
+//             'outer: for selection in selections {
+//                 if selection.id == last_added_selection {
+//                     let range = selection.display_range(&display_map).sorted();
+//                     debug_assert_eq!(range.start.row(), range.end.row());
+//                     let mut row = range.start.row();
+//                     let positions = if let SelectionGoal::HorizontalRange { start, end } =
+//                         selection.goal
+//                     {
+//                         start..end
+//                     } else {
+//                         let start_x = display_map.x_for_point(range.start, &text_layout_details);
+//                         let end_x = display_map.x_for_point(range.end, &text_layout_details);
+
+//                         start_x.min(end_x)..start_x.max(end_x)
+//                     };
+
+//                     while row != end_row {
+//                         if above {
+//                             row -= 1;
+//                         } else {
+//                             row += 1;
+//                         }
+
+//                         if let Some(new_selection) = self.selections.build_columnar_selection(
+//                             &display_map,
+//                             row,
+//                             &positions,
+//                             selection.reversed,
+//                             &text_layout_details,
+//                         ) {
+//                             state.stack.push(new_selection.id);
+//                             if above {
+//                                 new_selections.push(new_selection);
+//                                 new_selections.push(selection);
+//                             } else {
+//                                 new_selections.push(selection);
+//                                 new_selections.push(new_selection);
+//                             }
+
+//                             continue 'outer;
+//                         }
+//                     }
+//                 }
+
+//                 new_selections.push(selection);
+//             }
+//         } else {
+//             new_selections = selections;
+//             new_selections.retain(|s| s.id != last_added_selection);
+//             state.stack.pop();
+//         }
+
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.select(new_selections);
+//         });
+//         if state.stack.len() > 1 {
+//             self.add_selections_state = Some(state);
+//         }
+//     }
+
+//     pub fn select_next_match_internal(
+//         &mut self,
+//         display_map: &DisplaySnapshot,
+//         replace_newest: bool,
+//         autoscroll: Option<Autoscroll>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Result<()> {
+//         fn select_next_match_ranges(
+//             this: &mut Editor,
+//             range: Range<usize>,
+//             replace_newest: bool,
+//             auto_scroll: Option<Autoscroll>,
+//             cx: &mut ViewContext<Editor>,
+//         ) {
+//             this.unfold_ranges([range.clone()], false, true, cx);
+//             this.change_selections(auto_scroll, cx, |s| {
+//                 if replace_newest {
+//                     s.delete(s.newest_anchor().id);
+//                 }
+//                 s.insert_range(range.clone());
+//             });
+//         }
+
+//         let buffer = &display_map.buffer_snapshot;
+//         let mut selections = self.selections.all::<usize>(cx);
+//         if let Some(mut select_next_state) = self.select_next_state.take() {
+//             let query = &select_next_state.query;
+//             if !select_next_state.done {
+//                 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
+//                 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
+//                 let mut next_selected_range = None;
+
+//                 let bytes_after_last_selection =
+//                     buffer.bytes_in_range(last_selection.end..buffer.len());
+//                 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
+//                 let query_matches = query
+//                     .stream_find_iter(bytes_after_last_selection)
+//                     .map(|result| (last_selection.end, result))
+//                     .chain(
+//                         query
+//                             .stream_find_iter(bytes_before_first_selection)
+//                             .map(|result| (0, result)),
+//                     );
+
+//                 for (start_offset, query_match) in query_matches {
+//                     let query_match = query_match.unwrap(); // can only fail due to I/O
+//                     let offset_range =
+//                         start_offset + query_match.start()..start_offset + query_match.end();
+//                     let display_range = offset_range.start.to_display_point(&display_map)
+//                         ..offset_range.end.to_display_point(&display_map);
+
+//                     if !select_next_state.wordwise
+//                         || (!movement::is_inside_word(&display_map, display_range.start)
+//                             && !movement::is_inside_word(&display_map, display_range.end))
+//                     {
+//                         if selections
+//                             .iter()
+//                             .find(|selection| selection.range().overlaps(&offset_range))
+//                             .is_none()
+//                         {
+//                             next_selected_range = Some(offset_range);
+//                             break;
+//                         }
+//                     }
+//                 }
+
+//                 if let Some(next_selected_range) = next_selected_range {
+//                     select_next_match_ranges(
+//                         self,
+//                         next_selected_range,
+//                         replace_newest,
+//                         autoscroll,
+//                         cx,
+//                     );
+//                 } else {
+//                     select_next_state.done = true;
+//                 }
+//             }
+
+//             self.select_next_state = Some(select_next_state);
+//         } else if selections.len() == 1 {
+//             let selection = selections.last_mut().unwrap();
+//             if selection.start == selection.end {
+//                 let word_range = movement::surrounding_word(
+//                     &display_map,
+//                     selection.start.to_display_point(&display_map),
+//                 );
+//                 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
+//                 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
+//                 selection.goal = SelectionGoal::None;
+//                 selection.reversed = false;
+
+//                 let query = buffer
+//                     .text_for_range(selection.start..selection.end)
+//                     .collect::<String>();
+
+//                 let is_empty = query.is_empty();
+//                 let select_state = SelectNextState {
+//                     query: AhoCorasick::new(&[query])?,
+//                     wordwise: true,
+//                     done: is_empty,
+//                 };
+//                 select_next_match_ranges(
+//                     self,
+//                     selection.start..selection.end,
+//                     replace_newest,
+//                     autoscroll,
+//                     cx,
+//                 );
+//                 self.select_next_state = Some(select_state);
+//             } else {
+//                 let query = buffer
+//                     .text_for_range(selection.start..selection.end)
+//                     .collect::<String>();
+//                 self.select_next_state = Some(SelectNextState {
+//                     query: AhoCorasick::new(&[query])?,
+//                     wordwise: false,
+//                     done: false,
+//                 });
+//                 self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
+//             }
+//         }
+//         Ok(())
+//     }
+
+//     pub fn select_all_matches(
+//         &mut self,
+//         action: &SelectAllMatches,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Result<()> {
+//         self.push_to_selection_history();
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+//         loop {
+//             self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?;
+
+//             if self
+//                 .select_next_state
+//                 .as_ref()
+//                 .map(|selection_state| selection_state.done)
+//                 .unwrap_or(true)
+//             {
+//                 break;
+//             }
+//         }
+
+//         Ok(())
+//     }
+
+//     pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
+//         self.push_to_selection_history();
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         self.select_next_match_internal(
+//             &display_map,
+//             action.replace_newest,
+//             Some(Autoscroll::newest()),
+//             cx,
+//         )?;
+//         Ok(())
+//     }
+
+//     pub fn select_previous(
+//         &mut self,
+//         action: &SelectPrevious,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Result<()> {
+//         self.push_to_selection_history();
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = &display_map.buffer_snapshot;
+//         let mut selections = self.selections.all::<usize>(cx);
+//         if let Some(mut select_prev_state) = self.select_prev_state.take() {
+//             let query = &select_prev_state.query;
+//             if !select_prev_state.done {
+//                 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
+//                 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
+//                 let mut next_selected_range = None;
+//                 // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
+//                 let bytes_before_last_selection =
+//                     buffer.reversed_bytes_in_range(0..last_selection.start);
+//                 let bytes_after_first_selection =
+//                     buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
+//                 let query_matches = query
+//                     .stream_find_iter(bytes_before_last_selection)
+//                     .map(|result| (last_selection.start, result))
+//                     .chain(
+//                         query
+//                             .stream_find_iter(bytes_after_first_selection)
+//                             .map(|result| (buffer.len(), result)),
+//                     );
+//                 for (end_offset, query_match) in query_matches {
+//                     let query_match = query_match.unwrap(); // can only fail due to I/O
+//                     let offset_range =
+//                         end_offset - query_match.end()..end_offset - query_match.start();
+//                     let display_range = offset_range.start.to_display_point(&display_map)
+//                         ..offset_range.end.to_display_point(&display_map);
+
+//                     if !select_prev_state.wordwise
+//                         || (!movement::is_inside_word(&display_map, display_range.start)
+//                             && !movement::is_inside_word(&display_map, display_range.end))
+//                     {
+//                         next_selected_range = Some(offset_range);
+//                         break;
+//                     }
+//                 }
+
+//                 if let Some(next_selected_range) = next_selected_range {
+//                     self.unfold_ranges([next_selected_range.clone()], false, true, cx);
+//                     self.change_selections(Some(Autoscroll::newest()), cx, |s| {
+//                         if action.replace_newest {
+//                             s.delete(s.newest_anchor().id);
+//                         }
+//                         s.insert_range(next_selected_range);
+//                     });
+//                 } else {
+//                     select_prev_state.done = true;
+//                 }
+//             }
+
+//             self.select_prev_state = Some(select_prev_state);
+//         } else if selections.len() == 1 {
+//             let selection = selections.last_mut().unwrap();
+//             if selection.start == selection.end {
+//                 let word_range = movement::surrounding_word(
+//                     &display_map,
+//                     selection.start.to_display_point(&display_map),
+//                 );
+//                 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
+//                 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
+//                 selection.goal = SelectionGoal::None;
+//                 selection.reversed = false;
+
+//                 let query = buffer
+//                     .text_for_range(selection.start..selection.end)
+//                     .collect::<String>();
+//                 let query = query.chars().rev().collect::<String>();
+//                 let select_state = SelectNextState {
+//                     query: AhoCorasick::new(&[query])?,
+//                     wordwise: true,
+//                     done: false,
+//                 };
+//                 self.unfold_ranges([selection.start..selection.end], false, true, cx);
+//                 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
+//                     s.select(selections);
+//                 });
+//                 self.select_prev_state = Some(select_state);
+//             } else {
+//                 let query = buffer
+//                     .text_for_range(selection.start..selection.end)
+//                     .collect::<String>();
+//                 let query = query.chars().rev().collect::<String>();
+//                 self.select_prev_state = Some(SelectNextState {
+//                     query: AhoCorasick::new(&[query])?,
+//                     wordwise: false,
+//                     done: false,
+//                 });
+//                 self.select_previous(action, cx)?;
+//             }
+//         }
+//         Ok(())
+//     }
+
+//     pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
+//         let text_layout_details = &self.text_layout_details(cx);
+//         self.transact(cx, |this, cx| {
+//             let mut selections = this.selections.all::<Point>(cx);
+//             let mut edits = Vec::new();
+//             let mut selection_edit_ranges = Vec::new();
+//             let mut last_toggled_row = None;
+//             let snapshot = this.buffer.read(cx).read(cx);
+//             let empty_str: Arc<str> = "".into();
+//             let mut suffixes_inserted = Vec::new();
+
+//             fn comment_prefix_range(
+//                 snapshot: &MultiBufferSnapshot,
+//                 row: u32,
+//                 comment_prefix: &str,
+//                 comment_prefix_whitespace: &str,
+//             ) -> Range<Point> {
+//                 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
+
+//                 let mut line_bytes = snapshot
+//                     .bytes_in_range(start..snapshot.max_point())
+//                     .flatten()
+//                     .copied();
+
+//                 // If this line currently begins with the line comment prefix, then record
+//                 // the range containing the prefix.
+//                 if line_bytes
+//                     .by_ref()
+//                     .take(comment_prefix.len())
+//                     .eq(comment_prefix.bytes())
+//                 {
+//                     // Include any whitespace that matches the comment prefix.
+//                     let matching_whitespace_len = line_bytes
+//                         .zip(comment_prefix_whitespace.bytes())
+//                         .take_while(|(a, b)| a == b)
+//                         .count() as u32;
+//                     let end = Point::new(
+//                         start.row,
+//                         start.column + comment_prefix.len() as u32 + matching_whitespace_len,
+//                     );
+//                     start..end
+//                 } else {
+//                     start..start
+//                 }
+//             }
+
+//             fn comment_suffix_range(
+//                 snapshot: &MultiBufferSnapshot,
+//                 row: u32,
+//                 comment_suffix: &str,
+//                 comment_suffix_has_leading_space: bool,
+//             ) -> Range<Point> {
+//                 let end = Point::new(row, snapshot.line_len(row));
+//                 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
+
+//                 let mut line_end_bytes = snapshot
+//                     .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
+//                     .flatten()
+//                     .copied();
+
+//                 let leading_space_len = if suffix_start_column > 0
+//                     && line_end_bytes.next() == Some(b' ')
+//                     && comment_suffix_has_leading_space
+//                 {
+//                     1
+//                 } else {
+//                     0
+//                 };
+
+//                 // If this line currently begins with the line comment prefix, then record
+//                 // the range containing the prefix.
+//                 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
+//                     let start = Point::new(end.row, suffix_start_column - leading_space_len);
+//                     start..end
+//                 } else {
+//                     end..end
+//                 }
+//             }
+
+//             // TODO: Handle selections that cross excerpts
+//             for selection in &mut selections {
+//                 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
+//                 let language = if let Some(language) =
+//                     snapshot.language_scope_at(Point::new(selection.start.row, start_column))
+//                 {
+//                     language
+//                 } else {
+//                     continue;
+//                 };
+
+//                 selection_edit_ranges.clear();
+
+//                 // If multiple selections contain a given row, avoid processing that
+//                 // row more than once.
+//                 let mut start_row = selection.start.row;
+//                 if last_toggled_row == Some(start_row) {
+//                     start_row += 1;
+//                 }
+//                 let end_row =
+//                     if selection.end.row > selection.start.row && selection.end.column == 0 {
+//                         selection.end.row - 1
+//                     } else {
+//                         selection.end.row
+//                     };
+//                 last_toggled_row = Some(end_row);
+
+//                 if start_row > end_row {
+//                     continue;
+//                 }
+
+//                 // If the language has line comments, toggle those.
+//                 if let Some(full_comment_prefix) = language.line_comment_prefix() {
+//                     // Split the comment prefix's trailing whitespace into a separate string,
+//                     // as that portion won't be used for detecting if a line is a comment.
+//                     let comment_prefix = full_comment_prefix.trim_end_matches(' ');
+//                     let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
+//                     let mut all_selection_lines_are_comments = true;
+
+//                     for row in start_row..=end_row {
+//                         if snapshot.is_line_blank(row) && start_row < end_row {
+//                             continue;
+//                         }
+
+//                         let prefix_range = comment_prefix_range(
+//                             snapshot.deref(),
+//                             row,
+//                             comment_prefix,
+//                             comment_prefix_whitespace,
+//                         );
+//                         if prefix_range.is_empty() {
+//                             all_selection_lines_are_comments = false;
+//                         }
+//                         selection_edit_ranges.push(prefix_range);
+//                     }
+
+//                     if all_selection_lines_are_comments {
+//                         edits.extend(
+//                             selection_edit_ranges
+//                                 .iter()
+//                                 .cloned()
+//                                 .map(|range| (range, empty_str.clone())),
+//                         );
+//                     } else {
+//                         let min_column = selection_edit_ranges
+//                             .iter()
+//                             .map(|r| r.start.column)
+//                             .min()
+//                             .unwrap_or(0);
+//                         edits.extend(selection_edit_ranges.iter().map(|range| {
+//                             let position = Point::new(range.start.row, min_column);
+//                             (position..position, full_comment_prefix.clone())
+//                         }));
+//                     }
+//                 } else if let Some((full_comment_prefix, comment_suffix)) =
+//                     language.block_comment_delimiters()
+//                 {
+//                     let comment_prefix = full_comment_prefix.trim_end_matches(' ');
+//                     let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
+//                     let prefix_range = comment_prefix_range(
+//                         snapshot.deref(),
+//                         start_row,
+//                         comment_prefix,
+//                         comment_prefix_whitespace,
+//                     );
+//                     let suffix_range = comment_suffix_range(
+//                         snapshot.deref(),
+//                         end_row,
+//                         comment_suffix.trim_start_matches(' '),
+//                         comment_suffix.starts_with(' '),
+//                     );
+
+//                     if prefix_range.is_empty() || suffix_range.is_empty() {
+//                         edits.push((
+//                             prefix_range.start..prefix_range.start,
+//                             full_comment_prefix.clone(),
+//                         ));
+//                         edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
+//                         suffixes_inserted.push((end_row, comment_suffix.len()));
+//                     } else {
+//                         edits.push((prefix_range, empty_str.clone()));
+//                         edits.push((suffix_range, empty_str.clone()));
+//                     }
+//                 } else {
+//                     continue;
+//                 }
+//             }
+
+//             drop(snapshot);
+//             this.buffer.update(cx, |buffer, cx| {
+//                 buffer.edit(edits, None, cx);
+//             });
+
+//             // Adjust selections so that they end before any comment suffixes that
+//             // were inserted.
+//             let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
+//             let mut selections = this.selections.all::<Point>(cx);
+//             let snapshot = this.buffer.read(cx).read(cx);
+//             for selection in &mut selections {
+//                 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
+//                     match row.cmp(&selection.end.row) {
+//                         Ordering::Less => {
+//                             suffixes_inserted.next();
+//                             continue;
+//                         }
+//                         Ordering::Greater => break,
+//                         Ordering::Equal => {
+//                             if selection.end.column == snapshot.line_len(row) {
+//                                 if selection.is_empty() {
+//                                     selection.start.column -= suffix_len as u32;
+//                                 }
+//                                 selection.end.column -= suffix_len as u32;
+//                             }
+//                             break;
+//                         }
+//                     }
+//                 }
+//             }
+
+//             drop(snapshot);
+//             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
+
+//             let selections = this.selections.all::<Point>(cx);
+//             let selections_on_single_row = selections.windows(2).all(|selections| {
+//                 selections[0].start.row == selections[1].start.row
+//                     && selections[0].end.row == selections[1].end.row
+//                     && selections[0].start.row == selections[0].end.row
+//             });
+//             let selections_selecting = selections
+//                 .iter()
+//                 .any(|selection| selection.start != selection.end);
+//             let advance_downwards = action.advance_downwards
+//                 && selections_on_single_row
+//                 && !selections_selecting
+//                 && this.mode != EditorMode::SingleLine;
+
+//             if advance_downwards {
+//                 let snapshot = this.buffer.read(cx).snapshot(cx);
+
+//                 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                     s.move_cursors_with(|display_snapshot, display_point, _| {
+//                         let mut point = display_point.to_point(display_snapshot);
+//                         point.row += 1;
+//                         point = snapshot.clip_point(point, Bias::Left);
+//                         let display_point = point.to_display_point(display_snapshot);
+//                         let goal = SelectionGoal::HorizontalPosition(
+//                             display_snapshot.x_for_point(display_point, &text_layout_details),
+//                         );
+//                         (display_point, goal)
+//                     })
+//                 });
+//             }
+//         });
+//     }
+
+//     pub fn select_larger_syntax_node(
+//         &mut self,
+//         _: &SelectLargerSyntaxNode,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+//         let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
+
+//         let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
+//         let mut selected_larger_node = false;
+//         let new_selections = old_selections
+//             .iter()
+//             .map(|selection| {
+//                 let old_range = selection.start..selection.end;
+//                 let mut new_range = old_range.clone();
+//                 while let Some(containing_range) =
+//                     buffer.range_for_syntax_ancestor(new_range.clone())
+//                 {
+//                     new_range = containing_range;
+//                     if !display_map.intersects_fold(new_range.start)
+//                         && !display_map.intersects_fold(new_range.end)
+//                     {
+//                         break;
+//                     }
+//                 }
+
+//                 selected_larger_node |= new_range != old_range;
+//                 Selection {
+//                     id: selection.id,
+//                     start: new_range.start,
+//                     end: new_range.end,
+//                     goal: SelectionGoal::None,
+//                     reversed: selection.reversed,
+//                 }
+//             })
+//             .collect::<Vec<_>>();
+
+//         if selected_larger_node {
+//             stack.push(old_selections);
+//             self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(new_selections);
+//             });
+//         }
+//         self.select_larger_syntax_node_stack = stack;
+//     }
+
+//     pub fn select_smaller_syntax_node(
+//         &mut self,
+//         _: &SelectSmallerSyntaxNode,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
+//         if let Some(selections) = stack.pop() {
+//             self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 s.select(selections.to_vec());
+//             });
+//         }
+//         self.select_larger_syntax_node_stack = stack;
+//     }
+
+//     pub fn move_to_enclosing_bracket(
+//         &mut self,
+//         _: &MoveToEnclosingBracket,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//             s.move_offsets_with(|snapshot, selection| {
+//                 let Some(enclosing_bracket_ranges) =
+//                     snapshot.enclosing_bracket_ranges(selection.start..selection.end)
+//                 else {
+//                     return;
+//                 };
+
+//                 let mut best_length = usize::MAX;
+//                 let mut best_inside = false;
+//                 let mut best_in_bracket_range = false;
+//                 let mut best_destination = None;
+//                 for (open, close) in enclosing_bracket_ranges {
+//                     let close = close.to_inclusive();
+//                     let length = close.end() - open.start;
+//                     let inside = selection.start >= open.end && selection.end <= *close.start();
+//                     let in_bracket_range = open.to_inclusive().contains(&selection.head())
+//                         || close.contains(&selection.head());
+
+//                     // If best is next to a bracket and current isn't, skip
+//                     if !in_bracket_range && best_in_bracket_range {
+//                         continue;
+//                     }
+
+//                     // Prefer smaller lengths unless best is inside and current isn't
+//                     if length > best_length && (best_inside || !inside) {
+//                         continue;
+//                     }
+
+//                     best_length = length;
+//                     best_inside = inside;
+//                     best_in_bracket_range = in_bracket_range;
+//                     best_destination = Some(
+//                         if close.contains(&selection.start) && close.contains(&selection.end) {
+//                             if inside {
+//                                 open.end
+//                             } else {
+//                                 open.start
+//                             }
+//                         } else {
+//                             if inside {
+//                                 *close.start()
+//                             } else {
+//                                 *close.end()
+//                             }
+//                         },
+//                     );
+//                 }
+
+//                 if let Some(destination) = best_destination {
+//                     selection.collapse_to(destination, SelectionGoal::None);
+//                 }
+//             })
+//         });
+//     }
+
+//     pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
+//         self.end_selection(cx);
+//         self.selection_history.mode = SelectionHistoryMode::Undoing;
+//         if let Some(entry) = self.selection_history.undo_stack.pop_back() {
+//             self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
+//             self.select_next_state = entry.select_next_state;
+//             self.select_prev_state = entry.select_prev_state;
+//             self.add_selections_state = entry.add_selections_state;
+//             self.request_autoscroll(Autoscroll::newest(), cx);
+//         }
+//         self.selection_history.mode = SelectionHistoryMode::Normal;
+//     }
+
+//     pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
+//         self.end_selection(cx);
+//         self.selection_history.mode = SelectionHistoryMode::Redoing;
+//         if let Some(entry) = self.selection_history.redo_stack.pop_back() {
+//             self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
+//             self.select_next_state = entry.select_next_state;
+//             self.select_prev_state = entry.select_prev_state;
+//             self.add_selections_state = entry.add_selections_state;
+//             self.request_autoscroll(Autoscroll::newest(), cx);
+//         }
+//         self.selection_history.mode = SelectionHistoryMode::Normal;
+//     }
+
+//     fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
+//         self.go_to_diagnostic_impl(Direction::Next, cx)
+//     }
+
+//     fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
+//         self.go_to_diagnostic_impl(Direction::Prev, cx)
+//     }
+
+//     pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
+//         let buffer = self.buffer.read(cx).snapshot(cx);
+//         let selection = self.selections.newest::<usize>(cx);
+
+//         // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
+//         if direction == Direction::Next {
+//             if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
+//                 let (group_id, jump_to) = popover.activation_info();
+//                 if self.activate_diagnostics(group_id, cx) {
+//                     self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                         let mut new_selection = s.newest_anchor().clone();
+//                         new_selection.collapse_to(jump_to, SelectionGoal::None);
+//                         s.select_anchors(vec![new_selection.clone()]);
+//                     });
+//                 }
+//                 return;
+//             }
+//         }
+
+//         let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
+//             active_diagnostics
+//                 .primary_range
+//                 .to_offset(&buffer)
+//                 .to_inclusive()
+//         });
+//         let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
+//             if active_primary_range.contains(&selection.head()) {
+//                 *active_primary_range.end()
+//             } else {
+//                 selection.head()
+//             }
+//         } else {
+//             selection.head()
+//         };
+
+//         loop {
+//             let mut diagnostics = if direction == Direction::Prev {
+//                 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
+//             } else {
+//                 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
+//             };
+//             let group = diagnostics.find_map(|entry| {
+//                 if entry.diagnostic.is_primary
+//                     && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
+//                     && !entry.range.is_empty()
+//                     && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
+//                     && !entry.range.contains(&search_start)
+//                 {
+//                     Some((entry.range, entry.diagnostic.group_id))
+//                 } else {
+//                     None
+//                 }
+//             });
+
+//             if let Some((primary_range, group_id)) = group {
+//                 if self.activate_diagnostics(group_id, cx) {
+//                     self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                         s.select(vec![Selection {
+//                             id: selection.id,
+//                             start: primary_range.start,
+//                             end: primary_range.start,
+//                             reversed: false,
+//                             goal: SelectionGoal::None,
+//                         }]);
+//                     });
+//                 }
+//                 break;
+//             } else {
+//                 // Cycle around to the start of the buffer, potentially moving back to the start of
+//                 // the currently active diagnostic.
+//                 active_primary_range.take();
+//                 if direction == Direction::Prev {
+//                     if search_start == buffer.len() {
+//                         break;
+//                     } else {
+//                         search_start = buffer.len();
+//                     }
+//                 } else if search_start == 0 {
+//                     break;
+//                 } else {
+//                     search_start = 0;
+//                 }
+//             }
+//         }
+//     }
+
+//     fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
+//         let snapshot = self
+//             .display_map
+//             .update(cx, |display_map, cx| display_map.snapshot(cx));
+//         let selection = self.selections.newest::<Point>(cx);
+
+//         if !self.seek_in_direction(
+//             &snapshot,
+//             selection.head(),
+//             false,
+//             snapshot
+//                 .buffer_snapshot
+//                 .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
+//             cx,
+//         ) {
+//             let wrapped_point = Point::zero();
+//             self.seek_in_direction(
+//                 &snapshot,
+//                 wrapped_point,
+//                 true,
+//                 snapshot
+//                     .buffer_snapshot
+//                     .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
+//                 cx,
+//             );
+//         }
+//     }
+
+//     fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
+//         let snapshot = self
+//             .display_map
+//             .update(cx, |display_map, cx| display_map.snapshot(cx));
+//         let selection = self.selections.newest::<Point>(cx);
+
+//         if !self.seek_in_direction(
+//             &snapshot,
+//             selection.head(),
+//             false,
+//             snapshot
+//                 .buffer_snapshot
+//                 .git_diff_hunks_in_range_rev(0..selection.head().row),
+//             cx,
+//         ) {
+//             let wrapped_point = snapshot.buffer_snapshot.max_point();
+//             self.seek_in_direction(
+//                 &snapshot,
+//                 wrapped_point,
+//                 true,
+//                 snapshot
+//                     .buffer_snapshot
+//                     .git_diff_hunks_in_range_rev(0..wrapped_point.row),
+//                 cx,
+//             );
+//         }
+//     }
+
+//     fn seek_in_direction(
+//         &mut self,
+//         snapshot: &DisplaySnapshot,
+//         initial_point: Point,
+//         is_wrapped: bool,
+//         hunks: impl Iterator<Item = DiffHunk<u32>>,
+//         cx: &mut ViewContext<Editor>,
+//     ) -> bool {
+//         let display_point = initial_point.to_display_point(snapshot);
+//         let mut hunks = hunks
+//             .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
+//             .filter(|hunk| {
+//                 if is_wrapped {
+//                     true
+//                 } else {
+//                     !hunk.contains_display_row(display_point.row())
+//                 }
+//             })
+//             .dedup();
+
+//         if let Some(hunk) = hunks.next() {
+//             self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                 let row = hunk.start_display_row();
+//                 let point = DisplayPoint::new(row, 0);
+//                 s.select_display_ranges([point..point]);
+//             });
+
+//             true
+//         } else {
+//             false
+//         }
+//     }
+
+//     pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
+//         self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
+//     }
+
+//     pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
+//         self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
+//     }
+
+//     pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext<Self>) {
+//         self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx);
+//     }
+
+//     pub fn go_to_type_definition_split(
+//         &mut self,
+//         _: &GoToTypeDefinitionSplit,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx);
+//     }
+
+//     fn go_to_definition_of_kind(
+//         &mut self,
+//         kind: GotoDefinitionKind,
+//         split: bool,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let Some(workspace) = self.workspace(cx) else {
+//             return;
+//         };
+//         let buffer = self.buffer.read(cx);
+//         let head = self.selections.newest::<usize>(cx).head();
+//         let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
+//             text_anchor
+//         } else {
+//             return;
+//         };
+
+//         let project = workspace.read(cx).project().clone();
+//         let definitions = project.update(cx, |project, cx| match kind {
+//             GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
+//             GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
+//         });
+
+//         cx.spawn_labeled("Fetching Definition...", |editor, mut cx| async move {
+//             let definitions = definitions.await?;
+//             editor.update(&mut cx, |editor, cx| {
+//                 editor.navigate_to_definitions(
+//                     definitions
+//                         .into_iter()
+//                         .map(GoToDefinitionLink::Text)
+//                         .collect(),
+//                     split,
+//                     cx,
+//                 );
+//             })?;
+//             Ok::<(), anyhow::Error>(())
+//         })
+//         .detach_and_log_err(cx);
+//     }
+
+//     pub fn navigate_to_definitions(
+//         &mut self,
+//         mut definitions: Vec<GoToDefinitionLink>,
+//         split: bool,
+//         cx: &mut ViewContext<Editor>,
+//     ) {
+//         let Some(workspace) = self.workspace(cx) else {
+//             return;
+//         };
+//         let pane = workspace.read(cx).active_pane().clone();
+//         // If there is one definition, just open it directly
+//         if definitions.len() == 1 {
+//             let definition = definitions.pop().unwrap();
+//             let target_task = match definition {
+//                 GoToDefinitionLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
+//                 GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
+//                     self.compute_target_location(lsp_location, server_id, cx)
+//                 }
+//             };
+//             cx.spawn(|editor, mut cx| async move {
+//                 let target = target_task.await.context("target resolution task")?;
+//                 if let Some(target) = target {
+//                     editor.update(&mut cx, |editor, cx| {
+//                         let range = target.range.to_offset(target.buffer.read(cx));
+//                         let range = editor.range_for_match(&range);
+//                         if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
+//                             editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+//                                 s.select_ranges([range]);
+//                             });
+//                         } else {
+//                             cx.window_context().defer(move |cx| {
+//                                 let target_editor: ViewHandle<Self> =
+//                                     workspace.update(cx, |workspace, cx| {
+//                                         if split {
+//                                             workspace.split_project_item(target.buffer.clone(), cx)
+//                                         } else {
+//                                             workspace.open_project_item(target.buffer.clone(), cx)
+//                                         }
+//                                     });
+//                                 target_editor.update(cx, |target_editor, cx| {
+//                                     // When selecting a definition in a different buffer, disable the nav history
+//                                     // to avoid creating a history entry at the previous cursor location.
+//                                     pane.update(cx, |pane, _| pane.disable_history());
+//                                     target_editor.change_selections(
+//                                         Some(Autoscroll::fit()),
+//                                         cx,
+//                                         |s| {
+//                                             s.select_ranges([range]);
+//                                         },
+//                                     );
+//                                     pane.update(cx, |pane, _| pane.enable_history());
+//                                 });
+//                             });
+//                         }
+//                     })
+//                 } else {
+//                     Ok(())
+//                 }
+//             })
+//             .detach_and_log_err(cx);
+//         } else if !definitions.is_empty() {
+//             let replica_id = self.replica_id(cx);
+//             cx.spawn(|editor, mut cx| async move {
+//                 let (title, location_tasks) = editor
+//                     .update(&mut cx, |editor, cx| {
+//                         let title = definitions
+//                             .iter()
+//                             .find_map(|definition| match definition {
+//                                 GoToDefinitionLink::Text(link) => {
+//                                     link.origin.as_ref().map(|origin| {
+//                                         let buffer = origin.buffer.read(cx);
+//                                         format!(
+//                                             "Definitions for {}",
+//                                             buffer
+//                                                 .text_for_range(origin.range.clone())
+//                                                 .collect::<String>()
+//                                         )
+//                                     })
+//                                 }
+//                                 GoToDefinitionLink::InlayHint(_, _) => None,
+//                             })
+//                             .unwrap_or("Definitions".to_string());
+//                         let location_tasks = definitions
+//                             .into_iter()
+//                             .map(|definition| match definition {
+//                                 GoToDefinitionLink::Text(link) => {
+//                                     Task::Ready(Some(Ok(Some(link.target))))
+//                                 }
+//                                 GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
+//                                     editor.compute_target_location(lsp_location, server_id, cx)
+//                                 }
+//                             })
+//                             .collect::<Vec<_>>();
+//                         (title, location_tasks)
+//                     })
+//                     .context("location tasks preparation")?;
+
+//                 let locations = futures::future::join_all(location_tasks)
+//                     .await
+//                     .into_iter()
+//                     .filter_map(|location| location.transpose())
+//                     .collect::<Result<_>>()
+//                     .context("location tasks")?;
+//                 workspace.update(&mut cx, |workspace, cx| {
+//                     Self::open_locations_in_multibuffer(
+//                         workspace, locations, replica_id, title, split, cx,
+//                     )
+//                 });
+
+//                 anyhow::Ok(())
+//             })
+//             .detach_and_log_err(cx);
+//         }
+//     }
+
+//     fn compute_target_location(
+//         &self,
+//         lsp_location: lsp::Location,
+//         server_id: LanguageServerId,
+//         cx: &mut ViewContext<Editor>,
+//     ) -> Task<anyhow::Result<Option<Location>>> {
+//         let Some(project) = self.project.clone() else {
+//             return Task::Ready(Some(Ok(None)));
+//         };
+
+//         cx.spawn(move |editor, mut cx| async move {
+//             let location_task = editor.update(&mut cx, |editor, cx| {
+//                 project.update(cx, |project, cx| {
+//                     let language_server_name =
+//                         editor.buffer.read(cx).as_singleton().and_then(|buffer| {
+//                             project
+//                                 .language_server_for_buffer(buffer.read(cx), server_id, cx)
+//                                 .map(|(_, lsp_adapter)| {
+//                                     LanguageServerName(Arc::from(lsp_adapter.name()))
+//                                 })
+//                         });
+//                     language_server_name.map(|language_server_name| {
+//                         project.open_local_buffer_via_lsp(
+//                             lsp_location.uri.clone(),
+//                             server_id,
+//                             language_server_name,
+//                             cx,
+//                         )
+//                     })
+//                 })
+//             })?;
+//             let location = match location_task {
+//                 Some(task) => Some({
+//                     let target_buffer_handle = task.await.context("open local buffer")?;
+//                     let range = {
+//                         target_buffer_handle.update(&mut cx, |target_buffer, _| {
+//                             let target_start = target_buffer.clip_point_utf16(
+//                                 point_from_lsp(lsp_location.range.start),
+//                                 Bias::Left,
+//                             );
+//                             let target_end = target_buffer.clip_point_utf16(
+//                                 point_from_lsp(lsp_location.range.end),
+//                                 Bias::Left,
+//                             );
+//                             target_buffer.anchor_after(target_start)
+//                                 ..target_buffer.anchor_before(target_end)
+//                         })
+//                     };
+//                     Location {
+//                         buffer: target_buffer_handle,
+//                         range,
+//                     }
+//                 }),
+//                 None => None,
+//             };
+//             Ok(location)
+//         })
+//     }
+
+//     pub fn find_all_references(
+//         workspace: &mut Workspace,
+//         _: &FindAllReferences,
+//         cx: &mut ViewContext<Workspace>,
+//     ) -> Option<Task<Result<()>>> {
+//         let active_item = workspace.active_item(cx)?;
+//         let editor_handle = active_item.act_as::<Self>(cx)?;
+
+//         let editor = editor_handle.read(cx);
+//         let buffer = editor.buffer.read(cx);
+//         let head = editor.selections.newest::<usize>(cx).head();
+//         let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
+//         let replica_id = editor.replica_id(cx);
+
+//         let project = workspace.project().clone();
+//         let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
+//         Some(cx.spawn_labeled(
+//             "Finding All References...",
+//             |workspace, mut cx| async move {
+//                 let locations = references.await?;
+//                 if locations.is_empty() {
+//                     return Ok(());
+//                 }
+
+//                 workspace.update(&mut cx, |workspace, cx| {
+//                     let title = locations
+//                         .first()
+//                         .as_ref()
+//                         .map(|location| {
+//                             let buffer = location.buffer.read(cx);
+//                             format!(
+//                                 "References to `{}`",
+//                                 buffer
+//                                     .text_for_range(location.range.clone())
+//                                     .collect::<String>()
+//                             )
+//                         })
+//                         .unwrap();
+//                     Self::open_locations_in_multibuffer(
+//                         workspace, locations, replica_id, title, false, cx,
+//                     );
+//                 })?;
+
+//                 Ok(())
+//             },
+//         ))
+//     }
+
+//     /// Opens a multibuffer with the given project locations in it
+//     pub fn open_locations_in_multibuffer(
+//         workspace: &mut Workspace,
+//         mut locations: Vec<Location>,
+//         replica_id: ReplicaId,
+//         title: String,
+//         split: bool,
+//         cx: &mut ViewContext<Workspace>,
+//     ) {
+//         // If there are multiple definitions, open them in a multibuffer
+//         locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
+//         let mut locations = locations.into_iter().peekable();
+//         let mut ranges_to_highlight = Vec::new();
+
+//         let excerpt_buffer = cx.add_model(|cx| {
+//             let mut multibuffer = MultiBuffer::new(replica_id);
+//             while let Some(location) = locations.next() {
+//                 let buffer = location.buffer.read(cx);
+//                 let mut ranges_for_buffer = Vec::new();
+//                 let range = location.range.to_offset(buffer);
+//                 ranges_for_buffer.push(range.clone());
+
+//                 while let Some(next_location) = locations.peek() {
+//                     if next_location.buffer == location.buffer {
+//                         ranges_for_buffer.push(next_location.range.to_offset(buffer));
+//                         locations.next();
+//                     } else {
+//                         break;
+//                     }
+//                 }
+
+//                 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
+//                 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
+//                     location.buffer.clone(),
+//                     ranges_for_buffer,
+//                     1,
+//                     cx,
+//                 ))
+//             }
+
+//             multibuffer.with_title(title)
+//         });
+
+//         let editor = cx.add_view(|cx| {
+//             Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
+//         });
+//         editor.update(cx, |editor, cx| {
+//             editor.highlight_background::<Self>(
+//                 ranges_to_highlight,
+//                 |theme| theme.editor.highlighted_line_background,
+//                 cx,
+//             );
+//         });
+//         if split {
+//             workspace.split_item(SplitDirection::Right, Box::new(editor), cx);
+//         } else {
+//             workspace.add_item(Box::new(editor), cx);
+//         }
+//     }
+
+//     pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
+//         use language::ToOffset as _;
+
+//         let project = self.project.clone()?;
+//         let selection = self.selections.newest_anchor().clone();
+//         let (cursor_buffer, cursor_buffer_position) = self
+//             .buffer
+//             .read(cx)
+//             .text_anchor_for_position(selection.head(), cx)?;
+//         let (tail_buffer, _) = self
+//             .buffer
+//             .read(cx)
+//             .text_anchor_for_position(selection.tail(), cx)?;
+//         if tail_buffer != cursor_buffer {
+//             return None;
+//         }
+
+//         let snapshot = cursor_buffer.read(cx).snapshot();
+//         let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
+//         let prepare_rename = project.update(cx, |project, cx| {
+//             project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
+//         });
+
+//         Some(cx.spawn(|this, mut cx| async move {
+//             let rename_range = if let Some(range) = prepare_rename.await? {
+//                 Some(range)
+//             } else {
+//                 this.update(&mut cx, |this, cx| {
+//                     let buffer = this.buffer.read(cx).snapshot(cx);
+//                     let mut buffer_highlights = this
+//                         .document_highlights_for_position(selection.head(), &buffer)
+//                         .filter(|highlight| {
+//                             highlight.start.excerpt_id == selection.head().excerpt_id
+//                                 && highlight.end.excerpt_id == selection.head().excerpt_id
+//                         });
+//                     buffer_highlights
+//                         .next()
+//                         .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
+//                 })?
+//             };
+//             if let Some(rename_range) = rename_range {
+//                 let rename_buffer_range = rename_range.to_offset(&snapshot);
+//                 let cursor_offset_in_rename_range =
+//                     cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
+
+//                 this.update(&mut cx, |this, cx| {
+//                     this.take_rename(false, cx);
+//                     let style = this.style(cx);
+//                     let buffer = this.buffer.read(cx).read(cx);
+//                     let cursor_offset = selection.head().to_offset(&buffer);
+//                     let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
+//                     let rename_end = rename_start + rename_buffer_range.len();
+//                     let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
+//                     let mut old_highlight_id = None;
+//                     let old_name: Arc<str> = buffer
+//                         .chunks(rename_start..rename_end, true)
+//                         .map(|chunk| {
+//                             if old_highlight_id.is_none() {
+//                                 old_highlight_id = chunk.syntax_highlight_id;
+//                             }
+//                             chunk.text
+//                         })
+//                         .collect::<String>()
+//                         .into();
+
+//                     drop(buffer);
+
+//                     // Position the selection in the rename editor so that it matches the current selection.
+//                     this.show_local_selections = false;
+//                     let rename_editor = cx.add_view(|cx| {
+//                         let mut editor = Editor::single_line(None, cx);
+//                         if let Some(old_highlight_id) = old_highlight_id {
+//                             editor.override_text_style =
+//                                 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
+//                         }
+//                         editor.buffer.update(cx, |buffer, cx| {
+//                             buffer.edit([(0..0, old_name.clone())], None, cx)
+//                         });
+//                         editor.select_all(&SelectAll, cx);
+//                         editor
+//                     });
+
+//                     let ranges = this
+//                         .clear_background_highlights::<DocumentHighlightWrite>(cx)
+//                         .into_iter()
+//                         .flat_map(|(_, ranges)| ranges.into_iter())
+//                         .chain(
+//                             this.clear_background_highlights::<DocumentHighlightRead>(cx)
+//                                 .into_iter()
+//                                 .flat_map(|(_, ranges)| ranges.into_iter()),
+//                         )
+//                         .collect();
+
+//                     this.highlight_text::<Rename>(
+//                         ranges,
+//                         HighlightStyle {
+//                             fade_out: Some(style.rename_fade),
+//                             ..Default::default()
+//                         },
+//                         cx,
+//                     );
+//                     cx.focus(&rename_editor);
+//                     let block_id = this.insert_blocks(
+//                         [BlockProperties {
+//                             style: BlockStyle::Flex,
+//                             position: range.start.clone(),
+//                             height: 1,
+//                             render: Arc::new({
+//                                 let editor = rename_editor.clone();
+//                                 move |cx: &mut BlockContext| {
+//                                     ChildView::new(&editor, cx)
+//                                         .contained()
+//                                         .with_padding_left(cx.anchor_x)
+//                                         .into_any()
+//                                 }
+//                             }),
+//                             disposition: BlockDisposition::Below,
+//                         }],
+//                         Some(Autoscroll::fit()),
+//                         cx,
+//                     )[0];
+//                     this.pending_rename = Some(RenameState {
+//                         range,
+//                         old_name,
+//                         editor: rename_editor,
+//                         block_id,
+//                     });
+//                 })?;
+//             }
+
+//             Ok(())
+//         }))
+//     }
+
+//     pub fn confirm_rename(
+//         workspace: &mut Workspace,
+//         _: &ConfirmRename,
+//         cx: &mut ViewContext<Workspace>,
+//     ) -> Option<Task<Result<()>>> {
+//         let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
+
+//         let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
+//             let rename = editor.take_rename(false, cx)?;
+//             let buffer = editor.buffer.read(cx);
+//             let (start_buffer, start) =
+//                 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
+//             let (end_buffer, end) =
+//                 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
+//             if start_buffer == end_buffer {
+//                 let new_name = rename.editor.read(cx).text(cx);
+//                 Some((start_buffer, start..end, rename.old_name, new_name))
+//             } else {
+//                 None
+//             }
+//         })?;
+
+//         let rename = workspace.project().clone().update(cx, |project, cx| {
+//             project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
+//         });
+
+//         let editor = editor.downgrade();
+//         Some(cx.spawn(|workspace, mut cx| async move {
+//             let project_transaction = rename.await?;
+//             Self::open_project_transaction(
+//                 &editor,
+//                 workspace,
+//                 project_transaction,
+//                 format!("Rename: {} → {}", old_name, new_name),
+//                 cx.clone(),
+//             )
+//             .await?;
+
+//             editor.update(&mut cx, |editor, cx| {
+//                 editor.refresh_document_highlights(cx);
+//             })?;
+//             Ok(())
+//         }))
+//     }
+
+//     fn take_rename(
+//         &mut self,
+//         moving_cursor: bool,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<RenameState> {
+//         let rename = self.pending_rename.take()?;
+//         self.remove_blocks(
+//             [rename.block_id].into_iter().collect(),
+//             Some(Autoscroll::fit()),
+//             cx,
+//         );
+//         self.clear_highlights::<Rename>(cx);
+//         self.show_local_selections = true;
+
+//         if moving_cursor {
+//             let rename_editor = rename.editor.read(cx);
+//             let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
+
+//             // Update the selection to match the position of the selection inside
+//             // the rename editor.
+//             let snapshot = self.buffer.read(cx).read(cx);
+//             let rename_range = rename.range.to_offset(&snapshot);
+//             let cursor_in_editor = snapshot
+//                 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
+//                 .min(rename_range.end);
+//             drop(snapshot);
+
+//             self.change_selections(None, cx, |s| {
+//                 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
+//             });
+//         } else {
+//             self.refresh_document_highlights(cx);
+//         }
+
+//         Some(rename)
+//     }
+
+//     #[cfg(any(test, feature = "test-support"))]
+//     pub fn pending_rename(&self) -> Option<&RenameState> {
+//         self.pending_rename.as_ref()
+//     }
+
+//     fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
+//         let project = match &self.project {
+//             Some(project) => project.clone(),
+//             None => return None,
+//         };
+
+//         Some(self.perform_format(project, FormatTrigger::Manual, cx))
+//     }
+
+//     fn perform_format(
+//         &mut self,
+//         project: Model<Project>,
+//         trigger: FormatTrigger,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Task<Result<()>> {
+//         let buffer = self.buffer().clone();
+//         let buffers = buffer.read(cx).all_buffers();
+
+//         let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
+//         let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
+
+//         cx.spawn(|_, mut cx| async move {
+//             let transaction = futures::select_biased! {
+//                 _ = timeout => {
+//                     log::warn!("timed out waiting for formatting");
+//                     None
+//                 }
+//                 transaction = format.log_err().fuse() => transaction,
+//             };
+
+//             buffer.update(&mut cx, |buffer, cx| {
+//                 if let Some(transaction) = transaction {
+//                     if !buffer.is_singleton() {
+//                         buffer.push_transaction(&transaction.0, cx);
+//                     }
+//                 }
+
+//                 cx.notify();
+//             });
+
+//             Ok(())
+//         })
+//     }
+
+//     fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
+//         if let Some(project) = self.project.clone() {
+//             self.buffer.update(cx, |multi_buffer, cx| {
+//                 project.update(cx, |project, cx| {
+//                     project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
+//                 });
+//             })
+//         }
+//     }
+
+//     fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
+//         cx.show_character_palette();
+//     }
+
+//     fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
+//         if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
+//             let buffer = self.buffer.read(cx).snapshot(cx);
+//             let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
+//             let is_valid = buffer
+//                 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
+//                 .any(|entry| {
+//                     entry.diagnostic.is_primary
+//                         && !entry.range.is_empty()
+//                         && entry.range.start == primary_range_start
+//                         && entry.diagnostic.message == active_diagnostics.primary_message
+//                 });
+
+//             if is_valid != active_diagnostics.is_valid {
+//                 active_diagnostics.is_valid = is_valid;
+//                 let mut new_styles = HashMap::default();
+//                 for (block_id, diagnostic) in &active_diagnostics.blocks {
+//                     new_styles.insert(
+//                         *block_id,
+//                         diagnostic_block_renderer(diagnostic.clone(), is_valid),
+//                     );
+//                 }
+//                 self.display_map
+//                     .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
+//             }
+//         }
+//     }
+
+//     fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
+//         self.dismiss_diagnostics(cx);
+//         self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
+//             let buffer = self.buffer.read(cx).snapshot(cx);
+
+//             let mut primary_range = None;
+//             let mut primary_message = None;
+//             let mut group_end = Point::zero();
+//             let diagnostic_group = buffer
+//                 .diagnostic_group::<Point>(group_id)
+//                 .map(|entry| {
+//                     if entry.range.end > group_end {
+//                         group_end = entry.range.end;
+//                     }
+//                     if entry.diagnostic.is_primary {
+//                         primary_range = Some(entry.range.clone());
+//                         primary_message = Some(entry.diagnostic.message.clone());
+//                     }
+//                     entry
+//                 })
+//                 .collect::<Vec<_>>();
+//             let primary_range = primary_range?;
+//             let primary_message = primary_message?;
+//             let primary_range =
+//                 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
+
+//             let blocks = display_map
+//                 .insert_blocks(
+//                     diagnostic_group.iter().map(|entry| {
+//                         let diagnostic = entry.diagnostic.clone();
+//                         let message_height = diagnostic.message.lines().count() as u8;
+//                         BlockProperties {
+//                             style: BlockStyle::Fixed,
+//                             position: buffer.anchor_after(entry.range.start),
+//                             height: message_height,
+//                             render: diagnostic_block_renderer(diagnostic, true),
+//                             disposition: BlockDisposition::Below,
+//                         }
+//                     }),
+//                     cx,
+//                 )
+//                 .into_iter()
+//                 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
+//                 .collect();
+
+//             Some(ActiveDiagnosticGroup {
+//                 primary_range,
+//                 primary_message,
+//                 blocks,
+//                 is_valid: true,
+//             })
+//         });
+//         self.active_diagnostics.is_some()
+//     }
+
+//     fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
+//         if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
+//             self.display_map.update(cx, |display_map, cx| {
+//                 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
+//             });
+//             cx.notify();
+//         }
+//     }
+
+//     pub fn set_selections_from_remote(
+//         &mut self,
+//         selections: Vec<Selection<Anchor>>,
+//         pending_selection: Option<Selection<Anchor>>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let old_cursor_position = self.selections.newest_anchor().head();
+//         self.selections.change_with(cx, |s| {
+//             s.select_anchors(selections);
+//             if let Some(pending_selection) = pending_selection {
+//                 s.set_pending(pending_selection, SelectMode::Character);
+//             } else {
+//                 s.clear_pending();
+//             }
+//         });
+//         self.selections_did_change(false, &old_cursor_position, cx);
+//     }
+
+//     fn push_to_selection_history(&mut self) {
+//         self.selection_history.push(SelectionHistoryEntry {
+//             selections: self.selections.disjoint_anchors(),
+//             select_next_state: self.select_next_state.clone(),
+//             select_prev_state: self.select_prev_state.clone(),
+//             add_selections_state: self.add_selections_state.clone(),
+//         });
+//     }
+
+//     pub fn transact(
+//         &mut self,
+//         cx: &mut ViewContext<Self>,
+//         update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
+//     ) -> Option<TransactionId> {
+//         self.start_transaction_at(Instant::now(), cx);
+//         update(self, cx);
+//         self.end_transaction_at(Instant::now(), cx)
+//     }
+
+//     fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
+//         self.end_selection(cx);
+//         if let Some(tx_id) = self
+//             .buffer
+//             .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
+//         {
+//             self.selection_history
+//                 .insert_transaction(tx_id, self.selections.disjoint_anchors());
+//         }
+//     }
+
+//     fn end_transaction_at(
+//         &mut self,
+//         now: Instant,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<TransactionId> {
+//         if let Some(tx_id) = self
+//             .buffer
+//             .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
+//         {
+//             if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
+//                 *end_selections = Some(self.selections.disjoint_anchors());
+//             } else {
+//                 error!("unexpectedly ended a transaction that wasn't started by this editor");
+//             }
+
+//             cx.emit(Event::Edited);
+//             Some(tx_id)
+//         } else {
+//             None
+//         }
+//     }
+
+//     pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
+//         let mut fold_ranges = Vec::new();
+
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+//         let selections = self.selections.all_adjusted(cx);
+//         for selection in selections {
+//             let range = selection.range().sorted();
+//             let buffer_start_row = range.start.row;
+
+//             for row in (0..=range.end.row).rev() {
+//                 let fold_range = display_map.foldable_range(row);
+
+//                 if let Some(fold_range) = fold_range {
+//                     if fold_range.end.row >= buffer_start_row {
+//                         fold_ranges.push(fold_range);
+//                         if row <= range.start.row {
+//                             break;
+//                         }
+//                     }
+//                 }
+//             }
+//         }
+
+//         self.fold_ranges(fold_ranges, true, cx);
+//     }
+
+//     pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
+//         let buffer_row = fold_at.buffer_row;
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+//         if let Some(fold_range) = display_map.foldable_range(buffer_row) {
+//             let autoscroll = self
+//                 .selections
+//                 .all::<Point>(cx)
+//                 .iter()
+//                 .any(|selection| fold_range.overlaps(&selection.range()));
+
+//             self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
+//         }
+//     }
+
+//     pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let buffer = &display_map.buffer_snapshot;
+//         let selections = self.selections.all::<Point>(cx);
+//         let ranges = selections
+//             .iter()
+//             .map(|s| {
+//                 let range = s.display_range(&display_map).sorted();
+//                 let mut start = range.start.to_point(&display_map);
+//                 let mut end = range.end.to_point(&display_map);
+//                 start.column = 0;
+//                 end.column = buffer.line_len(end.row);
+//                 start..end
+//             })
+//             .collect::<Vec<_>>();
+
+//         self.unfold_ranges(ranges, true, true, cx);
+//     }
+
+//     pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+//         let intersection_range = Point::new(unfold_at.buffer_row, 0)
+//             ..Point::new(
+//                 unfold_at.buffer_row,
+//                 display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
+//             );
+
+//         let autoscroll = self
+//             .selections
+//             .all::<Point>(cx)
+//             .iter()
+//             .any(|selection| selection.range().overlaps(&intersection_range));
+
+//         self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
+//     }
+
+//     pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
+//         let selections = self.selections.all::<Point>(cx);
+//         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+//         let line_mode = self.selections.line_mode;
+//         let ranges = selections.into_iter().map(|s| {
+//             if line_mode {
+//                 let start = Point::new(s.start.row, 0);
+//                 let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
+//                 start..end
+//             } else {
+//                 s.start..s.end
+//             }
+//         });
+//         self.fold_ranges(ranges, true, cx);
+//     }
+
+//     pub fn fold_ranges<T: ToOffset + Clone>(
+//         &mut self,
+//         ranges: impl IntoIterator<Item = Range<T>>,
+//         auto_scroll: bool,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let mut ranges = ranges.into_iter().peekable();
+//         if ranges.peek().is_some() {
+//             self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
+
+//             if auto_scroll {
+//                 self.request_autoscroll(Autoscroll::fit(), cx);
+//             }
+
+//             cx.notify();
+//         }
+//     }
+
+//     pub fn unfold_ranges<T: ToOffset + Clone>(
+//         &mut self,
+//         ranges: impl IntoIterator<Item = Range<T>>,
+//         inclusive: bool,
+//         auto_scroll: bool,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         let mut ranges = ranges.into_iter().peekable();
+//         if ranges.peek().is_some() {
+//             self.display_map
+//                 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
+//             if auto_scroll {
+//                 self.request_autoscroll(Autoscroll::fit(), cx);
+//             }
+
+//             cx.notify();
+//         }
+//     }
+
+//     pub fn gutter_hover(
+//         &mut self,
+//         GutterHover { hovered }: &GutterHover,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.gutter_hovered = *hovered;
+//         cx.notify();
+//     }
+
+//     pub fn insert_blocks(
+//         &mut self,
+//         blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
+//         autoscroll: Option<Autoscroll>,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Vec<BlockId> {
+//         let blocks = self
+//             .display_map
+//             .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
+//         if let Some(autoscroll) = autoscroll {
+//             self.request_autoscroll(autoscroll, cx);
+//         }
+//         blocks
+//     }
+
+//     pub fn replace_blocks(
+//         &mut self,
+//         blocks: HashMap<BlockId, RenderBlock>,
+//         autoscroll: Option<Autoscroll>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.display_map
+//             .update(cx, |display_map, _| display_map.replace_blocks(blocks));
+//         if let Some(autoscroll) = autoscroll {
+//             self.request_autoscroll(autoscroll, cx);
+//         }
+//     }
+
+//     pub fn remove_blocks(
+//         &mut self,
+//         block_ids: HashSet<BlockId>,
+//         autoscroll: Option<Autoscroll>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.display_map.update(cx, |display_map, cx| {
+//             display_map.remove_blocks(block_ids, cx)
+//         });
+//         if let Some(autoscroll) = autoscroll {
+//             self.request_autoscroll(autoscroll, cx);
+//         }
+//     }
+
+//     pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
+//         self.display_map
+//             .update(cx, |map, cx| map.snapshot(cx))
+//             .longest_row()
+//     }
+
+//     pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
+//         self.display_map
+//             .update(cx, |map, cx| map.snapshot(cx))
+//             .max_point()
+//     }
+
+//     pub fn text(&self, cx: &AppContext) -> String {
+//         self.buffer.read(cx).read(cx).text()
+//     }
+
+//     pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
+//         self.transact(cx, |this, cx| {
+//             this.buffer
+//                 .read(cx)
+//                 .as_singleton()
+//                 .expect("you can only call set_text on editors for singleton buffers")
+//                 .update(cx, |buffer, cx| buffer.set_text(text, cx));
+//         });
+//     }
+
+//     pub fn display_text(&self, cx: &mut AppContext) -> String {
+//         self.display_map
+//             .update(cx, |map, cx| map.snapshot(cx))
+//             .text()
+//     }
+
+//     pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
+//         let mut wrap_guides = smallvec::smallvec![];
+
+//         if self.show_wrap_guides == Some(false) {
+//             return wrap_guides;
+//         }
+
+//         let settings = self.buffer.read(cx).settings_at(0, cx);
+//         if settings.show_wrap_guides {
+//             if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
+//                 wrap_guides.push((soft_wrap as usize, true));
+//             }
+//             wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
+//         }
+
+//         wrap_guides
+//     }
+
+//     pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
+//         let settings = self.buffer.read(cx).settings_at(0, cx);
+//         let mode = self
+//             .soft_wrap_mode_override
+//             .unwrap_or_else(|| settings.soft_wrap);
+//         match mode {
+//             language_settings::SoftWrap::None => SoftWrap::None,
+//             language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
+//             language_settings::SoftWrap::PreferredLineLength => {
+//                 SoftWrap::Column(settings.preferred_line_length)
+//             }
+//         }
+//     }
+
+//     pub fn set_soft_wrap_mode(
+//         &mut self,
+//         mode: language_settings::SoftWrap,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.soft_wrap_mode_override = Some(mode);
+//         cx.notify();
+//     }
+
+//     pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut AppContext) -> bool {
+//         self.display_map
+//             .update(cx, |map, cx| map.set_wrap_width(width, cx))
+//     }
+
+//     pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
+//         if self.soft_wrap_mode_override.is_some() {
+//             self.soft_wrap_mode_override.take();
+//         } else {
+//             let soft_wrap = match self.soft_wrap_mode(cx) {
+//                 SoftWrap::None => language_settings::SoftWrap::EditorWidth,
+//                 SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None,
+//             };
+//             self.soft_wrap_mode_override = Some(soft_wrap);
+//         }
+//         cx.notify();
+//     }
+
+//     pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
+//         self.show_gutter = show_gutter;
+//         cx.notify();
+//     }
+
+//     pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
+//         self.show_wrap_guides = Some(show_gutter);
+//         cx.notify();
+//     }
+
+//     pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
+//         if let Some(buffer) = self.buffer().read(cx).as_singleton() {
+//             if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
+//                 cx.reveal_path(&file.abs_path(cx));
+//             }
+//         }
+//     }
+
+//     pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
+//         if let Some(buffer) = self.buffer().read(cx).as_singleton() {
+//             if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
+//                 if let Some(path) = file.abs_path(cx).to_str() {
+//                     cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
+//                 }
+//             }
+//         }
+//     }
+
+//     pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
+//         if let Some(buffer) = self.buffer().read(cx).as_singleton() {
+//             if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
+//                 if let Some(path) = file.path().to_str() {
+//                     cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
+//                 }
+//             }
+//         }
+//     }
+
+//     pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
+//         self.highlighted_rows = rows;
+//     }
+
+//     pub fn highlighted_rows(&self) -> Option<Range<u32>> {
+//         self.highlighted_rows.clone()
+//     }
+
+//     pub fn highlight_background<T: 'static>(
+//         &mut self,
+//         ranges: Vec<Range<Anchor>>,
+//         color_fetcher: fn(&Theme) -> Color,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.background_highlights
+//             .insert(TypeId::of::<T>(), (color_fetcher, ranges));
+//         cx.notify();
+//     }
+
+//     pub fn highlight_inlay_background<T: 'static>(
+//         &mut self,
+//         ranges: Vec<InlayHighlight>,
+//         color_fetcher: fn(&Theme) -> Color,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         // TODO: no actual highlights happen for inlays currently, find a way to do that
+//         self.inlay_background_highlights
+//             .insert(Some(TypeId::of::<T>()), (color_fetcher, ranges));
+//         cx.notify();
+//     }
+
+//     pub fn clear_background_highlights<T: 'static>(
+//         &mut self,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Option<BackgroundHighlight> {
+//         let text_highlights = self.background_highlights.remove(&TypeId::of::<T>());
+//         let inlay_highlights = self
+//             .inlay_background_highlights
+//             .remove(&Some(TypeId::of::<T>()));
+//         if text_highlights.is_some() || inlay_highlights.is_some() {
+//             cx.notify();
+//         }
+//         text_highlights
+//     }
+
+//     #[cfg(feature = "test-support")]
+//     pub fn all_text_background_highlights(
+//         &mut self,
+//         cx: &mut ViewContext<Self>,
+//     ) -> Vec<(Range<DisplayPoint>, Color)> {
+//         let snapshot = self.snapshot(cx);
+//         let buffer = &snapshot.buffer_snapshot;
+//         let start = buffer.anchor_before(0);
+//         let end = buffer.anchor_after(buffer.len());
+//         let theme = theme::current(cx);
+//         self.background_highlights_in_range(start..end, &snapshot, theme.as_ref())
+//     }
+
+//     fn document_highlights_for_position<'a>(
+//         &'a self,
+//         position: Anchor,
+//         buffer: &'a MultiBufferSnapshot,
+//     ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
+//         let read_highlights = self
+//             .background_highlights
+//             .get(&TypeId::of::<DocumentHighlightRead>())
+//             .map(|h| &h.1);
+//         let write_highlights = self
+//             .background_highlights
+//             .get(&TypeId::of::<DocumentHighlightWrite>())
+//             .map(|h| &h.1);
+//         let left_position = position.bias_left(buffer);
+//         let right_position = position.bias_right(buffer);
+//         read_highlights
+//             .into_iter()
+//             .chain(write_highlights)
+//             .flat_map(move |ranges| {
+//                 let start_ix = match ranges.binary_search_by(|probe| {
+//                     let cmp = probe.end.cmp(&left_position, buffer);
+//                     if cmp.is_ge() {
+//                         Ordering::Greater
+//                     } else {
+//                         Ordering::Less
+//                     }
+//                 }) {
+//                     Ok(i) | Err(i) => i,
+//                 };
+
+//                 let right_position = right_position.clone();
+//                 ranges[start_ix..]
+//                     .iter()
+//                     .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
+//             })
+//     }
+
+//     pub fn background_highlights_in_range(
+//         &self,
+//         search_range: Range<Anchor>,
+//         display_snapshot: &DisplaySnapshot,
+//         theme: &Theme,
+//     ) -> Vec<(Range<DisplayPoint>, Color)> {
+//         let mut results = Vec::new();
+//         for (color_fetcher, ranges) in self.background_highlights.values() {
+//             let color = color_fetcher(theme);
+//             let start_ix = match ranges.binary_search_by(|probe| {
+//                 let cmp = probe
+//                     .end
+//                     .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
+//                 if cmp.is_gt() {
+//                     Ordering::Greater
+//                 } else {
+//                     Ordering::Less
+//                 }
+//             }) {
+//                 Ok(i) | Err(i) => i,
+//             };
+//             for range in &ranges[start_ix..] {
+//                 if range
+//                     .start
+//                     .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
+//                     .is_ge()
+//                 {
+//                     break;
+//                 }
+
+//                 let start = range.start.to_display_point(&display_snapshot);
+//                 let end = range.end.to_display_point(&display_snapshot);
+//                 results.push((start..end, color))
+//             }
+//         }
+//         results
+//     }
+
+//     pub fn background_highlight_row_ranges<T: 'static>(
+//         &self,
+//         search_range: Range<Anchor>,
+//         display_snapshot: &DisplaySnapshot,
+//         count: usize,
+//     ) -> Vec<RangeInclusive<DisplayPoint>> {
+//         let mut results = Vec::new();
+//         let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
+//             return vec![];
+//         };
+
+//         let start_ix = match ranges.binary_search_by(|probe| {
+//             let cmp = probe
+//                 .end
+//                 .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
+//             if cmp.is_gt() {
+//                 Ordering::Greater
+//             } else {
+//                 Ordering::Less
+//             }
+//         }) {
+//             Ok(i) | Err(i) => i,
+//         };
+//         let mut push_region = |start: Option<Point>, end: Option<Point>| {
+//             if let (Some(start_display), Some(end_display)) = (start, end) {
+//                 results.push(
+//                     start_display.to_display_point(display_snapshot)
+//                         ..=end_display.to_display_point(display_snapshot),
+//                 );
+//             }
+//         };
+//         let mut start_row: Option<Point> = None;
+//         let mut end_row: Option<Point> = None;
+//         if ranges.len() > count {
+//             return Vec::new();
+//         }
+//         for range in &ranges[start_ix..] {
+//             if range
+//                 .start
+//                 .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
+//                 .is_ge()
+//             {
+//                 break;
+//             }
+//             let end = range.end.to_point(&display_snapshot.buffer_snapshot);
+//             if let Some(current_row) = &end_row {
+//                 if end.row == current_row.row {
+//                     continue;
+//                 }
+//             }
+//             let start = range.start.to_point(&display_snapshot.buffer_snapshot);
+//             if start_row.is_none() {
+//                 assert_eq!(end_row, None);
+//                 start_row = Some(start);
+//                 end_row = Some(end);
+//                 continue;
+//             }
+//             if let Some(current_end) = end_row.as_mut() {
+//                 if start.row > current_end.row + 1 {
+//                     push_region(start_row, end_row);
+//                     start_row = Some(start);
+//                     end_row = Some(end);
+//                 } else {
+//                     // Merge two hunks.
+//                     *current_end = end;
+//                 }
+//             } else {
+//                 unreachable!();
+//             }
+//         }
+//         // We might still have a hunk that was not rendered (if there was a search hit on the last line)
+//         push_region(start_row, end_row);
+//         results
+//     }
+
+//     pub fn highlight_text<T: 'static>(
+//         &mut self,
+//         ranges: Vec<Range<Anchor>>,
+//         style: HighlightStyle,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.display_map.update(cx, |map, _| {
+//             map.highlight_text(TypeId::of::<T>(), ranges, style)
+//         });
+//         cx.notify();
+//     }
+
+//     pub fn highlight_inlays<T: 'static>(
+//         &mut self,
+//         highlights: Vec<InlayHighlight>,
+//         style: HighlightStyle,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.display_map.update(cx, |map, _| {
+//             map.highlight_inlays(TypeId::of::<T>(), highlights, style)
+//         });
+//         cx.notify();
+//     }
+
+//     pub fn text_highlights<'a, T: 'static>(
+//         &'a self,
+//         cx: &'a AppContext,
+//     ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
+//         self.display_map.read(cx).text_highlights(TypeId::of::<T>())
+//     }
+
+//     pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
+//         let cleared = self
+//             .display_map
+//             .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
+//         if cleared {
+//             cx.notify();
+//         }
+//     }
+
+//     pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
+//         self.blink_manager.read(cx).visible() && self.focused
+//     }
+
+//     fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
+//         cx.notify();
+//     }
+
+//     fn on_buffer_event(
+//         &mut self,
+//         multibuffer: Model<MultiBuffer>,
+//         event: &multi_buffer::Event,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         match event {
+//             multi_buffer::Event::Edited {
+//                 sigleton_buffer_edited,
+//             } => {
+//                 self.refresh_active_diagnostics(cx);
+//                 self.refresh_code_actions(cx);
+//                 if self.has_active_copilot_suggestion(cx) {
+//                     self.update_visible_copilot_suggestion(cx);
+//                 }
+//                 cx.emit(Event::BufferEdited);
+
+//                 if *sigleton_buffer_edited {
+//                     if let Some(project) = &self.project {
+//                         let project = project.read(cx);
+//                         let languages_affected = multibuffer
+//                             .read(cx)
+//                             .all_buffers()
+//                             .into_iter()
+//                             .filter_map(|buffer| {
+//                                 let buffer = buffer.read(cx);
+//                                 let language = buffer.language()?;
+//                                 if project.is_local()
+//                                     && project.language_servers_for_buffer(buffer, cx).count() == 0
+//                                 {
+//                                     None
+//                                 } else {
+//                                     Some(language)
+//                                 }
+//                             })
+//                             .cloned()
+//                             .collect::<HashSet<_>>();
+//                         if !languages_affected.is_empty() {
+//                             self.refresh_inlay_hints(
+//                                 InlayHintRefreshReason::BufferEdited(languages_affected),
+//                                 cx,
+//                             );
+//                         }
+//                     }
+//                 }
+//             }
+//             multi_buffer::Event::ExcerptsAdded {
+//                 buffer,
+//                 predecessor,
+//                 excerpts,
+//             } => {
+//                 cx.emit(Event::ExcerptsAdded {
+//                     buffer: buffer.clone(),
+//                     predecessor: *predecessor,
+//                     excerpts: excerpts.clone(),
+//                 });
+//                 self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
+//             }
+//             multi_buffer::Event::ExcerptsRemoved { ids } => {
+//                 self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
+//                 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
+//             }
+//             multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
+//             multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
+//             multi_buffer::Event::Saved => cx.emit(Event::Saved),
+//             multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
+//             multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
+//             multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged),
+//             multi_buffer::Event::Closed => cx.emit(Event::Closed),
+//             multi_buffer::Event::DiagnosticsUpdated => {
+//                 self.refresh_active_diagnostics(cx);
+//             }
+//             _ => {}
+//         };
+//     }
+
+//     fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
+//         cx.notify();
+//     }
+
+//     fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
+//         self.refresh_copilot_suggestions(true, cx);
+//         self.refresh_inlay_hints(
+//             InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
+//                 self.selections.newest_anchor().head(),
+//                 &self.buffer.read(cx).snapshot(cx),
+//                 cx,
+//             )),
+//             cx,
+//         );
+//     }
+
+//     pub fn set_searchable(&mut self, searchable: bool) {
+//         self.searchable = searchable;
+//     }
+
+//     pub fn searchable(&self) -> bool {
+//         self.searchable
+//     }
+
+//     fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
+//         let active_item = workspace.active_item(cx);
+//         let editor_handle = if let Some(editor) = active_item
+//             .as_ref()
+//             .and_then(|item| item.act_as::<Self>(cx))
+//         {
+//             editor
+//         } else {
+//             cx.propagate_action();
+//             return;
+//         };
+
+//         let editor = editor_handle.read(cx);
+//         let buffer = editor.buffer.read(cx);
+//         if buffer.is_singleton() {
+//             cx.propagate_action();
+//             return;
+//         }
+
+//         let mut new_selections_by_buffer = HashMap::default();
+//         for selection in editor.selections.all::<usize>(cx) {
+//             for (buffer, mut range, _) in
+//                 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
+//             {
+//                 if selection.reversed {
+//                     mem::swap(&mut range.start, &mut range.end);
+//                 }
+//                 new_selections_by_buffer
+//                     .entry(buffer)
+//                     .or_insert(Vec::new())
+//                     .push(range)
+//             }
+//         }
+
+//         editor_handle.update(cx, |editor, cx| {
+//             editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
+//         });
+//         let pane = workspace.active_pane().clone();
+//         pane.update(cx, |pane, _| pane.disable_history());
+
+//         // We defer the pane interaction because we ourselves are a workspace item
+//         // and activating a new item causes the pane to call a method on us reentrantly,
+//         // which panics if we're on the stack.
+//         cx.defer(move |workspace, cx| {
+//             for (buffer, ranges) in new_selections_by_buffer.into_iter() {
+//                 let editor = workspace.open_project_item::<Self>(buffer, cx);
+//                 editor.update(cx, |editor, cx| {
+//                     editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
+//                         s.select_ranges(ranges);
+//                     });
+//                 });
+//             }
+
+//             pane.update(cx, |pane, _| pane.enable_history());
+//         });
+//     }
+
+//     fn jump(
+//         workspace: &mut Workspace,
+//         path: ProjectPath,
+//         position: Point,
+//         anchor: language::Anchor,
+//         cx: &mut ViewContext<Workspace>,
+//     ) {
+//         let editor = workspace.open_path(path, None, true, cx);
+//         cx.spawn(|_, mut cx| async move {
+//             let editor = editor
+//                 .await?
+//                 .downcast::<Editor>()
+//                 .ok_or_else(|| anyhow!("opened item was not an editor"))?
+//                 .downgrade();
+//             editor.update(&mut cx, |editor, cx| {
+//                 let buffer = editor
+//                     .buffer()
+//                     .read(cx)
+//                     .as_singleton()
+//                     .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
+//                 let buffer = buffer.read(cx);
+//                 let cursor = if buffer.can_resolve(&anchor) {
+//                     language::ToPoint::to_point(&anchor, buffer)
+//                 } else {
+//                     buffer.clip_point(position, Bias::Left)
+//                 };
+
+//                 let nav_history = editor.nav_history.take();
+//                 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
+//                     s.select_ranges([cursor..cursor]);
+//                 });
+//                 editor.nav_history = nav_history;
+
+//                 anyhow::Ok(())
+//             })??;
+
+//             anyhow::Ok(())
+//         })
+//         .detach_and_log_err(cx);
+//     }
+
+//     fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
+//         let snapshot = self.buffer.read(cx).read(cx);
+//         let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
+//         Some(
+//             ranges
+//                 .iter()
+//                 .map(move |range| {
+//                     range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
+//                 })
+//                 .collect(),
+//         )
+//     }
+
+//     fn selection_replacement_ranges(
+//         &self,
+//         range: Range<OffsetUtf16>,
+//         cx: &AppContext,
+//     ) -> Vec<Range<OffsetUtf16>> {
+//         let selections = self.selections.all::<OffsetUtf16>(cx);
+//         let newest_selection = selections
+//             .iter()
+//             .max_by_key(|selection| selection.id)
+//             .unwrap();
+//         let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
+//         let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
+//         let snapshot = self.buffer.read(cx).read(cx);
+//         selections
+//             .into_iter()
+//             .map(|mut selection| {
+//                 selection.start.0 =
+//                     (selection.start.0 as isize).saturating_add(start_delta) as usize;
+//                 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
+//                 snapshot.clip_offset_utf16(selection.start, Bias::Left)
+//                     ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
+//             })
+//             .collect()
+//     }
+
+//     fn report_copilot_event(
+//         &self,
+//         suggestion_id: Option<String>,
+//         suggestion_accepted: bool,
+//         cx: &AppContext,
+//     ) {
+//         let Some(project) = &self.project else { return };
+
+//         // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension
+//         let file_extension = self
+//             .buffer
+//             .read(cx)
+//             .as_singleton()
+//             .and_then(|b| b.read(cx).file())
+//             .and_then(|file| Path::new(file.file_name(cx)).extension())
+//             .and_then(|e| e.to_str())
+//             .map(|a| a.to_string());
+
+//         let telemetry = project.read(cx).client().telemetry().clone();
+//         let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
+
+//         let event = ClickhouseEvent::Copilot {
+//             suggestion_id,
+//             suggestion_accepted,
+//             file_extension,
+//         };
+//         telemetry.report_clickhouse_event(event, telemetry_settings);
+//     }
+
+//     #[cfg(any(test, feature = "test-support"))]
+//     fn report_editor_event(
+//         &self,
+//         _operation: &'static str,
+//         _file_extension: Option<String>,
+//         _cx: &AppContext,
+//     ) {
+//     }
+
+//     #[cfg(not(any(test, feature = "test-support")))]
+//     fn report_editor_event(
+//         &self,
+//         operation: &'static str,
+//         file_extension: Option<String>,
+//         cx: &AppContext,
+//     ) {
+//         let Some(project) = &self.project else { return };
+
+//         // If None, we are in a file without an extension
+//         let file = self
+//             .buffer
+//             .read(cx)
+//             .as_singleton()
+//             .and_then(|b| b.read(cx).file());
+//         let file_extension = file_extension.or(file
+//             .as_ref()
+//             .and_then(|file| Path::new(file.file_name(cx)).extension())
+//             .and_then(|e| e.to_str())
+//             .map(|a| a.to_string()));
+
+//         let vim_mode = cx
+//             .global::<SettingsStore>()
+//             .raw_user_settings()
+//             .get("vim_mode")
+//             == Some(&serde_json::Value::Bool(true));
+//         let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
+//         let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None);
+//         let copilot_enabled_for_language = self
+//             .buffer
+//             .read(cx)
+//             .settings_at(0, cx)
+//             .show_copilot_suggestions;
+
+//         let telemetry = project.read(cx).client().telemetry().clone();
+//         let event = ClickhouseEvent::Editor {
+//             file_extension,
+//             vim_mode,
+//             operation,
+//             copilot_enabled,
+//             copilot_enabled_for_language,
+//         };
+//         telemetry.report_clickhouse_event(event, telemetry_settings)
+//     }
+
+//     /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
+//     /// with each line being an array of {text, highlight} objects.
+//     fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
+//         let Some(buffer) = self.buffer.read(cx).as_singleton() else {
+//             return;
+//         };
+
+//         #[derive(Serialize)]
+//         struct Chunk<'a> {
+//             text: String,
+//             highlight: Option<&'a str>,
+//         }
+
+//         let snapshot = buffer.read(cx).snapshot();
+//         let range = self
+//             .selected_text_range(cx)
+//             .and_then(|selected_range| {
+//                 if selected_range.is_empty() {
+//                     None
+//                 } else {
+//                     Some(selected_range)
+//                 }
+//             })
+//             .unwrap_or_else(|| 0..snapshot.len());
+
+//         let chunks = snapshot.chunks(range, true);
+//         let mut lines = Vec::new();
+//         let mut line: VecDeque<Chunk> = VecDeque::new();
+
+//         let theme = &theme::current(cx).editor.syntax;
+
+//         for chunk in chunks {
+//             let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme));
+//             let mut chunk_lines = chunk.text.split("\n").peekable();
+//             while let Some(text) = chunk_lines.next() {
+//                 let mut merged_with_last_token = false;
+//                 if let Some(last_token) = line.back_mut() {
+//                     if last_token.highlight == highlight {
+//                         last_token.text.push_str(text);
+//                         merged_with_last_token = true;
+//                     }
+//                 }
+
+//                 if !merged_with_last_token {
+//                     line.push_back(Chunk {
+//                         text: text.into(),
+//                         highlight,
+//                     });
+//                 }
+
+//                 if chunk_lines.peek().is_some() {
+//                     if line.len() > 1 && line.front().unwrap().text.is_empty() {
+//                         line.pop_front();
+//                     }
+//                     if line.len() > 1 && line.back().unwrap().text.is_empty() {
+//                         line.pop_back();
+//                     }
+
+//                     lines.push(mem::take(&mut line));
+//                 }
+//             }
+//         }
+
+//         let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
+//             return;
+//         };
+//         cx.write_to_clipboard(ClipboardItem::new(lines));
+//     }
+
+//     pub fn inlay_hint_cache(&self) -> &InlayHintCache {
+//         &self.inlay_hint_cache
+//     }
+
+//     pub fn replay_insert_event(
+//         &mut self,
+//         text: &str,
+//         relative_utf16_range: Option<Range<isize>>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if !self.input_enabled {
+//             cx.emit(Event::InputIgnored { text: text.into() });
+//             return;
+//         }
+//         if let Some(relative_utf16_range) = relative_utf16_range {
+//             let selections = self.selections.all::<OffsetUtf16>(cx);
+//             self.change_selections(None, cx, |s| {
+//                 let new_ranges = selections.into_iter().map(|range| {
+//                     let start = OffsetUtf16(
+//                         range
+//                             .head()
+//                             .0
+//                             .saturating_add_signed(relative_utf16_range.start),
+//                     );
+//                     let end = OffsetUtf16(
+//                         range
+//                             .head()
+//                             .0
+//                             .saturating_add_signed(relative_utf16_range.end),
+//                     );
+//                     start..end
+//                 });
+//                 s.select_ranges(new_ranges);
+//             });
+//         }
+
+//         self.handle_input(text, cx);
+//     }
+
+//     pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
+//         let Some(project) = self.project.as_ref() else {
+//             return false;
+//         };
+//         let project = project.read(cx);
+
+//         let mut supports = false;
+//         self.buffer().read(cx).for_each_buffer(|buffer| {
+//             if !supports {
+//                 supports = project
+//                     .language_servers_for_buffer(buffer.read(cx), cx)
+//                     .any(
+//                         |(_, server)| match server.capabilities().inlay_hint_provider {
+//                             Some(lsp::OneOf::Left(enabled)) => enabled,
+//                             Some(lsp::OneOf::Right(_)) => true,
+//                             None => false,
+//                         },
+//                     )
+//             }
+//         });
+//         supports
+//     }
+// }
 
 pub trait CollaborationHub {
     fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;

crates/editor2/src/editor_settings.rs 🔗

@@ -1,6 +1,6 @@
+use gpui::Settings;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::Setting;
 
 #[derive(Deserialize)]
 pub struct EditorSettings {
@@ -47,7 +47,7 @@ pub struct ScrollbarContent {
     pub selections: Option<bool>,
 }
 
-impl Setting for EditorSettings {
+impl Settings for EditorSettings {
     const KEY: Option<&'static str> = None;
 
     type FileContent = EditorSettingsContent;

crates/editor2/src/element.rs 🔗

@@ -1,60 +1,14 @@
 use super::{
-    display_map::{BlockContext, ToDisplayPoint},
-    Anchor, DisplayPoint, Editor, EditorMode, EditorSnapshot, SelectPhase, SoftWrap, ToPoint,
-    MAX_LINE_LEN,
+    display_map::ToDisplayPoint, DisplayPoint, Editor, EditorSnapshot, ToPoint, MAX_LINE_LEN,
 };
 use crate::{
-    display_map::{BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, TransformBlock},
-    editor_settings::ShowScrollbar,
-    git::{diff_hunk_to_display, DisplayDiffHunk},
-    hover_popover::{
-        hide_hover, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH,
-        MIN_POPOVER_LINE_HEIGHT,
-    },
-    link_go_to_definition::{
-        go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,
-        update_inlay_link_and_hover_points, GoToDefinitionTrigger,
-    },
+    display_map::{BlockStyle, DisplaySnapshot},
     mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,
 };
-use collections::{BTreeMap, HashMap};
-use git::diff::DiffHunkStatus;
-use gpui::{
-    color::Color,
-    elements::*,
-    fonts::TextStyle,
-    geometry::{
-        rect::RectF,
-        vector::{vec2f, Vector2F},
-        PathBuilder,
-    },
-    json::{self, ToJson},
-    platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
-    text_layout::{self, Line, RunStyle, TextLayoutCache},
-    AnyElement, Axis, CursorRegion, Element, EventContext, FontCache, MouseRegion, Quad,
-    SizeConstraint, ViewContext, WindowContext,
-};
-use itertools::Itertools;
-use json::json;
-use language::{
-    language_settings::ShowWhitespaceSetting, Bias, CursorShape, OffsetUtf16, Selection,
-};
-use project::{
-    project_settings::{GitGutterSetting, ProjectSettings},
-    ProjectPath,
-};
-use smallvec::SmallVec;
-use std::{
-    borrow::Cow,
-    cmp::{self, Ordering},
-    fmt::Write,
-    iter,
-    ops::Range,
-    sync::Arc,
-};
-use text::Point;
-use theme::SelectionStyle;
-use workspace::item::Item;
+use gpui::{AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun, TextSystem};
+use language::{CursorShape, Selection};
+use std::{ops::Range, sync::Arc};
+use sum_tree::Bias;
 
 enum FoldMarkers {}
 
@@ -129,1695 +83,1695 @@ impl EditorElement {
         }
     }
 
-    fn attach_mouse_handlers(
-        position_map: &Arc<PositionMap>,
-        has_popovers: bool,
-        visible_bounds: RectF,
-        text_bounds: RectF,
-        gutter_bounds: RectF,
-        bounds: RectF,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        enum EditorElementMouseHandlers {}
-        let view_id = cx.view_id();
-        cx.scene().push_mouse_region(
-            MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
-                .on_down(MouseButton::Left, {
-                    let position_map = position_map.clone();
-                    move |event, editor, cx| {
-                        if !Self::mouse_down(
-                            editor,
-                            event.platform_event,
-                            position_map.as_ref(),
-                            text_bounds,
-                            gutter_bounds,
-                            cx,
-                        ) {
-                            cx.propagate_event();
-                        }
-                    }
-                })
-                .on_down(MouseButton::Right, {
-                    let position_map = position_map.clone();
-                    move |event, editor, cx| {
-                        if !Self::mouse_right_down(
-                            editor,
-                            event.position,
-                            position_map.as_ref(),
-                            text_bounds,
-                            cx,
-                        ) {
-                            cx.propagate_event();
-                        }
-                    }
-                })
-                .on_up(MouseButton::Left, {
-                    let position_map = position_map.clone();
-                    move |event, editor, cx| {
-                        if !Self::mouse_up(
-                            editor,
-                            event.position,
-                            event.cmd,
-                            event.shift,
-                            event.alt,
-                            position_map.as_ref(),
-                            text_bounds,
-                            cx,
-                        ) {
-                            cx.propagate_event()
-                        }
-                    }
-                })
-                .on_drag(MouseButton::Left, {
-                    let position_map = position_map.clone();
-                    move |event, editor, cx| {
-                        if event.end {
-                            return;
-                        }
-
-                        if !Self::mouse_dragged(
-                            editor,
-                            event.platform_event,
-                            position_map.as_ref(),
-                            text_bounds,
-                            cx,
-                        ) {
-                            cx.propagate_event()
-                        }
-                    }
-                })
-                .on_move({
-                    let position_map = position_map.clone();
-                    move |event, editor, cx| {
-                        if !Self::mouse_moved(
-                            editor,
-                            event.platform_event,
-                            &position_map,
-                            text_bounds,
-                            cx,
-                        ) {
-                            cx.propagate_event()
-                        }
-                    }
-                })
-                .on_move_out(move |_, editor: &mut Editor, cx| {
-                    if has_popovers {
-                        hide_hover(editor, cx);
-                    }
-                })
-                .on_scroll({
-                    let position_map = position_map.clone();
-                    move |event, editor, cx| {
-                        if !Self::scroll(
-                            editor,
-                            event.position,
-                            *event.delta.raw(),
-                            event.delta.precise(),
-                            &position_map,
-                            bounds,
-                            cx,
-                        ) {
-                            cx.propagate_event()
-                        }
-                    }
-                }),
-        );
-
-        enum GutterHandlers {}
-        let view_id = cx.view_id();
-        let region_id = cx.view_id() + 1;
-        cx.scene().push_mouse_region(
-            MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
-                |hover, editor: &mut Editor, cx| {
-                    editor.gutter_hover(
-                        &GutterHover {
-                            hovered: hover.started,
-                        },
-                        cx,
-                    );
-                },
-            ),
-        )
-    }
-
-    fn mouse_down(
-        editor: &mut Editor,
-        MouseButtonEvent {
-            position,
-            modifiers:
-                Modifiers {
-                    shift,
-                    ctrl,
-                    alt,
-                    cmd,
-                    ..
-                },
-            mut click_count,
-            ..
-        }: MouseButtonEvent,
-        position_map: &PositionMap,
-        text_bounds: RectF,
-        gutter_bounds: RectF,
-        cx: &mut EventContext<Editor>,
-    ) -> bool {
-        if gutter_bounds.contains_point(position) {
-            click_count = 3; // Simulate triple-click when clicking the gutter to select lines
-        } else if !text_bounds.contains_point(position) {
-            return false;
-        }
-
-        let point_for_position = position_map.point_for_position(text_bounds, position);
-        let position = point_for_position.previous_valid;
-        if shift && alt {
-            editor.select(
-                SelectPhase::BeginColumnar {
-                    position,
-                    goal_column: point_for_position.exact_unclipped.column(),
-                },
-                cx,
-            );
-        } else if shift && !ctrl && !alt && !cmd {
-            editor.select(
-                SelectPhase::Extend {
-                    position,
-                    click_count,
-                },
-                cx,
-            );
-        } else {
-            editor.select(
-                SelectPhase::Begin {
-                    position,
-                    add: alt,
-                    click_count,
-                },
-                cx,
-            );
-        }
-
-        true
-    }
-
-    fn mouse_right_down(
-        editor: &mut Editor,
-        position: Vector2F,
-        position_map: &PositionMap,
-        text_bounds: RectF,
-        cx: &mut EventContext<Editor>,
-    ) -> bool {
-        if !text_bounds.contains_point(position) {
-            return false;
-        }
-        let point_for_position = position_map.point_for_position(text_bounds, position);
-        mouse_context_menu::deploy_context_menu(
-            editor,
-            position,
-            point_for_position.previous_valid,
-            cx,
-        );
-        true
-    }
-
-    fn mouse_up(
-        editor: &mut Editor,
-        position: Vector2F,
-        cmd: bool,
-        shift: bool,
-        alt: bool,
-        position_map: &PositionMap,
-        text_bounds: RectF,
-        cx: &mut EventContext<Editor>,
-    ) -> bool {
-        let end_selection = editor.has_pending_selection();
-        let pending_nonempty_selections = editor.has_pending_nonempty_selection();
-
-        if end_selection {
-            editor.select(SelectPhase::End, cx);
-        }
-
-        if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
-            let point = position_map.point_for_position(text_bounds, position);
-            let could_be_inlay = point.as_valid().is_none();
-            if shift || could_be_inlay {
-                go_to_fetched_type_definition(editor, point, alt, cx);
-            } else {
-                go_to_fetched_definition(editor, point, alt, cx);
-            }
-
-            return true;
-        }
-
-        end_selection
-    }
-
-    fn mouse_dragged(
-        editor: &mut Editor,
-        MouseMovedEvent {
-            modifiers: Modifiers { cmd, shift, .. },
-            position,
-            ..
-        }: MouseMovedEvent,
-        position_map: &PositionMap,
-        text_bounds: RectF,
-        cx: &mut EventContext<Editor>,
-    ) -> bool {
-        // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
-        // Don't trigger hover popover if mouse is hovering over context menu
-        let point = if text_bounds.contains_point(position) {
-            position_map
-                .point_for_position(text_bounds, position)
-                .as_valid()
-        } else {
-            None
-        };
-
-        update_go_to_definition_link(
-            editor,
-            point.map(GoToDefinitionTrigger::Text),
-            cmd,
-            shift,
-            cx,
-        );
-
-        if editor.has_pending_selection() {
-            let mut scroll_delta = Vector2F::zero();
-
-            let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
-            let top = text_bounds.origin_y() + vertical_margin;
-            let bottom = text_bounds.lower_left().y() - vertical_margin;
-            if position.y() < top {
-                scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
-            }
-            if position.y() > bottom {
-                scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
-            }
-
-            let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
-            let left = text_bounds.origin_x() + horizontal_margin;
-            let right = text_bounds.upper_right().x() - horizontal_margin;
-            if position.x() < left {
-                scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
-                    left - position.x(),
-                ))
-            }
-            if position.x() > right {
-                scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
-                    position.x() - right,
-                ))
-            }
-
-            let point_for_position = position_map.point_for_position(text_bounds, position);
-
-            editor.select(
-                SelectPhase::Update {
-                    position: point_for_position.previous_valid,
-                    goal_column: point_for_position.exact_unclipped.column(),
-                    scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
-                        .clamp(Vector2F::zero(), position_map.scroll_max),
-                },
-                cx,
-            );
-            hover_at(editor, point, cx);
-            true
-        } else {
-            hover_at(editor, point, cx);
-            false
-        }
-    }
-
-    fn mouse_moved(
-        editor: &mut Editor,
-        MouseMovedEvent {
-            modifiers: Modifiers { shift, cmd, .. },
-            position,
-            ..
-        }: MouseMovedEvent,
-        position_map: &PositionMap,
-        text_bounds: RectF,
-        cx: &mut ViewContext<Editor>,
-    ) -> bool {
-        // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
-        // Don't trigger hover popover if mouse is hovering over context menu
-        if text_bounds.contains_point(position) {
-            let point_for_position = position_map.point_for_position(text_bounds, position);
-            match point_for_position.as_valid() {
-                Some(point) => {
-                    update_go_to_definition_link(
-                        editor,
-                        Some(GoToDefinitionTrigger::Text(point)),
-                        cmd,
-                        shift,
-                        cx,
-                    );
-                    hover_at(editor, Some(point), cx);
-                }
-                None => {
-                    update_inlay_link_and_hover_points(
-                        &position_map.snapshot,
-                        point_for_position,
-                        editor,
-                        cmd,
-                        shift,
-                        cx,
-                    );
-                }
-            }
-        } else {
-            update_go_to_definition_link(editor, None, cmd, shift, cx);
-            hover_at(editor, None, cx);
-        }
-
-        true
-    }
-
-    fn scroll(
-        editor: &mut Editor,
-        position: Vector2F,
-        mut delta: Vector2F,
-        precise: bool,
-        position_map: &PositionMap,
-        bounds: RectF,
-        cx: &mut ViewContext<Editor>,
-    ) -> bool {
-        if !bounds.contains_point(position) {
-            return false;
-        }
-
-        let line_height = position_map.line_height;
-        let max_glyph_width = position_map.em_width;
-
-        let axis = if precise {
-            //Trackpad
-            position_map.snapshot.ongoing_scroll.filter(&mut delta)
-        } else {
-            //Not trackpad
-            delta *= vec2f(max_glyph_width, line_height);
-            None //Resets ongoing scroll
-        };
-
-        let scroll_position = position_map.snapshot.scroll_position();
-        let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
-        let y = (scroll_position.y() * line_height - delta.y()) / line_height;
-        let scroll_position = vec2f(x, y).clamp(Vector2F::zero(), position_map.scroll_max);
-        editor.scroll(scroll_position, axis, cx);
-
-        true
-    }
-
-    fn paint_background(
-        &self,
-        gutter_bounds: RectF,
-        text_bounds: RectF,
-        layout: &LayoutState,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let bounds = gutter_bounds.union_rect(text_bounds);
-        let scroll_top =
-            layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height;
-        cx.scene().push_quad(Quad {
-            bounds: gutter_bounds,
-            background: Some(self.style.gutter_background),
-            border: Border::new(0., Color::transparent_black()).into(),
-            corner_radii: Default::default(),
-        });
-        cx.scene().push_quad(Quad {
-            bounds: text_bounds,
-            background: Some(self.style.background),
-            border: Border::new(0., Color::transparent_black()).into(),
-            corner_radii: Default::default(),
-        });
-
-        if let EditorMode::Full = layout.mode {
-            let mut active_rows = layout.active_rows.iter().peekable();
-            while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
-                let mut end_row = *start_row;
-                while active_rows.peek().map_or(false, |r| {
-                    *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
-                }) {
-                    active_rows.next().unwrap();
-                    end_row += 1;
-                }
-
-                if !contains_non_empty_selection {
-                    let origin = vec2f(
-                        bounds.origin_x(),
-                        bounds.origin_y() + (layout.position_map.line_height * *start_row as f32)
-                            - scroll_top,
-                    );
-                    let size = vec2f(
-                        bounds.width(),
-                        layout.position_map.line_height * (end_row - start_row + 1) as f32,
-                    );
-                    cx.scene().push_quad(Quad {
-                        bounds: RectF::new(origin, size),
-                        background: Some(self.style.active_line_background),
-                        border: Border::default().into(),
-                        corner_radii: Default::default(),
-                    });
-                }
-            }
-
-            if let Some(highlighted_rows) = &layout.highlighted_rows {
-                let origin = vec2f(
-                    bounds.origin_x(),
-                    bounds.origin_y()
-                        + (layout.position_map.line_height * highlighted_rows.start as f32)
-                        - scroll_top,
-                );
-                let size = vec2f(
-                    bounds.width(),
-                    layout.position_map.line_height * highlighted_rows.len() as f32,
-                );
-                cx.scene().push_quad(Quad {
-                    bounds: RectF::new(origin, size),
-                    background: Some(self.style.highlighted_line_background),
-                    border: Border::default().into(),
-                    corner_radii: Default::default(),
-                });
-            }
-
-            let scroll_left =
-                layout.position_map.snapshot.scroll_position().x() * layout.position_map.em_width;
-
-            for (wrap_position, active) in layout.wrap_guides.iter() {
-                let x =
-                    (text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.)
-                        - scroll_left;
-
-                if x < text_bounds.origin_x()
-                    || (layout.show_scrollbars && x > self.scrollbar_left(&bounds))
-                {
-                    continue;
-                }
-
-                let color = if *active {
-                    self.style.active_wrap_guide
-                } else {
-                    self.style.wrap_guide
-                };
-                cx.scene().push_quad(Quad {
-                    bounds: RectF::new(
-                        vec2f(x, text_bounds.origin_y()),
-                        vec2f(1., text_bounds.height()),
-                    ),
-                    background: Some(color),
-                    border: Border::new(0., Color::transparent_black()).into(),
-                    corner_radii: Default::default(),
-                });
-            }
-        }
-    }
-
-    fn paint_gutter(
-        &mut self,
-        bounds: RectF,
-        visible_bounds: RectF,
-        layout: &mut LayoutState,
-        editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let line_height = layout.position_map.line_height;
-
-        let scroll_position = layout.position_map.snapshot.scroll_position();
-        let scroll_top = scroll_position.y() * line_height;
-
-        let show_gutter = matches!(
-            settings::get::<ProjectSettings>(cx).git.git_gutter,
-            Some(GitGutterSetting::TrackedFiles)
-        );
-
-        if show_gutter {
-            Self::paint_diff_hunks(bounds, layout, cx);
-        }
-
-        for (ix, line) in layout.line_number_layouts.iter().enumerate() {
-            if let Some(line) = line {
-                let line_origin = bounds.origin()
-                    + vec2f(
-                        bounds.width() - line.width() - layout.gutter_padding,
-                        ix as f32 * line_height - (scroll_top % line_height),
-                    );
-
-                line.paint(line_origin, visible_bounds, line_height, cx);
-            }
-        }
-
-        for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
-            if let Some(indicator) = fold_indicator.as_mut() {
-                let position = vec2f(
-                    bounds.width() - layout.gutter_padding,
-                    ix as f32 * line_height - (scroll_top % line_height),
-                );
-                let centering_offset = vec2f(
-                    (layout.gutter_padding + layout.gutter_margin - indicator.size().x()) / 2.,
-                    (line_height - indicator.size().y()) / 2.,
-                );
-
-                let indicator_origin = bounds.origin() + position + centering_offset;
-
-                indicator.paint(indicator_origin, visible_bounds, editor, cx);
-            }
-        }
-
-        if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
-            let mut x = 0.;
-            let mut y = *row as f32 * line_height - scroll_top;
-            x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
-            y += (line_height - indicator.size().y()) / 2.;
-            indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, editor, cx);
-        }
-    }
-
-    fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut ViewContext<Editor>) {
-        let diff_style = &theme::current(cx).editor.diff.clone();
-        let line_height = layout.position_map.line_height;
-
-        let scroll_position = layout.position_map.snapshot.scroll_position();
-        let scroll_top = scroll_position.y() * line_height;
-
-        for hunk in &layout.display_hunks {
-            let (display_row_range, status) = match hunk {
-                //TODO: This rendering is entirely a horrible hack
-                &DisplayDiffHunk::Folded { display_row: row } => {
-                    let start_y = row as f32 * line_height - scroll_top;
-                    let end_y = start_y + line_height;
-
-                    let width = diff_style.removed_width_em * line_height;
-                    let highlight_origin = bounds.origin() + vec2f(-width, start_y);
-                    let highlight_size = vec2f(width * 2., end_y - start_y);
-                    let highlight_bounds = RectF::new(highlight_origin, highlight_size);
-
-                    cx.scene().push_quad(Quad {
-                        bounds: highlight_bounds,
-                        background: Some(diff_style.modified),
-                        border: Border::new(0., Color::transparent_black()).into(),
-                        corner_radii: (1. * line_height).into(),
-                    });
-
-                    continue;
-                }
-
-                DisplayDiffHunk::Unfolded {
-                    display_row_range,
-                    status,
-                } => (display_row_range, status),
-            };
-
-            let color = match status {
-                DiffHunkStatus::Added => diff_style.inserted,
-                DiffHunkStatus::Modified => diff_style.modified,
-
-                //TODO: This rendering is entirely a horrible hack
-                DiffHunkStatus::Removed => {
-                    let row = display_row_range.start;
-
-                    let offset = line_height / 2.;
-                    let start_y = row as f32 * line_height - offset - scroll_top;
-                    let end_y = start_y + line_height;
-
-                    let width = diff_style.removed_width_em * line_height;
-                    let highlight_origin = bounds.origin() + vec2f(-width, start_y);
-                    let highlight_size = vec2f(width * 2., end_y - start_y);
-                    let highlight_bounds = RectF::new(highlight_origin, highlight_size);
-
-                    cx.scene().push_quad(Quad {
-                        bounds: highlight_bounds,
-                        background: Some(diff_style.deleted),
-                        border: Border::new(0., Color::transparent_black()).into(),
-                        corner_radii: (1. * line_height).into(),
-                    });
-
-                    continue;
-                }
-            };
-
-            let start_row = display_row_range.start;
-            let end_row = display_row_range.end;
-
-            let start_y = start_row as f32 * line_height - scroll_top;
-            let end_y = end_row as f32 * line_height - scroll_top;
-
-            let width = diff_style.width_em * line_height;
-            let highlight_origin = bounds.origin() + vec2f(-width, start_y);
-            let highlight_size = vec2f(width * 2., end_y - start_y);
-            let highlight_bounds = RectF::new(highlight_origin, highlight_size);
-
-            cx.scene().push_quad(Quad {
-                bounds: highlight_bounds,
-                background: Some(color),
-                border: Border::new(0., Color::transparent_black()).into(),
-                corner_radii: (diff_style.corner_radius * line_height).into(),
-            });
-        }
-    }
-
-    fn paint_text(
-        &mut self,
-        bounds: RectF,
-        visible_bounds: RectF,
-        layout: &mut LayoutState,
-        editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let style = &self.style;
-        let scroll_position = layout.position_map.snapshot.scroll_position();
-        let start_row = layout.visible_display_row_range.start;
-        let scroll_top = scroll_position.y() * layout.position_map.line_height;
-        let max_glyph_width = layout.position_map.em_width;
-        let scroll_left = scroll_position.x() * max_glyph_width;
-        let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
-        let line_end_overshoot = 0.15 * layout.position_map.line_height;
-        let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
-
-        cx.scene().push_layer(Some(bounds));
-
-        cx.scene().push_cursor_region(CursorRegion {
-            bounds,
-            style: if !editor.link_go_to_definition_state.definitions.is_empty() {
-                CursorStyle::PointingHand
-            } else {
-                CursorStyle::IBeam
-            },
-        });
-
-        let fold_corner_radius =
-            self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
-        for (id, range, color) in layout.fold_ranges.iter() {
-            self.paint_highlighted_range(
-                range.clone(),
-                *color,
-                fold_corner_radius,
-                fold_corner_radius * 2.,
-                layout,
-                content_origin,
-                scroll_top,
-                scroll_left,
-                bounds,
-                cx,
-            );
-
-            for bound in range_to_bounds(
-                &range,
-                content_origin,
-                scroll_left,
-                scroll_top,
-                &layout.visible_display_row_range,
-                line_end_overshoot,
-                &layout.position_map,
-            ) {
-                cx.scene().push_cursor_region(CursorRegion {
-                    bounds: bound,
-                    style: CursorStyle::PointingHand,
-                });
-
-                let display_row = range.start.row();
-
-                let buffer_row = DisplayPoint::new(display_row, 0)
-                    .to_point(&layout.position_map.snapshot.display_snapshot)
-                    .row;
-
-                let view_id = cx.view_id();
-                cx.scene().push_mouse_region(
-                    MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
-                        .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
-                            editor.unfold_at(&UnfoldAt { buffer_row }, cx)
-                        })
-                        .with_notify_on_hover(true)
-                        .with_notify_on_click(true),
-                )
-            }
-        }
-
-        for (range, color) in &layout.highlighted_ranges {
-            self.paint_highlighted_range(
-                range.clone(),
-                *color,
-                0.,
-                line_end_overshoot,
-                layout,
-                content_origin,
-                scroll_top,
-                scroll_left,
-                bounds,
-                cx,
-            );
-        }
-
-        let mut cursors = SmallVec::<[Cursor; 32]>::new();
-        let corner_radius = 0.15 * layout.position_map.line_height;
-        let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
-
-        for (selection_style, selections) in &layout.selections {
-            for selection in selections {
-                self.paint_highlighted_range(
-                    selection.range.clone(),
-                    selection_style.selection,
-                    corner_radius,
-                    corner_radius * 2.,
-                    layout,
-                    content_origin,
-                    scroll_top,
-                    scroll_left,
-                    bounds,
-                    cx,
-                );
-
-                if selection.is_local && !selection.range.is_empty() {
-                    invisible_display_ranges.push(selection.range.clone());
-                }
-                if !selection.is_local || editor.show_local_cursors(cx) {
-                    let cursor_position = selection.head;
-                    if layout
-                        .visible_display_row_range
-                        .contains(&cursor_position.row())
-                    {
-                        let cursor_row_layout = &layout.position_map.line_layouts
-                            [(cursor_position.row() - start_row) as usize]
-                            .line;
-                        let cursor_column = cursor_position.column() as usize;
-
-                        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
-                        let mut block_width =
-                            cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
-                        if block_width == 0.0 {
-                            block_width = layout.position_map.em_width;
-                        }
-                        let block_text = if let CursorShape::Block = selection.cursor_shape {
-                            layout
-                                .position_map
-                                .snapshot
-                                .chars_at(cursor_position)
-                                .next()
-                                .and_then(|(character, _)| {
-                                    let font_id =
-                                        cursor_row_layout.font_for_index(cursor_column)?;
-                                    let text = character.to_string();
-
-                                    Some(cx.text_layout_cache().layout_str(
-                                        &text,
-                                        cursor_row_layout.font_size(),
-                                        &[(
-                                            text.chars().count(),
-                                            RunStyle {
-                                                font_id,
-                                                color: style.background,
-                                                underline: Default::default(),
-                                            },
-                                        )],
-                                    ))
-                                })
-                        } else {
-                            None
-                        };
-
-                        let x = cursor_character_x - scroll_left;
-                        let y = cursor_position.row() as f32 * layout.position_map.line_height
-                            - scroll_top;
-                        if selection.is_newest {
-                            editor.pixel_position_of_newest_cursor = Some(vec2f(
-                                bounds.origin_x() + x + block_width / 2.,
-                                bounds.origin_y() + y + layout.position_map.line_height / 2.,
-                            ));
-                        }
-                        cursors.push(Cursor {
-                            color: selection_style.cursor,
-                            block_width,
-                            origin: vec2f(x, y),
-                            line_height: layout.position_map.line_height,
-                            shape: selection.cursor_shape,
-                            block_text,
-                        });
-                    }
-                }
-            }
-        }
-
-        if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
-            for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
-                let row = start_row + ix as u32;
-                line_with_invisibles.draw(
-                    layout,
-                    row,
-                    scroll_top,
-                    content_origin,
-                    scroll_left,
-                    visible_text_bounds,
-                    whitespace_setting,
-                    &invisible_display_ranges,
-                    visible_bounds,
-                    cx,
-                )
-            }
-        }
-
-        cx.scene().push_layer(Some(bounds));
-        for cursor in cursors {
-            cursor.paint(content_origin, cx);
-        }
-        cx.scene().pop_layer();
-
-        if let Some((position, context_menu)) = layout.context_menu.as_mut() {
-            cx.scene().push_stacking_context(None, None);
-            let cursor_row_layout =
-                &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
-            let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
-            let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
-            let mut list_origin = content_origin + vec2f(x, y);
-            let list_width = context_menu.size().x();
-            let list_height = context_menu.size().y();
-
-            // Snap the right edge of the list to the right edge of the window if
-            // its horizontal bounds overflow.
-            if list_origin.x() + list_width > cx.window_size().x() {
-                list_origin.set_x((cx.window_size().x() - list_width).max(0.));
-            }
-
-            if list_origin.y() + list_height > bounds.max_y() {
-                list_origin.set_y(list_origin.y() - layout.position_map.line_height - list_height);
-            }
-
-            context_menu.paint(
-                list_origin,
-                RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
-                editor,
-                cx,
-            );
-
-            cx.scene().pop_stacking_context();
-        }
-
-        if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
-            cx.scene().push_stacking_context(None, None);
-
-            // This is safe because we check on layout whether the required row is available
-            let hovered_row_layout =
-                &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
-
-            // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
-            // height. This is the size we will use to decide whether to render popovers above or below
-            // the hovered line.
-            let first_size = hover_popovers[0].size();
-            let height_to_reserve = first_size.y()
-                + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
-
-            // Compute Hovered Point
-            let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
-            let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
-            let hovered_point = content_origin + vec2f(x, y);
-
-            if hovered_point.y() - height_to_reserve > 0.0 {
-                // There is enough space above. Render popovers above the hovered point
-                let mut current_y = hovered_point.y();
-                for hover_popover in hover_popovers {
-                    let size = hover_popover.size();
-                    let mut popover_origin = vec2f(hovered_point.x(), current_y - size.y());
-
-                    let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
-                    if x_out_of_bounds < 0.0 {
-                        popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
-                    }
-
-                    hover_popover.paint(
-                        popover_origin,
-                        RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
-                        editor,
-                        cx,
-                    );
-
-                    current_y = popover_origin.y() - HOVER_POPOVER_GAP;
-                }
-            } else {
-                // There is not enough space above. Render popovers below the hovered point
-                let mut current_y = hovered_point.y() + layout.position_map.line_height;
-                for hover_popover in hover_popovers {
-                    let size = hover_popover.size();
-                    let mut popover_origin = vec2f(hovered_point.x(), current_y);
-
-                    let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
-                    if x_out_of_bounds < 0.0 {
-                        popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
-                    }
-
-                    hover_popover.paint(
-                        popover_origin,
-                        RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
-                        editor,
-                        cx,
-                    );
-
-                    current_y = popover_origin.y() + size.y() + HOVER_POPOVER_GAP;
-                }
-            }
-
-            cx.scene().pop_stacking_context();
-        }
-
-        cx.scene().pop_layer();
-    }
-
-    fn scrollbar_left(&self, bounds: &RectF) -> f32 {
-        bounds.max_x() - self.style.theme.scrollbar.width
-    }
-
-    fn paint_scrollbar(
-        &mut self,
-        bounds: RectF,
-        layout: &mut LayoutState,
-        editor: &Editor,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        enum ScrollbarMouseHandlers {}
-        if layout.mode != EditorMode::Full {
-            return;
-        }
-
-        let style = &self.style.theme.scrollbar;
-
-        let top = bounds.min_y();
-        let bottom = bounds.max_y();
-        let right = bounds.max_x();
-        let left = self.scrollbar_left(&bounds);
-        let row_range = &layout.scrollbar_row_range;
-        let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
-
-        let mut height = bounds.height();
-        let mut first_row_y_offset = 0.0;
-
-        // Impose a minimum height on the scrollbar thumb
-        let row_height = height / max_row;
-        let min_thumb_height =
-            style.min_height_factor * cx.font_cache.line_height(self.style.text.font_size);
-        let thumb_height = (row_range.end - row_range.start) * row_height;
-        if thumb_height < min_thumb_height {
-            first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
-            height -= min_thumb_height - thumb_height;
-        }
-
-        let y_for_row = |row: f32| -> f32 { top + first_row_y_offset + row * row_height };
-
-        let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
-        let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
-        let track_bounds = RectF::from_points(vec2f(left, top), vec2f(right, bottom));
-        let thumb_bounds = RectF::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom));
-
-        if layout.show_scrollbars {
-            cx.scene().push_quad(Quad {
-                bounds: track_bounds,
-                border: style.track.border.into(),
-                background: style.track.background_color,
-                ..Default::default()
-            });
-            let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
-            let theme = theme::current(cx);
-            let scrollbar_theme = &theme.editor.scrollbar;
-            if layout.is_singleton && scrollbar_settings.selections {
-                let start_anchor = Anchor::min();
-                let end_anchor = Anchor::max();
-                let color = scrollbar_theme.selections;
-                let border = Border {
-                    width: 1.,
-                    color: style.thumb.border.color,
-                    overlay: false,
-                    top: false,
-                    right: true,
-                    bottom: false,
-                    left: true,
-                };
-                let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
-                    let start_y = y_for_row(start.row() as f32);
-                    let mut end_y = y_for_row(end.row() as f32);
-                    if end_y - start_y < 1. {
-                        end_y = start_y + 1.;
-                    }
-                    let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
-
-                    cx.scene().push_quad(Quad {
-                        bounds,
-                        background: Some(color),
-                        border: border.into(),
-                        corner_radii: style.thumb.corner_radii.into(),
-                    })
-                };
-                let background_ranges = editor
-                    .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
-                        start_anchor..end_anchor,
-                        &layout.position_map.snapshot,
-                        50000,
-                    );
-                for row in background_ranges {
-                    let start = row.start();
-                    let end = row.end();
-                    push_region(*start, *end);
-                }
-            }
-
-            if layout.is_singleton && scrollbar_settings.git_diff {
-                let diff_style = scrollbar_theme.git.clone();
-                for hunk in layout
-                    .position_map
-                    .snapshot
-                    .buffer_snapshot
-                    .git_diff_hunks_in_range(0..(max_row.floor() as u32))
-                {
-                    let start_display = Point::new(hunk.buffer_range.start, 0)
-                        .to_display_point(&layout.position_map.snapshot.display_snapshot);
-                    let end_display = Point::new(hunk.buffer_range.end, 0)
-                        .to_display_point(&layout.position_map.snapshot.display_snapshot);
-                    let start_y = y_for_row(start_display.row() as f32);
-                    let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
-                        y_for_row((end_display.row() + 1) as f32)
-                    } else {
-                        y_for_row((end_display.row()) as f32)
-                    };
-
-                    if end_y - start_y < 1. {
-                        end_y = start_y + 1.;
-                    }
-                    let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
-
-                    let color = match hunk.status() {
-                        DiffHunkStatus::Added => diff_style.inserted,
-                        DiffHunkStatus::Modified => diff_style.modified,
-                        DiffHunkStatus::Removed => diff_style.deleted,
-                    };
-
-                    let border = Border {
-                        width: 1.,
-                        color: style.thumb.border.color,
-                        overlay: false,
-                        top: false,
-                        right: true,
-                        bottom: false,
-                        left: true,
-                    };
-
-                    cx.scene().push_quad(Quad {
-                        bounds,
-                        background: Some(color),
-                        border: border.into(),
-                        corner_radii: style.thumb.corner_radii.into(),
-                    })
-                }
-            }
-
-            cx.scene().push_quad(Quad {
-                bounds: thumb_bounds,
-                border: style.thumb.border.into(),
-                background: style.thumb.background_color,
-                corner_radii: style.thumb.corner_radii.into(),
-            });
-        }
-
-        cx.scene().push_cursor_region(CursorRegion {
-            bounds: track_bounds,
-            style: CursorStyle::Arrow,
-        });
-        let region_id = cx.view_id();
-        cx.scene().push_mouse_region(
-            MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
-                .on_move(move |event, editor: &mut Editor, cx| {
-                    if event.pressed_button.is_none() {
-                        editor.scroll_manager.show_scrollbar(cx);
-                    }
-                })
-                .on_down(MouseButton::Left, {
-                    let row_range = row_range.clone();
-                    move |event, editor: &mut Editor, cx| {
-                        let y = event.position.y();
-                        if y < thumb_top || thumb_bottom < y {
-                            let center_row = ((y - top) * max_row as f32 / height).round() as u32;
-                            let top_row = center_row
-                                .saturating_sub((row_range.end - row_range.start) as u32 / 2);
-                            let mut position = editor.scroll_position(cx);
-                            position.set_y(top_row as f32);
-                            editor.set_scroll_position(position, cx);
-                        } else {
-                            editor.scroll_manager.show_scrollbar(cx);
-                        }
-                    }
-                })
-                .on_drag(MouseButton::Left, {
-                    move |event, editor: &mut Editor, cx| {
-                        if event.end {
-                            return;
-                        }
-
-                        let y = event.prev_mouse_position.y();
-                        let new_y = event.position.y();
-                        if thumb_top < y && y < thumb_bottom {
-                            let mut position = editor.scroll_position(cx);
-                            position.set_y(position.y() + (new_y - y) * (max_row as f32) / height);
-                            if position.y() < 0.0 {
-                                position.set_y(0.);
-                            }
-                            editor.set_scroll_position(position, cx);
-                        }
-                    }
-                }),
-        );
-    }
-
-    #[allow(clippy::too_many_arguments)]
-    fn paint_highlighted_range(
-        &self,
-        range: Range<DisplayPoint>,
-        color: Color,
-        corner_radius: f32,
-        line_end_overshoot: f32,
-        layout: &LayoutState,
-        content_origin: Vector2F,
-        scroll_top: f32,
-        scroll_left: f32,
-        bounds: RectF,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let start_row = layout.visible_display_row_range.start;
-        let end_row = layout.visible_display_row_range.end;
-        if range.start != range.end {
-            let row_range = if range.end.column() == 0 {
-                cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
-            } else {
-                cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
-            };
-
-            let highlighted_range = HighlightedRange {
-                color,
-                line_height: layout.position_map.line_height,
-                corner_radius,
-                start_y: content_origin.y()
-                    + row_range.start as f32 * layout.position_map.line_height
-                    - scroll_top,
-                lines: row_range
-                    .into_iter()
-                    .map(|row| {
-                        let line_layout =
-                            &layout.position_map.line_layouts[(row - start_row) as usize].line;
-                        HighlightedRangeLine {
-                            start_x: if row == range.start.row() {
-                                content_origin.x()
-                                    + line_layout.x_for_index(range.start.column() as usize)
-                                    - scroll_left
-                            } else {
-                                content_origin.x() - scroll_left
-                            },
-                            end_x: if row == range.end.row() {
-                                content_origin.x()
-                                    + line_layout.x_for_index(range.end.column() as usize)
-                                    - scroll_left
-                            } else {
-                                content_origin.x() + line_layout.width() + line_end_overshoot
-                                    - scroll_left
-                            },
-                        }
-                    })
-                    .collect(),
-            };
-
-            highlighted_range.paint(bounds, cx);
-        }
-    }
-
-    fn paint_blocks(
-        &mut self,
-        bounds: RectF,
-        visible_bounds: RectF,
-        layout: &mut LayoutState,
-        editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let scroll_position = layout.position_map.snapshot.scroll_position();
-        let scroll_left = scroll_position.x() * layout.position_map.em_width;
-        let scroll_top = scroll_position.y() * layout.position_map.line_height;
-
-        for block in &mut layout.blocks {
-            let mut origin = bounds.origin()
-                + vec2f(
-                    0.,
-                    block.row as f32 * layout.position_map.line_height - scroll_top,
-                );
-            if !matches!(block.style, BlockStyle::Sticky) {
-                origin += vec2f(-scroll_left, 0.);
-            }
-            block.element.paint(origin, visible_bounds, editor, cx);
-        }
-    }
-
-    fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> f32 {
-        let style = &self.style;
-
-        cx.text_layout_cache()
-            .layout_str(
-                " ".repeat(column).as_str(),
-                style.text.font_size,
-                &[(
-                    column,
-                    RunStyle {
-                        font_id: style.text.font_id,
-                        color: Color::black(),
-                        underline: Default::default(),
-                    },
-                )],
-            )
-            .width()
-    }
-
-    fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> f32 {
-        let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
-        self.column_pixels(digit_count, cx)
-    }
+    // fn attach_mouse_handlers(
+    //     position_map: &Arc<PositionMap>,
+    //     has_popovers: bool,
+    //     visible_bounds: Bounds<Pixels>,
+    //     text_bounds: Bounds<Pixels>,
+    //     gutter_bounds: Bounds<Pixels>,
+    //     bounds: Bounds<Pixels>,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     enum EditorElementMouseHandlers {}
+    //     let view_id = cx.view_id();
+    //     cx.scene().push_mouse_region(
+    //         MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
+    //             .on_down(MouseButton::Left, {
+    //                 let position_map = position_map.clone();
+    //                 move |event, editor, cx| {
+    //                     if !Self::mouse_down(
+    //                         editor,
+    //                         event.platform_event,
+    //                         position_map.as_ref(),
+    //                         text_bounds,
+    //                         gutter_bounds,
+    //                         cx,
+    //                     ) {
+    //                         cx.propagate_event();
+    //                     }
+    //                 }
+    //             })
+    //             .on_down(MouseButton::Right, {
+    //                 let position_map = position_map.clone();
+    //                 move |event, editor, cx| {
+    //                     if !Self::mouse_right_down(
+    //                         editor,
+    //                         event.position,
+    //                         position_map.as_ref(),
+    //                         text_bounds,
+    //                         cx,
+    //                     ) {
+    //                         cx.propagate_event();
+    //                     }
+    //                 }
+    //             })
+    //             .on_up(MouseButton::Left, {
+    //                 let position_map = position_map.clone();
+    //                 move |event, editor, cx| {
+    //                     if !Self::mouse_up(
+    //                         editor,
+    //                         event.position,
+    //                         event.cmd,
+    //                         event.shift,
+    //                         event.alt,
+    //                         position_map.as_ref(),
+    //                         text_bounds,
+    //                         cx,
+    //                     ) {
+    //                         cx.propagate_event()
+    //                     }
+    //                 }
+    //             })
+    //             .on_drag(MouseButton::Left, {
+    //                 let position_map = position_map.clone();
+    //                 move |event, editor, cx| {
+    //                     if event.end {
+    //                         return;
+    //                     }
+
+    //                     if !Self::mouse_dragged(
+    //                         editor,
+    //                         event.platform_event,
+    //                         position_map.as_ref(),
+    //                         text_bounds,
+    //                         cx,
+    //                     ) {
+    //                         cx.propagate_event()
+    //                     }
+    //                 }
+    //             })
+    //             .on_move({
+    //                 let position_map = position_map.clone();
+    //                 move |event, editor, cx| {
+    //                     if !Self::mouse_moved(
+    //                         editor,
+    //                         event.platform_event,
+    //                         &position_map,
+    //                         text_bounds,
+    //                         cx,
+    //                     ) {
+    //                         cx.propagate_event()
+    //                     }
+    //                 }
+    //             })
+    //             .on_move_out(move |_, editor: &mut Editor, cx| {
+    //                 if has_popovers {
+    //                     hide_hover(editor, cx);
+    //                 }
+    //             })
+    //             .on_scroll({
+    //                 let position_map = position_map.clone();
+    //                 move |event, editor, cx| {
+    //                     if !Self::scroll(
+    //                         editor,
+    //                         event.position,
+    //                         *event.delta.raw(),
+    //                         event.delta.precise(),
+    //                         &position_map,
+    //                         bounds,
+    //                         cx,
+    //                     ) {
+    //                         cx.propagate_event()
+    //                     }
+    //                 }
+    //             }),
+    //     );
+
+    //     enum GutterHandlers {}
+    //     let view_id = cx.view_id();
+    //     let region_id = cx.view_id() + 1;
+    //     cx.scene().push_mouse_region(
+    //         MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
+    //             |hover, editor: &mut Editor, cx| {
+    //                 editor.gutter_hover(
+    //                     &GutterHover {
+    //                         hovered: hover.started,
+    //                     },
+    //                     cx,
+    //                 );
+    //             },
+    //         ),
+    //     )
+    // }
+
+    // fn mouse_down(
+    //     editor: &mut Editor,
+    //     MouseButtonEvent {
+    //         position,
+    //         modifiers:
+    //             Modifiers {
+    //                 shift,
+    //                 ctrl,
+    //                 alt,
+    //                 cmd,
+    //                 ..
+    //             },
+    //         mut click_count,
+    //         ..
+    //     }: MouseButtonEvent,
+    //     position_map: &PositionMap,
+    //     text_bounds: Bounds<Pixels>,
+    //     gutter_bounds: Bounds<Pixels>,
+    //     cx: &mut EventContext<Editor>,
+    // ) -> bool {
+    //     if gutter_bounds.contains_point(position) {
+    //         click_count = 3; // Simulate triple-click when clicking the gutter to select lines
+    //     } else if !text_bounds.contains_point(position) {
+    //         return false;
+    //     }
+
+    //     let point_for_position = position_map.point_for_position(text_bounds, position);
+    //     let position = point_for_position.previous_valid;
+    //     if shift && alt {
+    //         editor.select(
+    //             SelectPhase::BeginColumnar {
+    //                 position,
+    //                 goal_column: point_for_position.exact_unclipped.column(),
+    //             },
+    //             cx,
+    //         );
+    //     } else if shift && !ctrl && !alt && !cmd {
+    //         editor.select(
+    //             SelectPhase::Extend {
+    //                 position,
+    //                 click_count,
+    //             },
+    //             cx,
+    //         );
+    //     } else {
+    //         editor.select(
+    //             SelectPhase::Begin {
+    //                 position,
+    //                 add: alt,
+    //                 click_count,
+    //             },
+    //             cx,
+    //         );
+    //     }
+
+    //     true
+    // }
+
+    // fn mouse_right_down(
+    //     editor: &mut Editor,
+    //     position: gpui::Point<Pixels>,
+    //     position_map: &PositionMap,
+    //     text_bounds: Bounds<Pixels>,
+    //     cx: &mut EventContext<Editor>,
+    // ) -> bool {
+    //     if !text_bounds.contains_point(position) {
+    //         return false;
+    //     }
+    //     let point_for_position = position_map.point_for_position(text_bounds, position);
+    //     mouse_context_menu::deploy_context_menu(
+    //         editor,
+    //         position,
+    //         point_for_position.previous_valid,
+    //         cx,
+    //     );
+    //     true
+    // }
+
+    // fn mouse_up(
+    //     editor: &mut Editor,
+    //     position: gpui::Point<Pixels>,
+    //     cmd: bool,
+    //     shift: bool,
+    //     alt: bool,
+    //     position_map: &PositionMap,
+    //     text_bounds: Bounds<Pixels>,
+    //     cx: &mut EventContext<Editor>,
+    // ) -> bool {
+    //     let end_selection = editor.has_pending_selection();
+    //     let pending_nonempty_selections = editor.has_pending_nonempty_selection();
+
+    //     if end_selection {
+    //         editor.select(SelectPhase::End, cx);
+    //     }
+
+    //     if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
+    //         let point = position_map.point_for_position(text_bounds, position);
+    //         let could_be_inlay = point.as_valid().is_none();
+    //         if shift || could_be_inlay {
+    //             go_to_fetched_type_definition(editor, point, alt, cx);
+    //         } else {
+    //             go_to_fetched_definition(editor, point, alt, cx);
+    //         }
+
+    //         return true;
+    //     }
+
+    //     end_selection
+    // }
+
+    // fn mouse_dragged(
+    //     editor: &mut Editor,
+    //     MouseMovedEvent {
+    //         modifiers: Modifiers { cmd, shift, .. },
+    //         position,
+    //         ..
+    //     }: MouseMovedEvent,
+    //     position_map: &PositionMap,
+    //     text_bounds: Bounds<Pixels>,
+    //     cx: &mut EventContext<Editor>,
+    // ) -> bool {
+    //     // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
+    //     // Don't trigger hover popover if mouse is hovering over context menu
+    //     let point = if text_bounds.contains_point(position) {
+    //         position_map
+    //             .point_for_position(text_bounds, position)
+    //             .as_valid()
+    //     } else {
+    //         None
+    //     };
+
+    //     update_go_to_definition_link(
+    //         editor,
+    //         point.map(GoToDefinitionTrigger::Text),
+    //         cmd,
+    //         shift,
+    //         cx,
+    //     );
+
+    //     if editor.has_pending_selection() {
+    //         let mut scroll_delta = gpui::Point<Pixels>::zero();
+
+    //         let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
+    //         let top = text_bounds.origin_y() + vertical_margin;
+    //         let bottom = text_bounds.lower_left().y() - vertical_margin;
+    //         if position.y() < top {
+    //             scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
+    //         }
+    //         if position.y() > bottom {
+    //             scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
+    //         }
+
+    //         let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
+    //         let left = text_bounds.origin_x() + horizontal_margin;
+    //         let right = text_bounds.upper_right().x() - horizontal_margin;
+    //         if position.x() < left {
+    //             scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
+    //                 left - position.x(),
+    //             ))
+    //         }
+    //         if position.x() > right {
+    //             scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
+    //                 position.x() - right,
+    //             ))
+    //         }
+
+    //         let point_for_position = position_map.point_for_position(text_bounds, position);
+
+    //         editor.select(
+    //             SelectPhase::Update {
+    //                 position: point_for_position.previous_valid,
+    //                 goal_column: point_for_position.exact_unclipped.column(),
+    //                 scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
+    //                     .clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max),
+    //             },
+    //             cx,
+    //         );
+    //         hover_at(editor, point, cx);
+    //         true
+    //     } else {
+    //         hover_at(editor, point, cx);
+    //         false
+    //     }
+    // }
+
+    // fn mouse_moved(
+    //     editor: &mut Editor,
+    //     MouseMovedEvent {
+    //         modifiers: Modifiers { shift, cmd, .. },
+    //         position,
+    //         ..
+    //     }: MouseMovedEvent,
+    //     position_map: &PositionMap,
+    //     text_bounds: Bounds<Pixels>,
+    //     cx: &mut ViewContext<Editor>,
+    // ) -> bool {
+    //     // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
+    //     // Don't trigger hover popover if mouse is hovering over context menu
+    //     if text_bounds.contains_point(position) {
+    //         let point_for_position = position_map.point_for_position(text_bounds, position);
+    //         match point_for_position.as_valid() {
+    //             Some(point) => {
+    //                 update_go_to_definition_link(
+    //                     editor,
+    //                     Some(GoToDefinitionTrigger::Text(point)),
+    //                     cmd,
+    //                     shift,
+    //                     cx,
+    //                 );
+    //                 hover_at(editor, Some(point), cx);
+    //             }
+    //             None => {
+    //                 update_inlay_link_and_hover_points(
+    //                     &position_map.snapshot,
+    //                     point_for_position,
+    //                     editor,
+    //                     cmd,
+    //                     shift,
+    //                     cx,
+    //                 );
+    //             }
+    //         }
+    //     } else {
+    //         update_go_to_definition_link(editor, None, cmd, shift, cx);
+    //         hover_at(editor, None, cx);
+    //     }
+
+    //     true
+    // }
+
+    // fn scroll(
+    //     editor: &mut Editor,
+    //     position: gpui::Point<Pixels>,
+    //     mut delta: gpui::Point<Pixels>,
+    //     precise: bool,
+    //     position_map: &PositionMap,
+    //     bounds: Bounds<Pixels>,
+    //     cx: &mut ViewContext<Editor>,
+    // ) -> bool {
+    //     if !bounds.contains_point(position) {
+    //         return false;
+    //     }
+
+    //     let line_height = position_map.line_height;
+    //     let max_glyph_width = position_map.em_width;
+
+    //     let axis = if precise {
+    //         //Trackpad
+    //         position_map.snapshot.ongoing_scroll.filter(&mut delta)
+    //     } else {
+    //         //Not trackpad
+    //         delta *= vec2f(max_glyph_width, line_height);
+    //         None //Resets ongoing scroll
+    //     };
+
+    //     let scroll_position = position_map.snapshot.scroll_position();
+    //     let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
+    //     let y = (scroll_position.y() * line_height - delta.y()) / line_height;
+    //     let scroll_position = vec2f(x, y).clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max);
+    //     editor.scroll(scroll_position, axis, cx);
+
+    //     true
+    // }
+
+    // fn paint_background(
+    //     &self,
+    //     gutter_bounds: Bounds<Pixels>,
+    //     text_bounds: Bounds<Pixels>,
+    //     layout: &LayoutState,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     let bounds = gutter_bounds.union_rect(text_bounds);
+    //     let scroll_top =
+    //         layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height;
+    //     cx.scene().push_quad(Quad {
+    //         bounds: gutter_bounds,
+    //         background: Some(self.style.gutter_background),
+    //         border: Border::new(0., Color::transparent_black()).into(),
+    //         corner_radii: Default::default(),
+    //     });
+    //     cx.scene().push_quad(Quad {
+    //         bounds: text_bounds,
+    //         background: Some(self.style.background),
+    //         border: Border::new(0., Color::transparent_black()).into(),
+    //         corner_radii: Default::default(),
+    //     });
+
+    //     if let EditorMode::Full = layout.mode {
+    //         let mut active_rows = layout.active_rows.iter().peekable();
+    //         while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
+    //             let mut end_row = *start_row;
+    //             while active_rows.peek().map_or(false, |r| {
+    //                 *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
+    //             }) {
+    //                 active_rows.next().unwrap();
+    //                 end_row += 1;
+    //             }
+
+    //             if !contains_non_empty_selection {
+    //                 let origin = vec2f(
+    //                     bounds.origin_x(),
+    //                     bounds.origin_y() + (layout.position_map.line_height * *start_row as f32)
+    //                         - scroll_top,
+    //                 );
+    //                 let size = vec2f(
+    //                     bounds.width(),
+    //                     layout.position_map.line_height * (end_row - start_row + 1) as f32,
+    //                 );
+    //                 cx.scene().push_quad(Quad {
+    //                     bounds: Bounds<Pixels>::new(origin, size),
+    //                     background: Some(self.style.active_line_background),
+    //                     border: Border::default().into(),
+    //                     corner_radii: Default::default(),
+    //                 });
+    //             }
+    //         }
+
+    //         if let Some(highlighted_rows) = &layout.highlighted_rows {
+    //             let origin = vec2f(
+    //                 bounds.origin_x(),
+    //                 bounds.origin_y()
+    //                     + (layout.position_map.line_height * highlighted_rows.start as f32)
+    //                     - scroll_top,
+    //             );
+    //             let size = vec2f(
+    //                 bounds.width(),
+    //                 layout.position_map.line_height * highlighted_rows.len() as f32,
+    //             );
+    //             cx.scene().push_quad(Quad {
+    //                 bounds: Bounds<Pixels>::new(origin, size),
+    //                 background: Some(self.style.highlighted_line_background),
+    //                 border: Border::default().into(),
+    //                 corner_radii: Default::default(),
+    //             });
+    //         }
+
+    //         let scroll_left =
+    //             layout.position_map.snapshot.scroll_position().x() * layout.position_map.em_width;
+
+    //         for (wrap_position, active) in layout.wrap_guides.iter() {
+    //             let x =
+    //                 (text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.)
+    //                     - scroll_left;
+
+    //             if x < text_bounds.origin_x()
+    //                 || (layout.show_scrollbars && x > self.scrollbar_left(&bounds))
+    //             {
+    //                 continue;
+    //             }
+
+    //             let color = if *active {
+    //                 self.style.active_wrap_guide
+    //             } else {
+    //                 self.style.wrap_guide
+    //             };
+    //             cx.scene().push_quad(Quad {
+    //                 bounds: Bounds<Pixels>::new(
+    //                     vec2f(x, text_bounds.origin_y()),
+    //                     vec2f(1., text_bounds.height()),
+    //                 ),
+    //                 background: Some(color),
+    //                 border: Border::new(0., Color::transparent_black()).into(),
+    //                 corner_radii: Default::default(),
+    //             });
+    //         }
+    //     }
+    // }
+
+    // fn paint_gutter(
+    //     &mut self,
+    //     bounds: Bounds<Pixels>,
+    //     visible_bounds: Bounds<Pixels>,
+    //     layout: &mut LayoutState,
+    //     editor: &mut Editor,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     let line_height = layout.position_map.line_height;
+
+    //     let scroll_position = layout.position_map.snapshot.scroll_position();
+    //     let scroll_top = scroll_position.y() * line_height;
+
+    //     let show_gutter = matches!(
+    //         settings::get::<ProjectSettings>(cx).git.git_gutter,
+    //         Some(GitGutterSetting::TrackedFiles)
+    //     );
+
+    //     if show_gutter {
+    //         Self::paint_diff_hunks(bounds, layout, cx);
+    //     }
+
+    //     for (ix, line) in layout.line_number_layouts.iter().enumerate() {
+    //         if let Some(line) = line {
+    //             let line_origin = bounds.origin()
+    //                 + vec2f(
+    //                     bounds.width() - line.width() - layout.gutter_padding,
+    //                     ix as f32 * line_height - (scroll_top % line_height),
+    //                 );
+
+    //             line.paint(line_origin, visible_bounds, line_height, cx);
+    //         }
+    //     }
+
+    //     for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
+    //         if let Some(indicator) = fold_indicator.as_mut() {
+    //             let position = vec2f(
+    //                 bounds.width() - layout.gutter_padding,
+    //                 ix as f32 * line_height - (scroll_top % line_height),
+    //             );
+    //             let centering_offset = vec2f(
+    //                 (layout.gutter_padding + layout.gutter_margin - indicator.size().x()) / 2.,
+    //                 (line_height - indicator.size().y()) / 2.,
+    //             );
+
+    //             let indicator_origin = bounds.origin() + position + centering_offset;
+
+    //             indicator.paint(indicator_origin, visible_bounds, editor, cx);
+    //         }
+    //     }
+
+    //     if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
+    //         let mut x = 0.;
+    //         let mut y = *row as f32 * line_height - scroll_top;
+    //         x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
+    //         y += (line_height - indicator.size().y()) / 2.;
+    //         indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, editor, cx);
+    //     }
+    // }
+
+    // fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &mut LayoutState, cx: &mut ViewContext<Editor>) {
+    //     let diff_style = &theme::current(cx).editor.diff.clone();
+    //     let line_height = layout.position_map.line_height;
+
+    //     let scroll_position = layout.position_map.snapshot.scroll_position();
+    //     let scroll_top = scroll_position.y() * line_height;
+
+    //     for hunk in &layout.display_hunks {
+    //         let (display_row_range, status) = match hunk {
+    //             //TODO: This rendering is entirely a horrible hack
+    //             &DisplayDiffHunk::Folded { display_row: row } => {
+    //                 let start_y = row as f32 * line_height - scroll_top;
+    //                 let end_y = start_y + line_height;
+
+    //                 let width = diff_style.removed_width_em * line_height;
+    //                 let highlight_origin = bounds.origin() + vec2f(-width, start_y);
+    //                 let highlight_size = vec2f(width * 2., end_y - start_y);
+    //                 let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
+
+    //                 cx.scene().push_quad(Quad {
+    //                     bounds: highlight_bounds,
+    //                     background: Some(diff_style.modified),
+    //                     border: Border::new(0., Color::transparent_black()).into(),
+    //                     corner_radii: (1. * line_height).into(),
+    //                 });
+
+    //                 continue;
+    //             }
+
+    //             DisplayDiffHunk::Unfolded {
+    //                 display_row_range,
+    //                 status,
+    //             } => (display_row_range, status),
+    //         };
+
+    //         let color = match status {
+    //             DiffHunkStatus::Added => diff_style.inserted,
+    //             DiffHunkStatus::Modified => diff_style.modified,
+
+    //             //TODO: This rendering is entirely a horrible hack
+    //             DiffHunkStatus::Removed => {
+    //                 let row = display_row_range.start;
+
+    //                 let offset = line_height / 2.;
+    //                 let start_y = row as f32 * line_height - offset - scroll_top;
+    //                 let end_y = start_y + line_height;
+
+    //                 let width = diff_style.removed_width_em * line_height;
+    //                 let highlight_origin = bounds.origin() + vec2f(-width, start_y);
+    //                 let highlight_size = vec2f(width * 2., end_y - start_y);
+    //                 let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
+
+    //                 cx.scene().push_quad(Quad {
+    //                     bounds: highlight_bounds,
+    //                     background: Some(diff_style.deleted),
+    //                     border: Border::new(0., Color::transparent_black()).into(),
+    //                     corner_radii: (1. * line_height).into(),
+    //                 });
+
+    //                 continue;
+    //             }
+    //         };
+
+    //         let start_row = display_row_range.start;
+    //         let end_row = display_row_range.end;
+
+    //         let start_y = start_row as f32 * line_height - scroll_top;
+    //         let end_y = end_row as f32 * line_height - scroll_top;
+
+    //         let width = diff_style.width_em * line_height;
+    //         let highlight_origin = bounds.origin() + vec2f(-width, start_y);
+    //         let highlight_size = vec2f(width * 2., end_y - start_y);
+    //         let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
+
+    //         cx.scene().push_quad(Quad {
+    //             bounds: highlight_bounds,
+    //             background: Some(color),
+    //             border: Border::new(0., Color::transparent_black()).into(),
+    //             corner_radii: (diff_style.corner_radius * line_height).into(),
+    //         });
+    //     }
+    // }
+
+    // fn paint_text(
+    //     &mut self,
+    //     bounds: Bounds<Pixels>,
+    //     visible_bounds: Bounds<Pixels>,
+    //     layout: &mut LayoutState,
+    //     editor: &mut Editor,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     let style = &self.style;
+    //     let scroll_position = layout.position_map.snapshot.scroll_position();
+    //     let start_row = layout.visible_display_row_range.start;
+    //     let scroll_top = scroll_position.y() * layout.position_map.line_height;
+    //     let max_glyph_width = layout.position_map.em_width;
+    //     let scroll_left = scroll_position.x() * max_glyph_width;
+    //     let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
+    //     let line_end_overshoot = 0.15 * layout.position_map.line_height;
+    //     let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
+
+    //     cx.scene().push_layer(Some(bounds));
+
+    //     cx.scene().push_cursor_region(CursorRegion {
+    //         bounds,
+    //         style: if !editor.link_go_to_definition_state.definitions.is_empty() {
+    //             CursorStyle::PointingHand
+    //         } else {
+    //             CursorStyle::IBeam
+    //         },
+    //     });
+
+    //     let fold_corner_radius =
+    //         self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
+    //     for (id, range, color) in layout.fold_ranges.iter() {
+    //         self.paint_highlighted_range(
+    //             range.clone(),
+    //             *color,
+    //             fold_corner_radius,
+    //             fold_corner_radius * 2.,
+    //             layout,
+    //             content_origin,
+    //             scroll_top,
+    //             scroll_left,
+    //             bounds,
+    //             cx,
+    //         );
+
+    //         for bound in range_to_bounds(
+    //             &range,
+    //             content_origin,
+    //             scroll_left,
+    //             scroll_top,
+    //             &layout.visible_display_row_range,
+    //             line_end_overshoot,
+    //             &layout.position_map,
+    //         ) {
+    //             cx.scene().push_cursor_region(CursorRegion {
+    //                 bounds: bound,
+    //                 style: CursorStyle::PointingHand,
+    //             });
+
+    //             let display_row = range.start.row();
+
+    //             let buffer_row = DisplayPoint::new(display_row, 0)
+    //                 .to_point(&layout.position_map.snapshot.display_snapshot)
+    //                 .row;
+
+    //             let view_id = cx.view_id();
+    //             cx.scene().push_mouse_region(
+    //                 MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
+    //                     .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
+    //                         editor.unfold_at(&UnfoldAt { buffer_row }, cx)
+    //                     })
+    //                     .with_notify_on_hover(true)
+    //                     .with_notify_on_click(true),
+    //             )
+    //         }
+    //     }
+
+    //     for (range, color) in &layout.highlighted_ranges {
+    //         self.paint_highlighted_range(
+    //             range.clone(),
+    //             *color,
+    //             0.,
+    //             line_end_overshoot,
+    //             layout,
+    //             content_origin,
+    //             scroll_top,
+    //             scroll_left,
+    //             bounds,
+    //             cx,
+    //         );
+    //     }
+
+    //     let mut cursors = SmallVec::<[Cursor; 32]>::new();
+    //     let corner_radius = 0.15 * layout.position_map.line_height;
+    //     let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
+
+    //     for (selection_style, selections) in &layout.selections {
+    //         for selection in selections {
+    //             self.paint_highlighted_range(
+    //                 selection.range.clone(),
+    //                 selection_style.selection,
+    //                 corner_radius,
+    //                 corner_radius * 2.,
+    //                 layout,
+    //                 content_origin,
+    //                 scroll_top,
+    //                 scroll_left,
+    //                 bounds,
+    //                 cx,
+    //             );
+
+    //             if selection.is_local && !selection.range.is_empty() {
+    //                 invisible_display_ranges.push(selection.range.clone());
+    //             }
+    //             if !selection.is_local || editor.show_local_cursors(cx) {
+    //                 let cursor_position = selection.head;
+    //                 if layout
+    //                     .visible_display_row_range
+    //                     .contains(&cursor_position.row())
+    //                 {
+    //                     let cursor_row_layout = &layout.position_map.line_layouts
+    //                         [(cursor_position.row() - start_row) as usize]
+    //                         .line;
+    //                     let cursor_column = cursor_position.column() as usize;
+
+    //                     let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
+    //                     let mut block_width =
+    //                         cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
+    //                     if block_width == 0.0 {
+    //                         block_width = layout.position_map.em_width;
+    //                     }
+    //                     let block_text = if let CursorShape::Block = selection.cursor_shape {
+    //                         layout
+    //                             .position_map
+    //                             .snapshot
+    //                             .chars_at(cursor_position)
+    //                             .next()
+    //                             .and_then(|(character, _)| {
+    //                                 let font_id =
+    //                                     cursor_row_layout.font_for_index(cursor_column)?;
+    //                                 let text = character.to_string();
+
+    //                                 Some(cx.text_layout_cache().layout_str(
+    //                                     &text,
+    //                                     cursor_row_layout.font_size(),
+    //                                     &[(
+    //                                         text.chars().count(),
+    //                                         RunStyle {
+    //                                             font_id,
+    //                                             color: style.background,
+    //                                             underline: Default::default(),
+    //                                         },
+    //                                     )],
+    //                                 ))
+    //                             })
+    //                     } else {
+    //                         None
+    //                     };
+
+    //                     let x = cursor_character_x - scroll_left;
+    //                     let y = cursor_position.row() as f32 * layout.position_map.line_height
+    //                         - scroll_top;
+    //                     if selection.is_newest {
+    //                         editor.pixel_position_of_newest_cursor = Some(vec2f(
+    //                             bounds.origin_x() + x + block_width / 2.,
+    //                             bounds.origin_y() + y + layout.position_map.line_height / 2.,
+    //                         ));
+    //                     }
+    //                     cursors.push(Cursor {
+    //                         color: selection_style.cursor,
+    //                         block_width,
+    //                         origin: vec2f(x, y),
+    //                         line_height: layout.position_map.line_height,
+    //                         shape: selection.cursor_shape,
+    //                         block_text,
+    //                     });
+    //                 }
+    //             }
+    //         }
+    //     }
+
+    //     if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
+    //         for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
+    //             let row = start_row + ix as u32;
+    //             line_with_invisibles.draw(
+    //                 layout,
+    //                 row,
+    //                 scroll_top,
+    //                 content_origin,
+    //                 scroll_left,
+    //                 visible_text_bounds,
+    //                 whitespace_setting,
+    //                 &invisible_display_ranges,
+    //                 visible_bounds,
+    //                 cx,
+    //             )
+    //         }
+    //     }
+
+    //     cx.scene().push_layer(Some(bounds));
+    //     for cursor in cursors {
+    //         cursor.paint(content_origin, cx);
+    //     }
+    //     cx.scene().pop_layer();
+
+    //     if let Some((position, context_menu)) = layout.context_menu.as_mut() {
+    //         cx.scene().push_stacking_context(None, None);
+    //         let cursor_row_layout =
+    //             &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
+    //         let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
+    //         let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
+    //         let mut list_origin = content_origin + vec2f(x, y);
+    //         let list_width = context_menu.size().x();
+    //         let list_height = context_menu.size().y();
+
+    //         // Snap the right edge of the list to the right edge of the window if
+    //         // its horizontal bounds overflow.
+    //         if list_origin.x() + list_width > cx.window_size().x() {
+    //             list_origin.set_x((cx.window_size().x() - list_width).max(0.));
+    //         }
+
+    //         if list_origin.y() + list_height > bounds.max_y() {
+    //             list_origin.set_y(list_origin.y() - layout.position_map.line_height - list_height);
+    //         }
+
+    //         context_menu.paint(
+    //             list_origin,
+    //             Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+    //             editor,
+    //             cx,
+    //         );
+
+    //         cx.scene().pop_stacking_context();
+    //     }
+
+    //     if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
+    //         cx.scene().push_stacking_context(None, None);
+
+    //         // This is safe because we check on layout whether the required row is available
+    //         let hovered_row_layout =
+    //             &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
+
+    //         // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
+    //         // height. This is the size we will use to decide whether to render popovers above or below
+    //         // the hovered line.
+    //         let first_size = hover_popovers[0].size();
+    //         let height_to_reserve = first_size.y()
+    //             + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
+
+    //         // Compute Hovered Point
+    //         let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
+    //         let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
+    //         let hovered_point = content_origin + vec2f(x, y);
+
+    //         if hovered_point.y() - height_to_reserve > 0.0 {
+    //             // There is enough space above. Render popovers above the hovered point
+    //             let mut current_y = hovered_point.y();
+    //             for hover_popover in hover_popovers {
+    //                 let size = hover_popover.size();
+    //                 let mut popover_origin = vec2f(hovered_point.x(), current_y - size.y());
+
+    //                 let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
+    //                 if x_out_of_bounds < 0.0 {
+    //                     popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
+    //                 }
+
+    //                 hover_popover.paint(
+    //                     popover_origin,
+    //                     Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+    //                     editor,
+    //                     cx,
+    //                 );
+
+    //                 current_y = popover_origin.y() - HOVER_POPOVER_GAP;
+    //             }
+    //         } else {
+    //             // There is not enough space above. Render popovers below the hovered point
+    //             let mut current_y = hovered_point.y() + layout.position_map.line_height;
+    //             for hover_popover in hover_popovers {
+    //                 let size = hover_popover.size();
+    //                 let mut popover_origin = vec2f(hovered_point.x(), current_y);
+
+    //                 let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
+    //                 if x_out_of_bounds < 0.0 {
+    //                     popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
+    //                 }
+
+    //                 hover_popover.paint(
+    //                     popover_origin,
+    //                     Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+    //                     editor,
+    //                     cx,
+    //                 );
+
+    //                 current_y = popover_origin.y() + size.y() + HOVER_POPOVER_GAP;
+    //             }
+    //         }
+
+    //         cx.scene().pop_stacking_context();
+    //     }
+
+    //     cx.scene().pop_layer();
+    // }
+
+    // fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> f32 {
+    //     bounds.max_x() - self.style.theme.scrollbar.width
+    // }
+
+    // fn paint_scrollbar(
+    //     &mut self,
+    //     bounds: Bounds<Pixels>,
+    //     layout: &mut LayoutState,
+    //     editor: &Editor,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     enum ScrollbarMouseHandlers {}
+    //     if layout.mode != EditorMode::Full {
+    //         return;
+    //     }
+
+    //     let style = &self.style.theme.scrollbar;
+
+    //     let top = bounds.min_y();
+    //     let bottom = bounds.max_y();
+    //     let right = bounds.max_x();
+    //     let left = self.scrollbar_left(&bounds);
+    //     let row_range = &layout.scrollbar_row_range;
+    //     let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
+
+    //     let mut height = bounds.height();
+    //     let mut first_row_y_offset = 0.0;
+
+    //     // Impose a minimum height on the scrollbar thumb
+    //     let row_height = height / max_row;
+    //     let min_thumb_height =
+    //         style.min_height_factor * cx.font_cache.line_height(self.style.text.font_size);
+    //     let thumb_height = (row_range.end - row_range.start) * row_height;
+    //     if thumb_height < min_thumb_height {
+    //         first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
+    //         height -= min_thumb_height - thumb_height;
+    //     }
+
+    //     let y_for_row = |row: f32| -> f32 { top + first_row_y_offset + row * row_height };
+
+    //     let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
+    //     let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
+    //     let track_bounds = Bounds<Pixels>::from_points(vec2f(left, top), vec2f(right, bottom));
+    //     let thumb_bounds = Bounds<Pixels>::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom));
+
+    //     if layout.show_scrollbars {
+    //         cx.scene().push_quad(Quad {
+    //             bounds: track_bounds,
+    //             border: style.track.border.into(),
+    //             background: style.track.background_color,
+    //             ..Default::default()
+    //         });
+    //         let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
+    //         let theme = theme::current(cx);
+    //         let scrollbar_theme = &theme.editor.scrollbar;
+    //         if layout.is_singleton && scrollbar_settings.selections {
+    //             let start_anchor = Anchor::min();
+    //             let end_anchor = Anchor::max();
+    //             let color = scrollbar_theme.selections;
+    //             let border = Border {
+    //                 width: 1.,
+    //                 color: style.thumb.border.color,
+    //                 overlay: false,
+    //                 top: false,
+    //                 right: true,
+    //                 bottom: false,
+    //                 left: true,
+    //             };
+    //             let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
+    //                 let start_y = y_for_row(start.row() as f32);
+    //                 let mut end_y = y_for_row(end.row() as f32);
+    //                 if end_y - start_y < 1. {
+    //                     end_y = start_y + 1.;
+    //                 }
+    //                 let bounds = Bounds<Pixels>::from_points(vec2f(left, start_y), vec2f(right, end_y));
+
+    //                 cx.scene().push_quad(Quad {
+    //                     bounds,
+    //                     background: Some(color),
+    //                     border: border.into(),
+    //                     corner_radii: style.thumb.corner_radii.into(),
+    //                 })
+    //             };
+    //             let background_ranges = editor
+    //                 .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
+    //                     start_anchor..end_anchor,
+    //                     &layout.position_map.snapshot,
+    //                     50000,
+    //                 );
+    //             for row in background_ranges {
+    //                 let start = row.start();
+    //                 let end = row.end();
+    //                 push_region(*start, *end);
+    //             }
+    //         }
+
+    //         if layout.is_singleton && scrollbar_settings.git_diff {
+    //             let diff_style = scrollbar_theme.git.clone();
+    //             for hunk in layout
+    //                 .position_map
+    //                 .snapshot
+    //                 .buffer_snapshot
+    //                 .git_diff_hunks_in_range(0..(max_row.floor() as u32))
+    //             {
+    //                 let start_display = Point::new(hunk.buffer_range.start, 0)
+    //                     .to_display_point(&layout.position_map.snapshot.display_snapshot);
+    //                 let end_display = Point::new(hunk.buffer_range.end, 0)
+    //                     .to_display_point(&layout.position_map.snapshot.display_snapshot);
+    //                 let start_y = y_for_row(start_display.row() as f32);
+    //                 let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
+    //                     y_for_row((end_display.row() + 1) as f32)
+    //                 } else {
+    //                     y_for_row((end_display.row()) as f32)
+    //                 };
+
+    //                 if end_y - start_y < 1. {
+    //                     end_y = start_y + 1.;
+    //                 }
+    //                 let bounds = Bounds<Pixels>::from_points(vec2f(left, start_y), vec2f(right, end_y));
+
+    //                 let color = match hunk.status() {
+    //                     DiffHunkStatus::Added => diff_style.inserted,
+    //                     DiffHunkStatus::Modified => diff_style.modified,
+    //                     DiffHunkStatus::Removed => diff_style.deleted,
+    //                 };
+
+    //                 let border = Border {
+    //                     width: 1.,
+    //                     color: style.thumb.border.color,
+    //                     overlay: false,
+    //                     top: false,
+    //                     right: true,
+    //                     bottom: false,
+    //                     left: true,
+    //                 };
+
+    //                 cx.scene().push_quad(Quad {
+    //                     bounds,
+    //                     background: Some(color),
+    //                     border: border.into(),
+    //                     corner_radii: style.thumb.corner_radii.into(),
+    //                 })
+    //             }
+    //         }
+
+    //         cx.scene().push_quad(Quad {
+    //             bounds: thumb_bounds,
+    //             border: style.thumb.border.into(),
+    //             background: style.thumb.background_color,
+    //             corner_radii: style.thumb.corner_radii.into(),
+    //         });
+    //     }
+
+    //     cx.scene().push_cursor_region(CursorRegion {
+    //         bounds: track_bounds,
+    //         style: CursorStyle::Arrow,
+    //     });
+    //     let region_id = cx.view_id();
+    //     cx.scene().push_mouse_region(
+    //         MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
+    //             .on_move(move |event, editor: &mut Editor, cx| {
+    //                 if event.pressed_button.is_none() {
+    //                     editor.scroll_manager.show_scrollbar(cx);
+    //                 }
+    //             })
+    //             .on_down(MouseButton::Left, {
+    //                 let row_range = row_range.clone();
+    //                 move |event, editor: &mut Editor, cx| {
+    //                     let y = event.position.y();
+    //                     if y < thumb_top || thumb_bottom < y {
+    //                         let center_row = ((y - top) * max_row as f32 / height).round() as u32;
+    //                         let top_row = center_row
+    //                             .saturating_sub((row_range.end - row_range.start) as u32 / 2);
+    //                         let mut position = editor.scroll_position(cx);
+    //                         position.set_y(top_row as f32);
+    //                         editor.set_scroll_position(position, cx);
+    //                     } else {
+    //                         editor.scroll_manager.show_scrollbar(cx);
+    //                     }
+    //                 }
+    //             })
+    //             .on_drag(MouseButton::Left, {
+    //                 move |event, editor: &mut Editor, cx| {
+    //                     if event.end {
+    //                         return;
+    //                     }
+
+    //                     let y = event.prev_mouse_position.y();
+    //                     let new_y = event.position.y();
+    //                     if thumb_top < y && y < thumb_bottom {
+    //                         let mut position = editor.scroll_position(cx);
+    //                         position.set_y(position.y() + (new_y - y) * (max_row as f32) / height);
+    //                         if position.y() < 0.0 {
+    //                             position.set_y(0.);
+    //                         }
+    //                         editor.set_scroll_position(position, cx);
+    //                     }
+    //                 }
+    //             }),
+    //     );
+    // }
+
+    // #[allow(clippy::too_many_arguments)]
+    // fn paint_highlighted_range(
+    //     &self,
+    //     range: Range<DisplayPoint>,
+    //     color: Color,
+    //     corner_radius: f32,
+    //     line_end_overshoot: f32,
+    //     layout: &LayoutState,
+    //     content_origin: gpui::Point<Pixels>,
+    //     scroll_top: f32,
+    //     scroll_left: f32,
+    //     bounds: Bounds<Pixels>,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     let start_row = layout.visible_display_row_range.start;
+    //     let end_row = layout.visible_display_row_range.end;
+    //     if range.start != range.end {
+    //         let row_range = if range.end.column() == 0 {
+    //             cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
+    //         } else {
+    //             cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
+    //         };
+
+    //         let highlighted_range = HighlightedRange {
+    //             color,
+    //             line_height: layout.position_map.line_height,
+    //             corner_radius,
+    //             start_y: content_origin.y()
+    //                 + row_range.start as f32 * layout.position_map.line_height
+    //                 - scroll_top,
+    //             lines: row_range
+    //                 .into_iter()
+    //                 .map(|row| {
+    //                     let line_layout =
+    //                         &layout.position_map.line_layouts[(row - start_row) as usize].line;
+    //                     HighlightedRangeLine {
+    //                         start_x: if row == range.start.row() {
+    //                             content_origin.x()
+    //                                 + line_layout.x_for_index(range.start.column() as usize)
+    //                                 - scroll_left
+    //                         } else {
+    //                             content_origin.x() - scroll_left
+    //                         },
+    //                         end_x: if row == range.end.row() {
+    //                             content_origin.x()
+    //                                 + line_layout.x_for_index(range.end.column() as usize)
+    //                                 - scroll_left
+    //                         } else {
+    //                             content_origin.x() + line_layout.width() + line_end_overshoot
+    //                                 - scroll_left
+    //                         },
+    //                     }
+    //                 })
+    //                 .collect(),
+    //         };
+
+    //         highlighted_range.paint(bounds, cx);
+    //     }
+    // }
+
+    // fn paint_blocks(
+    //     &mut self,
+    //     bounds: Bounds<Pixels>,
+    //     visible_bounds: Bounds<Pixels>,
+    //     layout: &mut LayoutState,
+    //     editor: &mut Editor,
+    //     cx: &mut ViewContext<Editor>,
+    // ) {
+    //     let scroll_position = layout.position_map.snapshot.scroll_position();
+    //     let scroll_left = scroll_position.x() * layout.position_map.em_width;
+    //     let scroll_top = scroll_position.y() * layout.position_map.line_height;
+
+    //     for block in &mut layout.blocks {
+    //         let mut origin = bounds.origin()
+    //             + vec2f(
+    //                 0.,
+    //                 block.row as f32 * layout.position_map.line_height - scroll_top,
+    //             );
+    //         if !matches!(block.style, BlockStyle::Sticky) {
+    //             origin += vec2f(-scroll_left, 0.);
+    //         }
+    //         block.element.paint(origin, visible_bounds, editor, cx);
+    //     }
+    // }
+
+    // fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> f32 {
+    //     let style = &self.style;
+
+    //     cx.text_layout_cache()
+    //         .layout_str(
+    //             " ".repeat(column).as_str(),
+    //             style.text.font_size,
+    //             &[(
+    //                 column,
+    //                 RunStyle {
+    //                     font_id: style.text.font_id,
+    //                     color: Color::black(),
+    //                     underline: Default::default(),
+    //                 },
+    //             )],
+    //         )
+    //         .width()
+    // }
+
+    // fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> f32 {
+    //     let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
+    //     self.column_pixels(digit_count, cx)
+    // }
 
     //Folds contained in a hunk are ignored apart from shrinking visual size
     //If a fold contains any hunks then that fold line is marked as modified
-    fn layout_git_gutters(
-        &self,
-        display_rows: Range<u32>,
-        snapshot: &EditorSnapshot,
-    ) -> Vec<DisplayDiffHunk> {
-        let buffer_snapshot = &snapshot.buffer_snapshot;
-
-        let buffer_start_row = DisplayPoint::new(display_rows.start, 0)
-            .to_point(snapshot)
-            .row;
-        let buffer_end_row = DisplayPoint::new(display_rows.end, 0)
-            .to_point(snapshot)
-            .row;
-
-        buffer_snapshot
-            .git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
-            .map(|hunk| diff_hunk_to_display(hunk, snapshot))
-            .dedup()
-            .collect()
-    }
-
-    fn calculate_relative_line_numbers(
-        &self,
-        snapshot: &EditorSnapshot,
-        rows: &Range<u32>,
-        relative_to: Option<u32>,
-    ) -> HashMap<u32, u32> {
-        let mut relative_rows: HashMap<u32, u32> = Default::default();
-        let Some(relative_to) = relative_to else {
-            return relative_rows;
-        };
-
-        let start = rows.start.min(relative_to);
-        let end = rows.end.max(relative_to);
-
-        let buffer_rows = snapshot
-            .buffer_rows(start)
-            .take(1 + (end - start) as usize)
-            .collect::<Vec<_>>();
-
-        let head_idx = relative_to - start;
-        let mut delta = 1;
-        let mut i = head_idx + 1;
-        while i < buffer_rows.len() as u32 {
-            if buffer_rows[i as usize].is_some() {
-                if rows.contains(&(i + start)) {
-                    relative_rows.insert(i + start, delta);
-                }
-                delta += 1;
-            }
-            i += 1;
-        }
-        delta = 1;
-        i = head_idx.min(buffer_rows.len() as u32 - 1);
-        while i > 0 && buffer_rows[i as usize].is_none() {
-            i -= 1;
-        }
-
-        while i > 0 {
-            i -= 1;
-            if buffer_rows[i as usize].is_some() {
-                if rows.contains(&(i + start)) {
-                    relative_rows.insert(i + start, delta);
-                }
-                delta += 1;
-            }
-        }
-
-        relative_rows
-    }
-
-    fn layout_line_numbers(
-        &self,
-        rows: Range<u32>,
-        active_rows: &BTreeMap<u32, bool>,
-        newest_selection_head: DisplayPoint,
-        is_singleton: bool,
-        snapshot: &EditorSnapshot,
-        cx: &ViewContext<Editor>,
-    ) -> (
-        Vec<Option<text_layout::Line>>,
-        Vec<Option<(FoldStatus, BufferRow, bool)>>,
-    ) {
-        let style = &self.style;
-        let include_line_numbers = snapshot.mode == EditorMode::Full;
-        let mut line_number_layouts = Vec::with_capacity(rows.len());
-        let mut fold_statuses = Vec::with_capacity(rows.len());
-        let mut line_number = String::new();
-        let is_relative = settings::get::<EditorSettings>(cx).relative_line_numbers;
-        let relative_to = if is_relative {
-            Some(newest_selection_head.row())
-        } else {
-            None
-        };
-
-        let relative_rows = self.calculate_relative_line_numbers(&snapshot, &rows, relative_to);
-
-        for (ix, row) in snapshot
-            .buffer_rows(rows.start)
-            .take((rows.end - rows.start) as usize)
-            .enumerate()
-        {
-            let display_row = rows.start + ix as u32;
-            let (active, color) = if active_rows.contains_key(&display_row) {
-                (true, style.line_number_active)
-            } else {
-                (false, style.line_number)
-            };
-            if let Some(buffer_row) = row {
-                if include_line_numbers {
-                    line_number.clear();
-                    let default_number = buffer_row + 1;
-                    let number = relative_rows
-                        .get(&(ix as u32 + rows.start))
-                        .unwrap_or(&default_number);
-                    write!(&mut line_number, "{}", number).unwrap();
-                    line_number_layouts.push(Some(cx.text_layout_cache().layout_str(
-                        &line_number,
-                        style.text.font_size,
-                        &[(
-                            line_number.len(),
-                            RunStyle {
-                                font_id: style.text.font_id,
-                                color,
-                                underline: Default::default(),
-                            },
-                        )],
-                    )));
-                    fold_statuses.push(
-                        is_singleton
-                            .then(|| {
-                                snapshot
-                                    .fold_for_line(buffer_row)
-                                    .map(|fold_status| (fold_status, buffer_row, active))
-                            })
-                            .flatten(),
-                    )
-                }
-            } else {
-                fold_statuses.push(None);
-                line_number_layouts.push(None);
-            }
-        }
-
-        (line_number_layouts, fold_statuses)
-    }
-
-    fn layout_lines(
-        &mut self,
-        rows: Range<u32>,
-        line_number_layouts: &[Option<Line>],
-        snapshot: &EditorSnapshot,
-        cx: &ViewContext<Editor>,
-    ) -> Vec<LineWithInvisibles> {
-        if rows.start >= rows.end {
-            return Vec::new();
-        }
-
-        // When the editor is empty and unfocused, then show the placeholder.
-        if snapshot.is_empty() {
-            let placeholder_style = self
-                .style
-                .placeholder_text
-                .as_ref()
-                .unwrap_or(&self.style.text);
-            let placeholder_text = snapshot.placeholder_text();
-            let placeholder_lines = placeholder_text
-                .as_ref()
-                .map_or("", AsRef::as_ref)
-                .split('\n')
-                .skip(rows.start as usize)
-                .chain(iter::repeat(""))
-                .take(rows.len());
-            placeholder_lines
-                .map(|line| {
-                    cx.text_layout_cache().layout_str(
-                        line,
-                        placeholder_style.font_size,
-                        &[(
-                            line.len(),
-                            RunStyle {
-                                font_id: placeholder_style.font_id,
-                                color: placeholder_style.color,
-                                underline: Default::default(),
-                            },
-                        )],
-                    )
-                })
-                .map(|line| LineWithInvisibles {
-                    line,
-                    invisibles: Vec::new(),
-                })
-                .collect()
-        } else {
-            let style = &self.style;
-            let chunks = snapshot.highlighted_chunks(rows.clone(), true, style);
-
-            LineWithInvisibles::from_chunks(
-                chunks,
-                &style.text,
-                cx.text_layout_cache(),
-                cx.font_cache(),
-                MAX_LINE_LEN,
-                rows.len() as usize,
-                line_number_layouts,
-                snapshot.mode,
-            )
-        }
-    }
-
-    #[allow(clippy::too_many_arguments)]
-    fn layout_blocks(
-        &mut self,
-        rows: Range<u32>,
-        snapshot: &EditorSnapshot,
-        editor_width: f32,
-        scroll_width: f32,
-        gutter_padding: f32,
-        gutter_width: f32,
-        em_width: f32,
-        text_x: f32,
-        line_height: f32,
-        style: &EditorStyle,
-        line_layouts: &[LineWithInvisibles],
-        editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
-    ) -> (f32, Vec<BlockLayout>) {
-        let mut block_id = 0;
-        let scroll_x = snapshot.scroll_anchor.offset.x();
-        let (fixed_blocks, non_fixed_blocks) = snapshot
-            .blocks_in_range(rows.clone())
-            .partition::<Vec<_>, _>(|(_, block)| match block {
-                TransformBlock::ExcerptHeader { .. } => false,
-                TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed,
-            });
-        let mut render_block = |block: &TransformBlock, width: f32, block_id: usize| {
-            let mut element = match block {
-                TransformBlock::Custom(block) => {
-                    let align_to = block
-                        .position()
-                        .to_point(&snapshot.buffer_snapshot)
-                        .to_display_point(snapshot);
-                    let anchor_x = text_x
-                        + if rows.contains(&align_to.row()) {
-                            line_layouts[(align_to.row() - rows.start) as usize]
-                                .line
-                                .x_for_index(align_to.column() as usize)
-                        } else {
-                            layout_line(align_to.row(), snapshot, style, cx.text_layout_cache())
-                                .x_for_index(align_to.column() as usize)
-                        };
-
-                    block.render(&mut BlockContext {
-                        view_context: cx,
-                        anchor_x,
-                        gutter_padding,
-                        line_height,
-                        scroll_x,
-                        gutter_width,
-                        em_width,
-                        block_id,
-                    })
-                }
-                TransformBlock::ExcerptHeader {
-                    id,
-                    buffer,
-                    range,
-                    starts_new_buffer,
-                    ..
-                } => {
-                    let tooltip_style = theme::current(cx).tooltip.clone();
-                    let include_root = editor
-                        .project
-                        .as_ref()
-                        .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
-                        .unwrap_or_default();
-                    let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
-                        let jump_path = ProjectPath {
-                            worktree_id: file.worktree_id(cx),
-                            path: file.path.clone(),
-                        };
-                        let jump_anchor = range
-                            .primary
-                            .as_ref()
-                            .map_or(range.context.start, |primary| primary.start);
-                        let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
-
-                        enum JumpIcon {}
-                        MouseEventHandler::new::<JumpIcon, _>((*id).into(), cx, |state, _| {
-                            let style = style.jump_icon.style_for(state);
-                            Svg::new("icons/arrow_up_right.svg")
-                                .with_color(style.color)
-                                .constrained()
-                                .with_width(style.icon_width)
-                                .aligned()
-                                .contained()
-                                .with_style(style.container)
-                                .constrained()
-                                .with_width(style.button_width)
-                                .with_height(style.button_width)
-                        })
-                        .with_cursor_style(CursorStyle::PointingHand)
-                        .on_click(MouseButton::Left, move |_, editor, cx| {
-                            if let Some(workspace) = editor
-                                .workspace
-                                .as_ref()
-                                .and_then(|(workspace, _)| workspace.upgrade(cx))
-                            {
-                                workspace.update(cx, |workspace, cx| {
-                                    Editor::jump(
-                                        workspace,
-                                        jump_path.clone(),
-                                        jump_position,
-                                        jump_anchor,
-                                        cx,
-                                    );
-                                });
-                            }
-                        })
-                        .with_tooltip::<JumpIcon>(
-                            (*id).into(),
-                            "Jump to Buffer".to_string(),
-                            Some(Box::new(crate::OpenExcerpts)),
-                            tooltip_style.clone(),
-                            cx,
-                        )
-                        .aligned()
-                        .flex_float()
-                    });
-
-                    if *starts_new_buffer {
-                        let editor_font_size = style.text.font_size;
-                        let style = &style.diagnostic_path_header;
-                        let font_size = (style.text_scale_factor * editor_font_size).round();
-
-                        let path = buffer.resolve_file_path(cx, include_root);
-                        let mut filename = None;
-                        let mut parent_path = None;
-                        // Can't use .and_then() because `.file_name()` and `.parent()` return references :(
-                        if let Some(path) = path {
-                            filename = path.file_name().map(|f| f.to_string_lossy().to_string());
-                            parent_path =
-                                path.parent().map(|p| p.to_string_lossy().to_string() + "/");
-                        }
-
-                        Flex::row()
-                            .with_child(
-                                Label::new(
-                                    filename.unwrap_or_else(|| "untitled".to_string()),
-                                    style.filename.text.clone().with_font_size(font_size),
-                                )
-                                .contained()
-                                .with_style(style.filename.container)
-                                .aligned(),
-                            )
-                            .with_children(parent_path.map(|path| {
-                                Label::new(path, style.path.text.clone().with_font_size(font_size))
-                                    .contained()
-                                    .with_style(style.path.container)
-                                    .aligned()
-                            }))
-                            .with_children(jump_icon)
-                            .contained()
-                            .with_style(style.container)
-                            .with_padding_left(gutter_padding)
-                            .with_padding_right(gutter_padding)
-                            .expanded()
-                            .into_any_named("path header block")
-                    } else {
-                        let text_style = style.text.clone();
-                        Flex::row()
-                            .with_child(Label::new("⋯", text_style))
-                            .with_children(jump_icon)
-                            .contained()
-                            .with_padding_left(gutter_padding)
-                            .with_padding_right(gutter_padding)
-                            .expanded()
-                            .into_any_named("collapsed context")
-                    }
-                }
-            };
-
-            element.layout(
-                SizeConstraint {
-                    min: Vector2F::zero(),
-                    max: vec2f(width, block.height() as f32 * line_height),
-                },
-                editor,
-                cx,
-            );
-            element
-        };
-
-        let mut fixed_block_max_width = 0f32;
-        let mut blocks = Vec::new();
-        for (row, block) in fixed_blocks {
-            let element = render_block(block, f32::INFINITY, block_id);
-            block_id += 1;
-            fixed_block_max_width = fixed_block_max_width.max(element.size().x() + em_width);
-            blocks.push(BlockLayout {
-                row,
-                element,
-                style: BlockStyle::Fixed,
-            });
-        }
-        for (row, block) in non_fixed_blocks {
-            let style = match block {
-                TransformBlock::Custom(block) => block.style(),
-                TransformBlock::ExcerptHeader { .. } => BlockStyle::Sticky,
-            };
-            let width = match style {
-                BlockStyle::Sticky => editor_width,
-                BlockStyle::Flex => editor_width
-                    .max(fixed_block_max_width)
-                    .max(gutter_width + scroll_width),
-                BlockStyle::Fixed => unreachable!(),
-            };
-            let element = render_block(block, width, block_id);
-            block_id += 1;
-            blocks.push(BlockLayout {
-                row,
-                element,
-                style,
-            });
-        }
-        (
-            scroll_width.max(fixed_block_max_width - gutter_width),
-            blocks,
-        )
-    }
+    // fn layout_git_gutters(
+    //     &self,
+    //     display_rows: Range<u32>,
+    //     snapshot: &EditorSnapshot,
+    // ) -> Vec<DisplayDiffHunk> {
+    //     let buffer_snapshot = &snapshot.buffer_snapshot;
+
+    //     let buffer_start_row = DisplayPoint::new(display_rows.start, 0)
+    //         .to_point(snapshot)
+    //         .row;
+    //     let buffer_end_row = DisplayPoint::new(display_rows.end, 0)
+    //         .to_point(snapshot)
+    //         .row;
+
+    //     buffer_snapshot
+    //         .git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
+    //         .map(|hunk| diff_hunk_to_display(hunk, snapshot))
+    //         .dedup()
+    //         .collect()
+    // }
+
+    // fn calculate_relative_line_numbers(
+    //     &self,
+    //     snapshot: &EditorSnapshot,
+    //     rows: &Range<u32>,
+    //     relative_to: Option<u32>,
+    // ) -> HashMap<u32, u32> {
+    //     let mut relative_rows: HashMap<u32, u32> = Default::default();
+    //     let Some(relative_to) = relative_to else {
+    //         return relative_rows;
+    //     };
+
+    //     let start = rows.start.min(relative_to);
+    //     let end = rows.end.max(relative_to);
+
+    //     let buffer_rows = snapshot
+    //         .buffer_rows(start)
+    //         .take(1 + (end - start) as usize)
+    //         .collect::<Vec<_>>();
+
+    //     let head_idx = relative_to - start;
+    //     let mut delta = 1;
+    //     let mut i = head_idx + 1;
+    //     while i < buffer_rows.len() as u32 {
+    //         if buffer_rows[i as usize].is_some() {
+    //             if rows.contains(&(i + start)) {
+    //                 relative_rows.insert(i + start, delta);
+    //             }
+    //             delta += 1;
+    //         }
+    //         i += 1;
+    //     }
+    //     delta = 1;
+    //     i = head_idx.min(buffer_rows.len() as u32 - 1);
+    //     while i > 0 && buffer_rows[i as usize].is_none() {
+    //         i -= 1;
+    //     }
+
+    //     while i > 0 {
+    //         i -= 1;
+    //         if buffer_rows[i as usize].is_some() {
+    //             if rows.contains(&(i + start)) {
+    //                 relative_rows.insert(i + start, delta);
+    //             }
+    //             delta += 1;
+    //         }
+    //     }
+
+    //     relative_rows
+    // }
+
+    // fn layout_line_numbers(
+    //     &self,
+    //     rows: Range<u32>,
+    //     active_rows: &BTreeMap<u32, bool>,
+    //     newest_selection_head: DisplayPoint,
+    //     is_singleton: bool,
+    //     snapshot: &EditorSnapshot,
+    //     cx: &ViewContext<Editor>,
+    // ) -> (
+    //     Vec<Option<text_layout::Line>>,
+    //     Vec<Option<(FoldStatus, BufferRow, bool)>>,
+    // ) {
+    //     let style = &self.style;
+    //     let include_line_numbers = snapshot.mode == EditorMode::Full;
+    //     let mut line_number_layouts = Vec::with_capacity(rows.len());
+    //     let mut fold_statuses = Vec::with_capacity(rows.len());
+    //     let mut line_number = String::new();
+    //     let is_relative = settings::get::<EditorSettings>(cx).relative_line_numbers;
+    //     let relative_to = if is_relative {
+    //         Some(newest_selection_head.row())
+    //     } else {
+    //         None
+    //     };
+
+    //     let relative_rows = self.calculate_relative_line_numbers(&snapshot, &rows, relative_to);
+
+    //     for (ix, row) in snapshot
+    //         .buffer_rows(rows.start)
+    //         .take((rows.end - rows.start) as usize)
+    //         .enumerate()
+    //     {
+    //         let display_row = rows.start + ix as u32;
+    //         let (active, color) = if active_rows.contains_key(&display_row) {
+    //             (true, style.line_number_active)
+    //         } else {
+    //             (false, style.line_number)
+    //         };
+    //         if let Some(buffer_row) = row {
+    //             if include_line_numbers {
+    //                 line_number.clear();
+    //                 let default_number = buffer_row + 1;
+    //                 let number = relative_rows
+    //                     .get(&(ix as u32 + rows.start))
+    //                     .unwrap_or(&default_number);
+    //                 write!(&mut line_number, "{}", number).unwrap();
+    //                 line_number_layouts.push(Some(cx.text_layout_cache().layout_str(
+    //                     &line_number,
+    //                     style.text.font_size,
+    //                     &[(
+    //                         line_number.len(),
+    //                         RunStyle {
+    //                             font_id: style.text.font_id,
+    //                             color,
+    //                             underline: Default::default(),
+    //                         },
+    //                     )],
+    //                 )));
+    //                 fold_statuses.push(
+    //                     is_singleton
+    //                         .then(|| {
+    //                             snapshot
+    //                                 .fold_for_line(buffer_row)
+    //                                 .map(|fold_status| (fold_status, buffer_row, active))
+    //                         })
+    //                         .flatten(),
+    //                 )
+    //             }
+    //         } else {
+    //             fold_statuses.push(None);
+    //             line_number_layouts.push(None);
+    //         }
+    //     }
+
+    //     (line_number_layouts, fold_statuses)
+    // }
+
+    // fn layout_lines(
+    //     &mut self,
+    //     rows: Range<u32>,
+    //     line_number_layouts: &[Option<Line>],
+    //     snapshot: &EditorSnapshot,
+    //     cx: &ViewContext<Editor>,
+    // ) -> Vec<LineWithInvisibles> {
+    //     if rows.start >= rows.end {
+    //         return Vec::new();
+    //     }
+
+    //     // When the editor is empty and unfocused, then show the placeholder.
+    //     if snapshot.is_empty() {
+    //         let placeholder_style = self
+    //             .style
+    //             .placeholder_text
+    //             .as_ref()
+    //             .unwrap_or(&self.style.text);
+    //         let placeholder_text = snapshot.placeholder_text();
+    //         let placeholder_lines = placeholder_text
+    //             .as_ref()
+    //             .map_or("", AsRef::as_ref)
+    //             .split('\n')
+    //             .skip(rows.start as usize)
+    //             .chain(iter::repeat(""))
+    //             .take(rows.len());
+    //         placeholder_lines
+    //             .map(|line| {
+    //                 cx.text_layout_cache().layout_str(
+    //                     line,
+    //                     placeholder_style.font_size,
+    //                     &[(
+    //                         line.len(),
+    //                         RunStyle {
+    //                             font_id: placeholder_style.font_id,
+    //                             color: placeholder_style.color,
+    //                             underline: Default::default(),
+    //                         },
+    //                     )],
+    //                 )
+    //             })
+    //             .map(|line| LineWithInvisibles {
+    //                 line,
+    //                 invisibles: Vec::new(),
+    //             })
+    //             .collect()
+    //     } else {
+    //         let style = &self.style;
+    //         let chunks = snapshot.highlighted_chunks(rows.clone(), true, style);
+
+    //         LineWithInvisibles::from_chunks(
+    //             chunks,
+    //             &style.text,
+    //             cx.text_layout_cache(),
+    //             cx.font_cache(),
+    //             MAX_LINE_LEN,
+    //             rows.len() as usize,
+    //             line_number_layouts,
+    //             snapshot.mode,
+    //         )
+    //     }
+    // }
+
+    // #[allow(clippy::too_many_arguments)]
+    // fn layout_blocks(
+    //     &mut self,
+    //     rows: Range<u32>,
+    //     snapshot: &EditorSnapshot,
+    //     editor_width: f32,
+    //     scroll_width: f32,
+    //     gutter_padding: f32,
+    //     gutter_width: f32,
+    //     em_width: f32,
+    //     text_x: f32,
+    //     line_height: f32,
+    //     style: &EditorStyle,
+    //     line_layouts: &[LineWithInvisibles],
+    //     editor: &mut Editor,
+    //     cx: &mut ViewContext<Editor>,
+    // ) -> (f32, Vec<BlockLayout>) {
+    //     let mut block_id = 0;
+    //     let scroll_x = snapshot.scroll_anchor.offset.x();
+    //     let (fixed_blocks, non_fixed_blocks) = snapshot
+    //         .blocks_in_range(rows.clone())
+    //         .partition::<Vec<_>, _>(|(_, block)| match block {
+    //             TransformBlock::ExcerptHeader { .. } => false,
+    //             TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed,
+    //         });
+    //     let mut render_block = |block: &TransformBlock, width: f32, block_id: usize| {
+    //         let mut element = match block {
+    //             TransformBlock::Custom(block) => {
+    //                 let align_to = block
+    //                     .position()
+    //                     .to_point(&snapshot.buffer_snapshot)
+    //                     .to_display_point(snapshot);
+    //                 let anchor_x = text_x
+    //                     + if rows.contains(&align_to.row()) {
+    //                         line_layouts[(align_to.row() - rows.start) as usize]
+    //                             .line
+    //                             .x_for_index(align_to.column() as usize)
+    //                     } else {
+    //                         layout_line(align_to.row(), snapshot, style, cx.text_layout_cache())
+    //                             .x_for_index(align_to.column() as usize)
+    //                     };
+
+    //                 block.render(&mut BlockContext {
+    //                     view_context: cx,
+    //                     anchor_x,
+    //                     gutter_padding,
+    //                     line_height,
+    //                     scroll_x,
+    //                     gutter_width,
+    //                     em_width,
+    //                     block_id,
+    //                 })
+    //             }
+    //             TransformBlock::ExcerptHeader {
+    //                 id,
+    //                 buffer,
+    //                 range,
+    //                 starts_new_buffer,
+    //                 ..
+    //             } => {
+    //                 let tooltip_style = theme::current(cx).tooltip.clone();
+    //                 let include_root = editor
+    //                     .project
+    //                     .as_ref()
+    //                     .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
+    //                     .unwrap_or_default();
+    //                 let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
+    //                     let jump_path = ProjectPath {
+    //                         worktree_id: file.worktree_id(cx),
+    //                         path: file.path.clone(),
+    //                     };
+    //                     let jump_anchor = range
+    //                         .primary
+    //                         .as_ref()
+    //                         .map_or(range.context.start, |primary| primary.start);
+    //                     let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
+
+    //                     enum JumpIcon {}
+    //                     MouseEventHandler::new::<JumpIcon, _>((*id).into(), cx, |state, _| {
+    //                         let style = style.jump_icon.style_for(state);
+    //                         Svg::new("icons/arrow_up_right.svg")
+    //                             .with_color(style.color)
+    //                             .constrained()
+    //                             .with_width(style.icon_width)
+    //                             .aligned()
+    //                             .contained()
+    //                             .with_style(style.container)
+    //                             .constrained()
+    //                             .with_width(style.button_width)
+    //                             .with_height(style.button_width)
+    //                     })
+    //                     .with_cursor_style(CursorStyle::PointingHand)
+    //                     .on_click(MouseButton::Left, move |_, editor, cx| {
+    //                         if let Some(workspace) = editor
+    //                             .workspace
+    //                             .as_ref()
+    //                             .and_then(|(workspace, _)| workspace.upgrade(cx))
+    //                         {
+    //                             workspace.update(cx, |workspace, cx| {
+    //                                 Editor::jump(
+    //                                     workspace,
+    //                                     jump_path.clone(),
+    //                                     jump_position,
+    //                                     jump_anchor,
+    //                                     cx,
+    //                                 );
+    //                             });
+    //                         }
+    //                     })
+    //                     .with_tooltip::<JumpIcon>(
+    //                         (*id).into(),
+    //                         "Jump to Buffer".to_string(),
+    //                         Some(Box::new(crate::OpenExcerpts)),
+    //                         tooltip_style.clone(),
+    //                         cx,
+    //                     )
+    //                     .aligned()
+    //                     .flex_float()
+    //                 });
+
+    //                 if *starts_new_buffer {
+    //                     let editor_font_size = style.text.font_size;
+    //                     let style = &style.diagnostic_path_header;
+    //                     let font_size = (style.text_scale_factor * editor_font_size).round();
+
+    //                     let path = buffer.resolve_file_path(cx, include_root);
+    //                     let mut filename = None;
+    //                     let mut parent_path = None;
+    //                     // Can't use .and_then() because `.file_name()` and `.parent()` return references :(
+    //                     if let Some(path) = path {
+    //                         filename = path.file_name().map(|f| f.to_string_lossy().to_string());
+    //                         parent_path =
+    //                             path.parent().map(|p| p.to_string_lossy().to_string() + "/");
+    //                     }
+
+    //                     Flex::row()
+    //                         .with_child(
+    //                             Label::new(
+    //                                 filename.unwrap_or_else(|| "untitled".to_string()),
+    //                                 style.filename.text.clone().with_font_size(font_size),
+    //                             )
+    //                             .contained()
+    //                             .with_style(style.filename.container)
+    //                             .aligned(),
+    //                         )
+    //                         .with_children(parent_path.map(|path| {
+    //                             Label::new(path, style.path.text.clone().with_font_size(font_size))
+    //                                 .contained()
+    //                                 .with_style(style.path.container)
+    //                                 .aligned()
+    //                         }))
+    //                         .with_children(jump_icon)
+    //                         .contained()
+    //                         .with_style(style.container)
+    //                         .with_padding_left(gutter_padding)
+    //                         .with_padding_right(gutter_padding)
+    //                         .expanded()
+    //                         .into_any_named("path header block")
+    //                 } else {
+    //                     let text_style = style.text.clone();
+    //                     Flex::row()
+    //                         .with_child(Label::new("⋯", text_style))
+    //                         .with_children(jump_icon)
+    //                         .contained()
+    //                         .with_padding_left(gutter_padding)
+    //                         .with_padding_right(gutter_padding)
+    //                         .expanded()
+    //                         .into_any_named("collapsed context")
+    //                 }
+    //             }
+    //         };
+
+    //         element.layout(
+    //             SizeConstraint {
+    //                 min: gpui::Point<Pixels>::zero(),
+    //                 max: vec2f(width, block.height() as f32 * line_height),
+    //             },
+    //             editor,
+    //             cx,
+    //         );
+    //         element
+    //     };
+
+    //     let mut fixed_block_max_width = 0f32;
+    //     let mut blocks = Vec::new();
+    //     for (row, block) in fixed_blocks {
+    //         let element = render_block(block, f32::INFINITY, block_id);
+    //         block_id += 1;
+    //         fixed_block_max_width = fixed_block_max_width.max(element.size().x() + em_width);
+    //         blocks.push(BlockLayout {
+    //             row,
+    //             element,
+    //             style: BlockStyle::Fixed,
+    //         });
+    //     }
+    //     for (row, block) in non_fixed_blocks {
+    //         let style = match block {
+    //             TransformBlock::Custom(block) => block.style(),
+    //             TransformBlock::ExcerptHeader { .. } => BlockStyle::Sticky,
+    //         };
+    //         let width = match style {
+    //             BlockStyle::Sticky => editor_width,
+    //             BlockStyle::Flex => editor_width
+    //                 .max(fixed_block_max_width)
+    //                 .max(gutter_width + scroll_width),
+    //             BlockStyle::Fixed => unreachable!(),
+    //         };
+    //         let element = render_block(block, width, block_id);
+    //         block_id += 1;
+    //         blocks.push(BlockLayout {
+    //             row,
+    //             element,
+    //             style,
+    //         });
+    //     }
+    //     (
+    //         scroll_width.max(fixed_block_max_width - gutter_width),
+    //         blocks,
+    //     )
+    // }
 }
 
 #[derive(Debug)]

crates/editor2/src/hover_popover.rs 🔗

@@ -9,7 +9,7 @@ use gpui::{
     actions,
     elements::{Flex, MouseEventHandler, Padding, ParentElement, Text},
     platform::{CursorStyle, MouseButton},
-    AnyElement, AppContext, Element, ModelHandle, Task, ViewContext, WeakViewHandle,
+    AnyElement, AppContext, Element, Model, Task, ViewContext, WeakViewHandle,
 };
 use language::{
     markdown, Bias, DiagnosticEntry, DiagnosticSeverity, Language, LanguageRegistry, ParsedMarkdown,

crates/editor2/src/inlay_hint_cache.rs 🔗

@@ -11,7 +11,7 @@ use crate::{
 use anyhow::Context;
 use clock::Global;
 use futures::future;
-use gpui::{ModelContext, ModelHandle, Task, ViewContext};
+use gpui::{Model, ModelContext, Task, ViewContext};
 use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot};
 use parking_lot::RwLock;
 use project::{InlayHint, ResolveState};
@@ -3244,7 +3244,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
 
         cx.update(|cx| {
             cx.set_global(SettingsStore::test(cx));
-            theme::init((), cx);
+            theme::init(cx);
             client::init_settings(cx);
             language::init(cx);
             Project::init_settings(cx);

crates/editor2/src/items.rs 🔗

@@ -7,10 +7,8 @@ use anyhow::{Context, Result};
 use collections::HashSet;
 use futures::future::try_join_all;
 use gpui::{
-    elements::*,
-    geometry::vector::{vec2f, Vector2F},
-    AppContext, AsyncAppContext, Entity, ModelHandle, Subscription, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    point, AnyElement, AppContext, AsyncAppContext, Entity, Model, Pixels, Subscription, Task,
+    View, ViewContext, WeakView,
 };
 use language::{
     proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
@@ -49,12 +47,12 @@ impl FollowableItem for Editor {
     }
 
     fn from_state_proto(
-        pane: ViewHandle<workspace::Pane>,
-        workspace: ViewHandle<Workspace>,
+        pane: View<workspace::Pane>,
+        workspace: View<Workspace>,
         remote_id: ViewId,
         state: &mut Option<proto::view::Variant>,
         cx: &mut AppContext,
-    ) -> Option<Task<Result<ViewHandle<Self>>>> {
+    ) -> Option<Task<Result<View<Self>>>> {
         let project = workspace.read(cx).project().to_owned();
         let Some(proto::view::Variant::Editor(_)) = state else {
             return None;
@@ -286,7 +284,7 @@ impl FollowableItem for Editor {
 
     fn apply_update_proto(
         &mut self,
-        project: &ModelHandle<Project>,
+        project: &Model<Project>,
         message: update_view::Variant,
         cx: &mut ViewContext<Self>,
     ) -> Task<Result<()>> {
@@ -312,8 +310,8 @@ impl FollowableItem for Editor {
 }
 
 async fn update_editor_from_message(
-    this: WeakViewHandle<Editor>,
-    project: ModelHandle<Project>,
+    this: WeakView<Editor>,
+    project: Model<Project>,
     message: proto::update_view::Editor,
     cx: &mut AsyncAppContext,
 ) -> Result<()> {
@@ -353,7 +351,7 @@ async fn update_editor_from_message(
                     continue;
                 };
                 let buffer_id = excerpt.buffer_id;
-                let Some(buffer) = project.read(cx).buffer_for_id(buffer_id, cx) else {
+                let Some(buffer) = project.read(cx).buffer_for_id(buffer_id) else {
                     continue;
                 };
 
@@ -430,7 +428,7 @@ async fn update_editor_from_message(
             editor.set_scroll_anchor_remote(
                 ScrollAnchor {
                     anchor: scroll_top_anchor,
-                    offset: vec2f(message.scroll_x, message.scroll_y),
+                    offset: point(message.scroll_x, message.scroll_y),
                 },
                 cx,
             );
@@ -573,29 +571,26 @@ impl Item for Editor {
         }
     }
 
-    fn tab_content<T: 'static>(
-        &self,
-        detail: Option<usize>,
-        style: &theme::Tab,
-        cx: &AppContext,
-    ) -> AnyElement<T> {
-        Flex::row()
-            .with_child(Label::new(self.title(cx).to_string(), style.label.clone()).into_any())
-            .with_children(detail.and_then(|detail| {
-                let path = path_for_buffer(&self.buffer, detail, false, cx)?;
-                let description = path.to_string_lossy();
-                Some(
-                    Label::new(
-                        util::truncate_and_trailoff(&description, MAX_TAB_TITLE_LEN),
-                        style.description.text.clone(),
-                    )
-                    .contained()
-                    .with_style(style.description.container)
-                    .aligned(),
-                )
-            }))
-            .align_children_center()
-            .into_any()
+    fn tab_content<T: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<T> {
+        todo!();
+
+        // Flex::row()
+        //     .with_child(Label::new(self.title(cx).to_string(), style.label.clone()).into_any())
+        //     .with_children(detail.and_then(|detail| {
+        //         let path = path_for_buffer(&self.buffer, detail, false, cx)?;
+        //         let description = path.to_string_lossy();
+        //         Some(
+        //             Label::new(
+        //                 util::truncate_and_trailoff(&description, MAX_TAB_TITLE_LEN),
+        //                 style.description.text.clone(),
+        //             )
+        //             .contained()
+        //             .with_style(style.description.container)
+        //             .aligned(),
+        //         )
+        //     }))
+        //     .align_children_center()
+        //     .into_any()
     }
 
     fn for_each_project_item(&self, cx: &AppContext, f: &mut dyn FnMut(usize, &dyn project::Item)) {
@@ -646,11 +641,7 @@ impl Item for Editor {
         }
     }
 
-    fn save(
-        &mut self,
-        project: ModelHandle<Project>,
-        cx: &mut ViewContext<Self>,
-    ) -> Task<Result<()>> {
+    fn save(&mut self, project: Model<Project>, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
         self.report_editor_event("save", None, cx);
         let format = self.perform_format(project.clone(), FormatTrigger::Save, cx);
         let buffers = self.buffer().clone().read(cx).all_buffers();
@@ -690,7 +681,7 @@ impl Item for Editor {
 
     fn save_as(
         &mut self,
-        project: ModelHandle<Project>,
+        project: Model<Project>,
         abs_path: PathBuf,
         cx: &mut ViewContext<Self>,
     ) -> Task<Result<()>> {
@@ -710,11 +701,7 @@ impl Item for Editor {
         })
     }
 
-    fn reload(
-        &mut self,
-        project: ModelHandle<Project>,
-        cx: &mut ViewContext<Self>,
-    ) -> Task<Result<()>> {
+    fn reload(&mut self, project: Model<Project>, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
         let buffer = self.buffer().clone();
         let buffers = self.buffer.read(cx).all_buffers();
         let reload_buffers =
@@ -761,11 +748,11 @@ impl Item for Editor {
         result
     }
 
-    fn as_searchable(&self, handle: &ViewHandle<Self>) -> Option<Box<dyn SearchableItemHandle>> {
+    fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
         Some(Box::new(handle.clone()))
     }
 
-    fn pixel_position_of_cursor(&self, _: &AppContext) -> Option<Vector2F> {
+    fn pixel_position_of_cursor(&self, _: &AppContext) -> Option<gpui::Point<Pixels>> {
         self.pixel_position_of_newest_cursor
     }
 
@@ -773,35 +760,36 @@ impl Item for Editor {
         ToolbarItemLocation::PrimaryLeft { flex: None }
     }
 
-    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
-        let cursor = self.selections.newest_anchor().head();
-        let multibuffer = &self.buffer().read(cx);
-        let (buffer_id, symbols) =
-            multibuffer.symbols_containing(cursor, Some(&theme.editor.syntax), cx)?;
-        let buffer = multibuffer.buffer(buffer_id)?;
-
-        let buffer = buffer.read(cx);
-        let filename = buffer
-            .snapshot()
-            .resolve_file_path(
-                cx,
-                self.project
-                    .as_ref()
-                    .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
-                    .unwrap_or_default(),
-            )
-            .map(|path| path.to_string_lossy().to_string())
-            .unwrap_or_else(|| "untitled".to_string());
-
-        let mut breadcrumbs = vec![BreadcrumbText {
-            text: filename,
-            highlights: None,
-        }];
-        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
-            text: symbol.text,
-            highlights: Some(symbol.highlight_ranges),
-        }));
-        Some(breadcrumbs)
+    fn breadcrumbs(&self, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
+        todo!();
+        // let cursor = self.selections.newest_anchor().head();
+        // let multibuffer = &self.buffer().read(cx);
+        // let (buffer_id, symbols) =
+        //     multibuffer.symbols_containing(cursor, Some(&theme.editor.syntax), cx)?;
+        // let buffer = multibuffer.buffer(buffer_id)?;
+
+        // let buffer = buffer.read(cx);
+        // let filename = buffer
+        //     .snapshot()
+        //     .resolve_file_path(
+        //         cx,
+        //         self.project
+        //             .as_ref()
+        //             .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
+        //             .unwrap_or_default(),
+        //     )
+        //     .map(|path| path.to_string_lossy().to_string())
+        //     .unwrap_or_else(|| "untitled".to_string());
+
+        // let mut breadcrumbs = vec![BreadcrumbText {
+        //     text: filename,
+        //     highlights: None,
+        // }];
+        // breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
+        //     text: symbol.text,
+        //     highlights: Some(symbol.highlight_ranges),
+        // }));
+        // Some(breadcrumbs)
     }
 
     fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
@@ -810,7 +798,7 @@ impl Item for Editor {
         self.workspace = Some((workspace.weak_handle(), workspace.database_id()));
 
         fn serialize(
-            buffer: ModelHandle<Buffer>,
+            buffer: Model<Buffer>,
             workspace_id: WorkspaceId,
             item_id: ItemId,
             cx: &mut AppContext,
@@ -847,12 +835,12 @@ impl Item for Editor {
     }
 
     fn deserialize(
-        project: ModelHandle<Project>,
-        _workspace: WeakViewHandle<Workspace>,
+        project: Model<Project>,
+        _workspace: WeakView<Workspace>,
         workspace_id: workspace::WorkspaceId,
         item_id: ItemId,
         cx: &mut ViewContext<Pane>,
-    ) -> Task<Result<ViewHandle<Self>>> {
+    ) -> Task<Result<View<Self>>> {
         let project_item: Result<_> = project.update(cx, |project, cx| {
             // Look up the path with this key associated, create a self with that path
             let path = DB
@@ -894,8 +882,8 @@ impl ProjectItem for Editor {
     type Item = Buffer;
 
     fn for_project_item(
-        project: ModelHandle<Project>,
-        buffer: ModelHandle<Buffer>,
+        project: Model<Project>,
+        buffer: Model<Buffer>,
         cx: &mut ViewContext<Self>,
     ) -> Self {
         Self::for_buffer(buffer, Some(project), cx)
@@ -1134,89 +1122,89 @@ pub struct CursorPosition {
     _observe_active_editor: Option<Subscription>,
 }
 
-impl Default for CursorPosition {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl CursorPosition {
-    pub fn new() -> Self {
-        Self {
-            position: None,
-            selected_count: 0,
-            _observe_active_editor: None,
-        }
-    }
-
-    fn update_position(&mut self, editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) {
-        let editor = editor.read(cx);
-        let buffer = editor.buffer().read(cx).snapshot(cx);
-
-        self.selected_count = 0;
-        let mut last_selection: Option<Selection<usize>> = None;
-        for selection in editor.selections.all::<usize>(cx) {
-            self.selected_count += selection.end - selection.start;
-            if last_selection
-                .as_ref()
-                .map_or(true, |last_selection| selection.id > last_selection.id)
-            {
-                last_selection = Some(selection);
-            }
-        }
-        self.position = last_selection.map(|s| s.head().to_point(&buffer));
-
-        cx.notify();
-    }
-}
-
-impl Entity for CursorPosition {
-    type Event = ();
-}
-
-impl View for CursorPosition {
-    fn ui_name() -> &'static str {
-        "CursorPosition"
-    }
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-        if let Some(position) = self.position {
-            let theme = &theme::current(cx).workspace.status_bar;
-            let mut text = format!(
-                "{}{FILE_ROW_COLUMN_DELIMITER}{}",
-                position.row + 1,
-                position.column + 1
-            );
-            if self.selected_count > 0 {
-                write!(text, " ({} selected)", self.selected_count).unwrap();
-            }
-            Label::new(text, theme.cursor_position.clone()).into_any()
-        } else {
-            Empty::new().into_any()
-        }
-    }
-}
-
-impl StatusItemView for CursorPosition {
-    fn set_active_pane_item(
-        &mut self,
-        active_pane_item: Option<&dyn ItemHandle>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
-            self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
-            self.update_position(editor, cx);
-        } else {
-            self.position = None;
-            self._observe_active_editor = None;
-        }
-
-        cx.notify();
-    }
-}
+// impl Default for CursorPosition {
+//     fn default() -> Self {
+//         Self::new()
+//     }
+// }
+
+// impl CursorPosition {
+//     pub fn new() -> Self {
+//         Self {
+//             position: None,
+//             selected_count: 0,
+//             _observe_active_editor: None,
+//         }
+//     }
+
+//     fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
+//         let editor = editor.read(cx);
+//         let buffer = editor.buffer().read(cx).snapshot(cx);
+
+//         self.selected_count = 0;
+//         let mut last_selection: Option<Selection<usize>> = None;
+//         for selection in editor.selections.all::<usize>(cx) {
+//             self.selected_count += selection.end - selection.start;
+//             if last_selection
+//                 .as_ref()
+//                 .map_or(true, |last_selection| selection.id > last_selection.id)
+//             {
+//                 last_selection = Some(selection);
+//             }
+//         }
+//         self.position = last_selection.map(|s| s.head().to_point(&buffer));
+
+//         cx.notify();
+//     }
+// }
+
+// impl Entity for CursorPosition {
+//     type Event = ();
+// }
+
+// impl View for CursorPosition {
+//     fn ui_name() -> &'static str {
+//         "CursorPosition"
+//     }
+
+//     fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
+//         if let Some(position) = self.position {
+//             let theme = &theme::current(cx).workspace.status_bar;
+//             let mut text = format!(
+//                 "{}{FILE_ROW_COLUMN_DELIMITER}{}",
+//                 position.row + 1,
+//                 position.column + 1
+//             );
+//             if self.selected_count > 0 {
+//                 write!(text, " ({} selected)", self.selected_count).unwrap();
+//             }
+//             Label::new(text, theme.cursor_position.clone()).into_any()
+//         } else {
+//             Empty::new().into_any()
+//         }
+//     }
+// }
+
+// impl StatusItemView for CursorPosition {
+//     fn set_active_pane_item(
+//         &mut self,
+//         active_pane_item: Option<&dyn ItemHandle>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
+//             self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
+//             self.update_position(editor, cx);
+//         } else {
+//             self.position = None;
+//             self._observe_active_editor = None;
+//         }
+
+//         cx.notify();
+//     }
+// }
 
 fn path_for_buffer<'a>(
-    buffer: &ModelHandle<MultiBuffer>,
+    buffer: &Model<MultiBuffer>,
     height: usize,
     include_filename: bool,
     cx: &'a AppContext,

crates/editor2/src/movement.rs 🔗

@@ -919,7 +919,7 @@ mod tests {
 
     fn init_test(cx: &mut gpui::AppContext) {
         cx.set_global(SettingsStore::test(cx));
-        theme::init((), cx);
+        theme::init(cx);
         language::init(cx);
         crate::init(cx);
         Project::init_settings(cx);

crates/editor2/src/scroll/actions.rs 🔗

@@ -1,152 +1,148 @@
-use gpui::{actions, geometry::vector::Vector2F, AppContext, Axis, ViewContext};
-use language::Bias;
-
-use crate::{Editor, EditorMode};
-
-use super::{autoscroll::Autoscroll, scroll_amount::ScrollAmount, ScrollAnchor};
-
-actions!(
-    editor,
-    [
-        LineDown,
-        LineUp,
-        HalfPageDown,
-        HalfPageUp,
-        PageDown,
-        PageUp,
-        NextScreen,
-        ScrollCursorTop,
-        ScrollCursorCenter,
-        ScrollCursorBottom,
-    ]
-);
+use gpui::AppContext;
+
+// actions!(
+//     editor,
+//     [
+//         LineDown,
+//         LineUp,
+//         HalfPageDown,
+//         HalfPageUp,
+//         PageDown,
+//         PageUp,
+//         NextScreen,
+//         ScrollCursorTop,
+//         ScrollCursorCenter,
+//         ScrollCursorBottom,
+//     ]
+// );
 
 pub fn init(cx: &mut AppContext) {
-    cx.add_action(Editor::next_screen);
-    cx.add_action(Editor::scroll_cursor_top);
-    cx.add_action(Editor::scroll_cursor_center);
-    cx.add_action(Editor::scroll_cursor_bottom);
-    cx.add_action(|this: &mut Editor, _: &LineDown, cx| {
-        this.scroll_screen(&ScrollAmount::Line(1.), cx)
-    });
-    cx.add_action(|this: &mut Editor, _: &LineUp, cx| {
-        this.scroll_screen(&ScrollAmount::Line(-1.), cx)
-    });
-    cx.add_action(|this: &mut Editor, _: &HalfPageDown, cx| {
-        this.scroll_screen(&ScrollAmount::Page(0.5), cx)
-    });
-    cx.add_action(|this: &mut Editor, _: &HalfPageUp, cx| {
-        this.scroll_screen(&ScrollAmount::Page(-0.5), cx)
-    });
-    cx.add_action(|this: &mut Editor, _: &PageDown, cx| {
-        this.scroll_screen(&ScrollAmount::Page(1.), cx)
-    });
-    cx.add_action(|this: &mut Editor, _: &PageUp, cx| {
-        this.scroll_screen(&ScrollAmount::Page(-1.), cx)
-    });
+    /// todo!()
+    // cx.add_action(Editor::next_screen);
+    // cx.add_action(Editor::scroll_cursor_top);
+    // cx.add_action(Editor::scroll_cursor_center);
+    // cx.add_action(Editor::scroll_cursor_bottom);
+    // cx.add_action(|this: &mut Editor, _: &LineDown, cx| {
+    //     this.scroll_screen(&ScrollAmount::Line(1.), cx)
+    // });
+    // cx.add_action(|this: &mut Editor, _: &LineUp, cx| {
+    //     this.scroll_screen(&ScrollAmount::Line(-1.), cx)
+    // });
+    // cx.add_action(|this: &mut Editor, _: &HalfPageDown, cx| {
+    //     this.scroll_screen(&ScrollAmount::Page(0.5), cx)
+    // });
+    // cx.add_action(|this: &mut Editor, _: &HalfPageUp, cx| {
+    //     this.scroll_screen(&ScrollAmount::Page(-0.5), cx)
+    // });
+    // cx.add_action(|this: &mut Editor, _: &PageDown, cx| {
+    //     this.scroll_screen(&ScrollAmount::Page(1.), cx)
+    // });
+    // cx.add_action(|this: &mut Editor, _: &PageUp, cx| {
+    //     this.scroll_screen(&ScrollAmount::Page(-1.), cx)
+    // });
 }
 
-impl Editor {
-    pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) -> Option<()> {
-        if self.take_rename(true, cx).is_some() {
-            return None;
-        }
-
-        if self.mouse_context_menu.read(cx).visible() {
-            return None;
-        }
-
-        if matches!(self.mode, EditorMode::SingleLine) {
-            cx.propagate_action();
-            return None;
-        }
-        self.request_autoscroll(Autoscroll::Next, cx);
-        Some(())
-    }
-
-    pub fn scroll(
-        &mut self,
-        scroll_position: Vector2F,
-        axis: Option<Axis>,
-        cx: &mut ViewContext<Self>,
-    ) {
-        self.scroll_manager.update_ongoing_scroll(axis);
-        self.set_scroll_position(scroll_position, cx);
-    }
-
-    fn scroll_cursor_top(editor: &mut Editor, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
-        let snapshot = editor.snapshot(cx).display_snapshot;
-        let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
-
-        let mut new_screen_top = editor.selections.newest_display(cx).head();
-        *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
-        *new_screen_top.column_mut() = 0;
-        let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
-        let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
-
-        editor.set_scroll_anchor(
-            ScrollAnchor {
-                anchor: new_anchor,
-                offset: Default::default(),
-            },
-            cx,
-        )
-    }
-
-    fn scroll_cursor_center(
-        editor: &mut Editor,
-        _: &ScrollCursorCenter,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let snapshot = editor.snapshot(cx).display_snapshot;
-        let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
-            visible_rows as u32
-        } else {
-            return;
-        };
-
-        let mut new_screen_top = editor.selections.newest_display(cx).head();
-        *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
-        *new_screen_top.column_mut() = 0;
-        let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
-        let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
-
-        editor.set_scroll_anchor(
-            ScrollAnchor {
-                anchor: new_anchor,
-                offset: Default::default(),
-            },
-            cx,
-        )
-    }
-
-    fn scroll_cursor_bottom(
-        editor: &mut Editor,
-        _: &ScrollCursorBottom,
-        cx: &mut ViewContext<Editor>,
-    ) {
-        let snapshot = editor.snapshot(cx).display_snapshot;
-        let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
-        let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
-            visible_rows as u32
-        } else {
-            return;
-        };
-
-        let mut new_screen_top = editor.selections.newest_display(cx).head();
-        *new_screen_top.row_mut() = new_screen_top
-            .row()
-            .saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
-        *new_screen_top.column_mut() = 0;
-        let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
-        let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
-
-        editor.set_scroll_anchor(
-            ScrollAnchor {
-                anchor: new_anchor,
-                offset: Default::default(),
-            },
-            cx,
-        )
-    }
-}
+// impl Editor {
+//     pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) -> Option<()> {
+//         if self.take_rename(true, cx).is_some() {
+//             return None;
+//         }
+
+//         if self.mouse_context_menu.read(cx).visible() {
+//             return None;
+//         }
+
+//         if matches!(self.mode, EditorMode::SingleLine) {
+//             cx.propagate_action();
+//             return None;
+//         }
+//         self.request_autoscroll(Autoscroll::Next, cx);
+//         Some(())
+//     }
+
+//     pub fn scroll(
+//         &mut self,
+//         scroll_position: Vector2F,
+//         axis: Option<Axis>,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         self.scroll_manager.update_ongoing_scroll(axis);
+//         self.set_scroll_position(scroll_position, cx);
+//     }
+
+//     fn scroll_cursor_top(editor: &mut Editor, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
+//         let snapshot = editor.snapshot(cx).display_snapshot;
+//         let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
+
+//         let mut new_screen_top = editor.selections.newest_display(cx).head();
+//         *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
+//         *new_screen_top.column_mut() = 0;
+//         let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
+//         let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
+
+//         editor.set_scroll_anchor(
+//             ScrollAnchor {
+//                 anchor: new_anchor,
+//                 offset: Default::default(),
+//             },
+//             cx,
+//         )
+//     }
+
+//     fn scroll_cursor_center(
+//         editor: &mut Editor,
+//         _: &ScrollCursorCenter,
+//         cx: &mut ViewContext<Editor>,
+//     ) {
+//         let snapshot = editor.snapshot(cx).display_snapshot;
+//         let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
+//             visible_rows as u32
+//         } else {
+//             return;
+//         };
+
+//         let mut new_screen_top = editor.selections.newest_display(cx).head();
+//         *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
+//         *new_screen_top.column_mut() = 0;
+//         let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
+//         let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
+
+//         editor.set_scroll_anchor(
+//             ScrollAnchor {
+//                 anchor: new_anchor,
+//                 offset: Default::default(),
+//             },
+//             cx,
+//         )
+//     }
+
+//     fn scroll_cursor_bottom(
+//         editor: &mut Editor,
+//         _: &ScrollCursorBottom,
+//         cx: &mut ViewContext<Editor>,
+//     ) {
+//         let snapshot = editor.snapshot(cx).display_snapshot;
+//         let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
+//         let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
+//             visible_rows as u32
+//         } else {
+//             return;
+//         };
+
+//         let mut new_screen_top = editor.selections.newest_display(cx).head();
+//         *new_screen_top.row_mut() = new_screen_top
+//             .row()
+//             .saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
+//         *new_screen_top.column_mut() = 0;
+//         let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
+//         let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
+
+//         editor.set_scroll_anchor(
+//             ScrollAnchor {
+//                 anchor: new_anchor,
+//                 offset: Default::default(),
+//             },
+//             cx,
+//         )
+//     }
+// }

crates/editor2/src/selections_collection.rs 🔗

@@ -6,7 +6,7 @@ use std::{
 };
 
 use collections::HashMap;
-use gpui::{AppContext, ModelHandle};
+use gpui::{AppContext, Model};
 use itertools::Itertools;
 use language::{Bias, Point, Selection, SelectionGoal, TextDimension, ToPoint};
 use util::post_inc;

crates/editor2/src/test.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
     DisplayPoint, Editor, EditorMode, MultiBuffer,
 };
 
-use gpui::{ModelHandle, ViewContext};
+use gpui::{Model, ViewContext};
 
 use project::Project;
 use util::test::{marked_text_offsets, marked_text_ranges};

crates/language2/src/buffer.rs 🔗

@@ -1,6 +1,7 @@
 pub use crate::{
     diagnostic_set::DiagnosticSet,
     highlight_map::{HighlightId, HighlightMap},
+    markdown::ParsedMarkdown,
     proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT,
 };
 use crate::{

crates/workspace2/src/workspace2.rs 🔗

@@ -13,9 +13,12 @@ mod status_bar;
 mod toolbar;
 mod workspace_settings;
 
-use crate::persistence::model::{
-    DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup,
-    SerializedWorkspace,
+pub use crate::persistence::{
+    model::{
+        DockData, DockStructure, ItemId, SerializedItem, SerializedPane, SerializedPaneGroup,
+        SerializedWorkspace,
+    },
+    WorkspaceDb,
 };
 use anyhow::{anyhow, Context as _, Result};
 use call2::ActiveCall;
@@ -44,15 +47,13 @@ use node_runtime::NodeRuntime;
 use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
 pub use pane::*;
 pub use pane_group::*;
-use persistence::{
-    model::{ItemId, WorkspaceLocation},
-    DB,
-};
+use persistence::{model::WorkspaceLocation, DB};
 use postage::stream::Stream;
 use project2::{Project, ProjectEntryId, ProjectPath, Worktree};
 use serde::Deserialize;
 use settings2::Settings;
 use status_bar::StatusBar;
+pub use status_bar::StatusItemView;
 use std::{
     any::TypeId,
     borrow::Cow,

crates/zed2/Cargo.toml 🔗

@@ -34,7 +34,7 @@ copilot = { package = "copilot2", path = "../copilot2" }
 # copilot_button = { path = "../copilot_button" }
 # diagnostics = { path = "../diagnostics" }
 db = { package = "db2", path = "../db2" }
-# editor = { path = "../editor" }
+editor = { package="editor2", path = "../editor2" }
 # feedback = { path = "../feedback" }
 # file_finder = { path = "../file_finder" }
 # search = { path = "../search" }