@@ -154,7 +154,7 @@ pub struct Project {
git_diff_debouncer: DelayedDebounced,
nonce: u128,
_maintain_buffer_languages: Task<()>,
- _maintain_workspace_config: Task<()>,
+ _maintain_workspace_config: Task<Result<()>>,
terminals: Terminals,
copilot_lsp_subscription: Option<gpui2::Subscription>,
copilot_log_subscription: Option<lsp2::Subscription>,
@@ -196,7 +196,7 @@ impl DelayedDebounced {
self.cancel_channel = Some(sender);
let previous_task = self.task.take();
- self.task = Some(cx.spawn(|project, mut cx| async move {
+ self.task = Some(cx.spawn(move |project, mut cx| async move {
let mut timer = cx.executor().timer(delay).fuse();
if let Some(previous_task) = previous_task {
previous_task.await;
@@ -623,9 +623,9 @@ impl Project {
fs: Arc<dyn Fs>,
cx: &mut AppContext,
) -> Handle<Self> {
- cx.add_model(|cx: &mut ModelContext<Self>| {
+ cx.entity(|cx: &mut ModelContext<Self>| {
let (tx, rx) = mpsc::unbounded();
- cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
+ cx.spawn(move |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));
@@ -708,7 +708,7 @@ impl Project {
}
let (tx, rx) = mpsc::unbounded();
- cx.spawn(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
+ cx.spawn(move |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));
@@ -783,7 +783,7 @@ impl Project {
let _ = this.add_worktree(&worktree, cx);
}
this
- });
+ })?;
let subscription = subscription.set_model(&this, &mut cx);
let user_ids = response
@@ -800,7 +800,7 @@ impl Project {
this.set_collaborators_from_proto(response.payload.collaborators, cx)?;
this.client_subscriptions.push(subscription);
anyhow::Ok(())
- })?;
+ })??;
Ok(this)
}
@@ -822,7 +822,7 @@ impl Project {
fn shutdown_language_servers(
&mut self,
- cx: &mut ModelContext<Self>,
+ _cx: &mut ModelContext<Self>,
) -> impl Future<Output = ()> {
let shutdown_futures = self
.language_servers
@@ -988,7 +988,7 @@ impl Project {
cx.notify();
}
- pub fn buffer_for_id(&self, remote_id: u64, cx: &AppContext) -> Option<Handle<Buffer>> {
+ pub fn buffer_for_id(&self, remote_id: u64) -> Option<Handle<Buffer>> {
self.opened_buffers
.get(&remote_id)
.and_then(|buffer| buffer.upgrade())
@@ -1006,7 +1006,7 @@ impl Project {
self.user_store.clone()
}
- pub fn opened_buffers(&self, cx: &AppContext) -> Vec<Handle<Buffer>> {
+ pub fn opened_buffers(&self) -> Vec<Handle<Buffer>> {
self.opened_buffers
.values()
.filter_map(|b| b.upgrade())
@@ -1068,10 +1068,7 @@ impl Project {
}
/// Collect all worktrees, including ones that don't appear in the project panel
- pub fn worktrees<'a>(
- &'a self,
- cx: &'a AppContext,
- ) -> impl 'a + DoubleEndedIterator<Item = Handle<Worktree>> {
+ pub fn worktrees<'a>(&'a self) -> impl 'a + DoubleEndedIterator<Item = Handle<Worktree>> {
self.worktrees
.iter()
.filter_map(move |worktree| worktree.upgrade())
@@ -1099,7 +1096,7 @@ impl Project {
}
pub fn worktree_for_id(&self, id: WorktreeId, cx: &AppContext) -> Option<Handle<Worktree>> {
- self.worktrees(cx)
+ self.worktrees()
.find(|worktree| worktree.read(cx).id() == id)
}
@@ -1108,7 +1105,7 @@ impl Project {
entry_id: ProjectEntryId,
cx: &AppContext,
) -> Option<Handle<Worktree>> {
- self.worktrees(cx)
+ self.worktrees()
.find(|worktree| worktree.read(cx).contains_entry(entry_id))
}
@@ -1126,7 +1123,7 @@ impl Project {
}
pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool {
- for worktree in self.worktrees(cx) {
+ for worktree in self.worktrees() {
let worktree = worktree.read(cx).as_local();
if worktree.map_or(false, |w| w.contains_abs_path(path)) {
return true;
@@ -1153,7 +1150,7 @@ impl Project {
} else {
let client = self.client.clone();
let project_id = self.remote_id().unwrap();
- Some(cx.spawn(|_, mut cx| async move {
+ Some(cx.spawn(move |_, mut cx| async move {
let response = client
.request(proto::CreateProjectEntry {
worktree_id: project_path.worktree_id.to_proto(),
@@ -1172,7 +1169,7 @@ impl Project {
response.worktree_scan_id as usize,
cx,
)
- })
+ })?
.await
}))
}
@@ -1197,7 +1194,7 @@ impl Project {
let client = self.client.clone();
let project_id = self.remote_id().unwrap();
- Some(cx.spawn(|_, mut cx| async move {
+ Some(cx.spawn(move |_, mut cx| async move {
let response = client
.request(proto::CopyProjectEntry {
project_id,
@@ -1215,7 +1212,7 @@ impl Project {
response.worktree_scan_id as usize,
cx,
)
- })
+ })?
.await
}))
}
@@ -1240,7 +1237,7 @@ impl Project {
let client = self.client.clone();
let project_id = self.remote_id().unwrap();
- Some(cx.spawn(|_, mut cx| async move {
+ Some(cx.spawn(move |_, mut cx| async move {
let response = client
.request(proto::RenameProjectEntry {
project_id,
@@ -1280,7 +1277,7 @@ impl Project {
} else {
let client = self.client.clone();
let project_id = self.remote_id().unwrap();
- Some(cx.spawn(|_, mut cx| async move {
+ Some(cx.spawn(move |_, mut cx| async move {
let response = client
.request(proto::DeleteProjectEntry {
project_id,
@@ -1294,7 +1291,7 @@ impl Project {
response.worktree_scan_id as usize,
cx,
)
- })
+ })?
.await
}))
}
@@ -1317,7 +1314,7 @@ impl Project {
project_id: self.remote_id().unwrap(),
entry_id: entry_id.to_proto(),
});
- Some(cx.spawn(|_, mut cx| async move {
+ Some(cx.spawn(move |_, mut cx| async move {
let response = request.await?;
if let Some(worktree) = worktree.upgrade() {
worktree
@@ -1326,7 +1323,7 @@ impl Project {
.as_remote_mut()
.unwrap()
.wait_for_snapshot(response.worktree_scan_id as usize)
- })
+ })?
.await?;
}
Ok(())
@@ -1341,7 +1338,7 @@ impl Project {
self.client_subscriptions.push(
self.client
.subscribe_to_entity(project_id)?
- .set_model(&cx.handle().upgrade(), &mut cx.to_async()),
+ .set_model(&cx.handle(), &mut cx.to_async()),
);
for open_buffer in self.opened_buffers.values_mut() {
@@ -1380,7 +1377,7 @@ impl Project {
}
let store = cx.global::<SettingsStore>();
- for worktree in self.worktrees(cx) {
+ for worktree in self.worktrees() {
let worktree_id = worktree.read(cx).id().to_proto();
for (path, content) in store.local_settings(worktree.entity_id().as_u64() as usize) {
self.client
@@ -1403,8 +1400,8 @@ impl Project {
while let Some(update) = updates_rx.next().await {
match update {
LocalProjectUpdate::WorktreesChanged => {
- let worktrees = this.update(&mut cx, |this, cx| {
- this.worktrees(cx).collect::<Vec<_>>()
+ let worktrees = this.update(&mut cx, |this, _cx| {
+ this.worktrees().collect::<Vec<_>>()
})?;
let update_project = this
.update(&mut cx, |this, cx| {
@@ -1441,9 +1438,9 @@ impl Project {
let Some(buffer) = buffer else { continue };
let operations =
- buffer.read_with(&cx, |b, cx| b.serialize_ops(None, cx));
+ buffer.update(&mut cx, |b, cx| b.serialize_ops(None, cx))?;
let operations = operations.await;
- let state = buffer.read_with(&cx, |buffer, _| buffer.to_proto());
+ let state = buffer.update(&mut cx, |buffer, _| buffer.to_proto())?;
let initial_state = proto::CreateBufferForPeer {
project_id,
@@ -1452,7 +1449,7 @@ impl Project {
};
if client.send(initial_state).log_err().is_some() {
let client = client.clone();
- cx.background()
+ cx.executor()
.spawn(async move {
let mut chunks = split_operations(operations).peekable();
while let Some(chunk) = chunks.next() {
@@ -1683,12 +1680,12 @@ impl Project {
cx: &mut ModelContext<Self>,
) -> Task<Result<(ProjectEntryId, AnyHandle)>> {
let task = self.open_buffer(path, cx);
- cx.spawn_weak(|_, cx| async move {
+ cx.spawn(move |_, mut cx| async move {
let buffer = task.await?;
let project_entry_id = buffer
- .read(&cx, |buffer, cx| {
+ .update(&mut cx, |buffer, cx| {
File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
- })
+ })?
.ok_or_else(|| anyhow!("no project entry"))?;
let buffer: &AnyHandle = &buffer;
@@ -1749,14 +1746,15 @@ impl Project {
this.loading_buffers_by_path.remove(&project_path);
let buffer = load_result.map_err(Arc::new)?;
Ok(buffer)
- }));
+ })?);
+ anyhow::Ok(())
})
.detach();
rx
}
};
- cx.foreground().spawn(async move {
+ cx.executor().spawn(async move {
wait_for_loading_buffer(loading_watch)
.await
.map_err(|error| anyhow!("{}", error))
@@ -1774,9 +1772,9 @@ impl Project {
let worktree = worktree.as_local_mut().unwrap();
worktree.load_buffer(buffer_id, path, cx)
});
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let buffer = load_buffer.await?;
- this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
+ this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))??;
Ok(buffer)
})
}
@@ -1792,7 +1790,7 @@ impl Project {
let remote_worktree_id = worktree.read(cx).id();
let path = path.clone();
let path_string = path.to_string_lossy().to_string();
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let response = rpc
.request(proto::OpenBufferByPath {
project_id,
@@ -1802,7 +1800,7 @@ impl Project {
.await?;
this.update(&mut cx, |this, cx| {
this.wait_for_remote_buffer(response.buffer_id, cx)
- })
+ })?
.await
})
}
@@ -1815,34 +1813,35 @@ impl Project {
language_server_name: LanguageServerName,
cx: &mut ModelContext<Self>,
) -> Task<Result<Handle<Buffer>>> {
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let abs_path = abs_path
.to_file_path()
.map_err(|_| anyhow!("can't convert URI to path"))?;
let (worktree, relative_path) = if let Some(result) =
- this.read(&cx, |this, cx| this.find_local_worktree(&abs_path, cx))
+ this.update(&mut cx, |this, cx| this.find_local_worktree(&abs_path, cx))?
{
result
} else {
let worktree = this
.update(&mut cx, |this, cx| {
this.create_local_worktree(&abs_path, false, cx)
- })
+ })?
.await?;
this.update(&mut cx, |this, cx| {
this.language_server_ids.insert(
(worktree.read(cx).id(), language_server_name),
language_server_id,
);
- });
+ })
+ .ok();
(worktree, PathBuf::new())
};
let project_path = ProjectPath {
- worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()),
+ worktree_id: worktree.update(&mut cx, |worktree, _| worktree.id())?,
path: relative_path.into(),
};
- this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
+ this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx))?
.await
})
}
@@ -1852,7 +1851,7 @@ impl Project {
id: u64,
cx: &mut ModelContext<Self>,
) -> Task<Result<Handle<Buffer>>> {
- if let Some(buffer) = self.buffer_for_id(id, cx) {
+ if let Some(buffer) = self.buffer_for_id(id) {
Task::ready(Ok(buffer))
} else if self.is_local() {
Task::ready(Err(anyhow!("buffer {} does not exist", id)))
@@ -1860,11 +1859,11 @@ impl Project {
let request = self
.client
.request(proto::OpenBufferById { project_id, id });
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let buffer_id = request.await?.buffer_id;
this.update(&mut cx, |this, cx| {
this.wait_for_remote_buffer(buffer_id, cx)
- })
+ })?
.await
})
} else {
@@ -1877,10 +1876,11 @@ impl Project {
buffers: HashSet<Handle<Buffer>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
- cx.spawn(|this, mut cx| async move {
- let save_tasks = buffers
- .into_iter()
- .map(|buffer| this.update(&mut cx, |this, cx| this.save_buffer(buffer, cx)));
+ cx.spawn(move |this, mut cx| async move {
+ let save_tasks = buffers.into_iter().filter_map(|buffer| {
+ this.update(&mut cx, |this, cx| this.save_buffer(buffer, cx))
+ .ok()
+ });
try_join_all(save_tasks).await?;
Ok(())
})
@@ -1912,11 +1912,11 @@ impl Project {
let old_file = File::from_dyn(buffer.read(cx).file())
.filter(|f| f.is_local())
.cloned();
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
if let Some(old_file) = &old_file {
this.update(&mut cx, |this, cx| {
this.unregister_buffer_from_language_servers(&buffer, old_file, cx);
- });
+ })?;
}
let (worktree, path) = worktree_task.await?;
worktree
@@ -1925,13 +1925,13 @@ impl Project {
worktree.save_buffer(buffer.clone(), path.into(), true, cx)
}
Worktree::Remote(_) => panic!("cannot remote buffers as new files"),
- })
+ })?
.await?;
this.update(&mut cx, |this, cx| {
this.detect_language_for_buffer(&buffer, cx);
this.register_buffer_with_language_servers(&buffer, cx);
- });
+ })?;
Ok(())
})
}
@@ -2242,7 +2242,7 @@ impl Project {
is_local,
&mut cx,
)
- .await;
+ .await?;
this.update(&mut cx, |this, _| {
if let Some(project_id) = this.remote_id() {
@@ -2254,7 +2254,7 @@ impl Project {
})
.log_err();
}
- });
+ })?;
}
}
}
@@ -2266,7 +2266,7 @@ impl Project {
is_local,
&mut cx,
)
- .await;
+ .await?;
}
Ok(())
@@ -2431,9 +2431,9 @@ impl Project {
const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration =
Duration::from_secs(1);
- let task = cx.spawn(|this, mut cx| async move {
+ let task = cx.spawn(move |this, mut cx| async move {
cx.executor().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
- if let Some(this) = this.upgrade(&cx) {
+ if let Some(this) = this.upgrade() {
this.update(&mut cx, |this, cx| {
this.disk_based_diagnostics_finished(
language_server_id,
@@ -2447,7 +2447,7 @@ impl Project {
},
)
.ok();
- });
+ }).ok();
}
});
*simulate_disk_based_diagnostics_completion = Some(task);
@@ -2521,20 +2521,18 @@ impl Project {
}
fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext<Self>) -> Task<()> {
- cx.spawn(|this, mut cx| async move {
- let buffers: Vec<_> = this.update(&mut cx, |this, _| {
- this.buffers_needing_diff.drain().collect()
- });
-
- let tasks: Vec<_> = this.update(&mut cx, |_, cx| {
- buffers
- .iter()
- .filter_map(|buffer| {
- let buffer = buffer.upgrade()?;
- buffer.update(cx, |buffer, cx| buffer.git_diff_recalc(cx))
- })
- .collect()
- });
+ let buffers = self.buffers_needing_diff.drain().collect::<Vec<_>>();
+ cx.spawn(move |this, mut cx| async move {
+ let tasks: Vec<_> = buffers
+ .iter()
+ .filter_map(|buffer| {
+ let buffer = buffer.upgrade()?;
+ buffer
+ .update(&mut cx, |buffer, cx| buffer.git_diff_recalc(cx))
+ .ok()
+ .flatten()
+ })
+ .collect();
futures::future::join_all(tasks).await;
@@ -2549,7 +2547,8 @@ impl Project {
}
}
}
- });
+ })
+ .ok();
})
}
@@ -2581,74 +2580,78 @@ impl Project {
) -> Task<()> {
let mut subscription = languages.subscribe();
let mut prev_reload_count = languages.reload_count();
- cx.spawn_weak(|project, mut cx| async move {
+ cx.spawn(move |project, mut cx| async move {
while let Some(()) = subscription.next().await {
- if let Some(project) = project.upgrade(&cx) {
+ if let Some(project) = project.upgrade() {
// If the language registry has been reloaded, then remove and
// re-assign the languages on all open buffers.
let reload_count = languages.reload_count();
if reload_count > prev_reload_count {
prev_reload_count = reload_count;
- project.update(&mut cx, |this, cx| {
- let buffers = this
- .opened_buffers
- .values()
- .filter_map(|b| b.upgrade())
- .collect::<Vec<_>>();
- for buffer in buffers {
- if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned() {
- this.unregister_buffer_from_language_servers(&buffer, &f, cx);
- buffer.update(cx, |buffer, cx| buffer.set_language(None, cx));
+ project
+ .update(&mut cx, |this, cx| {
+ let buffers = this
+ .opened_buffers
+ .values()
+ .filter_map(|b| b.upgrade())
+ .collect::<Vec<_>>();
+ for buffer in buffers {
+ if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
+ {
+ this.unregister_buffer_from_language_servers(
+ &buffer, &f, cx,
+ );
+ buffer
+ .update(cx, |buffer, cx| buffer.set_language(None, cx));
+ }
}
- }
- });
+ })
+ .ok();
}
- project.update(&mut cx, |project, cx| {
- let mut plain_text_buffers = Vec::new();
- let mut buffers_with_unknown_injections = Vec::new();
- for buffer in project.opened_buffers.values() {
- if let Some(handle) = buffer.upgrade() {
- let buffer = &handle.read(cx);
- if buffer.language().is_none()
- || buffer.language() == Some(&*language2::PLAIN_TEXT)
- {
- plain_text_buffers.push(handle);
- } else if buffer.contains_unknown_injections() {
- buffers_with_unknown_injections.push(handle);
+ project
+ .update(&mut cx, |project, cx| {
+ let mut plain_text_buffers = Vec::new();
+ let mut buffers_with_unknown_injections = Vec::new();
+ for buffer in project.opened_buffers.values() {
+ if let Some(handle) = buffer.upgrade() {
+ let buffer = &handle.read(cx);
+ if buffer.language().is_none()
+ || buffer.language() == Some(&*language2::PLAIN_TEXT)
+ {
+ plain_text_buffers.push(handle);
+ } else if buffer.contains_unknown_injections() {
+ buffers_with_unknown_injections.push(handle);
+ }
}
}
- }
- for buffer in plain_text_buffers {
- project.detect_language_for_buffer(&buffer, cx);
- project.register_buffer_with_language_servers(&buffer, cx);
- }
+ for buffer in plain_text_buffers {
+ project.detect_language_for_buffer(&buffer, cx);
+ project.register_buffer_with_language_servers(&buffer, cx);
+ }
- for buffer in buffers_with_unknown_injections {
- buffer.update(cx, |buffer, cx| buffer.reparse(cx));
- }
- });
+ for buffer in buffers_with_unknown_injections {
+ buffer.update(cx, |buffer, cx| buffer.reparse(cx));
+ }
+ })
+ .ok();
}
}
})
}
- fn maintain_workspace_config(cx: &mut ModelContext<Project>) -> Task<()> {
+ fn maintain_workspace_config(cx: &mut ModelContext<Project>) -> Task<Result<()>> {
let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
- let settings_observation = cx.observe_global::<SettingsStore, _>(move |_, _| {
+ let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
*settings_changed_tx.borrow_mut() = ();
});
- cx.spawn_weak(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
while let Some(_) = settings_changed_rx.next().await {
- let Some(this) = this.upgrade(&cx) else {
- break;
- };
-
- let servers: Vec<_> = this.read_with(&cx, |this, _| {
+ let servers: Vec<_> = this.update(&mut cx, |this, _| {
this.language_servers
.values()
.filter_map(|state| match state {
@@ -2658,11 +2661,11 @@ impl Project {
} => Some((adapter.clone(), server.clone())),
})
.collect()
- });
+ })?;
for (adapter, server) in servers {
let workspace_config =
- cx.update(|cx| adapter.workspace_configuration(cx)).await;
+ cx.update(|cx| adapter.workspace_configuration(cx))?.await;
server
.notify::<lsp2::notification::DidChangeConfiguration>(
lsp2::DidChangeConfigurationParams {
@@ -2674,6 +2677,7 @@ impl Project {
}
drop(settings_observation);
+ anyhow::Ok(())
})
}
@@ -2717,12 +2721,12 @@ impl Project {
let task_buffer = buffer.clone();
let prettier_installation_task =
self.install_default_formatters(worktree, &new_language, &settings, cx);
- cx.spawn(|project, mut cx| async move {
+ cx.spawn(move |project, mut cx| async move {
prettier_installation_task.await?;
let _ = project
.update(&mut cx, |project, cx| {
project.prettier_instance_for_buffer(&task_buffer, cx)
- })
+ })?
.await;
anyhow::Ok(())
})
@@ -2806,9 +2810,9 @@ impl Project {
let language = language.clone();
let key = key.clone();
- cx.spawn_weak(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let result = Self::setup_and_insert_language_server(
- this,
+ this.clone(),
initialization_options,
pending_server,
adapter.clone(),
@@ -2839,7 +2843,8 @@ impl Project {
installation_test_binary,
cx,
)
- });
+ })
+ .ok();
}
}
@@ -2883,10 +2888,15 @@ impl Project {
// TODO: This is race-safe with regards to preventing new instances from
// starting while deleting, but existing instances in other projects are going
// to be very confused and messed up
- this.update(&mut cx, |this, cx| {
- this.languages.delete_server_container(adapter.clone(), cx)
- })
- .await;
+ let Some(task) = this
+ .update(&mut cx, |this, cx| {
+ this.languages.delete_server_container(adapter.clone(), cx)
+ })
+ .log_err()
+ else {
+ return;
+ };
+ task.await;
this.update(&mut cx, |this, mut cx| {
let worktrees = this.worktrees.clone();
@@ -2907,6 +2917,7 @@ impl Project {
);
}
})
+ .ok();
}))
}
@@ -2921,7 +2932,7 @@ impl Project {
cx: &mut AsyncAppContext,
) -> Result<Option<Arc<LanguageServer>>> {
let setup = Self::setup_pending_language_server(
- this,
+ this.clone(),
initialization_options,
pending_server,
adapter.clone(),
@@ -2947,7 +2958,7 @@ impl Project {
key,
cx,
)
- })?;
+ })??;
Ok(Some(language_server))
}
@@ -2960,7 +2971,7 @@ impl Project {
server_id: LanguageServerId,
cx: &mut AsyncAppContext,
) -> Result<Option<Arc<LanguageServer>>> {
- let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx)).await;
+ let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx))?.await;
let language_server = match pending_server.task.await? {
Some(server) => server,
None => return Ok(None),
@@ -2969,8 +2980,8 @@ impl Project {
language_server
.on_notification::<lsp2::notification::PublishDiagnostics, _>({
let adapter = adapter.clone();
+ let this = this.clone();
move |mut params, mut cx| {
- let this = this;
let adapter = adapter.clone();
adapter.process_diagnostics(&mut params);
if let Some(this) = this.upgrade() {
@@ -2982,7 +2993,8 @@ impl Project {
cx,
)
.log_err();
- });
+ })
+ .ok();
}
}
})
@@ -2991,11 +3003,11 @@ impl Project {
language_server
.on_request::<lsp2::request::WorkspaceConfiguration, _, _>({
let adapter = adapter.clone();
- move |params, mut cx| {
+ move |params, cx| {
let adapter = adapter.clone();
async move {
let workspace_config =
- cx.update(|cx| adapter.workspace_configuration(cx)).await;
+ cx.update(|cx| adapter.workspace_configuration(cx))?.await;
Ok(params
.items
.into_iter()
@@ -3019,9 +3031,11 @@ impl Project {
// avoid stalling any language server like `gopls` which waits for a response
// to these requests when initializing.
language_server
- .on_request::<lsp2::request::WorkDoneProgressCreate, _, _>(
- move |params, mut cx| async move {
- if let Some(this) = this.upgrade() {
+ .on_request::<lsp2::request::WorkDoneProgressCreate, _, _>({
+ let this = this.clone();
+ move |params, mut cx| {
+ let this = this.clone();
+ async move {
this.update(&mut cx, |this, _| {
if let Some(status) = this.language_server_statuses.get_mut(&server_id)
{
@@ -3029,27 +3043,33 @@ impl Project {
status.progress_tokens.insert(token);
}
}
- });
+ })?;
+
+ Ok(())
}
- Ok(())
- },
- )
+ }
+ })
.detach();
language_server
.on_request::<lsp2::request::RegisterCapability, _, _>({
- move |params, mut cx| async move {
- let this = this.upgrade().ok_or_else(|| anyhow!("project dropped"))?;
- for reg in params.registrations {
- if reg.method == "workspace/didChangeWatchedFiles" {
- if let Some(options) = reg.register_options {
- let options = serde_json::from_value(options)?;
- this.update(&mut cx, |this, cx| {
- this.on_lsp_did_change_watched_files(server_id, options, cx);
- });
+ let this = this.clone();
+ move |params, mut cx| {
+ let this = this.clone();
+ async move {
+ for reg in params.registrations {
+ if reg.method == "workspace/didChangeWatchedFiles" {
+ if let Some(options) = reg.register_options {
+ let options = serde_json::from_value(options)?;
+ this.update(&mut cx, |this, cx| {
+ this.on_lsp_did_change_watched_files(
+ server_id, options, cx,
+ );
+ })?;
+ }
}
}
+ Ok(())
}
- Ok(())
}
})
.detach();
@@ -3057,24 +3077,34 @@ impl Project {
language_server
.on_request::<lsp2::request::ApplyWorkspaceEdit, _, _>({
let adapter = adapter.clone();
+ let this = this.clone();
move |params, cx| {
- Self::on_lsp_workspace_edit(this, params, server_id, adapter.clone(), cx)
+ Self::on_lsp_workspace_edit(
+ this.clone(),
+ params,
+ server_id,
+ adapter.clone(),
+ cx,
+ )
}
})
.detach();
language_server
.on_request::<lsp2::request::InlayHintRefreshRequest, _, _>({
- move |(), mut cx| async move {
- let this = this.upgrade().ok_or_else(|| anyhow!("project dropped"))?;
- this.update(&mut cx, |project, cx| {
- cx.emit(Event::RefreshInlayHints);
- project.remote_id().map(|project_id| {
- project.client.send(proto::RefreshInlayHints { project_id })
- })
- })
- .transpose()?;
- Ok(())
+ let this = this.clone();
+ move |(), mut cx| {
+ let this = this.clone();
+ async move {
+ this.update(&mut cx, |project, cx| {
+ cx.emit(Event::RefreshInlayHints);
+ project.remote_id().map(|project_id| {
+ project.client.send(proto::RefreshInlayHints { project_id })
+ })
+ })?
+ .transpose()?;
+ Ok(())
+ }
}
})
.detach();
@@ -3092,7 +3122,8 @@ impl Project {
disk_based_diagnostics_progress_token.clone(),
cx,
);
- });
+ })
+ .ok();
}
})
.detach();
@@ -3282,7 +3313,7 @@ impl Project {
let server_state = self.language_servers.remove(&server_id);
cx.emit(Event::LanguageServerRemoved(server_id));
- cx.spawn_weak(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let mut root_path = None;
let server = match server_state {
@@ -3298,11 +3329,12 @@ impl Project {
}
}
- if let Some(this) = this.upgrade(&cx) {
+ if let Some(this) = this.upgrade() {
this.update(&mut cx, |this, cx| {
this.language_server_statuses.remove(&server_id);
cx.notify();
- });
+ })
+ .ok();
}
(root_path, orphaned_worktrees)
@@ -3358,7 +3390,7 @@ impl Project {
}
let mut stops = stops.into_iter();
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let (original_root_path, mut orphaned_worktrees) = stops.next().unwrap().await;
for stop in stops {
let (_, worktrees) = stop.await;
@@ -3392,7 +3424,8 @@ impl Project {
}
}
}
- });
+ })
+ .ok();
})
.detach();
}
@@ -3412,7 +3445,7 @@ impl Project {
return;
}
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
log::info!("About to spawn test binary");
// A lack of test binary counts as a failure
@@ -3451,9 +3484,12 @@ impl Project {
if errored {
log::warn!("test binary check failed");
- let task = this.update(&mut cx, move |this, mut cx| {
- this.reinstall_language_server(language, adapter, server_id, &mut cx)
- });
+ let task = this
+ .update(&mut cx, move |this, mut cx| {
+ this.reinstall_language_server(language, adapter, server_id, &mut cx)
+ })
+ .ok()
+ .flatten();
if let Some(task) = task {
task.await;
@@ -3718,7 +3754,7 @@ impl Project {
.upgrade()
.ok_or_else(|| anyhow!("project project closed"))?;
let language_server = this
- .read(&cx, |this, _| this.language_server_for_id(server_id))
+ .update(&mut 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(),
@@ -3735,7 +3771,7 @@ impl Project {
this.last_workspace_edits_by_language_server
.insert(server_id, transaction);
}
- });
+ })?;
Ok(lsp2::ApplyWorkspaceEditResponse {
applied: true,
failed_change: None,
@@ -4004,7 +4040,7 @@ impl Project {
let remote_buffers = self.remote_id().zip(remote_buffers);
let client = self.client.clone();
- cx.spawn(|this, mut cx| async move {
+ cx.spawn(move |this, mut cx| async move {
let mut project_transaction = ProjectTransaction::default();
if let Some((project_id, remote_buffers)) = remote_buffers {