WIP

Antonio Scandurra created

Change summary

crates/gpui2/src/subscription.rs        |  6 +-
crates/project2/src/project2.rs         | 78 ++++++++++++--------------
crates/project2/src/project_settings.rs |  5 +
crates/project2/src/terminals.rs        | 10 +-
4 files changed, 47 insertions(+), 52 deletions(-)

Detailed changes

crates/gpui2/src/subscription.rs 🔗

@@ -21,8 +21,8 @@ struct SubscriberSetState<EmitterKey, Callback> {
 
 impl<EmitterKey, Callback> SubscriberSet<EmitterKey, Callback>
 where
-    EmitterKey: 'static + Ord + Clone + Debug,
-    Callback: 'static,
+    EmitterKey: 'static + Send + Sync + Ord + Clone + Debug,
+    Callback: 'static + Send + Sync,
 {
     pub fn new() -> Self {
         Self(Arc::new(Mutex::new(SubscriberSetState {
@@ -96,7 +96,7 @@ where
 
 #[must_use]
 pub struct Subscription {
-    unsubscribe: Option<Box<dyn FnOnce()>>,
+    unsubscribe: Option<Box<dyn FnOnce() + Send + Sync>>,
 }
 
 impl Subscription {

crates/project2/src/project2.rs 🔗

@@ -26,7 +26,8 @@ use futures::{
 };
 use globset::{Glob, GlobSet, GlobSetBuilder};
 use gpui2::{
-    AnyHandle, AppContext, AsyncAppContext, EventEmitter, Handle, ModelContext, Task, WeakHandle,
+    AnyHandle, AppContext, AsyncAppContext, EventEmitter, Executor, Handle, ModelContext, Task,
+    WeakHandle,
 };
 use itertools::Itertools;
 use language2::{
@@ -648,6 +649,7 @@ impl Project {
                 _subscriptions: vec![
                     cx.observe_global::<SettingsStore, _>(Self::on_settings_changed),
                     cx.on_release(Self::release),
+                    cx.on_app_quit(Self::shutdown_language_servers),
                 ],
                 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
                 _maintain_workspace_config: Self::maintain_workspace_config(cx),
@@ -733,7 +735,10 @@ impl Project {
                 next_entry_id: Default::default(),
                 next_diagnostic_group_id: Default::default(),
                 client_subscriptions: Default::default(),
-                _subscriptions: vec![cx.on_release(Self::release)],
+                _subscriptions: vec![
+                    cx.on_release(Self::release),
+                    cx.on_app_quit(Self::shutdown_language_servers),
+                ],
                 client: client.clone(),
                 client_state: Some(ProjectClientState::Remote {
                     sharing_has_stopped: false,
@@ -816,6 +821,24 @@ impl Project {
         }
     }
 
+    fn shutdown_language_servers(&mut self) -> impl Future<Output = ()> {
+        let shutdown_futures = self
+            .language_servers
+            .drain()
+            .map(|(_, server_state)| async {
+                use LanguageServerState::*;
+                match server_state {
+                    Running { server, .. } => server.shutdown()?.await,
+                    Starting(task) => task.await?.shutdown()?.await,
+                }
+            })
+            .collect::<Vec<_>>();
+
+        async move {
+            futures::future::join_all(shutdown_futures).await;
+        }
+    }
+
     // #[cfg(any(test, feature = "test-support"))]
     // pub async fn test(
     //     fs: Arc<dyn Fs>,
@@ -2948,7 +2971,7 @@ impl Project {
                     let this = this;
                     let adapter = adapter.clone();
                     adapter.process_diagnostics(&mut params);
-                    if let Some(this) = this.upgrade(&cx) {
+                    if let Some(this) = this.upgrade() {
                         this.update(&mut cx, |this, cx| {
                             this.update_diagnostics(
                                 server_id,
@@ -2996,7 +3019,7 @@ impl Project {
         language_server
             .on_request::<lsp2::request::WorkDoneProgressCreate, _, _>(
                 move |params, mut cx| async move {
-                    if let Some(this) = this.upgrade(&cx) {
+                    if let Some(this) = this.upgrade() {
                         this.update(&mut cx, |this, _| {
                             if let Some(status) = this.language_server_statuses.get_mut(&server_id)
                             {
@@ -3013,9 +3036,7 @@ impl Project {
         language_server
             .on_request::<lsp2::request::RegisterCapability, _, _>({
                 move |params, mut cx| async move {
-                    let this = this
-                        .upgrade(&cx)
-                        .ok_or_else(|| anyhow!("project dropped"))?;
+                    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 {
@@ -3043,9 +3064,7 @@ impl Project {
         language_server
             .on_request::<lsp2::request::InlayHintRefreshRequest, _, _>({
                 move |(), mut cx| async move {
-                    let this = this
-                        .upgrade(&cx)
-                        .ok_or_else(|| anyhow!("project dropped"))?;
+                    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| {
@@ -3063,7 +3082,7 @@ impl Project {
 
         language_server
             .on_notification::<lsp2::notification::Progress, _>(move |params, mut cx| {
-                if let Some(this) = this.upgrade(&cx) {
+                if let Some(this) = this.upgrade() {
                     this.update(&mut cx, |this, cx| {
                         this.on_lsp_progress(
                             params,
@@ -3694,7 +3713,7 @@ impl Project {
         mut cx: AsyncAppContext,
     ) -> Result<lsp2::ApplyWorkspaceEditResponse> {
         let this = this
-            .upgrade(&cx)
+            .upgrade()
             .ok_or_else(|| anyhow!("project project closed"))?;
         let language_server = this
             .read_with(&cx, |this, _| this.language_server_for_id(server_id))
@@ -4823,7 +4842,7 @@ impl Project {
                             None
                         };
                         Ok(transaction)
-                    })
+                    })?
                 } else {
                     Ok(None)
                 }
@@ -5659,11 +5678,12 @@ impl Project {
             .detach();
         result_rx
     }
+
     /// Pick paths that might potentially contain a match of a given search query.
     async fn background_search(
         unnamed_buffers: Vec<Handle<Buffer>>,
         opened_buffers: HashMap<Arc<Path>, (Handle<Buffer>, BufferSnapshot)>,
-        background: Arc<Background>,
+        executor: Executor,
         fs: Arc<dyn Fs>,
         workers: usize,
         query: SearchQuery,
@@ -5694,7 +5714,7 @@ impl Project {
                 .await
                 .log_err();
         }
-        background
+        executor
             .scoped(|scope| {
                 for worker_ix in 0..workers {
                     let worker_start_ix = worker_ix * paths_per_worker;
@@ -8104,7 +8124,7 @@ impl Project {
     fn edits_from_lsp(
         &mut self,
         buffer: &Handle<Buffer>,
-        lsp2_edits: impl 'static + Send + IntoIterator<Item = lsp2::TextEdit>,
+        lsp_edits: impl 'static + Send + IntoIterator<Item = lsp2::TextEdit>,
         server_id: LanguageServerId,
         version: Option<i32>,
         cx: &mut ModelContext<Self>,
@@ -8698,32 +8718,6 @@ impl EventEmitter for Project {
     type Event = Event;
 }
 
-impl Entity for Project {
-    fn app_will_quit(
-        &mut self,
-        _: &mut AppContext,
-    ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
-        let shutdown_futures = self
-            .language_servers
-            .drain()
-            .map(|(_, server_state)| async {
-                use LanguageServerState::*;
-                match server_state {
-                    Running { server, .. } => server.shutdown()?.await,
-                    Starting(task) => task.await?.shutdown()?.await,
-                }
-            })
-            .collect::<Vec<_>>();
-
-        Some(
-            async move {
-                futures::future::join_all(shutdown_futures).await;
-            }
-            .boxed(),
-        )
-    }
-}
-
 impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
     fn from((worktree_id, path): (WorktreeId, P)) -> Self {
         Self {

crates/project2/src/project_settings.rs 🔗

@@ -1,7 +1,8 @@
 use collections::HashMap;
+use gpui2::AppContext;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::Setting;
+use settings2::Setting;
 use std::sync::Arc;
 
 #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
@@ -40,7 +41,7 @@ impl Setting for ProjectSettings {
     fn load(
         default_value: &Self::FileContent,
         user_values: &[&Self::FileContent],
-        _: &gpui::AppContext,
+        _: &AppContext,
     ) -> anyhow::Result<Self> {
         Self::load_via_json_merge(default_value, user_values)
     }

crates/project2/src/terminals.rs 🔗

@@ -1,5 +1,5 @@
 use crate::Project;
-use gpui::{AnyWindowHandle, ModelContext, ModelHandle, WeakModelHandle};
+use gpui2::{AnyWindowHandle, Handle, ModelContext, WeakHandle};
 use std::path::{Path, PathBuf};
 use terminal::{
     terminal_settings::{self, TerminalSettings, VenvSettingsContent},
@@ -10,7 +10,7 @@ use terminal::{
 use std::os::unix::ffi::OsStrExt;
 
 pub struct Terminals {
-    pub(crate) local_handles: Vec<WeakModelHandle<terminal::Terminal>>,
+    pub(crate) local_handles: Vec<WeakHandle<terminal::Terminal>>,
 }
 
 impl Project {
@@ -19,13 +19,13 @@ impl Project {
         working_directory: Option<PathBuf>,
         window: AnyWindowHandle,
         cx: &mut ModelContext<Self>,
-    ) -> anyhow::Result<ModelHandle<Terminal>> {
+    ) -> anyhow::Result<Handle<Terminal>> {
         if self.is_remote() {
             return Err(anyhow::anyhow!(
                 "creating terminals as a guest is not supported yet"
             ));
         } else {
-            let settings = settings::get::<TerminalSettings>(cx);
+            let settings = settings2::get::<TerminalSettings>(cx);
             let python_settings = settings.detect_venv.clone();
             let shell = settings.shell.clone();
 
@@ -103,7 +103,7 @@ impl Project {
     fn activate_python_virtual_environment(
         &mut self,
         activate_script: Option<PathBuf>,
-        terminal_handle: &ModelHandle<Terminal>,
+        terminal_handle: &Handle<Terminal>,
         cx: &mut ModelContext<Project>,
     ) {
         if let Some(activate_script) = activate_script {