This commit is contained in:
Antonio Scandurra 2023-10-23 11:53:24 +02:00
parent 0de4a93ec7
commit c0e8ae5dfa
4 changed files with 47 additions and 52 deletions

View file

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

View file

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

View file

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

View file

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