diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 96ed1ee2c02779ac7007e8f2d8ebf3b6c6c71b77..8ac9d41111d50cdaf23a7c72da09700c456578ba 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -1850,6 +1850,20 @@ impl UpdateModel for ModelContext<'_, M> { } } +impl Deref for ModelContext<'_, M> { + type Target = MutableAppContext; + + fn deref(&self) -> &Self::Target { + &self.app + } +} + +impl DerefMut for ModelContext<'_, M> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.app + } +} + pub struct ViewContext<'a, T: ?Sized> { app: &'a mut MutableAppContext, window_id: usize, diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 3eabb62edb5be06355265181be00e112f30e07e9..6fead48cf0c5680ee907e80fa8081d7afafddaa8 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -21,7 +21,7 @@ use gpui::{ ViewContext, WeakViewHandle, }; use parking_lot::Mutex; -use postage::{prelude::Stream, watch}; +use postage::watch; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use smol::Timer; @@ -368,7 +368,7 @@ pub enum SelectAction { pub struct Editor { handle: WeakViewHandle, buffer: ModelHandle, - display_map: DisplayMap, + display_map: ModelHandle, selection_set_id: SelectionSetId, pending_selection: Option, next_selection_id: usize, @@ -417,17 +417,11 @@ impl Editor { settings: watch::Receiver, cx: &mut ViewContext, ) -> Self { + let display_map = + cx.add_model(|cx| DisplayMap::new(buffer.clone(), settings.borrow().clone(), None, cx)); 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); - - let mut notifications = display_map.notifications(); - cx.spawn(|this, mut cx| async move { - while notifications.recv().await.is_some() { - this.update(&mut cx, |_, cx| cx.notify()); - } - }) - .detach(); + cx.observe_model(&display_map, Self::on_display_map_changed); let mut next_selection_id = 0; let selection_set_id = buffer.update(cx, |buffer, cx| { @@ -470,7 +464,7 @@ impl Editor { let settings = self.settings.borrow(); Snapshot { - display_snapshot: self.display_map.snapshot(cx), + display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)), gutter_visible: !self.single_line, scroll_position: *self.scroll_position.lock(), theme: settings.theme.clone(), @@ -504,7 +498,7 @@ impl Editor { line_height: f32, cx: &mut MutableAppContext, ) -> bool { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut scroll_position = self.scroll_position.lock(); let scroll_top = scroll_position.y(); scroll_position @@ -564,7 +558,7 @@ impl Editor { layouts: &[text_layout::Line], cx: &mut MutableAppContext, ) -> bool { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut target_left = std::f32::INFINITY; let mut target_right = 0.0_f32; for selection in self.selections(cx) { @@ -616,7 +610,7 @@ impl Editor { cx.emit(Event::Activate); } - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let cursor = display_map.anchor_before(position, Bias::Left); let selection = Selection { id: post_inc(&mut self.next_selection_id), @@ -640,7 +634,7 @@ impl Editor { scroll_position: Vector2F, cx: &mut ViewContext, ) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let cursor = display_map.anchor_before(position, Bias::Left); if let Some(selection) = self.pending_selection.as_mut() { @@ -719,7 +713,7 @@ impl Editor { T: IntoIterator>, { let mut selections = Vec::new(); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); for range in ranges { let mut start = range.start; let mut end = range.end; @@ -794,7 +788,7 @@ impl Editor { pub fn backspace(&mut self, _: &(), cx: &mut ViewContext) { self.start_transaction(cx); let mut selections = self.selections(cx.as_ref()).to_vec(); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); { let buffer = self.buffer.read(cx); for selection in &mut selections { @@ -816,7 +810,7 @@ impl Editor { pub fn delete(&mut self, _: &(), cx: &mut ViewContext) { self.start_transaction(cx); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx.as_ref()).to_vec(); { let buffer = self.buffer.read(cx); @@ -840,7 +834,7 @@ impl Editor { pub fn delete_line(&mut self, _: &(), cx: &mut ViewContext) { self.start_transaction(cx); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let app = cx.as_ref(); let buffer = self.buffer.read(app); @@ -926,7 +920,7 @@ impl Editor { } self.update_selections(selections.clone(), false, cx); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let mut edits = Vec::new(); @@ -975,7 +969,7 @@ impl Editor { pub fn move_line_up(&mut self, _: &(), cx: &mut ViewContext) { self.start_transaction(cx); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let app = cx.as_ref(); let buffer = self.buffer.read(cx); @@ -1060,7 +1054,7 @@ impl Editor { pub fn move_line_down(&mut self, _: &(), cx: &mut ViewContext) { self.start_transaction(cx); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let app = cx.as_ref(); let buffer = self.buffer.read(cx); @@ -1275,7 +1269,7 @@ impl Editor { } pub fn move_left(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { @@ -1299,7 +1293,7 @@ impl Editor { } pub fn select_left(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx.as_ref()).to_vec(); { let buffer = self.buffer.read(cx); @@ -1315,7 +1309,7 @@ impl Editor { } pub fn move_right(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx.as_ref()).to_vec(); { for selection in &mut selections { @@ -1338,7 +1332,7 @@ impl Editor { } pub fn select_right(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx.as_ref()).to_vec(); { let app = cx.as_ref(); @@ -1355,7 +1349,7 @@ impl Editor { } pub fn move_up(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if self.single_line { cx.propagate_action(); } else { @@ -1381,7 +1375,7 @@ impl Editor { } pub fn select_up(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx.as_ref()).to_vec(); { let app = cx.as_ref(); @@ -1400,7 +1394,7 @@ impl Editor { if self.single_line { cx.propagate_action(); } else { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx.as_ref()).to_vec(); { for selection in &mut selections { @@ -1423,7 +1417,7 @@ impl Editor { } pub fn select_down(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { let app = cx.as_ref(); @@ -1439,7 +1433,7 @@ impl Editor { } pub fn move_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { for selection in &mut selections { @@ -1456,7 +1450,7 @@ impl Editor { } pub fn select_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { let buffer = self.buffer.read(cx); @@ -1479,7 +1473,7 @@ impl Editor { } pub fn move_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { for selection in &mut selections { @@ -1496,7 +1490,7 @@ impl Editor { } pub fn select_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { let buffer = self.buffer.read(cx); @@ -1519,7 +1513,7 @@ impl Editor { } pub fn move_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { for selection in &mut selections { @@ -1540,7 +1534,7 @@ impl Editor { toggle_indent: &bool, cx: &mut ViewContext, ) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { let buffer = self.buffer.read(cx); @@ -1564,7 +1558,7 @@ impl Editor { } pub fn move_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { for selection in &mut selections { @@ -1581,7 +1575,7 @@ impl Editor { } pub fn select_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.selections(cx).to_vec(); { let buffer = self.buffer.read(cx); @@ -1660,7 +1654,7 @@ impl Editor { } pub fn select_line(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let mut selections = self.selections(cx).to_vec(); let max_point = buffer.max_point(); @@ -1722,7 +1716,7 @@ impl Editor { } fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| 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(); @@ -1815,7 +1809,7 @@ impl Editor { } pub fn select_larger_syntax_node(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); @@ -1932,7 +1926,7 @@ impl Editor { range: Range, cx: &'a mut MutableAppContext, ) -> impl 'a + Iterator> { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| 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); @@ -2056,7 +2050,7 @@ impl Editor { pub fn fold(&mut self, _: &(), cx: &mut ViewContext) { let mut fold_ranges = Vec::new(); - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| 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; @@ -2078,7 +2072,7 @@ impl Editor { } pub fn unfold(&mut self, _: &(), cx: &mut ViewContext) { - let display_map = self.display_map.snapshot(cx); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let ranges = self .selections(cx) @@ -2150,7 +2144,7 @@ impl Editor { fn fold_ranges(&mut self, ranges: Vec>, cx: &mut ViewContext) { if !ranges.is_empty() { - self.display_map.fold(ranges, cx); + self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); *self.autoscroll_requested.lock() = true; cx.notify(); } @@ -2158,26 +2152,35 @@ impl Editor { fn unfold_ranges(&mut self, ranges: Vec>, cx: &mut ViewContext) { if !ranges.is_empty() { - self.display_map.unfold(ranges, cx); + self.display_map + .update(cx, |map, cx| map.unfold(ranges, cx)); *self.autoscroll_requested.lock() = true; cx.notify(); } } pub fn line_len(&self, display_row: u32, cx: &mut MutableAppContext) -> u32 { - self.display_map.snapshot(cx).line_len(display_row) + self.display_map + .update(cx, |map, cx| map.snapshot(cx)) + .line_len(display_row) } pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 { - self.display_map.snapshot(cx).longest_row() + self.display_map + .update(cx, |map, cx| map.snapshot(cx)) + .longest_row() } pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint { - self.display_map.snapshot(cx).max_point() + self.display_map + .update(cx, |map, cx| map.snapshot(cx)) + .max_point() } pub fn text(&self, cx: &mut MutableAppContext) -> String { - self.display_map.snapshot(cx).text() + self.display_map + .update(cx, |map, cx| map.snapshot(cx)) + .text() } pub fn font_size(&self) -> f32 { @@ -2185,7 +2188,8 @@ impl Editor { } pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) -> bool { - self.display_map.set_wrap_width(Some(width), cx) + self.display_map + .update(cx, |map, cx| map.set_wrap_width(Some(width), cx)) } fn next_blink_epoch(&mut self) -> usize { @@ -2259,6 +2263,10 @@ impl Editor { buffer::Event::Reparsed => {} } } + + fn on_display_map_changed(&mut self, _: ModelHandle, cx: &mut ViewContext) { + cx.notify(); + } } impl Snapshot { diff --git a/zed/src/editor/display_map.rs b/zed/src/editor/display_map.rs index 0a9bc0b2133762ee1648eb6b08a9c688427f999d..7b13d1f05ee2a8c5be80854b2331beef88da67da 100644 --- a/zed/src/editor/display_map.rs +++ b/zed/src/editor/display_map.rs @@ -5,8 +5,7 @@ mod wrap_map; use super::{buffer, Anchor, Bias, Buffer, Point, Settings, ToOffset, ToPoint}; use fold_map::FoldMap; -use gpui::{ModelHandle, MutableAppContext}; -use postage::prelude::Stream; +use gpui::{Entity, ModelContext, ModelHandle}; use std::ops::Range; use tab_map::TabMap; pub use wrap_map::BufferRows; @@ -16,7 +15,11 @@ pub struct DisplayMap { buffer: ModelHandle, fold_map: FoldMap, tab_map: TabMap, - wrap_map: WrapMap, + wrap_map: ModelHandle, +} + +impl Entity for DisplayMap { + type Event = (); } impl DisplayMap { @@ -24,11 +27,12 @@ impl DisplayMap { buffer: ModelHandle, settings: Settings, wrap_width: Option, - cx: &mut MutableAppContext, + cx: &mut ModelContext, ) -> Self { let (fold_map, snapshot) = FoldMap::new(buffer.clone(), cx); let (tab_map, snapshot) = TabMap::new(snapshot, settings.tab_size); - let wrap_map = WrapMap::new(snapshot, settings, wrap_width, cx); + let wrap_map = cx.add_model(|cx| WrapMap::new(snapshot, settings, wrap_width, cx)); + cx.observe(&wrap_map, |_, _, cx| cx.notify()); DisplayMap { buffer, fold_map, @@ -37,10 +41,12 @@ impl DisplayMap { } } - pub fn snapshot(&self, cx: &mut MutableAppContext) -> DisplayMapSnapshot { + pub fn snapshot(&self, cx: &mut ModelContext) -> 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); + let wraps_snapshot = self + .wrap_map + .update(cx, |map, cx| map.sync(tabs_snapshot.clone(), edits, cx)); DisplayMapSnapshot { buffer_snapshot: self.buffer.read(cx).snapshot(), folds_snapshot, @@ -52,35 +58,36 @@ impl DisplayMap { pub fn fold( &mut self, ranges: impl IntoIterator>, - cx: &mut MutableAppContext, + cx: &mut ModelContext, ) { let (mut fold_map, snapshot, edits) = self.fold_map.write(cx); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); - self.wrap_map.sync(snapshot, edits, cx); + self.wrap_map + .update(cx, |map, cx| map.sync(snapshot, edits, cx)); let (snapshot, edits) = fold_map.fold(ranges, cx); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); - self.wrap_map.sync(snapshot, edits, cx); + self.wrap_map + .update(cx, |map, cx| map.sync(snapshot, edits, cx)); } pub fn unfold( &mut self, ranges: impl IntoIterator>, - cx: &mut MutableAppContext, + cx: &mut ModelContext, ) { let (mut fold_map, snapshot, edits) = self.fold_map.write(cx); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); - self.wrap_map.sync(snapshot, edits, cx); + self.wrap_map + .update(cx, |map, cx| map.sync(snapshot, edits, cx)); let (snapshot, edits) = fold_map.unfold(ranges, cx); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); - self.wrap_map.sync(snapshot, edits, cx); + self.wrap_map + .update(cx, |map, cx| map.sync(snapshot, edits, cx)); } - pub fn set_wrap_width(&self, width: Option, cx: &mut MutableAppContext) -> bool { - self.wrap_map.set_wrap_width(width, cx) - } - - pub fn notifications(&self) -> impl Stream { - self.wrap_map.notifications() + pub fn set_wrap_width(&self, width: Option, cx: &mut ModelContext) -> bool { + self.wrap_map + .update(cx, |map, cx| map.set_wrap_width(width, cx)) } } @@ -282,6 +289,7 @@ mod tests { util::RandomCharIter, }; use buffer::History; + use gpui::MutableAppContext; use rand::prelude::*; use std::{env, sync::Arc}; @@ -321,11 +329,11 @@ mod tests { Buffer::new(0, text, cx) }); let wrap_width = Some(rng.gen_range(20.0..=100.0)); - let map = cx.update(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx)); + let map = cx.add_model(|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.update(|cx| map.snapshot(cx)); + let snapshot = map.update(&mut cx, |map, cx| map.snapshot(cx)); let expected_buffer_rows = (0..=snapshot.max_point().row()) .map(|display_row| { DisplayPoint::new(display_row, 0) @@ -366,9 +374,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.update(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx)); + let map = cx.add_model(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx)); - let snapshot = cx.update(|cx| map.snapshot(cx)); + let snapshot = map.update(&mut cx, |map, cx| map.snapshot(cx)); assert_eq!( snapshot .chunks_at(DisplayPoint::new(0, 3)) @@ -389,7 +397,7 @@ mod tests { buffer.edit(vec![ix..ix], "and ", cx); }); - let snapshot = cx.update(|cx| map.snapshot(cx)); + let snapshot = map.update(&mut cx, |map, cx| map.snapshot(cx)); assert_eq!( snapshot .chunks_at(DisplayPoint::new(1, 0)) @@ -402,12 +410,14 @@ mod tests { fn test_chunks_at(cx: &mut gpui::MutableAppContext) { let text = sample_text(6, 6); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); - let map = DisplayMap::new( - buffer.clone(), - Settings::new(cx.font_cache()).unwrap().with_tab_size(4), - None, - cx, - ); + let map = cx.add_model(|cx| { + DisplayMap::new( + buffer.clone(), + Settings::new(cx.font_cache()).unwrap().with_tab_size(4), + None, + cx, + ) + }); buffer.update(cx, |buffer, cx| { buffer.edit( vec![ @@ -421,19 +431,19 @@ mod tests { }); assert_eq!( - &map.snapshot(cx) + &map.update(cx, |map, cx| map.snapshot(cx)) .chunks_at(DisplayPoint::new(1, 0)) .collect::()[0..10], " b bb" ); assert_eq!( - &map.snapshot(cx) + &map.update(cx, |map, cx| map.snapshot(cx)) .chunks_at(DisplayPoint::new(1, 2)) .collect::()[0..10], " b bbbb" ); assert_eq!( - &map.snapshot(cx) + &map.update(cx, |map, cx| map.snapshot(cx)) .chunks_at(DisplayPoint::new(1, 6)) .collect::()[0..13], " bbbbb\nc c" @@ -484,7 +494,7 @@ mod tests { }); buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; - let mut map = cx.update(|cx| { + let map = cx.add_model(|cx| { DisplayMap::new( buffer, Settings::new(cx.font_cache()).unwrap().with_tab_size(2), @@ -512,7 +522,9 @@ mod tests { ] ); - cx.update(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)); + map.update(&mut cx, |map, cx| { + map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx) + }); assert_eq!( cx.update(|cx| highlighted_chunks(0..2, &map, &theme, cx)), vec![ @@ -579,7 +591,7 @@ mod tests { buffer_font_size: 16.0, ..Settings::new(&font_cache).unwrap() }; - let mut map = cx.update(|cx| DisplayMap::new(buffer, settings, Some(40.0), cx)); + let map = cx.add_model(|cx| DisplayMap::new(buffer, settings, Some(40.0), cx)); assert_eq!( cx.update(|cx| highlighted_chunks(0..5, &map, &theme, cx)), [ @@ -593,7 +605,9 @@ mod tests { [("{}\n\n".to_string(), None)] ); - cx.update(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)); + map.update(&mut cx, |map, cx| { + map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx) + }); assert_eq!( cx.update(|cx| highlighted_chunks(1..4, &map, &theme, cx)), [ @@ -611,13 +625,15 @@ 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 map = DisplayMap::new( - buffer.clone(), - Settings::new(cx.font_cache()).unwrap().with_tab_size(4), - None, - cx, - ); - let map = map.snapshot(cx); + let map = cx.add_model(|cx| { + DisplayMap::new( + buffer.clone(), + Settings::new(cx.font_cache()).unwrap().with_tab_size(4), + None, + cx, + ) + }); + let map = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!(map.text(), display_text); for (input_column, bias, output_column) in vec![ @@ -650,13 +666,15 @@ 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 map = DisplayMap::new( - buffer.clone(), - Settings::new(cx.font_cache()).unwrap().with_tab_size(4), - None, - cx, - ); - let map = map.snapshot(cx); + let map = cx.add_model(|cx| { + DisplayMap::new( + buffer.clone(), + Settings::new(cx.font_cache()).unwrap().with_tab_size(4), + None, + cx, + ) + }); + let map = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!(map.text(), "✅ α\nβ \n🏀β γ"); let point = Point::new(0, "✅\t\t".len() as u32); @@ -716,23 +734,29 @@ mod tests { #[gpui::test] fn test_max_point(cx: &mut gpui::MutableAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, "aaa\n\t\tbbb", cx)); - let map = DisplayMap::new( - buffer.clone(), - Settings::new(cx.font_cache()).unwrap().with_tab_size(4), - None, - cx, - ); - assert_eq!(map.snapshot(cx).max_point(), DisplayPoint::new(1, 11)) + let map = cx.add_model(|cx| { + DisplayMap::new( + buffer.clone(), + Settings::new(cx.font_cache()).unwrap().with_tab_size(4), + None, + cx, + ) + }); + assert_eq!( + map.update(cx, |map, cx| map.snapshot(cx)).max_point(), + DisplayPoint::new(1, 11) + ) } fn highlighted_chunks<'a>( rows: Range, - map: &DisplayMap, + map: &ModelHandle, theme: &'a Theme, cx: &mut MutableAppContext, ) -> Vec<(String, Option<&'a str>)> { + let mut snapshot = map.update(cx, |map, cx| map.snapshot(cx)); let mut chunks: Vec<(String, Option<&str>)> = Vec::new(); - for (chunk, style_id) in map.snapshot(cx).highlighted_chunks_for_rows(rows) { + for (chunk, style_id) in snapshot.highlighted_chunks_for_rows(rows) { let style_name = theme.syntax_style_name(style_id); if let Some((last_chunk, last_style_name)) = chunks.last_mut() { if style_name == *last_style_name { diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index cde048f400436d8d61a41af92800c3fbd0eea303..52ec29168443ee10c3451e34c3259e432e59f257 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -10,24 +10,22 @@ use crate::{ util::Bias, Settings, }; -use gpui::{MutableAppContext, Task}; -use parking_lot::Mutex; -use postage::{prelude::Stream, sink::Sink, watch}; +use gpui::{Entity, ModelContext, Task}; use smol::future::yield_now; use std::{collections::VecDeque, ops::Range, sync::Arc, time::Duration}; -#[derive(Clone)] -pub struct WrapMap(Arc>); - -struct WrapMapState { +pub struct WrapMap { snapshot: Snapshot, pending_edits: VecDeque<(TabSnapshot, Vec)>, wrap_width: Option, background_task: Option>, - updates: (watch::Sender<()>, watch::Receiver<()>), line_wrapper: Arc, } +impl Entity for WrapMap { + type Event = (); +} + #[derive(Clone)] pub struct Snapshot { tab_snapshot: TabSnapshot, @@ -78,12 +76,11 @@ impl WrapMap { tab_snapshot: TabSnapshot, settings: Settings, wrap_width: Option, - cx: &mut MutableAppContext, + cx: &mut ModelContext, ) -> Self { - let this = Self(Arc::new(Mutex::new(WrapMapState { + let mut this = Self { background_task: None, wrap_width: None, - updates: watch::channel(), pending_edits: Default::default(), snapshot: Snapshot::new(tab_snapshot), line_wrapper: Arc::new(LineWrapper::new( @@ -91,49 +88,38 @@ impl WrapMap { cx.font_cache(), settings, )), - }))); + }; this.set_wrap_width(wrap_width, cx); this } #[cfg(test)] pub fn is_rewrapping(&self) -> bool { - self.0.lock().background_task.is_some() - } - - pub fn notifications(&self) -> impl Stream { - let state = self.0.lock(); - let mut rx = state.updates.1.clone(); - // The first item in the stream always returns what's stored on the watch, but we only want - // to receive notifications occurring after calling this method, so we discard the first - // item. - let _ = rx.blocking_recv(); - rx + self.background_task.is_some() } pub fn sync( - &self, + &mut self, tab_snapshot: TabSnapshot, edits: Vec, - cx: &mut MutableAppContext, + cx: &mut ModelContext, ) -> Snapshot { - self.0.lock().pending_edits.push_back((tab_snapshot, edits)); + self.pending_edits.push_back((tab_snapshot, edits)); self.flush_edits(cx); - self.0.lock().snapshot.clone() + self.snapshot.clone() } - pub fn set_wrap_width(&self, wrap_width: Option, cx: &mut MutableAppContext) -> bool { - let mut state = self.0.lock(); - if wrap_width == state.wrap_width { + pub fn set_wrap_width(&mut self, wrap_width: Option, cx: &mut ModelContext) -> bool { + if wrap_width == self.wrap_width { return false; } - state.wrap_width = wrap_width; - state.background_task.take(); + self.wrap_width = wrap_width; + self.background_task.take(); if let Some(wrap_width) = wrap_width { - let mut new_snapshot = state.snapshot.clone(); - let line_wrapper = state.line_wrapper.clone(); + let mut new_snapshot = self.snapshot.clone(); + let line_wrapper = self.line_wrapper.clone(); let task = cx.background().spawn(async move { let tab_snapshot = new_snapshot.tab_snapshot.clone(); let range = TabPoint::zero()..tab_snapshot.max_point(); @@ -156,19 +142,17 @@ impl WrapMap { .block_with_timeout(Duration::from_millis(5), task) { Ok(snapshot) => { - state.snapshot = snapshot; + self.snapshot = snapshot; } Err(wrap_task) => { - let this = self.clone(); - state.background_task = Some(cx.spawn(|mut cx| async move { + self.background_task = Some(cx.spawn(|this, mut cx| async move { let snapshot = wrap_task.await; - { - let mut state = this.0.lock(); - state.snapshot = snapshot; - state.background_task = None; - } - cx.update(|cx| this.flush_edits(cx)); - this.0.lock().updates.0.blocking_send(()).ok(); + this.update(&mut cx, |this, cx| { + this.snapshot = snapshot; + this.background_task = None; + this.flush_edits(cx); + cx.notify(); + }); })); } } @@ -177,26 +161,24 @@ impl WrapMap { true } - fn flush_edits(&self, cx: &mut MutableAppContext) { - let mut state = self.0.lock(); - - while let Some((tab_snapshot, _)) = state.pending_edits.front() { - if tab_snapshot.version() <= state.snapshot.tab_snapshot.version() { - state.pending_edits.pop_front(); + fn flush_edits(&mut self, cx: &mut ModelContext) { + while let Some((tab_snapshot, _)) = self.pending_edits.front() { + if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() { + self.pending_edits.pop_front(); } else { break; } } - if state.pending_edits.is_empty() { + if self.pending_edits.is_empty() { return; } - if let Some(wrap_width) = state.wrap_width { - if state.background_task.is_none() { - let pending_edits = state.pending_edits.clone(); - let mut snapshot = state.snapshot.clone(); - let line_wrapper = state.line_wrapper.clone(); + if let Some(wrap_width) = self.wrap_width { + if self.background_task.is_none() { + let pending_edits = self.pending_edits.clone(); + let mut snapshot = self.snapshot.clone(); + let line_wrapper = self.line_wrapper.clone(); let update_task = cx.background().spawn(async move { for (tab_snapshot, edits) in pending_edits { @@ -212,35 +194,33 @@ impl WrapMap { .block_with_timeout(Duration::from_micros(500), update_task) { Ok(snapshot) => { - state.snapshot = snapshot; + self.snapshot = snapshot; } Err(update_task) => { - let this = self.clone(); - state.background_task = Some(cx.spawn(|mut cx| async move { + self.background_task = Some(cx.spawn(|this, mut cx| async move { let snapshot = update_task.await; - { - let mut state = this.0.lock(); - state.snapshot = snapshot; - state.background_task = None; - } - cx.update(|cx| this.flush_edits(cx)); - this.0.lock().updates.0.blocking_send(()).ok(); + this.update(&mut cx, |this, cx| { + this.snapshot = snapshot; + this.background_task = None; + this.flush_edits(cx); + cx.notify(); + }); })); } } } } - while let Some((tab_snapshot, _)) = state.pending_edits.front() { - if tab_snapshot.version() <= state.snapshot.tab_snapshot.version() { - state.pending_edits.pop_front(); + while let Some((tab_snapshot, _)) = self.pending_edits.front() { + if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() { + self.pending_edits.pop_front(); } else { break; } } - for (tab_snapshot, edits) in state.pending_edits.clone() { - state.snapshot.interpolate(tab_snapshot, &edits); + for (tab_snapshot, edits) in self.pending_edits.clone() { + self.snapshot.interpolate(tab_snapshot, &edits); } } } @@ -769,7 +749,9 @@ mod tests { }, util::RandomCharIter, }; + use gpui::ModelHandle; use rand::prelude::*; + use smol::channel; use std::env; #[gpui::test] @@ -816,7 +798,7 @@ mod tests { folds_snapshot.text() ); log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text()); - let wrap_map = cx.update(|cx| { + let wrap_map = cx.add_model(|cx| { WrapMap::new( tabs_snapshot.clone(), settings.clone(), @@ -824,17 +806,18 @@ mod tests { cx, ) }); - let mut notifications = wrap_map.notifications(); + let (_observer, notifications) = Observer::new(&wrap_map, &mut cx); let mut line_wrapper = LineWrapper::new(font_system, &font_cache, settings); let unwrapped_text = tabs_snapshot.text(); let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper); - if wrap_map.is_rewrapping() { - notifications.recv().await; + if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) { + notifications.recv().await.unwrap(); } - let snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx)); + let snapshot = + wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx)); let actual_text = snapshot.text(); assert_eq!( actual_text, expected_text, @@ -858,12 +841,15 @@ mod tests { let unwrapped_text = tabs_snapshot.text(); let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper); - let mut snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot.clone(), edits, cx)); + let mut snapshot = wrap_map.update(&mut cx, |map, cx| { + map.sync(tabs_snapshot.clone(), edits, cx) + }); snapshot.check_invariants(&mut rng); - if wrap_map.is_rewrapping() { - notifications.recv().await; - snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx)); + if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) { + notifications.recv().await.unwrap(); + snapshot = + wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx)); } snapshot.check_invariants(&mut rng); @@ -952,4 +938,26 @@ mod tests { } } } + + struct Observer; + + impl Entity for Observer { + type Event = (); + } + + impl Observer { + fn new( + handle: &ModelHandle, + cx: &mut gpui::TestAppContext, + ) -> (ModelHandle, channel::Receiver<()>) { + let (notify_tx, notify_rx) = channel::unbounded(); + let observer = cx.add_model(|cx| { + cx.observe(handle, move |_, _, _| { + let _ = notify_tx.try_send(()); + }); + Observer + }); + (observer, notify_rx) + } + } }