WIP

Nathan Sobo created

Change summary

gpui/src/app.rs                            |   8 
zed/src/editor.rs                          | 449 +++++++++++------------
zed/src/editor/display_map.rs              |  65 +-
zed/src/editor/display_map/line_wrapper.rs |   2 
zed/src/editor/display_map/wrap_map.rs     |  16 
zed/src/editor/element.rs                  | 139 ++++---
zed/src/file_finder.rs                     |   4 
zed/src/workspace.rs                       |   2 
8 files changed, 354 insertions(+), 331 deletions(-)

Detailed changes

gpui/src/app.rs šŸ”—

@@ -23,7 +23,7 @@ use std::{
     fmt::{self, Debug},
     hash::{Hash, Hasher},
     marker::PhantomData,
-    ops::Deref,
+    ops::{Deref, DerefMut},
     path::{Path, PathBuf},
     rc::{self, Rc},
     sync::{Arc, Weak},
@@ -2110,6 +2110,12 @@ impl<M> Deref for ViewContext<'_, M> {
     }
 }
 
+impl<M> DerefMut for ViewContext<'_, M> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.app
+    }
+}
+
 impl<M> AsMut<MutableAppContext> for ViewContext<'_, M> {
     fn as_mut(&mut self) -> &mut MutableAppContext {
         self.app

zed/src/editor.rs šŸ”—

@@ -4,7 +4,7 @@ mod element;
 pub mod movement;
 
 use crate::{
-    settings::{Settings, StyleId},
+    settings::{Settings, StyleId, Theme},
     util::{post_inc, Bias},
     workspace,
     worktree::{File, Worktree},
@@ -15,10 +15,10 @@ pub use display_map::DisplayPoint;
 use display_map::*;
 pub use element::*;
 use gpui::{
-    color::ColorU, fonts::Properties as FontProperties, geometry::vector::Vector2F,
-    keymap::Binding, text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity,
-    FontCache, ModelHandle, MutableAppContext, Task, TextLayoutCache, View, ViewContext,
-    WeakViewHandle,
+    color::ColorU, font_cache::FamilyId, fonts::Properties as FontProperties,
+    geometry::vector::Vector2F, keymap::Binding, text_layout, AppContext, ClipboardItem, Element,
+    ElementBox, Entity, FontCache, ModelHandle, MutableAppContext, Task, TextLayoutCache, View,
+    ViewContext, WeakViewHandle,
 };
 use parking_lot::Mutex;
 use postage::{prelude::Stream, watch};
@@ -384,6 +384,15 @@ pub struct Editor {
     single_line: bool,
 }
 
+struct Snapshot {
+    display_snapshot: DisplayMapSnapshot,
+    gutter_visible: bool,
+    scroll_position: Vector2F,
+    theme: Arc<Theme>,
+    font_family: FamilyId,
+    font_size: f32,
+}
+
 struct AddSelectionsState {
     above: bool,
     stack: Vec<usize>,
@@ -410,8 +419,7 @@ impl Editor {
     ) -> Self {
         cx.observe_model(&buffer, Self::on_buffer_changed);
         cx.subscribe_to_model(&buffer, Self::on_buffer_event);
-        let display_map =
-            DisplayMap::new(buffer.clone(), settings.borrow().clone(), None, cx.as_ref());
+        let display_map = DisplayMap::new(buffer.clone(), settings.borrow().clone(), None, cx);
 
         let mut notifications = display_map.notifications();
         cx.spawn(|this, mut cx| async move {
@@ -458,8 +466,17 @@ impl Editor {
         &self.buffer
     }
 
-    pub fn is_gutter_visible(&self) -> bool {
-        !self.single_line
+    pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> Snapshot {
+        let settings = self.settings.borrow();
+
+        Snapshot {
+            display_snapshot: self.display_map.snapshot(cx),
+            gutter_visible: !self.single_line,
+            scroll_position: *self.scroll_position.lock(),
+            theme: settings.theme.clone(),
+            font_family: settings.buffer_font_family,
+            font_size: settings.buffer_font_size,
+        }
     }
 
     fn scroll(&mut self, scroll_position: &Vector2F, cx: &mut ViewContext<Self>) {
@@ -481,7 +498,7 @@ impl Editor {
         &self,
         viewport_height: f32,
         line_height: f32,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> bool {
         let display_map = self.display_map.snapshot(cx);
         let mut scroll_position = self.scroll_position.lock();
@@ -541,7 +558,7 @@ impl Editor {
         scroll_width: f32,
         max_glyph_width: f32,
         layouts: &[text_layout::Line],
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) {
         let display_map = self.display_map.snapshot(cx);
         let mut target_left = std::f32::INFINITY;
@@ -591,7 +608,7 @@ impl Editor {
             cx.emit(Event::Activate);
         }
 
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let cursor = display_map.anchor_before(position, Bias::Left);
         let selection = Selection {
             id: post_inc(&mut self.next_selection_id),
@@ -616,7 +633,7 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         let buffer = self.buffer.read(cx);
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let cursor = display_map.anchor_before(position, Bias::Left);
         if let Some(selection) = self.pending_selection.as_mut() {
             selection.set_head(buffer, cursor);
@@ -694,7 +711,7 @@ impl Editor {
         T: IntoIterator<Item = &'a Range<DisplayPoint>>,
     {
         let mut selections = Vec::new();
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         for range in ranges {
             let mut start = range.start;
             let mut end = range.end;
@@ -769,7 +786,7 @@ impl Editor {
     pub fn backspace(&mut self, _: &(), cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
         let mut selections = self.selections(cx.as_ref()).to_vec();
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         {
             let buffer = self.buffer.read(cx);
             for selection in &mut selections {
@@ -791,7 +808,7 @@ impl Editor {
 
     pub fn delete(&mut self, _: &(), cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let mut selections = self.selections(cx.as_ref()).to_vec();
         {
             let buffer = self.buffer.read(cx);
@@ -821,7 +838,7 @@ impl Editor {
         let mut new_cursors = Vec::new();
         let mut edit_ranges = Vec::new();
 
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let mut selections = self.selections(app).iter().peekable();
         while let Some(selection) = selections.next() {
             let (mut rows, _) = selection.buffer_rows_for_display_rows(false, &display_map);
@@ -902,7 +919,7 @@ impl Editor {
         self.update_selections(selections.clone(), false, cx);
 
         let buffer = self.buffer.read(cx);
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
 
         let mut edits = Vec::new();
         let mut selections_iter = selections.iter_mut().peekable();
@@ -952,7 +969,7 @@ impl Editor {
 
         let app = cx.as_ref();
         let buffer = self.buffer.read(cx);
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
 
         let mut edits = Vec::new();
         let mut new_selection_ranges = Vec::new();
@@ -1037,7 +1054,7 @@ impl Editor {
 
         let app = cx.as_ref();
         let buffer = self.buffer.read(cx);
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
 
         let mut edits = Vec::new();
         let mut new_selection_ranges = Vec::new();
@@ -1250,8 +1267,8 @@ impl Editor {
     }
 
     pub fn move_left(&mut self, _: &(), cx: &mut ViewContext<Self>) {
+        let display_map = self.display_map.snapshot(cx);
         let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
         let mut selections = self.selections(app).to_vec();
         {
             for selection in &mut selections {
@@ -1274,7 +1291,7 @@ impl Editor {
     }
 
     pub fn select_left(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let mut selections = self.selections(cx.as_ref()).to_vec();
         {
             let buffer = self.buffer.read(cx);
@@ -1290,7 +1307,7 @@ impl Editor {
     }
 
     pub fn move_right(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let mut selections = self.selections(cx.as_ref()).to_vec();
         {
             for selection in &mut selections {
@@ -1313,7 +1330,7 @@ impl Editor {
     }
 
     pub fn select_right(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let mut selections = self.selections(cx.as_ref()).to_vec();
         {
             let app = cx.as_ref();
@@ -1330,7 +1347,7 @@ impl Editor {
     }
 
     pub fn move_up(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         if self.single_line {
             cx.propagate_action();
         } else {
@@ -1356,7 +1373,7 @@ impl Editor {
     }
 
     pub fn select_up(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.snapshot(cx.as_ref());
+        let display_map = self.display_map.snapshot(cx);
         let mut selections = self.selections(cx.as_ref()).to_vec();
         {
             let app = cx.as_ref();
@@ -1375,7 +1392,7 @@ impl Editor {
         if self.single_line {
             cx.propagate_action();
         } else {
-            let display_map = self.display_map.snapshot(cx.as_ref());
+            let display_map = self.display_map.snapshot(cx);
             let mut selections = self.selections(cx.as_ref()).to_vec();
             {
                 for selection in &mut selections {
@@ -1398,8 +1415,8 @@ impl Editor {
     }
 
     pub fn select_down(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.snapshot(cx.as_ref());
-        let mut selections = self.selections(cx.as_ref()).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             let app = cx.as_ref();
             let buffer = self.buffer.read(app);
@@ -1414,9 +1431,8 @@ impl Editor {
     }
 
     pub fn move_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             for selection in &mut selections {
                 let head = selection.head().to_display_point(&display_map);
@@ -1432,9 +1448,8 @@ impl Editor {
     }
 
     pub fn select_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             let buffer = self.buffer.read(cx);
             for selection in &mut selections {
@@ -1456,9 +1471,8 @@ impl Editor {
     }
 
     pub fn move_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             for selection in &mut selections {
                 let head = selection.head().to_display_point(&display_map);
@@ -1474,9 +1488,8 @@ impl Editor {
     }
 
     pub fn select_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             let buffer = self.buffer.read(cx);
             for selection in &mut selections {
@@ -1498,9 +1511,8 @@ impl Editor {
     }
 
     pub fn move_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             for selection in &mut selections {
                 let head = selection.head().to_display_point(&display_map);
@@ -1520,9 +1532,8 @@ impl Editor {
         toggle_indent: &bool,
         cx: &mut ViewContext<Self>,
     ) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             let buffer = self.buffer.read(cx);
             for selection in &mut selections {
@@ -1545,9 +1556,8 @@ impl Editor {
     }
 
     pub fn move_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             for selection in &mut selections {
                 let head = selection.head().to_display_point(&display_map);
@@ -1563,9 +1573,8 @@ impl Editor {
     }
 
     pub fn select_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         {
             let buffer = self.buffer.read(cx);
             for selection in &mut selections {
@@ -1643,10 +1652,9 @@ impl Editor {
     }
 
     pub fn select_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let buffer = self.buffer.read(app);
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let buffer = self.buffer.read(cx);
+        let mut selections = self.selections(cx).to_vec();
         let max_point = buffer.max_point();
         for selection in &mut selections {
             let (rows, _) = selection.buffer_rows_for_display_rows(true, &display_map);
@@ -1706,9 +1714,8 @@ impl Editor {
     }
 
     fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        let mut selections = self.selections(app).to_vec();
+        let display_map = self.display_map.snapshot(cx);
+        let mut selections = self.selections(cx).to_vec();
         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();
@@ -1800,13 +1807,12 @@ impl Editor {
     }
 
     pub fn select_larger_syntax_node(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let buffer = self.buffer.read(app);
-        let display_map = self.display_map.snapshot(app);
+        let display_map = self.display_map.snapshot(cx);
+        let buffer = self.buffer.read(cx);
 
         let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
         let mut selected_larger_node = false;
-        let old_selections = self.selections(app).to_vec();
+        let old_selections = self.selections(cx).to_vec();
         let mut new_selection_ranges = Vec::new();
         for selection in &old_selections {
             let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
@@ -1916,10 +1922,10 @@ impl Editor {
         &'a self,
         set_id: SelectionSetId,
         range: Range<DisplayPoint>,
-        cx: &'a AppContext,
+        cx: &'a mut MutableAppContext,
     ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
-        let buffer = self.buffer.read(cx);
         let display_map = self.display_map.snapshot(cx);
+        let buffer = self.buffer.read(cx);
         let selections = &buffer.selection_set(set_id).unwrap().selections;
         let start = display_map.anchor_before(range.start, Bias::Left);
         let start_index = self.selection_insertion_index(selections, &start, cx);
@@ -2042,9 +2048,8 @@ impl Editor {
     pub fn fold(&mut self, _: &(), cx: &mut ViewContext<Self>) {
         let mut fold_ranges = Vec::new();
 
-        let app = cx.as_ref();
-        let display_map = self.display_map.snapshot(app);
-        for selection in self.selections(app) {
+        let display_map = self.display_map.snapshot(cx);
+        for selection in self.selections(cx) {
             let range = selection.display_range(&display_map).sorted();
             let buffer_start_row = range.start.to_buffer_point(&display_map, Bias::Left).row;
 
@@ -2065,11 +2070,10 @@ impl Editor {
     }
 
     pub fn unfold(&mut self, _: &(), cx: &mut ViewContext<Self>) {
-        let app = cx.as_ref();
-        let buffer = self.buffer.read(app);
-        let display_map = self.display_map.snapshot(app);
+        let display_map = self.display_map.snapshot(cx);
+        let buffer = self.buffer.read(cx);
         let ranges = self
-            .selections(app)
+            .selections(cx)
             .iter()
             .map(|s| {
                 let range = s.display_range(&display_map).sorted();
@@ -2138,7 +2142,7 @@ impl Editor {
 
     fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
         if !ranges.is_empty() {
-            self.display_map.fold(ranges, cx.as_ref());
+            self.display_map.fold(ranges, cx);
             *self.autoscroll_requested.lock() = true;
             cx.notify();
         }
@@ -2146,25 +2150,25 @@ impl Editor {
 
     fn unfold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
         if !ranges.is_empty() {
-            self.display_map.unfold(ranges, cx.as_ref());
+            self.display_map.unfold(ranges, cx);
             *self.autoscroll_requested.lock() = true;
             cx.notify();
         }
     }
 
-    pub fn line_len(&self, display_row: u32, cx: &AppContext) -> u32 {
+    pub fn line_len(&self, display_row: u32, cx: &mut MutableAppContext) -> u32 {
         self.display_map.snapshot(cx).line_len(display_row)
     }
 
-    pub fn longest_row(&self, cx: &AppContext) -> u32 {
+    pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
         self.display_map.snapshot(cx).longest_row()
     }
 
-    pub fn max_point(&self, cx: &AppContext) -> DisplayPoint {
+    pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
         self.display_map.snapshot(cx).max_point()
     }
 
-    pub fn text(&self, cx: &AppContext) -> String {
+    pub fn text(&self, cx: &mut MutableAppContext) -> String {
         self.display_map.snapshot(cx).text()
     }
 
@@ -2172,34 +2176,104 @@ impl Editor {
         self.settings.borrow().buffer_font_size
     }
 
+    pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) {
+        self.display_map.set_wrap_width(Some(width), cx);
+    }
+
+    fn next_blink_epoch(&mut self) -> usize {
+        self.blink_epoch += 1;
+        self.blink_epoch
+    }
+
+    fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
+        self.cursors_visible = true;
+        cx.notify();
+
+        let epoch = self.next_blink_epoch();
+        cx.spawn(|this, mut cx| {
+            let this = this.downgrade();
+            async move {
+                Timer::after(CURSOR_BLINK_INTERVAL).await;
+                if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
+                    this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
+                }
+            }
+        })
+        .detach();
+    }
+
+    fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
+        if epoch == self.blink_epoch {
+            self.blinking_paused = false;
+            self.blink_cursors(epoch, cx);
+        }
+    }
+
+    fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
+        if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
+            self.cursors_visible = !self.cursors_visible;
+            cx.notify();
+
+            let epoch = self.next_blink_epoch();
+            cx.spawn(|this, mut cx| {
+                let this = this.downgrade();
+                async move {
+                    Timer::after(CURSOR_BLINK_INTERVAL).await;
+                    if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
+                        this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
+                    }
+                }
+            })
+            .detach();
+        }
+    }
+
+    pub fn cursors_visible(&self) -> bool {
+        self.cursors_visible
+    }
+
+    fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
+        cx.notify();
+    }
+
+    fn on_buffer_event(
+        &mut self,
+        _: ModelHandle<Buffer>,
+        event: &buffer::Event,
+        cx: &mut ViewContext<Self>,
+    ) {
+        match event {
+            buffer::Event::Edited => cx.emit(Event::Edited),
+            buffer::Event::Dirtied => cx.emit(Event::Dirtied),
+            buffer::Event::Saved => cx.emit(Event::Saved),
+            buffer::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
+            buffer::Event::Reloaded => cx.emit(Event::FileHandleChanged),
+            buffer::Event::Reparsed => {}
+        }
+    }
+}
+
+impl Snapshot {
     pub fn font_ascent(&self, font_cache: &FontCache) -> f32 {
-        let settings = self.settings.borrow();
-        let font_id = font_cache.default_font(settings.buffer_font_family);
+        let font_id = font_cache.default_font(self.font_family);
         let ascent = font_cache.metric(font_id, |m| m.ascent);
-        font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
+        font_cache.scale_metric(ascent, font_id, self.font_size)
     }
 
     pub fn font_descent(&self, font_cache: &FontCache) -> f32 {
-        let settings = self.settings.borrow();
-        let font_id = font_cache.default_font(settings.buffer_font_family);
-        let ascent = font_cache.metric(font_id, |m| m.descent);
-        font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
+        let font_id = font_cache.default_font(self.font_family);
+        let descent = font_cache.metric(font_id, |m| m.descent);
+        font_cache.scale_metric(descent, font_id, self.font_size)
     }
 
     pub fn line_height(&self, font_cache: &FontCache) -> f32 {
-        let settings = self.settings.borrow();
-        let font_id = font_cache.default_font(settings.buffer_font_family);
-        font_cache.line_height(font_id, settings.buffer_font_size)
+        let font_id = font_cache.default_font(self.font_family);
+        font_cache.line_height(font_id, self.font_size)
     }
 
     pub fn em_width(&self, font_cache: &FontCache) -> f32 {
-        let settings = self.settings.borrow();
-        let font_id = font_cache.default_font(settings.buffer_font_family);
-        font_cache.em_width(font_id, settings.buffer_font_size)
-    }
-
-    pub fn set_wrap_width(&self, width: f32, cx: &AppContext) {
-        self.display_map.set_wrap_width(Some(width), cx);
+        let font_id = font_cache.default_font(self.font_family);
+        font_cache.em_width(font_id, self.font_size)
     }
 
     // TODO: Can we make this not return a result?
@@ -2209,11 +2283,12 @@ impl Editor {
         layout_cache: &TextLayoutCache,
         cx: &AppContext,
     ) -> Result<f32> {
-        let settings = self.settings.borrow();
-        let font_size = settings.buffer_font_size;
-        let font_id =
-            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
-        let digit_count = (self.buffer.read(cx).row_count() as f32).log10().floor() as usize + 1;
+        let font_size = self.font_size;
+        let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
+        let digit_count = (self.display_snapshot.buffer_row_count() as f32)
+            .log10()
+            .floor() as usize
+            + 1;
 
         Ok(layout_cache
             .layout_str(
@@ -2229,16 +2304,13 @@ impl Editor {
         viewport_height: f32,
         font_cache: &FontCache,
         layout_cache: &TextLayoutCache,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Result<Vec<text_layout::Line>> {
-        let settings = self.settings.borrow();
-        let font_size = settings.buffer_font_size;
-        let font_id =
-            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
+        let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
 
-        let start_row = self.scroll_position().y() as usize;
+        let start_row = self.scroll_position.y() as usize;
         let end_row = cmp::min(
-            self.max_point(cx).row() as usize,
+            self.display_snapshot.max_point().row() as usize,
             start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
         );
         let line_count = end_row - start_row + 1;
@@ -2246,8 +2318,7 @@ impl Editor {
         let mut layouts = Vec::with_capacity(line_count);
         let mut line_number = String::new();
         for buffer_row in self
-            .display_map
-            .snapshot(cx)
+            .display_snapshot
             .buffer_rows(start_row as u32)
             .take(line_count)
         {
@@ -2255,7 +2326,7 @@ impl Editor {
             write!(&mut line_number, "{}", buffer_row + 1).unwrap();
             layouts.push(layout_cache.layout_str(
                 &line_number,
-                font_size,
+                self.font_size,
                 &[(line_number.len(), font_id, ColorU::black())],
             ));
         }
@@ -2268,17 +2339,13 @@ impl Editor {
         mut rows: Range<u32>,
         font_cache: &FontCache,
         layout_cache: &TextLayoutCache,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Result<Vec<text_layout::Line>> {
-        let mut display_map = self.display_map.snapshot(cx);
-        rows.end = cmp::min(rows.end, display_map.max_point().row() + 1);
+        rows.end = cmp::min(rows.end, self.display_snapshot.max_point().row() + 1);
         if rows.start >= rows.end {
             return Ok(Vec::new());
         }
 
-        let settings = self.settings.borrow();
-        let font_size = settings.buffer_font_size;
-        let font_family = settings.buffer_font_family;
         let mut prev_font_properties = FontProperties::new();
         let mut prev_font_id = font_cache
             .select_font(font_family, &prev_font_properties)
@@ -2288,13 +2355,14 @@ impl Editor {
         let mut line = String::new();
         let mut styles = Vec::new();
         let mut row = rows.start;
-        let chunks = display_map.highlighted_chunks_for_rows(rows.clone());
-        let theme = settings.theme.clone();
+        let chunks = self
+            .display_snapshot
+            .highlighted_chunks_for_rows(rows.clone());
 
         'outer: for (chunk, style_ix) in chunks.chain(Some(("\n", StyleId::default()))) {
             for (ix, line_chunk) in chunk.split('\n').enumerate() {
                 if ix > 0 {
-                    layouts.push(layout_cache.layout_str(&line, font_size, &styles));
+                    layouts.push(layout_cache.layout_str(&line, self.font_size, &styles));
                     line.clear();
                     styles.clear();
                     row += 1;
@@ -2304,12 +2372,12 @@ impl Editor {
                 }
 
                 if !line_chunk.is_empty() {
-                    let (color, font_properties) = theme.syntax_style(style_ix);
+                    let (color, font_properties) = self.theme.syntax_style(style_ix);
                     // Avoid a lookup if the font properties match the previous ones.
                     let font_id = if font_properties == prev_font_properties {
                         prev_font_id
                     } else {
-                        font_cache.select_font(font_family, &font_properties)?
+                        font_cache.select_font(self.font_family, &font_properties)?
                     };
                     line.push_str(line_chunk);
                     styles.push((line_chunk.len(), font_id, color));
@@ -2327,93 +2395,22 @@ impl Editor {
         row: u32,
         font_cache: &FontCache,
         layout_cache: &TextLayoutCache,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Result<text_layout::Line> {
-        let settings = self.settings.borrow();
-        let display_map = self.display_map.snapshot(cx);
-        let font_id =
-            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
+        let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
 
-        let line = display_map.line(row);
+        let line = self.display_snapshot.line(row);
 
         Ok(layout_cache.layout_str(
             &line,
-            settings.buffer_font_size,
-            &[(display_map.line_len(row) as usize, font_id, ColorU::black())],
+            self.font_size,
+            &[(
+                self.display_snapshot.line_len(row) as usize,
+                font_id,
+                ColorU::black(),
+            )],
         ))
     }
-
-    fn next_blink_epoch(&mut self) -> usize {
-        self.blink_epoch += 1;
-        self.blink_epoch
-    }
-
-    fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
-        self.cursors_visible = true;
-        cx.notify();
-
-        let epoch = self.next_blink_epoch();
-        cx.spawn(|this, mut cx| {
-            let this = this.downgrade();
-            async move {
-                Timer::after(CURSOR_BLINK_INTERVAL).await;
-                if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
-                    this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
-                }
-            }
-        })
-        .detach();
-    }
-
-    fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
-        if epoch == self.blink_epoch {
-            self.blinking_paused = false;
-            self.blink_cursors(epoch, cx);
-        }
-    }
-
-    fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
-        if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
-            self.cursors_visible = !self.cursors_visible;
-            cx.notify();
-
-            let epoch = self.next_blink_epoch();
-            cx.spawn(|this, mut cx| {
-                let this = this.downgrade();
-                async move {
-                    Timer::after(CURSOR_BLINK_INTERVAL).await;
-                    if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
-                        this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
-                    }
-                }
-            })
-            .detach();
-        }
-    }
-
-    pub fn cursors_visible(&self) -> bool {
-        self.cursors_visible
-    }
-
-    fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
-        cx.notify();
-    }
-
-    fn on_buffer_event(
-        &mut self,
-        _: ModelHandle<Buffer>,
-        event: &buffer::Event,
-        cx: &mut ViewContext<Self>,
-    ) {
-        match event {
-            buffer::Event::Edited => cx.emit(Event::Edited),
-            buffer::Event::Dirtied => cx.emit(Event::Dirtied),
-            buffer::Event::Saved => cx.emit(Event::Saved),
-            buffer::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
-            buffer::Event::Reloaded => cx.emit(Event::FileHandleChanged),
-            buffer::Event::Reparsed => {}
-        }
-    }
 }
 
 pub enum Event {
@@ -2571,7 +2568,7 @@ mod tests {
 
         let view = buffer_view.read(cx);
         assert_eq!(
-            view.selection_ranges(cx.as_ref()),
+            view.selection_ranges(cx),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
         );
 
@@ -2581,7 +2578,7 @@ mod tests {
 
         let view = buffer_view.read(cx);
         assert_eq!(
-            view.selection_ranges(cx.as_ref()),
+            view.selection_ranges(cx),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
         );
 
@@ -2591,7 +2588,7 @@ mod tests {
 
         let view = buffer_view.read(cx);
         assert_eq!(
-            view.selection_ranges(cx.as_ref()),
+            view.selection_ranges(cx),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
         );
 
@@ -2602,7 +2599,7 @@ mod tests {
 
         let view = buffer_view.read(cx);
         assert_eq!(
-            view.selection_ranges(cx.as_ref()),
+            view.selection_ranges(cx),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
         );
 
@@ -2613,7 +2610,7 @@ mod tests {
 
         let view = buffer_view.read(cx);
         assert_eq!(
-            view.selection_ranges(cx.as_ref()),
+            view.selection_ranges(cx),
             [
                 DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
                 DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
@@ -2626,7 +2623,7 @@ mod tests {
 
         let view = buffer_view.read(cx);
         assert_eq!(
-            view.selection_ranges(cx.as_ref()),
+            view.selection_ranges(cx),
             [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
         );
     }
@@ -2641,7 +2638,7 @@ mod tests {
             view.begin_selection(DisplayPoint::new(2, 2), false, cx);
         });
         assert_eq!(
-            view.read(cx).selection_ranges(cx.as_ref()),
+            view.update(cx, |view, cx| view.selection_ranges(cx)),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
         );
 
@@ -2649,7 +2646,7 @@ mod tests {
             view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
         });
         assert_eq!(
-            view.read(cx).selection_ranges(cx.as_ref()),
+            view.update(cx, |view, cx| view.selection_ranges(cx)),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
         );
 
@@ -2658,7 +2655,7 @@ mod tests {
             view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
         });
         assert_eq!(
-            view.read(cx).selection_ranges(cx.as_ref()),
+            view.update(cx, |view, cx| view.selection_ranges(cx)),
             [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
         );
     }
@@ -2679,7 +2676,7 @@ mod tests {
             view.end_selection(cx);
         });
         assert_eq!(
-            view.read(cx).selection_ranges(cx.as_ref()),
+            view.update(cx, |view, cx| view.selection_ranges(cx)),
             [
                 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
                 DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
@@ -2688,13 +2685,13 @@ mod tests {
 
         view.update(cx, |view, cx| view.cancel(&(), cx));
         assert_eq!(
-            view.read(cx).selection_ranges(cx.as_ref()),
+            view.update(cx, |view, cx| view.selection_ranges(cx)),
             [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
         );
 
         view.update(cx, |view, cx| view.cancel(&(), cx));
         assert_eq!(
-            view.read(cx).selection_ranges(cx.as_ref()),
+            view.update(cx, |view, cx| view.selection_ranges(cx)),
             [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
         );
     }
@@ -2711,7 +2708,7 @@ mod tests {
 
         let layouts = view
             .read(cx)
-            .layout_line_numbers(1000.0, &font_cache, &layout_cache, cx.as_ref())
+            .layout_line_numbers(1000.0, &font_cache, &layout_cache, cx)
             .unwrap();
         assert_eq!(layouts.len(), 6);
     }
@@ -2750,7 +2747,7 @@ mod tests {
                 .unwrap();
             view.fold(&(), cx);
             assert_eq!(
-                view.text(cx.as_ref()),
+                view.text(cx),
                 "
                     impl Foo {
                         // Hello!
@@ -2771,7 +2768,7 @@ mod tests {
 
             view.fold(&(), cx);
             assert_eq!(
-                view.text(cx.as_ref()),
+                view.text(cx),
                 "
                     impl Foo {…
                     }
@@ -2781,7 +2778,7 @@ mod tests {
 
             view.unfold(&(), cx);
             assert_eq!(
-                view.text(cx.as_ref()),
+                view.text(cx),
                 "
                     impl Foo {
                         // Hello!
@@ -2801,7 +2798,7 @@ mod tests {
             );
 
             view.unfold(&(), cx);
-            assert_eq!(view.text(cx.as_ref()), buffer.read(cx).text());
+            assert_eq!(view.text(cx), buffer.read(cx).text());
         });
     }
 
@@ -2824,43 +2821,43 @@ mod tests {
 
         view.update(cx, |view, cx| {
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
             );
 
             view.move_down(&(), cx);
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
             );
 
             view.move_right(&(), cx);
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
             );
 
             view.move_left(&(), cx);
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
             );
 
             view.move_up(&(), cx);
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
             );
 
             view.move_to_end(&(), cx);
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
             );
 
             view.move_to_beginning(&(), cx);
             assert_eq!(
-                view.selection_ranges(cx.as_ref()),
+                view.selection_ranges(cx),
                 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
             );
 

zed/src/editor/display_map.rs šŸ”—

@@ -5,7 +5,7 @@ mod wrap_map;
 
 use super::{buffer, Anchor, Bias, Buffer, Point, Settings, ToOffset, ToPoint};
 use fold_map::FoldMap;
-use gpui::{AppContext, ModelHandle};
+use gpui::{ModelHandle, MutableAppContext};
 use postage::prelude::Stream;
 use std::ops::Range;
 use tab_map::TabMap;
@@ -24,7 +24,7 @@ impl DisplayMap {
         buffer: ModelHandle<Buffer>,
         settings: Settings,
         wrap_width: Option<f32>,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Self {
         let (fold_map, snapshot) = FoldMap::new(buffer.clone(), cx);
         let (tab_map, snapshot) = TabMap::new(snapshot, settings.tab_size);
@@ -37,7 +37,7 @@ impl DisplayMap {
         }
     }
 
-    pub fn snapshot(&self, cx: &AppContext) -> DisplayMapSnapshot {
+    pub fn snapshot(&self, cx: &mut MutableAppContext) -> DisplayMapSnapshot {
         let (folds_snapshot, edits) = self.fold_map.read(cx);
         let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits);
         let wraps_snapshot = self.wrap_map.sync(tabs_snapshot.clone(), edits, cx);
@@ -52,7 +52,7 @@ impl DisplayMap {
     pub fn fold<T: ToOffset>(
         &mut self,
         ranges: impl IntoIterator<Item = Range<T>>,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) {
         let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
@@ -65,7 +65,7 @@ impl DisplayMap {
     pub fn unfold<T: ToOffset>(
         &mut self,
         ranges: impl IntoIterator<Item = Range<T>>,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) {
         let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
@@ -75,7 +75,7 @@ impl DisplayMap {
         self.wrap_map.sync(snapshot, edits, cx);
     }
 
-    pub fn set_wrap_width(&self, width: Option<f32>, cx: &AppContext) {
+    pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) {
         self.wrap_map.set_wrap_width(width, cx);
     }
 
@@ -96,6 +96,10 @@ impl DisplayMapSnapshot {
         self.wraps_snapshot.buffer_rows(start_row)
     }
 
+    pub fn buffer_row_count(&self) -> u32 {
+        self.buffer_snapshot.max_point().row + 1
+    }
+
     pub fn max_point(&self) -> DisplayPoint {
         DisplayPoint(self.wraps_snapshot.max_point())
     }
@@ -317,11 +321,11 @@ mod tests {
                 Buffer::new(0, text, cx)
             });
             let wrap_width = Some(rng.gen_range(20.0..=100.0));
-            let map = cx.read(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
+            let map = cx.update(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
 
             for _op_ix in 0..operations {
                 buffer.update(&mut cx, |buffer, cx| buffer.randomly_mutate(&mut rng, cx));
-                let snapshot = cx.read(|cx| map.snapshot(cx));
+                let snapshot = cx.update(|cx| map.snapshot(cx));
                 let expected_buffer_rows = (0..=snapshot.max_point().row())
                     .map(|display_row| {
                         DisplayPoint::new(display_row, 0)
@@ -362,9 +366,9 @@ mod tests {
 
         let text = "one two three four five\nsix seven eight";
         let buffer = cx.add_model(|cx| Buffer::new(0, text.to_string(), cx));
-        let map = cx.read(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
+        let map = cx.update(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
 
-        let snapshot = cx.read(|cx| map.snapshot(cx));
+        let snapshot = cx.update(|cx| map.snapshot(cx));
         assert_eq!(
             snapshot
                 .chunks_at(DisplayPoint::new(0, 3))
@@ -385,7 +389,7 @@ mod tests {
             buffer.edit(vec![ix..ix], "and ", cx);
         });
 
-        let snapshot = cx.read(|cx| map.snapshot(cx));
+        let snapshot = cx.update(|cx| map.snapshot(cx));
         assert_eq!(
             snapshot
                 .chunks_at(DisplayPoint::new(1, 0))
@@ -402,7 +406,7 @@ mod tests {
             buffer.clone(),
             Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
             None,
-            cx.as_ref(),
+            cx,
         );
         buffer.update(cx, |buffer, cx| {
             buffer.edit(
@@ -417,19 +421,19 @@ mod tests {
         });
 
         assert_eq!(
-            &map.snapshot(cx.as_ref())
+            &map.snapshot(cx)
                 .chunks_at(DisplayPoint::new(1, 0))
                 .collect::<String>()[0..10],
             "    b   bb"
         );
         assert_eq!(
-            &map.snapshot(cx.as_ref())
+            &map.snapshot(cx)
                 .chunks_at(DisplayPoint::new(1, 2))
                 .collect::<String>()[0..10],
             "  b   bbbb"
         );
         assert_eq!(
-            &map.snapshot(cx.as_ref())
+            &map.snapshot(cx)
                 .chunks_at(DisplayPoint::new(1, 6))
                 .collect::<String>()[0..13],
             "  bbbbb\nc   c"
@@ -480,7 +484,7 @@ mod tests {
         });
         buffer.condition(&cx, |buf, _| !buf.is_parsing()).await;
 
-        let mut map = cx.read(|cx| {
+        let mut map = cx.update(|cx| {
             DisplayMap::new(
                 buffer,
                 Settings::new(cx.font_cache()).unwrap().with_tab_size(2),
@@ -489,7 +493,7 @@ mod tests {
             )
         });
         assert_eq!(
-            cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
+            cx.update(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
             vec![
                 ("fn ".to_string(), None),
                 ("outer".to_string(), Some("fn.name")),
@@ -500,7 +504,7 @@ mod tests {
             ]
         );
         assert_eq!(
-            cx.read(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
+            cx.update(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
             vec![
                 ("    fn ".to_string(), Some("mod.body")),
                 ("inner".to_string(), Some("fn.name")),
@@ -508,9 +512,9 @@ mod tests {
             ]
         );
 
-        cx.read(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
+        cx.update(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
         assert_eq!(
-            cx.read(|cx| highlighted_chunks(0..2, &map, &theme, cx)),
+            cx.update(|cx| highlighted_chunks(0..2, &map, &theme, cx)),
             vec![
                 ("fn ".to_string(), None),
                 ("out".to_string(), Some("fn.name")),
@@ -575,9 +579,9 @@ mod tests {
             buffer_font_size: 16.0,
             ..Settings::new(&font_cache).unwrap()
         };
-        let mut map = cx.read(|cx| DisplayMap::new(buffer, settings, Some(40.0), cx));
+        let mut map = cx.update(|cx| DisplayMap::new(buffer, settings, Some(40.0), cx));
         assert_eq!(
-            cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
+            cx.update(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
             [
                 ("fn \n".to_string(), None),
                 ("oute\nr".to_string(), Some("fn.name")),
@@ -585,13 +589,13 @@ mod tests {
             ]
         );
         assert_eq!(
-            cx.read(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
+            cx.update(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
             [("{}\n\n".to_string(), None)]
         );
 
-        cx.read(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
+        cx.update(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
         assert_eq!(
-            cx.read(|cx| highlighted_chunks(1..4, &map, &theme, cx)),
+            cx.update(|cx| highlighted_chunks(1..4, &map, &theme, cx)),
             [
                 ("out".to_string(), Some("fn.name")),
                 ("…\n".to_string(), None),
@@ -607,7 +611,6 @@ mod tests {
         let text = "\n'a', 'α',\t'āœ‹',\t'āŽ', 'šŸ'\n";
         let display_text = "\n'a', 'α',   'āœ‹',    'āŽ', 'šŸ'\n";
         let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
-        let cx = cx.as_ref();
         let map = DisplayMap::new(
             buffer.clone(),
             Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
@@ -647,7 +650,6 @@ mod tests {
     fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) {
         let text = "āœ…\t\tα\nβ\t\nšŸ€Ī²\t\tγ";
         let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
-        let cx = cx.as_ref();
         let map = DisplayMap::new(
             buffer.clone(),
             Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
@@ -718,19 +720,16 @@ mod tests {
             buffer.clone(),
             Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
             None,
-            cx.as_ref(),
+            cx,
         );
-        assert_eq!(
-            map.snapshot(cx.as_ref()).max_point(),
-            DisplayPoint::new(1, 11)
-        )
+        assert_eq!(map.snapshot(cx).max_point(), DisplayPoint::new(1, 11))
     }
 
     fn highlighted_chunks<'a>(
         rows: Range<u32>,
         map: &DisplayMap,
         theme: &'a Theme,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Vec<(String, Option<&'a str>)> {
         let mut chunks: Vec<(String, Option<&str>)> = Vec::new();
         for (chunk, style_id) in map.snapshot(cx).highlighted_chunks_for_rows(rows) {

zed/src/editor/display_map/line_wrapper.rs šŸ”—

@@ -126,7 +126,7 @@ mod tests {
             ..Settings::new(&font_cache).unwrap()
         };
 
-        let mut wrapper = LineWrapper::new(font_system, font_cache, settings);
+        let wrapper = LineWrapper::new(font_system, font_cache, settings);
 
         assert_eq!(
             wrapper.wrap_line_with_shaping("aa bbb cccc ddddd eeee", 72.0),

zed/src/editor/display_map/wrap_map.rs šŸ”—

@@ -12,7 +12,7 @@ use crate::{
     util::Bias,
     Settings,
 };
-use gpui::{executor::Background, AppContext, Task};
+use gpui::{executor::Background, MutableAppContext, Task};
 use parking_lot::Mutex;
 use postage::{prelude::Stream, sink::Sink, watch};
 use smol::future::yield_now;
@@ -80,7 +80,7 @@ impl WrapMap {
         tab_snapshot: TabSnapshot,
         settings: Settings,
         wrap_width: Option<f32>,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Self {
         let this = Self(Arc::new(Mutex::new(WrapMapState {
             background_task: None,
@@ -116,14 +116,14 @@ impl WrapMap {
         &self,
         tab_snapshot: TabSnapshot,
         edits: Vec<TabEdit>,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Snapshot {
         self.0.lock().pending_edits.push_back((tab_snapshot, edits));
         self.flush_edits(cx.background());
         self.0.lock().snapshot.clone()
     }
 
-    pub fn set_wrap_width(&self, wrap_width: Option<f32>, cx: &AppContext) {
+    pub fn set_wrap_width(&self, wrap_width: Option<f32>, cx: &mut MutableAppContext) {
         let mut state = self.0.lock();
         if wrap_width == state.wrap_width {
             return;
@@ -814,7 +814,7 @@ mod tests {
                 folds_snapshot.text()
             );
             log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
-            let wrap_map = cx.read(|cx| {
+            let wrap_map = cx.update(|cx| {
                 WrapMap::new(
                     tabs_snapshot.clone(),
                     settings.clone(),
@@ -832,7 +832,7 @@ mod tests {
                 notifications.recv().await;
             }
 
-            let snapshot = cx.read(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
+            let snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
             let actual_text = snapshot.text();
             assert_eq!(
                 actual_text, expected_text,
@@ -856,12 +856,12 @@ mod tests {
 
                 let unwrapped_text = tabs_snapshot.text();
                 let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
-                let mut snapshot = cx.read(|cx| wrap_map.sync(tabs_snapshot.clone(), edits, cx));
+                let mut snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot.clone(), edits, cx));
                 snapshot.check_invariants(&mut rng);
 
                 if wrap_map.is_rewrapping() {
                     notifications.recv().await;
-                    snapshot = cx.read(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
+                    snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
                 }
 
                 snapshot.check_invariants(&mut rng);

zed/src/editor/element.rs šŸ”—

@@ -1,3 +1,5 @@
+use crate::time::ReplicaId;
+
 use super::{DisplayPoint, Editor, SelectAction};
 use gpui::{
     color::ColorU,
@@ -9,12 +11,15 @@ use gpui::{
     json::{self, ToJson},
     text_layout::{self, TextLayoutCache},
     AfterLayoutContext, AppContext, Border, Element, Event, EventContext, FontCache, LayoutContext,
-    PaintContext, Quad, Scene, SizeConstraint, WeakViewHandle,
+    MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
 };
 use json::json;
 use smallvec::SmallVec;
-use std::cmp::Ordering;
-use std::cmp::{self};
+use std::{cmp::Ordering, ops::Range};
+use std::{
+    cmp::{self},
+    collections::HashMap,
+};
 
 pub struct EditorElement {
     view: WeakViewHandle<Editor>,
@@ -29,6 +34,13 @@ impl EditorElement {
         self.view.upgrade(cx).unwrap().read(cx)
     }
 
+    fn update_view<F, T>(&self, cx: &mut MutableAppContext, f: F) -> T
+    where
+        F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
+    {
+        self.view.upgrade(cx).unwrap().update(cx, f)
+    }
+
     fn mouse_down(
         &self,
         position: Vector2F,
@@ -38,9 +50,10 @@ impl EditorElement {
         cx: &mut EventContext,
     ) -> bool {
         if paint.text_bounds.contains_point(position) {
-            let view = self.view(cx.app.as_ref());
-            let position =
-                paint.point_for_position(view, layout, position, cx.font_cache, cx.app.as_ref());
+            let position = self.update_view(cx.app, |view, cx| {
+                let font_cache = cx.font_cache().clone();
+                paint.point_for_position(view, layout, position, &font_cache, cx)
+            });
             cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd });
             true
         } else {
@@ -94,19 +107,15 @@ impl EditorElement {
                 ))
             }
 
-            let action = SelectAction::Update {
-                position: paint.point_for_position(
-                    view,
-                    layout,
-                    position,
-                    cx.font_cache,
-                    cx.app.as_ref(),
-                ),
+            let font_cache = cx.font_cache.clone();
+            let text_layout_cache = cx.text_layout_cache.clone();
+            let action = self.update_view(cx.app, |view, cx| SelectAction::Update {
+                position: paint.point_for_position(view, layout, position, &font_cache, cx),
                 scroll_position: (view.scroll_position() + scroll_delta).clamp(
                     Vector2F::zero(),
-                    layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app),
+                    layout.scroll_max(view, &font_cache, &text_layout_cache, cx),
                 ),
-            };
+            });
 
             cx.dispatch_action("buffer:select", action);
             true
@@ -160,7 +169,9 @@ impl EditorElement {
         let y = (view.scroll_position().y() * line_height - delta.y()) / line_height;
         let scroll_position = vec2f(x, y).clamp(
             Vector2F::zero(),
-            layout.scroll_max(view, font_cache, layout_cache, cx.app),
+            self.update_view(cx.app, |view, cx| {
+                layout.scroll_max(view, font_cache, layout_cache, cx)
+            }),
         );
 
         cx.dispatch_action("buffer:scroll", scroll_position);
@@ -226,14 +237,11 @@ impl EditorElement {
         let mut cursors = SmallVec::<[Cursor; 32]>::new();
 
         let content_origin = bounds.origin() + layout.text_offset;
-        for selection_set_id in view.active_selection_sets(cx.app) {
-            let (selection_color, cursor_color) =
-                colors[selection_set_id.replica_id as usize % colors.len()];
-            for selection in view.selections_in_range(
-                selection_set_id,
-                DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
-                cx.app,
-            ) {
+
+        for (replica_id, selections) in &layout.selections {
+            let (selection_color, cursor_color) = colors[*replica_id as usize % colors.len()];
+
+            for selection in selections {
                 if selection.start != selection.end {
                     let range_start = cmp::min(selection.start, selection.end);
                     let range_end = cmp::max(selection.start, selection.end);
@@ -326,17 +334,12 @@ impl Element for EditorElement {
         constraint: SizeConstraint,
         cx: &mut LayoutContext,
     ) -> (Vector2F, Self::LayoutState) {
-        let app = &mut cx.app;
         let mut size = constraint.max;
-        if size.y().is_infinite() {
-            let view = self.view(app);
-            size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(cx.font_cache));
-        }
         if size.x().is_infinite() {
             unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
         }
 
-        let view = self.view(app);
+        let view = self.view(cx.app);
 
         let font_cache = &cx.font_cache;
         let layout_cache = &cx.text_layout_cache;
@@ -346,7 +349,7 @@ impl Element for EditorElement {
         let gutter_width;
         if view.is_gutter_visible() {
             gutter_padding = view.em_width(cx.font_cache);
-            match view.max_line_number_width(cx.font_cache, cx.text_layout_cache, app) {
+            match view.max_line_number_width(cx.font_cache, cx.text_layout_cache, cx.app) {
                 Err(error) => {
                     log::error!("error computing max line number width: {}", error);
                     return (size, None);
@@ -366,12 +369,18 @@ impl Element for EditorElement {
         let wrap_width = text_size.x() - text_offset.x() - overscroll.x();
         // TODO: Core text doesn't seem to be keeping our lines below the specified wrap width. Find out why.
         let wrap_width = wrap_width - em_width;
-        view.set_wrap_width(wrap_width, app);
+        self.update_view(cx.app, |view, cx| {
+            view.set_wrap_width(wrap_width, cx);
+        });
+
+        if size.y().is_infinite() {
+            size.set_y((view.max_point(cx.app).row() + 1) as f32 * view.line_height(cx.font_cache));
+        }
 
-        let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, app);
+        let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx.app);
 
         let line_number_layouts = if view.is_gutter_visible() {
-            match view.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache, app) {
+            match view.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache, cx.app) {
                 Err(error) => {
                     log::error!("error laying out line numbers: {}", error);
                     return (size, None);
@@ -388,7 +397,7 @@ impl Element for EditorElement {
 
         let mut max_visible_line_width = 0.0;
         let line_layouts =
-            match view.layout_lines(start_row..end_row, font_cache, layout_cache, app) {
+            match view.layout_lines(start_row..end_row, font_cache, layout_cache, cx.app) {
                 Err(error) => {
                     log::error!("error laying out lines: {}", error);
                     return (size, None);
@@ -404,21 +413,34 @@ impl Element for EditorElement {
                 }
             };
 
-        (
+        let mut selections = HashMap::new();
+        for selection_set_id in view.active_selection_sets(cx.app) {
+            selections.insert(
+                selection_set_id.replica_id,
+                view.selections_in_range(
+                    selection_set_id,
+                    DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
+                    cx.app,
+                )
+                .collect(),
+            );
+        }
+
+        let layout_state = Some(LayoutState {
             size,
-            Some(LayoutState {
-                size,
-                gutter_size,
-                gutter_padding,
-                text_size,
-                overscroll,
-                text_offset,
-                line_layouts,
-                line_number_layouts,
-                max_visible_line_width,
-                autoscroll_horizontally,
-            }),
-        )
+            gutter_size,
+            gutter_padding,
+            text_size,
+            overscroll,
+            text_offset,
+            line_layouts,
+            line_number_layouts,
+            selections,
+            max_visible_line_width,
+            autoscroll_horizontally,
+        });
+
+        (size, layout_state)
     }
 
     fn after_layout(
@@ -428,12 +450,10 @@ impl Element for EditorElement {
         cx: &mut AfterLayoutContext,
     ) {
         if let Some(layout) = layout {
-            let app = cx.app.as_ref();
-
-            let view = self.view(app);
+            let view = self.view(cx.app);
             view.clamp_scroll_left(
                 layout
-                    .scroll_max(view, cx.font_cache, cx.text_layout_cache, app)
+                    .scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app)
                     .x(),
             );
 
@@ -441,10 +461,10 @@ impl Element for EditorElement {
                 view.autoscroll_horizontally(
                     view.scroll_position().y() as u32,
                     layout.text_size.x(),
-                    layout.scroll_width(view, cx.font_cache, cx.text_layout_cache, app),
+                    layout.scroll_width(view, cx.font_cache, cx.text_layout_cache, cx.app),
                     view.em_width(cx.font_cache),
                     &layout.line_layouts,
-                    app,
+                    cx.app,
                 );
             }
         }
@@ -528,6 +548,7 @@ pub struct LayoutState {
     text_size: Vector2F,
     line_layouts: Vec<text_layout::Line>,
     line_number_layouts: Vec<text_layout::Line>,
+    selections: HashMap<ReplicaId, Vec<Range<DisplayPoint>>>,
     overscroll: Vector2F,
     text_offset: Vector2F,
     max_visible_line_width: f32,
@@ -540,7 +561,7 @@ impl LayoutState {
         view: &Editor,
         font_cache: &FontCache,
         layout_cache: &TextLayoutCache,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> f32 {
         let row = view.longest_row(cx);
         let longest_line_width = view
@@ -555,7 +576,7 @@ impl LayoutState {
         view: &Editor,
         font_cache: &FontCache,
         layout_cache: &TextLayoutCache,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> Vector2F {
         vec2f(
             ((self.scroll_width(view, font_cache, layout_cache, cx) - self.text_size.x())
@@ -578,7 +599,7 @@ impl PaintState {
         layout: &LayoutState,
         position: Vector2F,
         font_cache: &FontCache,
-        cx: &AppContext,
+        cx: &mut MutableAppContext,
     ) -> DisplayPoint {
         let scroll_position = view.scroll_position();
         let position = position - self.text_bounds.origin();

zed/src/file_finder.rs šŸ”—

@@ -311,7 +311,7 @@ impl FileFinder {
     }
 
     fn workspace_updated(&mut self, _: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) {
-        if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx.as_ref()), cx) {
+        if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx), cx) {
             task.detach();
         }
     }
@@ -324,7 +324,7 @@ impl FileFinder {
     ) {
         match event {
             editor::Event::Edited => {
-                let query = self.query_buffer.read(cx).text(cx.as_ref());
+                let query = self.query_buffer.update(cx, |buffer, cx| buffer.text(cx));
                 if query.is_empty() {
                     self.latest_search_id = util::post_inc(&mut self.search_count);
                     self.matches.clear();

zed/src/workspace.rs šŸ”—

@@ -1329,7 +1329,7 @@ mod tests {
                 .to_any()
                 .downcast::<Editor>()
                 .unwrap();
-            assert!(editor.read(cx).text(cx.as_ref()).is_empty());
+            assert!(editor.update(cx, |editor, cx| editor.text(cx).is_empty()));
         });
     }