From 1ba9e4827128e5f386aa3da62f9ffdf29c75ef3f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 16 Jul 2021 17:53:23 +0200 Subject: [PATCH] Start on adding a randomized test for `BackgroundWrapper` Co-Authored-By: Nathan Sobo --- gpui/src/app.rs | 24 +++--- gpui/src/lib.rs | 2 +- zed/src/editor/display_map.rs | 4 +- zed/src/editor/display_map/wrap_map.rs | 111 +++++++++++++++++++++---- 4 files changed, 111 insertions(+), 30 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index b356a883f6..edb0f17dc1 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -147,7 +147,7 @@ impl App { let cx = app.0.clone(); foreground_platform.on_menu_command(Box::new(move |command, arg| { let mut cx = cx.borrow_mut(); - if let Some(key_window_id) = cx.platform.key_window_id() { + if let Some(key_window_id) = cx.cx.platform.key_window_id() { if let Some((presenter, _)) = cx.presenters_and_platform_windows.get(&key_window_id) { let presenter = presenter.clone(); @@ -374,7 +374,7 @@ impl TestAppContext { } pub fn platform(&self) -> Arc { - self.cx.borrow().platform.clone() + self.cx.borrow().cx.platform.clone() } pub fn foreground(&self) -> Rc { @@ -566,7 +566,6 @@ type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext); pub struct MutableAppContext { weak_self: Option>>, foreground_platform: Rc, - platform: Arc, assets: Arc, cx: AppContext, actions: HashMap>>>, @@ -598,7 +597,6 @@ impl MutableAppContext { Self { weak_self: None, foreground_platform, - platform, assets: Arc::new(AssetCache::new(asset_source)), cx: AppContext { models: Default::default(), @@ -608,6 +606,7 @@ impl MutableAppContext { ref_counts: Arc::new(Mutex::new(RefCounts::default())), background, font_cache: Arc::new(FontCache::new(fonts)), + platform, }, actions: HashMap::new(), global_actions: HashMap::new(), @@ -631,7 +630,7 @@ impl MutableAppContext { } pub fn platform(&self) -> Arc { - self.platform.clone() + self.cx.platform.clone() } pub fn font_cache(&self) -> &Arc { @@ -992,7 +991,7 @@ impl MutableAppContext { } fn open_platform_window(&mut self, window_id: usize) { - let mut window = self.platform.open_window( + let mut window = self.cx.platform.open_window( window_id, WindowOptions { bounds: RectF::new(vec2f(0., 0.), vec2f(1024., 768.)), @@ -1000,7 +999,7 @@ impl MutableAppContext { }, self.foreground.clone(), ); - let text_layout_cache = TextLayoutCache::new(self.platform.fonts()); + let text_layout_cache = TextLayoutCache::new(self.cx.platform.fonts()); let presenter = Rc::new(RefCell::new(Presenter::new( window_id, self.cx.font_cache.clone(), @@ -1387,11 +1386,11 @@ impl MutableAppContext { } pub fn write_to_clipboard(&self, item: ClipboardItem) { - self.platform.write_to_clipboard(item); + self.cx.platform.write_to_clipboard(item); } pub fn read_from_clipboard(&self) -> Option { - self.platform.read_from_clipboard() + self.cx.platform.read_from_clipboard() } } @@ -1485,6 +1484,7 @@ pub struct AppContext { background: Arc, ref_counts: Arc>, font_cache: Arc, + platform: Arc, } impl AppContext { @@ -1524,10 +1524,14 @@ impl AppContext { &self.background } - pub fn font_cache(&self) -> &FontCache { + pub fn font_cache(&self) -> &Arc { &self.font_cache } + pub fn platform(&self) -> &Arc { + &self.platform + } + pub fn value(&self, id: usize) -> ValueHandle { let key = (TypeId::of::(), id); let mut values = self.values.write(); diff --git a/gpui/src/lib.rs b/gpui/src/lib.rs index b8f77bcebd..955d35e7e0 100644 --- a/gpui/src/lib.rs +++ b/gpui/src/lib.rs @@ -25,7 +25,7 @@ pub mod json; pub mod keymap; mod platform; pub use gpui_macros::test; -pub use platform::{Event, PathPromptOptions, Platform, PromptLevel}; +pub use platform::{Event, FontSystem, PathPromptOptions, Platform, PromptLevel}; pub use presenter::{ AfterLayoutContext, Axis, DebugContext, EventContext, LayoutContext, PaintContext, SizeConstraint, Vector2FExt, diff --git a/zed/src/editor/display_map.rs b/zed/src/editor/display_map.rs index adabf3f177..24fbbc4cd6 100644 --- a/zed/src/editor/display_map.rs +++ b/zed/src/editor/display_map.rs @@ -21,7 +21,9 @@ impl DisplayMap { let fold_map = FoldMap::new(buffer.clone(), cx); let (snapshot, edits) = fold_map.read(cx); assert_eq!(edits.len(), 0); - let wrap_map = WrapMap::new(snapshot, cx); + // TODO: take `wrap_width` as a parameter. + let config = { todo!() }; + let wrap_map = WrapMap::new(snapshot, config, cx); DisplayMap { buffer, fold_map, diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index bf8a20f587..07822833c3 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use crate::{ editor::{display_map::fold_map, Point, TextSummary}, + settings::Settings, sum_tree::{self, SumTree}, util::Bias, }; -use gpui::{AppContext, Task}; +use gpui::{font_cache::FamilyId, AppContext, FontCache, FontSystem, Task}; use parking_lot::Mutex; use postage::{prelude::Sink, watch}; use smol::channel; @@ -19,6 +22,12 @@ struct State { interpolated_version: usize, } +pub struct Config { + pub wrap_width: f32, + pub font_family: FamilyId, + pub font_size: f32, +} + pub struct WrapMap { state: Mutex, edits_tx: channel::Sender<(fold_map::Snapshot, Vec)>, @@ -27,7 +36,9 @@ pub struct WrapMap { } impl WrapMap { - pub fn new(folds_snapshot: fold_map::Snapshot, cx: &AppContext) -> Self { + pub fn new(folds_snapshot: fold_map::Snapshot, config: Config, cx: &AppContext) -> Self { + let font_cache = cx.font_cache().clone(); + let font_system = cx.platform().fonts(); let snapshot = Snapshot { transforms: SumTree::from_item( Transform { @@ -45,8 +56,10 @@ impl WrapMap { watch::channel_with(snapshot.clone()); let (edits_tx, edits_rx) = channel::unbounded(); let background_task = cx.background().spawn(async move { - let mut wrapper = BackgroundWrapper::new(edits_rx, background_snapshots_tx); - wrapper.run(folds_snapshot).await; + let mut wrapper = BackgroundWrapper::new(config, font_cache, font_system); + wrapper + .run(folds_snapshot, edits_rx, background_snapshots_tx) + .await; }); Self { @@ -68,19 +81,18 @@ impl WrapMap { } struct BackgroundWrapper { - edits_rx: channel::Receiver<(fold_map::Snapshot, Vec)>, - snapshots_tx: watch::Sender, + config: Config, + font_cache: Arc, + font_system: Arc, snapshot: Snapshot, } impl BackgroundWrapper { - fn new( - edits_rx: channel::Receiver<(fold_map::Snapshot, Vec)>, - snapshots_tx: watch::Sender, - ) -> Self { + fn new(config: Config, font_cache: Arc, font_system: Arc) -> Self { Self { - edits_rx, - snapshots_tx, + config, + font_cache, + font_system, snapshot: Snapshot { transforms: Default::default(), version: Default::default(), @@ -88,23 +100,30 @@ impl BackgroundWrapper { } } - async fn run(&mut self, snapshot: fold_map::Snapshot) { + async fn run( + &mut self, + snapshot: fold_map::Snapshot, + edits_rx: channel::Receiver<(fold_map::Snapshot, Vec)>, + mut snapshots_tx: watch::Sender, + ) { let edit = fold_map::Edit { old_bytes: 0..0, new_bytes: 0..snapshot.len(), }; - if !self.sync(snapshot, vec![edit]).await { + self.sync(snapshot, vec![edit]); + if snapshots_tx.send(self.snapshot.clone()).await.is_err() { return; } - while let Ok((snapshot, edits)) = self.edits_rx.recv().await { - if !self.sync(snapshot, edits).await { + while let Ok((snapshot, edits)) = edits_rx.recv().await { + self.sync(snapshot, edits); + if snapshots_tx.send(self.snapshot.clone()).await.is_err() { break; } } } - async fn sync(&mut self, snapshot: fold_map::Snapshot, edits: Vec) -> bool { + fn sync(&mut self, snapshot: fold_map::Snapshot, edits: Vec) { let mut new_transforms = SumTree::new(); { // let mut old_cursor = self.snapshot.transforms.cursor::(); @@ -118,7 +137,6 @@ impl BackgroundWrapper { self.snapshot.transforms = new_transforms; self.snapshot.version = snapshot.version; - self.snapshots_tx.send(self.snapshot.clone()).await.is_ok() } } @@ -156,3 +174,60 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point { *self += &summary.folded.lines; } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::editor::display_map::fold_map::FoldMap; + use crate::editor::{Buffer, ToPoint}; + use crate::util::RandomCharIter; + use rand::prelude::*; + use std::env; + use Bias::{Left, Right}; + + #[gpui::test] + fn test_random_folds(cx: &mut gpui::MutableAppContext) { + let iterations = env::var("ITERATIONS") + .map(|i| i.parse().expect("invalid `ITERATIONS` variable")) + .unwrap_or(100); + let operations = env::var("OPERATIONS") + .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + .unwrap_or(10); + let seed_range = if let Ok(seed) = env::var("SEED") { + let seed = seed.parse().expect("invalid `SEED` variable"); + seed..seed + 1 + } else { + 0..iterations + }; + + for seed in seed_range { + dbg!(seed); + let mut rng = StdRng::seed_from_u64(seed); + + let buffer = cx.add_model(|cx| { + let len = rng.gen_range(0..10); + let text = RandomCharIter::new(&mut rng).take(len).collect::(); + Buffer::new(0, text, cx) + }); + let fold_map = FoldMap::new(buffer.clone(), cx.as_ref()); + let (snapshot, _) = fold_map.read(cx.as_ref()); + let font_cache = cx.font_cache().clone(); + let font_system = cx.platform().fonts(); + let config = Config { + wrap_width: rng.gen_range(100.0..=1000.0), + font_family: font_cache.load_family(&["Helvetica"]).unwrap(), + font_size: 14.0, + }; + let mut wrapper = BackgroundWrapper::new(config, font_cache.clone(), font_system); + let edit = fold_map::Edit { + old_bytes: 0..0, + new_bytes: 0..snapshot.len(), + }; + wrapper.sync(snapshot, vec![edit]); + // for line in wrapper.snapshot.text().lines() { + // font_cache. + // } + // assert_eq!(wrap_map.snapshot().text()) + } + } +}