diff --git a/gpui/src/executor.rs b/gpui/src/executor.rs index e437a9597f9a931f9e5b72484f41a7b11ae2618b..f9cb8edc44e21bf92e9084b82279f0b0bd26ebd5 100644 --- a/gpui/src/executor.rs +++ b/gpui/src/executor.rs @@ -9,6 +9,7 @@ use std::{ fmt::{self, Debug}, marker::PhantomData, mem, + ops::RangeInclusive, pin::Pin, rc::Rc, sync::{ @@ -46,6 +47,7 @@ struct DeterministicState { scheduled: Vec<(Runnable, Backtrace)>, spawned_from_foreground: Vec<(Runnable, Backtrace)>, forbid_parking: bool, + block_on_ticks: RangeInclusive, } pub struct Deterministic { @@ -62,6 +64,7 @@ impl Deterministic { scheduled: Default::default(), spawned_from_foreground: Default::default(), forbid_parking: false, + block_on_ticks: 0..=1000, })), parker: Default::default(), } @@ -330,13 +333,19 @@ impl Foreground { pub fn forbid_parking(&self) { match self { - Self::Platform { .. } => panic!("can't call this method on a platform executor"), - Self::Test(_) => panic!("can't call this method on a test executor"), Self::Deterministic(executor) => { let mut state = executor.state.lock(); state.forbid_parking = true; state.rng = StdRng::seed_from_u64(state.seed); } + _ => panic!("this method can only be called on a deterministic executor"), + } + } + + pub fn set_block_on_ticks(&self, range: RangeInclusive) { + match self { + Self::Deterministic(executor) => executor.state.lock().block_on_ticks = range, + _ => panic!("this method can only be called on a deterministic executor"), } } } @@ -386,7 +395,11 @@ impl Background { smol::block_on(async move { util::timeout(timeout, future).await.ok() }) } Self::Deterministic(executor) => { - let max_ticks = executor.state.lock().rng.gen_range(1..=1000); + let max_ticks = { + let mut state = executor.state.lock(); + let range = state.block_on_ticks.clone(); + state.rng.gen_range(range) + }; executor.block_on(max_ticks, future) } } diff --git a/zed/src/editor/display_map.rs b/zed/src/editor/display_map.rs index 60790cdb9bc8fee54762c596acb80fb932a06408..d19285be85850fd9731192cf79472d05aba51805 100644 --- a/zed/src/editor/display_map.rs +++ b/zed/src/editor/display_map.rs @@ -38,10 +38,12 @@ impl DisplayMap { pub fn snapshot(&self, cx: &AppContext) -> 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); DisplayMapSnapshot { buffer_snapshot: self.buffer.read(cx).snapshot(), folds_snapshot, tabs_snapshot, + wraps_snapshot, } } @@ -51,7 +53,11 @@ impl DisplayMap { cx: &AppContext, ) { let (mut fold_map, snapshot, edits) = self.fold_map.write(cx); - let edits = fold_map.fold(ranges, cx); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + self.wrap_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); } pub fn unfold( @@ -60,7 +66,11 @@ impl DisplayMap { cx: &AppContext, ) { let (mut fold_map, snapshot, edits) = self.fold_map.write(cx); - let edits = fold_map.unfold(ranges, cx); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + self.wrap_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); } pub fn set_wrap_width(&self, width: Option) { @@ -72,6 +82,7 @@ pub struct DisplayMapSnapshot { buffer_snapshot: buffer::Snapshot, folds_snapshot: fold_map::Snapshot, tabs_snapshot: tab_map::Snapshot, + wraps_snapshot: wrap_map::Snapshot, } impl DisplayMapSnapshot { @@ -80,11 +91,11 @@ impl DisplayMapSnapshot { } pub fn max_point(&self) -> DisplayPoint { - DisplayPoint(self.tabs_snapshot.max_point()) + DisplayPoint(self.wraps_snapshot.max_point()) } - pub fn chunks_at(&self, point: DisplayPoint) -> tab_map::Chunks { - self.tabs_snapshot.chunks_at(point.0) + pub fn chunks_at(&self, point: DisplayPoint) -> wrap_map::Chunks { + self.wraps_snapshot.chunks_at(point.0) } pub fn highlighted_chunks_for_rows(&mut self, rows: Range) -> tab_map::HighlightedChunks { @@ -122,7 +133,7 @@ impl DisplayMapSnapshot { } pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint { - DisplayPoint(self.tabs_snapshot.clip_point(point.0, bias)) + DisplayPoint(self.wraps_snapshot.clip_point(point.0, bias)) } pub fn folds_in_range<'a, T>( @@ -194,11 +205,11 @@ impl DisplayMapSnapshot { } #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] -pub struct DisplayPoint(tab_map::OutputPoint); +pub struct DisplayPoint(wrap_map::OutputPoint); impl DisplayPoint { pub fn new(row: u32, column: u32) -> Self { - Self(tab_map::OutputPoint::new(row, column)) + Self(wrap_map::OutputPoint::new(row, column)) } pub fn zero() -> Self { @@ -222,22 +233,24 @@ impl DisplayPoint { } pub fn to_buffer_point(self, map: &DisplayMapSnapshot, bias: Bias) -> Point { - map.folds_snapshot - .to_input_point(map.tabs_snapshot.to_input_point(self.0, bias).0) + let unwrapped_point = map.wraps_snapshot.to_input_point(self.0); + let unexpanded_point = map.tabs_snapshot.to_input_point(unwrapped_point, bias).0; + map.folds_snapshot.to_input_point(unexpanded_point) } pub fn to_buffer_offset(self, map: &DisplayMapSnapshot, bias: Bias) -> usize { - map.folds_snapshot - .to_input_offset(map.tabs_snapshot.to_input_point(self.0, bias).0) + let unwrapped_point = map.wraps_snapshot.to_input_point(self.0); + let unexpanded_point = map.tabs_snapshot.to_input_point(unwrapped_point, bias).0; + map.folds_snapshot.to_input_offset(unexpanded_point) } } impl Point { pub fn to_display_point(self, map: &DisplayMapSnapshot) -> DisplayPoint { - DisplayPoint( - map.tabs_snapshot - .to_output_point(map.folds_snapshot.to_output_point(self)), - ) + let folded_point = map.folds_snapshot.to_output_point(self); + let expanded_point = map.tabs_snapshot.to_output_point(folded_point); + let wrapped_point = map.wraps_snapshot.to_output_point(expanded_point); + DisplayPoint(wrapped_point) } } @@ -258,6 +271,48 @@ mod tests { use buffer::History; use std::sync::Arc; + #[gpui::test] + async fn test_soft_wraps(mut cx: gpui::TestAppContext) { + cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX); + + let font_cache = cx.font_cache(); + + let settings = Settings { + buffer_font_family: font_cache.load_family(&["Helvetica"]).unwrap(), + ui_font_family: font_cache.load_family(&["Helvetica"]).unwrap(), + buffer_font_size: 12.0, + ui_font_size: 12.0, + tab_size: 4, + theme: Arc::new(Theme::default()), + }; + let wrap_width = Some(64.); + + 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 snapshot = cx.read(|cx| map.snapshot(cx)); + assert_eq!( + snapshot + .chunks_at(DisplayPoint::new(0, 3)) + .collect::(), + " two \nthree four \nfive\nsix seven \neight" + ); + + buffer.update(&mut cx, |buffer, cx| { + let ix = buffer.text().find("seven").unwrap(); + buffer.edit(vec![ix..ix], "and ", cx); + }); + + let snapshot = cx.read(|cx| map.snapshot(cx)); + assert_eq!( + snapshot + .chunks_at(DisplayPoint::new(1, 0)) + .collect::(), + "three four \nfive\nsix and \nseven eight" + ); + } + #[gpui::test] fn test_chunks_at(cx: &mut gpui::MutableAppContext) { let text = sample_text(6, 6); diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 800fff06d1cef0fd2329bb9380c96def37a1dffe..ff88cde06fb68ac865a49a7f6d05757f57502f6e 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -14,7 +14,7 @@ use parking_lot::Mutex; use std::{ cmp::{self, Ordering}, iter, - ops::{Range, Sub}, + ops::Range, sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; @@ -47,14 +47,6 @@ impl OutputPoint { } } -impl Sub for OutputPoint { - type Output = OutputPoint; - - fn sub(self, other: Self) -> Self::Output { - Self(self.0 - other.0) - } -} - pub struct FoldMapWriter<'a>(&'a mut FoldMap); impl<'a> FoldMapWriter<'a> { @@ -906,8 +898,8 @@ impl<'a> Iterator for InputRows<'a> { } if self.cursor.item().is_some() { - let overshoot = self.output_point - *self.cursor.seek_start(); - let input_point = *self.cursor.sum_start() + overshoot.0; + let overshoot = self.output_point.0 - self.cursor.seek_start().0; + let input_point = *self.cursor.sum_start() + overshoot; *self.output_point.row_mut() += 1; Some(input_point.row) } else { diff --git a/zed/src/editor/display_map/tab_map.rs b/zed/src/editor/display_map/tab_map.rs index 5066dd1e77117cee0a27966bb01fc96d3fbdc677..41228d82bdf34d4ed60135561aea0651392404cb 100644 --- a/zed/src/editor/display_map/tab_map.rs +++ b/zed/src/editor/display_map/tab_map.rs @@ -5,10 +5,7 @@ use super::fold_map::{ OutputOffset as InputOffset, OutputPoint as InputPoint, Snapshot as InputSnapshot, }; use crate::{editor::rope, settings::StyleId, util::Bias}; -use std::{ - mem, - ops::{Add, AddAssign, Range}, -}; +use std::{mem, ops::Range}; pub struct TabMap(Mutex); @@ -268,20 +265,6 @@ impl From for OutputPoint { } } -impl AddAssign for OutputPoint { - fn add_assign(&mut self, rhs: Self) { - self.0 += &rhs.0; - } -} - -impl Add for OutputPoint { - type Output = OutputPoint; - - fn add(self, other: Self) -> Self::Output { - Self(self.0 + other.0) - } -} - #[derive(Clone, Debug, PartialEq, Eq)] pub struct Edit { pub old_lines: Range, diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index 1d436fe8ac6c1e98f41f033d2b406763ff07fdcd..8dfef04a112c04206ef5676b0c160b05694990b9 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -14,12 +14,7 @@ use postage::{ watch, }; use smol::channel; -use std::{ - collections::VecDeque, - ops::{AddAssign, Range, Sub}, - sync::Arc, - time::Duration, -}; +use std::{collections::VecDeque, ops::Range, sync::Arc, time::Duration}; #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] pub struct OutputPoint(super::Point); @@ -50,20 +45,6 @@ impl OutputPoint { } } -impl AddAssign for OutputPoint { - fn add_assign(&mut self, rhs: Self) { - self.0 += &rhs.0; - } -} - -impl Sub for OutputPoint { - type Output = OutputPoint; - - fn sub(self, other: Self) -> Self::Output { - Self(self.0 - other.0) - } -} - #[derive(Clone)] pub struct Snapshot { transforms: SumTree, @@ -145,10 +126,10 @@ impl Snapshot { } pub fn chunks_at(&self, point: OutputPoint) -> Chunks { - let mut transforms = self.transforms.cursor(); + let mut transforms = self.transforms.cursor::(); transforms.seek(&point, Bias::Right, &()); let input_position = - *transforms.sum_start() + InputPoint((point - *transforms.seek_start()).0); + InputPoint(transforms.sum_start().0 + (point.0 - transforms.seek_start().0)); let input_chunks = self.input.chunks_at(input_position); Chunks { input_chunks, @@ -157,6 +138,26 @@ impl Snapshot { input_chunk: "", } } + + pub fn max_point(&self) -> OutputPoint { + self.to_output_point(self.input.max_point()) + } + + pub fn to_input_point(&self, point: OutputPoint) -> InputPoint { + let mut cursor = self.transforms.cursor::(); + cursor.seek(&point, Bias::Right, &()); + InputPoint(cursor.sum_start().0 + (point.0 - cursor.seek_start().0)) + } + + pub fn to_output_point(&self, point: InputPoint) -> OutputPoint { + let mut cursor = self.transforms.cursor::(); + cursor.seek(&point, Bias::Right, &()); + OutputPoint(cursor.sum_start().0 + (point.0 - cursor.seek_start().0)) + } + + pub fn clip_point(&self, point: OutputPoint, bias: Bias) -> OutputPoint { + self.to_output_point(self.input.clip_point(self.to_input_point(point), bias)) + } } pub struct Chunks<'a> { @@ -558,13 +559,13 @@ impl sum_tree::Summary for TransformSummary { impl<'a> sum_tree::Dimension<'a, TransformSummary> for InputPoint { fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { - *self += InputPoint(summary.input.lines); + self.0 += summary.input.lines; } } impl<'a> sum_tree::Dimension<'a, TransformSummary> for OutputPoint { fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { - *self += OutputPoint(summary.output.lines); + self.0 += summary.output.lines; } } @@ -578,7 +579,6 @@ mod tests { }, util::RandomCharIter, }; - use futures::StreamExt; use gpui::fonts::FontId; use rand::prelude::*; use std::env;