From aa3fb28f812f3ca8b702f6298fcb758673ab56be Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 21 Oct 2023 18:21:14 +0200 Subject: [PATCH] WIP --- crates/gpui2/src/app.rs | 50 ++++++++++++++------------ crates/gpui2/src/app/async_context.rs | 40 +++++++++++++++++++-- crates/gpui2/src/app/model_context.rs | 14 ++++++++ crates/gpui2/src/executor.rs | 5 +++ crates/gpui2/src/gpui2.rs | 28 +++++++++++++++ crates/gpui2/src/window.rs | 28 +++++++++++++++ crates/settings2/src/settings_file.rs | 27 +++++++------- crates/settings2/src/settings_store.rs | 9 +++-- crates/zed2/src/main.rs | 2 +- 9 files changed, 161 insertions(+), 42 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 19d95d2d14519c2c929df4b341482b5bc028d2e3..b1ede0ff2d9e579f05336acd654393a5fea64995 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -406,24 +406,6 @@ impl AppContext { .unwrap() } - pub fn update_global(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R - where - G: 'static + Send + Sync, - { - let mut global = self - .global_stacks_by_type - .get_mut(&TypeId::of::()) - .and_then(|stack| stack.pop()) - .ok_or_else(|| anyhow!("no state of type {} exists", type_name::())) - .unwrap(); - let result = f(global.downcast_mut().unwrap(), self); - self.global_stacks_by_type - .get_mut(&TypeId::of::()) - .unwrap() - .push(global); - result - } - pub fn default_global(&mut self) -> &mut G { let stack = self .global_stacks_by_type @@ -448,18 +430,20 @@ impl AppContext { } } - pub(crate) fn push_global(&mut self, state: T) { + pub(crate) fn push_global(&mut self, global: T) { self.global_stacks_by_type .entry(TypeId::of::()) .or_default() - .push(Box::new(state)); + .push(Box::new(global)); } - pub(crate) fn pop_global(&mut self) { + pub(crate) fn pop_global(&mut self) -> Box { self.global_stacks_by_type .get_mut(&TypeId::of::()) .and_then(|stack| stack.pop()) - .expect("state stack underflow"); + .expect("state stack underflow") + .downcast() + .unwrap() } pub(crate) fn push_text_style(&mut self, text_style: TextStyleRefinement) { @@ -497,6 +481,10 @@ impl Context for AppContext { type EntityContext<'a, 'w, T: Send + Sync + 'static> = ModelContext<'a, T>; type Result = T; + fn refresh(&mut self) { + self.push_effect(Effect::Refresh); + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, @@ -524,6 +512,24 @@ impl Context for AppContext { fn read_global(&self, read: impl FnOnce(&G, &Self) -> R) -> R { read(self.global(), self) } + + fn update_global(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R + where + G: 'static + Send + Sync, + { + let mut global = self + .global_stacks_by_type + .get_mut(&TypeId::of::()) + .and_then(|stack| stack.pop()) + .ok_or_else(|| anyhow!("no state of type {} exists", type_name::())) + .unwrap(); + let result = f(global.downcast_mut().unwrap(), self); + self.global_stacks_by_type + .get_mut(&TypeId::of::()) + .unwrap() + .push(global); + result + } } impl MainThread { diff --git a/crates/gpui2/src/app/async_context.rs b/crates/gpui2/src/app/async_context.rs index f4d1166b04cda4e514dd429de107e41b81ae8b93..c9a89a6bbafeeaa967f633174cf6114f9dad8841 100644 --- a/crates/gpui2/src/app/async_context.rs +++ b/crates/gpui2/src/app/async_context.rs @@ -13,6 +13,16 @@ impl Context for AsyncAppContext { type EntityContext<'a, 'w, T: 'static + Send + Sync> = ModelContext<'a, T>; type Result = Result; + fn refresh(&mut self) -> Self::Result<()> { + let app = self + .0 + .upgrade() + .ok_or_else(|| anyhow!("app was released"))?; + let mut lock = app.lock(); // Need this to compile + lock.refresh(); + Ok(()) + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, @@ -21,7 +31,7 @@ impl Context for AsyncAppContext { .0 .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); + let mut lock = app.lock(); // Need this to compile Ok(lock.entity(build_entity)) } @@ -34,7 +44,7 @@ impl Context for AsyncAppContext { .0 .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); + let mut lock = app.lock(); // Need this to compile Ok(lock.update_entity(handle, update)) } @@ -46,9 +56,21 @@ impl Context for AsyncAppContext { .0 .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); + let lock = app.lock(); // Need this to compile Ok(lock.read_global(read)) } + + fn update_global( + &mut self, + update: impl FnOnce(&mut G, &mut Self::BorrowedContext<'_, '_>) -> R, + ) -> Self::Result { + let app = self + .0 + .upgrade() + .ok_or_else(|| anyhow!("app was released"))?; + let mut lock = app.lock(); // Need this to compile + Ok(lock.update_global(update)) + } } impl AsyncAppContext { @@ -106,6 +128,10 @@ impl Context for AsyncWindowContext { type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>; type Result = Result; + fn refresh(&mut self) -> Self::Result<()> { + self.app.refresh() + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, R>) -> R, @@ -129,4 +155,12 @@ impl Context for AsyncWindowContext { ) -> Result { self.app.read_window(self.window, |cx| cx.read_global(read)) } + + fn update_global( + &mut self, + update: impl FnOnce(&mut G, &mut Self::BorrowedContext<'_, '_>) -> R, + ) -> Result { + self.app + .update_window(self.window, |cx| cx.update_global(update)) + } } diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index b4996880a653c2ec589456e6ccfedc29ebeca8c3..7318ecdc6518a3999be0dc8cb7babea66c5e5be0 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -136,6 +136,10 @@ impl<'a, T: 'static> Context for ModelContext<'a, T> { type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>; type Result = U; + fn refresh(&mut self) { + self.app.refresh(); + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U, @@ -157,4 +161,14 @@ impl<'a, T: 'static> Context for ModelContext<'a, T> { ) -> R { read(self.app.global(), self) } + + fn update_global(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R + where + G: 'static + Send + Sync, + { + let mut global = self.app.pop_global::(); + let result = f(global.as_mut(), self); + self.app.push_global(global); + result + } } diff --git a/crates/gpui2/src/executor.rs b/crates/gpui2/src/executor.rs index 6db06f03a551ec23331d4c00eebee9e5f42a60e3..802e62d7b338d48a6d4834d62a13aab824fed28a 100644 --- a/crates/gpui2/src/executor.rs +++ b/crates/gpui2/src/executor.rs @@ -128,6 +128,11 @@ impl Executor { Task::Spawned(task) } + pub fn block(&self, future: impl Future) -> R { + // todo!("integrate with deterministic dispatcher") + futures::executor::block_on(future) + } + pub fn is_main_thread(&self) -> bool { self.dispatcher.is_main_thread() } diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 0fb83007bcb8278a664861d60b61a2899db20d42..d25c563d34f44e9d0c4c629942214871f9a1a174 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -70,6 +70,8 @@ pub trait Context { type EntityContext<'a, 'w, T: 'static + Send + Sync>; type Result; + fn refresh(&mut self) -> Self::Result<()>; + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, @@ -85,6 +87,13 @@ pub trait Context { &self, read: impl FnOnce(&G, &Self::BorrowedContext<'_, '_>) -> R, ) -> Self::Result; + + fn update_global( + &mut self, + f: impl FnOnce(&mut G, &mut Self::BorrowedContext<'_, '_>) -> R, + ) -> Self::Result + where + G: 'static + Send + Sync; } pub enum GlobalKey { @@ -115,6 +124,10 @@ impl Context for MainThread { type EntityContext<'a, 'w, T: 'static + Send + Sync> = MainThread>; type Result = C::Result; + fn refresh(&mut self) -> Self::Result<()> { + self.0.refresh() + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, @@ -160,6 +173,21 @@ impl Context for MainThread { read(global, cx) }) } + + fn update_global( + &mut self, + update: impl FnOnce(&mut G, &mut Self::BorrowedContext<'_, '_>) -> R, + ) -> Self::Result { + self.0.update_global(|global, cx| { + let cx = unsafe { + mem::transmute::< + &mut C::BorrowedContext<'_, '_>, + &mut MainThread>, + >(cx) + }; + update(global, cx) + }) + } } pub trait BorrowAppContext { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 476898c60e23165994ba39cb647a4bd2d4c4f921..997513a5be175ddc83ef4b88dca8d99d1cfa057b 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1060,6 +1060,10 @@ impl Context for WindowContext<'_, '_> { type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>; type Result = T; + fn refresh(&mut self) { + self.app.refresh(); + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, @@ -1090,6 +1094,16 @@ impl Context for WindowContext<'_, '_> { fn read_global(&self, read: impl FnOnce(&G, &Self) -> R) -> R { read(self.app.global(), self) } + + fn update_global(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R + where + G: 'static + Send + Sync, + { + let mut global = self.app.pop_global::(); + let result = f(global.as_mut(), self); + self.app.push_global(global); + result + } } impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> { @@ -1540,6 +1554,10 @@ where type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>; type Result = U; + fn refresh(&mut self) { + self.app.refresh(); + } + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2, @@ -1561,6 +1579,16 @@ where ) -> R { read(self.global(), self) } + + fn update_global(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R + where + G: 'static + Send + Sync, + { + let mut global = self.app.pop_global::(); + let result = f(global.as_mut(), self); + self.app.push_global(global); + result + } } impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> { diff --git a/crates/settings2/src/settings_file.rs b/crates/settings2/src/settings_file.rs index c4b6b9bd1daeea30500dc282cdea812364ea34d5..936bcac0ad5178bbf4932bdc6588f86f2b773887 100644 --- a/crates/settings2/src/settings_file.rs +++ b/crates/settings2/src/settings_file.rs @@ -2,7 +2,7 @@ use crate::{settings_store::SettingsStore, Setting}; use anyhow::Result; use fs::Fs; use futures::{channel::mpsc, StreamExt}; -use gpui2::{AppContext, Context}; +use gpui2::{AppContext, Context, Executor}; use std::{ io::ErrorKind, path::{Path, PathBuf}, @@ -48,7 +48,7 @@ pub fn test_settings() -> String { } pub fn watch_config_file( - executor: Arc, + executor: &Executor, fs: Arc, path: PathBuf, ) -> mpsc::UnboundedReceiver { @@ -83,7 +83,7 @@ pub fn handle_settings_file_changes( mut user_settings_file_rx: mpsc::UnboundedReceiver, cx: &mut AppContext, ) { - let user_settings_content = cx.background().block(user_settings_file_rx.next()).unwrap(); + let user_settings_content = cx.executor().block(user_settings_file_rx.next()).unwrap(); cx.update_global(|store: &mut SettingsStore, cx| { store .set_user_settings(&user_settings_content, cx) @@ -91,14 +91,15 @@ pub fn handle_settings_file_changes( }); cx.spawn(move |mut cx| async move { while let Some(user_settings_content) = user_settings_file_rx.next().await { - cx.update(|cx| { - cx.update_global(|store: &mut SettingsStore, cx| { - store - .set_user_settings(&user_settings_content, cx) - .log_err(); - }); - cx.refresh_windows(); + let result = cx.update_global(|store: &mut SettingsStore, cx| { + store + .set_user_settings(&user_settings_content, cx) + .log_err(); + cx.refresh(); }); + if result.is_err() { + break; // App dropped + } } }) .detach(); @@ -124,10 +125,10 @@ pub fn update_settings_file( update: impl 'static + Send + FnOnce(&mut T::FileContent), ) { cx.spawn(|cx| async move { - let old_text = load_settings(&fs).await; - let new_text = cx.read_global(|store: &SettingsStore, cx| { + let old_text = load_settings(&fs).await?; + let new_text = cx.read_global(|store: &SettingsStore, _cx| { store.new_text_for_update::(old_text, update) - }); + })?; fs.atomic_write(paths::SETTINGS.clone(), new_text).await?; anyhow::Ok(()) }) diff --git a/crates/settings2/src/settings_store.rs b/crates/settings2/src/settings_store.rs index 354985a6861b6f40222c7d96208e184feb8c9479..af60fb9978cb62c76d4f89358d25762977f6b010 100644 --- a/crates/settings2/src/settings_store.rs +++ b/crates/settings2/src/settings_store.rs @@ -18,7 +18,7 @@ use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _}; /// A value that can be defined as a user setting. /// /// Settings can be loaded from a combination of multiple JSON files. -pub trait Setting: 'static { +pub trait Setting: 'static + Send + Sync { /// The name of a key within the JSON file from which this setting should /// be deserialized. If this is `None`, then the setting will be deserialized /// from the root object. @@ -89,7 +89,10 @@ pub struct SettingsStore { raw_default_settings: serde_json::Value, raw_user_settings: serde_json::Value, raw_local_settings: BTreeMap<(usize, Arc), serde_json::Value>, - tab_size_callback: Option<(TypeId, Box Option>)>, + tab_size_callback: Option<( + TypeId, + Box Option + Send + Sync + 'static>, + )>, } impl Default for SettingsStore { @@ -110,7 +113,7 @@ struct SettingValue { local_values: Vec<(usize, Arc, T)>, } -trait AnySettingValue { +trait AnySettingValue: 'static + Send + Sync { fn key(&self) -> Option<&'static str>; fn setting_type_name(&self) -> &'static str; fn deserialize_setting(&self, json: &serde_json::Value) -> Result; diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 4330f5af591a623f9111014e6587e8ea511ccd0f..1b6802ee5f16c6bd2e423f9f7fe345bc10d30265 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -14,7 +14,7 @@ use log::LevelFilter; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; -use settings::{default_settings, handle_settings_file_changes, watch_config_file, SettingsStore}; +use settings2::{default_settings, handle_settings_file_changes, watch_config_file, SettingsStore}; use simplelog::ConfigBuilder; use smol::process::Command; use std::{