This commit is contained in:
Antonio Scandurra 2023-10-23 16:38:28 +02:00
parent efbf0c828d
commit 7832120a4c
5 changed files with 80 additions and 76 deletions

View File

@ -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(),

View File

@ -28,7 +28,13 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
self.entity_id
}
pub fn handle(&self) -> WeakHandle<T> {
pub fn handle(&self) -> Handle<T> {
self.weak_handle()
.upgrade()
.expect("The entity must be alive if we have a model context")
}
pub fn weak_handle(&self) -> WeakHandle<T> {
self.app.entities.weak_handle(self.entity_id)
}
@ -37,7 +43,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
handle: &Handle<E>,
on_notify: impl Fn(&mut T, Handle<E>, &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<E>,
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::<G>(),
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<Output = ()> + 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<Output = R> + Send + 'static,
R: Send + 'static,
{
let this = self.handle();
let this = self.weak_handle();
self.app.spawn(|cx| f(this, cx))
}
}

View File

@ -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::<Vec<_>>());
let worktrees =
this.read(&cx, |this, cx| this.worktrees(cx).collect::<Vec<_>>());
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<LanguageServer>,
cx: &mut AsyncAppContext,
) -> Result<ProjectTransaction> {
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<Self>,
) -> Task<Result<Option<Transaction>>> {
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<anyhow::Result<<R as LspCommand>::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::<SettingsStore, _, _>(|store, cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.clear_local_settings(handle_id, cx).log_err()
});
})
@ -6319,8 +6314,7 @@ impl Project {
let future_buffers = future_buffers.collect::<Vec<_>>().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<Path>, _)> =
futures::future::join_all(settings_contents).await;
cx.update(|cx| {
cx.update_global::<SettingsStore, _, _>(|store, cx| {
cx.update_global::<SettingsStore, _>(|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::<SettingsStore, _, _>(|store, cx| {
cx.update_global::<SettingsStore, _>(|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<Result<Handle<Buffer>>> {
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::<copilot2::request::LogMessage, _>(
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,

View File

@ -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(),

View File

@ -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};