diff --git a/crates/client2/src/user.rs b/crates/client2/src/user.rs index 43e484637688bccfd232ee11bb5752d5190dcb95..2aaae6dc8516db9c1793304405f771c9ac505a05 100644 --- a/crates/client2/src/user.rs +++ b/crates/client2/src/user.rs @@ -122,9 +122,9 @@ impl UserStore { let (mut current_user_tx, current_user_rx) = watch::channel(); let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded(); let rpc_subscriptions = vec![ - client.add_message_handler(cx.handle(), Self::handle_update_contacts), - client.add_message_handler(cx.handle(), Self::handle_update_invite_info), - client.add_message_handler(cx.handle(), Self::handle_show_contacts), + client.add_message_handler(cx.weak_handle(), Self::handle_update_contacts), + client.add_message_handler(cx.weak_handle(), Self::handle_update_invite_info), + client.add_message_handler(cx.weak_handle(), Self::handle_show_contacts), ]; Self { users: Default::default(), diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 86d2517817f90cbfc711580375ed50bf16f998ab..0b84cbe93ed997044429e2f3f92f3e504bdb1695 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -28,7 +28,13 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { self.entity_id } - pub fn handle(&self) -> WeakHandle { + pub fn handle(&self) -> Handle { + self.weak_handle() + .upgrade() + .expect("The entity must be alive if we have a model context") + } + + pub fn weak_handle(&self) -> WeakHandle { self.app.entities.weak_handle(self.entity_id) } @@ -37,7 +43,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { handle: &Handle, on_notify: impl Fn(&mut T, Handle, &mut ModelContext<'_, T>) + Send + Sync + 'static, ) -> Subscription { - let this = self.handle(); + let this = self.weak_handle(); let handle = handle.downgrade(); self.app.observers.insert( handle.entity_id, @@ -60,7 +66,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { + Sync + 'static, ) -> Subscription { - let this = self.handle(); + let this = self.weak_handle(); let handle = handle.downgrade(); self.app.event_listeners.insert( handle.entity_id, @@ -94,7 +100,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { handle: &Handle, on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static, ) -> Subscription { - let this = self.handle(); + let this = self.weak_handle(); self.app.release_listeners.insert( handle.entity_id, Box::new(move |entity, cx| { @@ -110,7 +116,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { &mut self, f: impl Fn(&mut T, &mut ModelContext<'_, T>) + Send + Sync + 'static, ) -> Subscription { - let handle = self.handle(); + let handle = self.weak_handle(); self.global_observers.insert( TypeId::of::(), Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()), @@ -124,7 +130,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { where Fut: 'static + Future + Send, { - let handle = self.handle(); + let handle = self.weak_handle(); self.app.quit_observers.insert( (), Box::new(move |cx| { @@ -165,7 +171,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { Fut: Future + Send + 'static, R: Send + 'static, { - let this = self.handle(); + let this = self.weak_handle(); self.app.spawn(|cx| f(this, cx)) } } diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 0064a1211e5de7f6fac23aabdbca603e0f3b7e94..8d8ec6e86c841de43fdd626512a0767b5d6b36fc 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -587,7 +587,7 @@ impl Project { client.add_model_request_handler(Self::handle_rename_project_entry); client.add_model_request_handler(Self::handle_copy_project_entry); client.add_model_request_handler(Self::handle_delete_project_entry); - client.add_model_request_handler(Self::handle_expand_project_entry); + client. m.,add_model_request_handler(Self::handle_expand_project_entry); client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion); client.add_model_request_handler(Self::handle_apply_code_action); client.add_model_request_handler(Self::handle_on_type_formatting); @@ -1400,16 +1400,16 @@ impl Project { self.client_state = Some(ProjectClientState::Local { remote_id: project_id, updates_tx, - _send_updates: cx.spawn_weak(move |this, mut cx| async move { + _send_updates: cx.spawn(move |this, mut cx| async move { while let Some(update) = updates_rx.next().await { - let Some(this) = this.upgrade(&cx) else { break }; + let Some(this) = this.upgrade() else { break }; match update { LocalProjectUpdate::WorktreesChanged => { - let worktrees = this - .read_with(&cx, |this, cx| this.worktrees(cx).collect::>()); + let worktrees = + this.read(&cx, |this, cx| this.worktrees(cx).collect::>()); let update_project = this - .read_with(&cx, |this, cx| { + .read(&cx, |this, cx| { this.client.request(proto::UpdateProject { project_id, worktrees: this.worktree_metadata_protos(cx), @@ -1668,7 +1668,7 @@ impl Project { return Err(anyhow!("creating buffers as a guest is not supported yet")); } let id = post_inc(&mut self.next_buffer_id); - let buffer = cx.add_model(|cx| { + let buffer = cx.entity(|cx| { Buffer::new(self.replica_id(), id, text).with_language( language.unwrap_or_else(|| language2::PLAIN_TEXT.clone()), cx, @@ -1687,7 +1687,7 @@ impl Project { cx.spawn_weak(|_, cx| async move { let buffer = task.await?; let project_entry_id = buffer - .read_with(&cx, |buffer, cx| { + .read(&cx, |buffer, cx| { File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx)) }) .ok_or_else(|| anyhow!("no project entry"))?; @@ -1821,7 +1821,7 @@ impl Project { .to_file_path() .map_err(|_| anyhow!("can't convert URI to path"))?; let (worktree, relative_path) = if let Some(result) = - this.read_with(&cx, |this, cx| this.find_local_worktree(&abs_path, cx)) + this.read(&cx, |this, cx| this.find_local_worktree(&abs_path, cx)) { result } else { @@ -2181,7 +2181,7 @@ impl Project { cx: &AsyncAppContext, ) { for (buffer_id, operations) in operations_by_buffer_id.drain() { - let request = this.read_with(cx, |this, _| { + let request = this.read(cx, |this, _| { let project_id = this.remote_id()?; Some(this.client.request(proto::UpdateBuffer { buffer_id, @@ -2203,7 +2203,7 @@ impl Project { while let Some(changes) = changes.next().await { let this = this.upgrade()?; - let is_local = this.read_with(&cx, |this, _| this.is_local()); + let is_local = this.read(&cx, |this, _| this.is_local()); for change in changes { match change { @@ -2245,7 +2245,7 @@ impl Project { ) .await; - this.read_with(&cx, |this, _| { + this.read(&cx, |this, _| { if let Some(project_id) = this.remote_id() { this.client .send(proto::UpdateLanguageServer { @@ -3359,14 +3359,14 @@ impl Project { } let mut stops = stops.into_iter(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { let (original_root_path, mut orphaned_worktrees) = stops.next().unwrap().await; for stop in stops { let (_, worktrees) = stop.await; orphaned_worktrees.extend_from_slice(&worktrees); } - let this = match this.upgrade(&cx) { + let this = match this.upgrade() { Some(this) => this, None => return, }; @@ -3719,7 +3719,7 @@ impl Project { .upgrade() .ok_or_else(|| anyhow!("project project closed"))?; let language_server = this - .read_with(&cx, |this, _| this.language_server_for_id(server_id)) + .read(&cx, |this, _| this.language_server_for_id(server_id)) .ok_or_else(|| anyhow!("language server not found"))?; let transaction = Self::deserialize_workspace_edit( this.clone(), @@ -4418,9 +4418,7 @@ impl Project { let stdout = String::from_utf8(output.stdout)?; Ok(Some( - buffer - .read_with(cx, |buffer, cx| buffer.diff(stdout, cx)) - .await, + buffer.read(cx, |buffer, cx| buffer.diff(stdout, cx)).await, )) } else { Ok(None) @@ -5120,7 +5118,7 @@ impl Project { language_server: Arc, cx: &mut AsyncAppContext, ) -> Result { - let fs = this.read_with(cx, |this, _| this.fs.clone()); + let fs = this.read(cx, |this, _| this.fs.clone()); let mut operations = Vec::new(); if let Some(document_changes) = edit.document_changes { match document_changes { @@ -5310,7 +5308,7 @@ impl Project { push_to_history: bool, cx: &mut ModelContext, ) -> Task>> { - let (position, tab_size) = buffer.read_with(cx, |buffer, cx| { + let (position, tab_size) = buffer.read(cx, |buffer, cx| { let position = position.to_point_utf16(buffer); ( position, @@ -5554,7 +5552,7 @@ impl Project { .iter() .filter_map(|(_, b)| { let buffer = b.upgrade()?; - let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot()); + let snapshot = buffer.read(cx, |buffer, _| buffer.snapshot()); if let Some(path) = snapshot.file().map(|file| file.path()) { Some((path.clone(), (buffer, snapshot))) } else { @@ -5857,16 +5855,13 @@ impl Project { ) -> Task::Response>> { let rpc = self.client.clone(); let message = request.to_proto(project_id, buffer.read(cx)); - cx.spawn_weak(|this, cx| async move { + cx.spawn(|this, cx| async move { // Ensure the project is still alive by the time the task // is scheduled. - this.upgrade(&cx) - .ok_or_else(|| anyhow!("project dropped"))?; + this.upgrade().context("project dropped")?; let response = rpc.request(message).await?; - let this = this - .upgrade(&cx) - .ok_or_else(|| anyhow!("project dropped"))?; - if this.read_with(&cx, |this, _| this.is_read_only()) { + let this = this.upgrade().context("project dropped")?; + if this.update(&mut cx, |this, _| this.is_read_only()) { Err(anyhow!("disconnected before completing request")) } else { request @@ -5908,12 +5903,12 @@ impl Project { SearchMatchCandidate::Path { worktree_id, path } => this .update(&mut cx, |this, cx| { this.open_buffer((worktree_id, path), cx) - }) + })? .await .log_err(), }; if let Some(buffer) = buffer { - let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot()); + let snapshot = buffer.read(&cx, |buffer, _| buffer.snapshot()); buffers_tx .send((Some((buffer, snapshot)), index)) .await @@ -6073,7 +6068,7 @@ impl Project { let handle_id = worktree.id(); cx.observe_release(worktree, move |this, worktree, cx| { let _ = this.remove_worktree(worktree.id(), cx); - cx.update_global::(|store, cx| { + cx.update_global::(|store, cx| { store.clear_local_settings(handle_id, cx).log_err() }); }) @@ -6319,8 +6314,7 @@ impl Project { let future_buffers = future_buffers.collect::>().await; // Reload the diff base for every buffer whose containing git repository has changed. - let snapshot = - worktree_handle.read_with(&cx, |tree, _| tree.as_local().unwrap().snapshot()); + let snapshot = worktree_handle.read(&cx, |tree, _| tree.as_local().unwrap().snapshot()); let diff_bases_by_buffer = cx .background() .spawn(async move { @@ -6397,7 +6391,7 @@ impl Project { let settings_contents: Vec<(Arc, _)> = futures::future::join_all(settings_contents).await; cx.update(|cx| { - cx.update_global::(|store, cx| { + cx.update_global::(|store, cx| { for (directory, file_content) in settings_contents { let file_content = file_content.and_then(|content| content.log_err()); store @@ -6750,7 +6744,7 @@ impl Project { this.update(&mut cx, |this, cx| { let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); if let Some(worktree) = this.worktree_for_id(worktree_id, cx) { - cx.update_global::(|store, cx| { + cx.update_global::(|store, cx| { store .set_local_settings( worktree.id(), @@ -6860,7 +6854,7 @@ impl Project { this.worktree_for_entry(entry_id, cx) .ok_or_else(|| anyhow!("worktree not found")) })??; - let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id()); + let worktree_scan_id = worktree.read(&cx, |worktree, _| worktree.scan_id()); worktree .update(&mut cx, |worktree, cx| { worktree @@ -6895,7 +6889,7 @@ impl Project { .ok_or_else(|| anyhow!("invalid entry")) })?? .await?; - let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id()) as u64; + let worktree_scan_id = worktree.read(&cx, |worktree, _| worktree.scan_id()) as u64; Ok(proto::ExpandProjectEntryResponse { worktree_scan_id }) } @@ -7563,7 +7557,7 @@ impl Project { { let sender_id = envelope.original_sender_id()?; let buffer_id = T::buffer_id_from_proto(&envelope.payload); - let buffer_handle = this.read_with(&cx, |this, _| { + let buffer_handle = this.read(&cx, |this, _| { this.opened_buffers .get(&buffer_id) .and_then(|buffer| buffer.upgrade(&cx)) @@ -7653,9 +7647,9 @@ impl Project { .symbol .ok_or_else(|| anyhow!("invalid symbol"))?; let symbol = this - .read_with(&cx, |this, _| this.deserialize_symbol(symbol)) + .read(&cx, |this, _| this.deserialize_symbol(symbol)) .await?; - let symbol = this.read_with(&cx, |this, _| { + let symbol = this.read(&cx, |this, _| { let signature = this.symbol_signature(&symbol.path); if signature == symbol.signature { Ok(symbol) @@ -7692,13 +7686,13 @@ impl Project { let buffer = this .update(&mut cx, |this, cx| { this.open_buffer_by_id(envelope.payload.id, cx) - }) + })? .await?; this.update(&mut cx, |this, cx| { Ok(proto::OpenBufferResponse { buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx), }) - }) + })? } async fn handle_open_buffer_by_path( @@ -7717,14 +7711,14 @@ impl Project { }, cx, ) - }); + })?; let buffer = open_buffer.await?; this.update(&mut cx, |this, cx| { Ok(proto::OpenBufferResponse { buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx), }) - }) + })? } fn serialize_project_transaction_for_peer( @@ -7761,7 +7755,7 @@ impl Project { let buffer = this .update(&mut cx, |this, cx| { this.wait_for_remote_buffer(buffer_id, cx) - }) + })? .await?; let transaction = language2::proto::deserialize_transaction(transaction)?; project_transaction.0.insert(buffer, transaction); @@ -7771,7 +7765,7 @@ impl Project { buffer .update(&mut cx, |buffer, _| { buffer.wait_for_edits(transaction.edit_ids.iter().copied()) - }) + })? .await?; if push_to_history { @@ -7807,7 +7801,7 @@ impl Project { ) -> Task>> { let mut opened_buffer_rx = self.opened_buffer.1.clone(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { let buffer = loop { let Some(this) = this.upgrade(&cx) else { return Err(anyhow!("project dropped")); @@ -7864,7 +7858,7 @@ impl Project { let client = self.client.clone(); cx.spawn(|this, cx| async move { - let (buffers, incomplete_buffer_ids) = this.read_with(&cx, |this, cx| { + let (buffers, incomplete_buffer_ids) = this.read(&cx, |this, cx| { let buffers = this .opened_buffers .iter() @@ -7895,7 +7889,7 @@ impl Project { let client = client.clone(); let buffer_id = buffer.id; let remote_version = language2::proto::deserialize_version(&buffer.version); - this.read_with(&cx, |this, cx| { + this.read(&cx, |this, cx| { if let Some(buffer) = this.buffer_for_id(buffer_id, cx) { let operations = buffer.read(cx).serialize_ops(Some(remote_version), cx); cx.background().spawn(async move { @@ -8122,7 +8116,7 @@ impl Project { })?; } Ok(()) - }) + })? } #[allow(clippy::type_complexity)] @@ -8377,8 +8371,8 @@ impl Project { let Some(node) = self.node.as_ref().map(Arc::clone) else { return Task::ready(None); }; + let fs = self.fs.clone(); cx.spawn(|this, mut cx| async move { - let fs = this.update(&mut cx, |project, _| Arc::clone(&project.fs))?; let prettier_dir = match cx .executor() .spawn(Prettier::locate( @@ -8403,22 +8397,25 @@ impl Project { } }; - if let Some(existing_prettier) = this.update(&mut cx, |project, _| { - project - .prettier_instances - .get(&(worktree_id, prettier_dir.clone())) - .cloned() - }) { + if let Some(existing_prettier) = this + .update(&mut cx, |project, _| { + project + .prettier_instances + .get(&(worktree_id, prettier_dir.clone())) + .cloned() + }) + .ok() + .flatten() + { return Some(existing_prettier); } log::info!("Found prettier in {prettier_dir:?}, starting."); let task_prettier_dir = prettier_dir.clone(); - let weak_project = this.downgrade(); - let new_server_id = - this.update(&mut cx, |this, _| this.languages.next_language_server_id()); let new_prettier_task = cx .spawn(|mut cx| async move { + let new_server_id = + this.update(&mut cx, |this, _| this.languages.next_language_server_id())?; let prettier = Prettier::start( worktree_id.map(|id| id.to_usize()), new_server_id, @@ -8431,10 +8428,10 @@ impl Project { .map_err(Arc::new)?; log::info!("Started prettier in {:?}", prettier.prettier_dir()); - if let Some((project, prettier_server)) = - weak_project.upgrade(&mut cx).zip(prettier.server()) + if let Some(prettier_server) = + prettier.server() { - project.update(&mut cx, |project, cx| { + this.update(&mut cx, |project, cx| { let name = if prettier.is_default() { LanguageServerName(Arc::from("prettier (default)")) } else { @@ -8479,7 +8476,7 @@ impl Project { .supplementary_language_servers .insert(new_server_id, (name, Arc::clone(prettier_server))); cx.emit(Event::LanguageServerAdded(new_server_id)); - }); + })?; } Ok(Arc::new(prettier)).map_err(Arc::new) }) @@ -8596,7 +8593,7 @@ fn subscribe_for_copilot_events( let copilot_log_subscription = copilot_server .on_notification::( move |params, mut cx| { - if let Some(project) = weak_project.upgrade(&mut cx) { + if let Some(project) = weak_project.upgrade() { project.update(&mut cx, |_, cx| { cx.emit(Event::LanguageServerLog( new_server_id, diff --git a/crates/project2/src/worktree.rs b/crates/project2/src/worktree.rs index a5057a9355cb101bf9e499212d879c813696d0cf..5c7d848a2d00cca04eab28d212407a9e77f94924 100644 --- a/crates/project2/src/worktree.rs +++ b/crates/project2/src/worktree.rs @@ -310,7 +310,7 @@ impl Worktree { ignores_by_parent_abs_path: Default::default(), git_repositories: Default::default(), snapshot: Snapshot { - id: WorktreeId::from_usize(cx.entity_id()), + id: WorktreeId::from_usize(cx.entity_id().as_u64() as usize), abs_path: abs_path.clone(), root_name: root_name.clone(), root_char_bag: root_name.chars().map(|c| c.to_ascii_lowercase()).collect(), diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 1a62bb84f07bc3b4e57af36e210b49cab44e86b7..61e56236ea3ddb9df0f58d7ed37fed5b5d196a98 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -16,6 +16,7 @@ use isahc::{prelude::Configurable, Request}; use language2::LanguageRegistry; use log::LevelFilter; +use node_runtime::RealNodeRuntime; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; use settings2::{default_settings, handle_settings_file_changes, watch_config_file, SettingsStore};