diff --git a/Cargo.lock b/Cargo.lock index 3554c220c2711ea736bef591f1d023b12b2b7be8..99b7f650c000a26f42d43b8da496578573dfe1dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6005,7 +6005,7 @@ dependencies = [ "node_runtime", "parking_lot 0.11.2", "postage", - "prettier", + "prettier2", "pretty_assertions", "rand 0.8.5", "regex", diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 8c69330074c83583239542a4c87f5084bc2f58d6..ad7318d5297aad6c8ee82fb19f112600923383aa 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -316,6 +316,9 @@ impl AppContext { Effect::NotifyGlobalObservers { global_type } => { self.apply_notify_global_observers_effect(global_type); } + Effect::Defer { callback } => { + self.apply_defer_effect(callback); + } } } else { break; @@ -436,6 +439,10 @@ impl AppContext { .retain(&type_id, |observer| observer(self)); } + fn apply_defer_effect(&mut self, callback: Box) { + callback(self); + } + pub fn to_async(&self) -> AsyncAppContext { AsyncAppContext { app: unsafe { mem::transmute(self.this.clone()) }, @@ -496,6 +503,12 @@ impl AppContext { }) } + pub fn defer(&mut self, f: impl FnOnce(&mut AppContext) + 'static + Send + Sync) { + self.push_effect(Effect::Defer { + callback: Box::new(f), + }); + } + pub fn text_system(&self) -> &Arc { &self.text_system } @@ -772,6 +785,9 @@ pub(crate) enum Effect { NotifyGlobalObservers { global_type: TypeId, }, + Defer { + callback: Box, + }, } pub(crate) struct AnyDrag { diff --git a/crates/project2/Cargo.toml b/crates/project2/Cargo.toml index e953faaf2fe2e72ca8ba565a94b03dc9691064fc..2109d596b5575de8b780c1fd882165115c3115b1 100644 --- a/crates/project2/Cargo.toml +++ b/crates/project2/Cargo.toml @@ -15,7 +15,7 @@ test-support = [ "language2/test-support", "settings2/test-support", "text/test-support", - "prettier/test-support", + "prettier2/test-support", ] [dependencies] @@ -33,7 +33,7 @@ gpui2 = { path = "../gpui2" } language2 = { path = "../language2" } lsp2 = { path = "../lsp2" } node_runtime = { path = "../node_runtime" } -prettier = { path = "../prettier" } +prettier2 = { path = "../prettier2" } rpc = { path = "../rpc" } settings2 = { path = "../settings2" } sum_tree = { path = "../sum_tree" } @@ -76,7 +76,7 @@ gpui2 = { path = "../gpui2", features = ["test-support"] } language2 = { path = "../language2", features = ["test-support"] } lsp2 = { path = "../lsp2", features = ["test-support"] } settings2 = { path = "../settings2", features = ["test-support"] } -prettier = { path = "../prettier", features = ["test-support"] } +prettier2 = { path = "../prettier2", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } rpc = { path = "../rpc", features = ["test-support"] } git2.workspace = true diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 066cf80e04a0bf16866e2623878c5824f4144e93..ea8f6bf1a4107f11c99cee1e199ab54e539fff6d 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -26,8 +26,8 @@ use futures::{ }; use globset::{Glob, GlobSet, GlobSetBuilder}; use gpui2::{ - AnyHandle, AppContext, AsyncAppContext, EventEmitter, Executor, Handle, ModelContext, Task, - WeakHandle, + AnyHandle, AppContext, AsyncAppContext, Context, EventEmitter, Executor, Handle, ModelContext, + Task, WeakHandle, }; use itertools::Itertools; use language2::{ @@ -53,7 +53,7 @@ use lsp2::{ use lsp_command::*; use node_runtime::NodeRuntime; use postage::watch; -use prettier::{LocateStart, Prettier, PRETTIER_SERVER_FILE, PRETTIER_SERVER_JS}; +use prettier2::{LocateStart, Prettier, PRETTIER_SERVER_FILE, PRETTIER_SERVER_JS}; use project_settings::{LspSettings, ProjectSettings}; use rand::prelude::*; use search::SearchQuery; @@ -186,7 +186,7 @@ impl DelayedDebounced { fn fire_new(&mut self, delay: Duration, cx: &mut ModelContext, func: F) where - F: 'static + FnOnce(&mut Project, &mut ModelContext) -> Task<()>, + F: 'static + Send + FnOnce(&mut Project, &mut ModelContext) -> Task<()>, { if let Some(channel) = self.cancel_channel.take() { _ = channel.send(()); @@ -256,7 +256,7 @@ enum ProjectClientState { Local { remote_id: u64, updates_tx: mpsc::UnboundedSender, - _send_updates: Task<()>, + _send_updates: Task>, }, Remote { sharing_has_stopped: bool, @@ -702,14 +702,13 @@ impl Project { let mut worktrees = Vec::new(); for worktree in response.payload.worktrees { - let worktree = cx.update(|cx| { - Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx) - }); + let worktree = + Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx); worktrees.push(worktree); } let (tx, rx) = mpsc::unbounded(); - cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx)) + cx.spawn(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx)) .detach(); let copilot_lsp_subscription = Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx)); @@ -1402,26 +1401,25 @@ impl Project { updates_tx, _send_updates: cx.spawn(move |this, mut cx| async move { while let Some(update) = updates_rx.next().await { - let Some(this) = this.upgrade() else { break }; - match update { LocalProjectUpdate::WorktreesChanged => { - let worktrees = - this.read(&cx, |this, cx| this.worktrees(cx).collect::>()); + let worktrees = this.update(&mut cx, |this, cx| { + this.worktrees(cx).collect::>() + })?; let update_project = this - .read(&cx, |this, cx| { + .update(&mut cx, |this, cx| { this.client.request(proto::UpdateProject { project_id, worktrees: this.worktree_metadata_protos(cx), }) - }) + })? .await; if update_project.is_ok() { for worktree in worktrees { worktree.update(&mut cx, |worktree, cx| { let worktree = worktree.as_local_mut().unwrap(); worktree.share(project_id, cx).detach_and_log_err(cx) - }); + })?; } } } @@ -1439,7 +1437,7 @@ impl Project { } else { None } - }); + })?; let Some(buffer) = buffer else { continue }; let operations = @@ -1481,6 +1479,7 @@ impl Project { } } } + Ok(()) }), }); @@ -2169,26 +2168,26 @@ impl Project { this: WeakHandle, rx: UnboundedReceiver, mut cx: AsyncAppContext, - ) -> Option<()> { + ) -> Result<()> { const MAX_BATCH_SIZE: usize = 128; let mut operations_by_buffer_id = HashMap::default(); async fn flush_operations( - this: &Handle, + this: &WeakHandle, operations_by_buffer_id: &mut HashMap>, needs_resync_with_host: &mut bool, is_local: bool, - cx: &AsyncAppContext, - ) { + cx: &mut AsyncAppContext, + ) -> Result<()> { for (buffer_id, operations) in operations_by_buffer_id.drain() { - let request = this.read(cx, |this, _| { + let request = this.update(cx, |this, _| { let project_id = this.remote_id()?; Some(this.client.request(proto::UpdateBuffer { buffer_id, project_id, operations, })) - }); + })?; if let Some(request) = request { if request.await.is_err() && !is_local { *needs_resync_with_host = true; @@ -2196,14 +2195,14 @@ impl Project { } } } + Ok(()) } let mut needs_resync_with_host = false; let mut changes = rx.ready_chunks(MAX_BATCH_SIZE); while let Some(changes) = changes.next().await { - let this = this.upgrade()?; - let is_local = this.read(&cx, |this, _| this.is_local()); + let is_local = this.update(&mut cx, |this, _| this.is_local())?; for change in changes { match change { @@ -2224,7 +2223,7 @@ impl Project { BufferOrderedMessage::Resync => { operations_by_buffer_id.clear(); if this - .update(&mut cx, |this, cx| this.synchronize_remote_buffers(cx)) + .update(&mut cx, |this, cx| this.synchronize_remote_buffers(cx))? .await .is_ok() { @@ -2241,11 +2240,11 @@ impl Project { &mut operations_by_buffer_id, &mut needs_resync_with_host, is_local, - &cx, + &mut cx, ) .await; - this.read(&cx, |this, _| { + this.update(&mut cx, |this, _| { if let Some(project_id) = this.remote_id() { this.client .send(proto::UpdateLanguageServer { @@ -2265,12 +2264,12 @@ impl Project { &mut operations_by_buffer_id, &mut needs_resync_with_host, is_local, - &cx, + &mut cx, ) .await; } - None + Ok(()) } fn on_buffer_event( @@ -2432,7 +2431,7 @@ impl Project { const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1); - let task = cx.spawn_weak(|this, mut cx| async move { + let task = cx.spawn(|this, mut cx| async move { cx.executor().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await; if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, cx| { @@ -7065,7 +7064,7 @@ impl Project { } let buffer_id = state.id; - let buffer = cx.add_model(|_| { + let buffer = cx.entity(|_| { Buffer::from_proto(this.replica_id(), state, buffer_file).unwrap() }); this.incomplete_remote_buffers @@ -7169,7 +7168,7 @@ impl Project { mut cx: AsyncAppContext, ) -> Result { let buffer_id = envelope.payload.buffer_id; - let (project_id, buffer) = this.update(&mut cx, |this, cx| { + let (project_id, buffer) = this.update(&mut cx, |this, _cx| { let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?; let buffer = this .opened_buffers @@ -7339,12 +7338,12 @@ impl Project { } let trigger = FormatTrigger::from_proto(envelope.payload.trigger); Ok::<_, anyhow::Error>(this.format(buffers, false, trigger, cx)) - })?; + })??; let project_transaction = format.await?; let project_transaction = this.update(&mut cx, |this, cx| { this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx) - }); + })?; Ok(proto::FormatBuffersResponse { transaction: Some(project_transaction), }) @@ -7371,13 +7370,13 @@ impl Project { language.cloned(), ); Ok::<_, anyhow::Error>((buffer, completion)) - })?; + })??; let completion = completion.await?; let apply_additional_edits = this.update(&mut cx, |this, cx| { this.apply_additional_edits_for_completion(buffer, completion, false, cx) - }); + })?; Ok(proto::ApplyCompletionAdditionalEditsResponse { transaction: apply_additional_edits @@ -7407,12 +7406,12 @@ impl Project { .and_then(|buffer| buffer.upgrade()) .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?; Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx)) - })?; + })??; let project_transaction = apply_code_action.await?; let project_transaction = this.update(&mut cx, |this, cx| { this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx) - }); + })?; Ok(proto::ApplyCodeActionResponse { transaction: Some(project_transaction), }) @@ -7441,7 +7440,7 @@ impl Project { envelope.payload.trigger.clone(), cx, )) - })?; + })??; let transaction = on_type_formatting .await? @@ -7462,13 +7461,13 @@ impl Project { .get(&envelope.payload.buffer_id) .and_then(|buffer| buffer.upgrade()) .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id)) - })?; + })??; let buffer_version = deserialize_version(&envelope.payload.version); buffer .update(&mut cx, |buffer, _| { buffer.wait_for_version(buffer_version.clone()) - }) + })? .await .with_context(|| { format!( @@ -7557,12 +7556,12 @@ impl Project { { let sender_id = envelope.original_sender_id()?; let buffer_id = T::buffer_id_from_proto(&envelope.payload); - let buffer_handle = this.read(&cx, |this, _| { + let buffer_handle = this.update(&mut cx, |this, _cx| { this.opened_buffers .get(&buffer_id) - .and_then(|buffer| buffer.upgrade(&cx)) + .and_then(|buffer| buffer.upgrade()) .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id)) - })?; + })??; let request = T::from_proto( envelope.payload, this.clone(), @@ -7570,11 +7569,11 @@ impl Project { cx.clone(), ) .await?; - let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version()); + let buffer_version = buffer_handle.update(&mut cx, |buffer, _| buffer.version())?; let response = this .update(&mut cx, |this, cx| { this.request_lsp(buffer_handle, LanguageServerToQuery::Primary, request, cx) - }) + })? .await?; this.update(&mut cx, |this, cx| { Ok(T::response_to_proto( @@ -7584,7 +7583,7 @@ impl Project { &buffer_version, cx, )) - }) + })? } async fn handle_get_project_symbols( diff --git a/crates/project2/src/worktree.rs b/crates/project2/src/worktree.rs index fe621fdccb49df939d539f9799f2d910020057a8..b8e75bb22813071640cbf2ccbe8ca646f1953227 100644 --- a/crates/project2/src/worktree.rs +++ b/crates/project2/src/worktree.rs @@ -399,14 +399,14 @@ impl Worktree { }) } - pub fn remote( + pub fn remote( project_remote_id: u64, replica_id: ReplicaId, worktree: proto::WorktreeMetadata, client: Arc, cx: &mut AppContext, ) -> Handle { - cx.add_model(|cx: &mut ModelContext| { + cx.entity(|cx: &mut ModelContext| { let snapshot = Snapshot { id: WorktreeId(worktree.id as usize), abs_path: Arc::from(PathBuf::from(worktree.abs_path)),