diff --git a/crates/dap/src/session.rs b/crates/dap/src/session.rs index a2aa2c632c4892..65afbc4987fc23 100644 --- a/crates/dap/src/session.rs +++ b/crates/dap/src/session.rs @@ -1,6 +1,5 @@ use anyhow::Result; use collections::HashMap; -use dap_types::Capabilities; use gpui::{ModelContext, Task}; use std::sync::Arc; use task::DebugAdapterConfig; @@ -25,7 +24,6 @@ pub struct DebugSession { id: DebugSessionId, ignore_breakpoints: bool, configuration: DebugAdapterConfig, - capabilities: HashMap, clients: HashMap>, } @@ -36,7 +34,6 @@ impl DebugSession { configuration, ignore_breakpoints: false, clients: HashMap::default(), - capabilities: HashMap::default(), } } @@ -70,28 +67,6 @@ impl DebugSession { cx.notify(); } - pub fn capabilities(&self, client_id: &DebugAdapterClientId) -> Capabilities { - self.capabilities - .get(client_id) - .cloned() - .unwrap_or_default() - } - - pub fn update_capabilities( - &mut self, - client_id: &DebugAdapterClientId, - new_capabilities: Capabilities, - cx: &mut ModelContext, - ) { - if let Some(capabilities) = self.capabilities.get_mut(client_id) { - *capabilities = capabilities.merge(new_capabilities); - } else { - self.capabilities.insert(*client_id, new_capabilities); - } - - cx.notify(); - } - pub fn add_client(&mut self, client: Arc, cx: &mut ModelContext) { self.clients.insert(client.id(), client); cx.notify(); diff --git a/crates/debugger_ui/src/console.rs b/crates/debugger_ui/src/console.rs index fe9b58ef9ff65b..de20f079d6cc04 100644 --- a/crates/debugger_ui/src/console.rs +++ b/crates/debugger_ui/src/console.rs @@ -221,14 +221,13 @@ impl CompletionProvider for ConsoleQueryBarCompletionProvider { return Task::ready(Ok(Vec::new())); }; - let support_completions = console.update(cx, |this, cx| { - this.dap_store - .update(cx, |store, cx| { - store.capabilities_by_id(&this.client_id, cx) - }) - .supports_completions_request - .unwrap_or_default() - }); + let support_completions = console + .read(cx) + .dap_store + .read(cx) + .capabilities_by_id(&console.read(cx).client_id) + .supports_completions_request + .unwrap_or_default(); if support_completions { self.client_completions(&console, buffer, buffer_position, cx) diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index 5594245cb74fff..023fa6eacb3e6a 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -561,7 +561,7 @@ impl DebugPanel { Events::Module(event) => self.handle_module_event(&client_id, event, cx), Events::LoadedSource(event) => self.handle_loaded_source_event(&client_id, event, cx), Events::Capabilities(event) => { - self.handle_capabilities_changed_event(client_id, event, cx); + self.handle_capabilities_changed_event(session_id, client_id, event, cx); } Events::Memory(_) => {} Events::Process(_) => {} @@ -582,7 +582,7 @@ impl DebugPanel { ) { if let Some(capabilities) = capabilities { self.dap_store.update(cx, |store, cx| { - store.merge_capabilities_for_client(&client_id, capabilities, cx); + store.merge_capabilities_for_client(&session_id, &client_id, capabilities, cx); }); cx.emit(DebugPanelEvent::CapabilitiesChanged(*client_id)); @@ -917,12 +917,13 @@ impl DebugPanel { fn handle_capabilities_changed_event( &mut self, + session_id: &DebugSessionId, client_id: &DebugAdapterClientId, event: &CapabilitiesEvent, cx: &mut ViewContext, ) { self.dap_store.update(cx, |store, cx| { - store.merge_capabilities_for_client(client_id, &event.capabilities, cx); + store.merge_capabilities_for_client(session_id, client_id, &event.capabilities, cx); }); cx.emit(DebugPanelEvent::CapabilitiesChanged(*client_id)); diff --git a/crates/debugger_ui/src/debugger_panel_item.rs b/crates/debugger_ui/src/debugger_panel_item.rs index 8a84ecc5dbb6b8..a2251b81f8ee6a 100644 --- a/crates/debugger_ui/src/debugger_panel_item.rs +++ b/crates/debugger_ui/src/debugger_panel_item.rs @@ -428,20 +428,19 @@ impl DebugPanelItem { return; } - self.dap_store.update(cx, |dap_store, cx| { - if let Some((downstream_client, project_id)) = dap_store.downstream_client() { - let message = proto_conversions::capabilities_to_proto( - &dap_store.capabilities_by_id(client_id, cx), - *project_id, - self.session_id.to_proto(), - self.client_id.to_proto(), - ); - - downstream_client.send(message).log_err(); - } - }); - + // notify the view that the capabilities have changed cx.notify(); + + if let Some((downstream_client, project_id)) = self.dap_store.read(cx).downstream_client() { + let message = proto_conversions::capabilities_to_proto( + &self.dap_store.read(cx).capabilities_by_id(client_id), + *project_id, + self.session_id.to_proto(), + self.client_id.to_proto(), + ); + + downstream_client.send(message).log_err(); + } } pub(crate) fn update_adapter( @@ -502,9 +501,7 @@ impl DebugPanelItem { } pub fn capabilities(&self, cx: &mut ViewContext) -> Capabilities { - self.dap_store.update(cx, |store, cx| { - store.capabilities_by_id(&self.client_id, cx) - }) + self.dap_store.read(cx).capabilities_by_id(&self.client_id) } fn clear_highlights(&self, cx: &mut ViewContext) { diff --git a/crates/debugger_ui/src/variable_list.rs b/crates/debugger_ui/src/variable_list.rs index edf02e4690207a..4486172e7d1591 100644 --- a/crates/debugger_ui/src/variable_list.rs +++ b/crates/debugger_ui/src/variable_list.rs @@ -831,12 +831,12 @@ impl VariableList { ) { let this = cx.view().clone(); - let support_set_variable = self.dap_store.update(cx, |store, cx| { - store - .capabilities_by_id(&self.client_id, cx) - .supports_set_variable - .unwrap_or_default() - }); + let support_set_variable = self + .dap_store + .read(cx) + .capabilities_by_id(&self.client_id) + .supports_set_variable + .unwrap_or_default(); let context_menu = ContextMenu::build(cx, |menu, cx| { menu.entry( diff --git a/crates/project/src/dap_store.rs b/crates/project/src/dap_store.rs index 64cbb2a3822338..ac05c840e93415 100644 --- a/crates/project/src/dap_store.rs +++ b/crates/project/src/dap_store.rs @@ -109,6 +109,7 @@ pub struct DapStore { mode: DapStoreMode, downstream_client: Option<(AnyProtoClient, u64)>, breakpoints: BTreeMap>, + capabilities: HashMap, client_by_session: HashMap, active_debug_line: Option<(DebugAdapterClientId, ProjectPath, u32)>, } @@ -155,6 +156,7 @@ impl DapStore { downstream_client: None, active_debug_line: None, breakpoints: Default::default(), + capabilities: Default::default(), client_by_session: Default::default(), } } @@ -172,6 +174,7 @@ impl DapStore { downstream_client: None, active_debug_line: None, breakpoints: Default::default(), + capabilities: Default::default(), client_by_session: Default::default(), } } @@ -241,34 +244,34 @@ impl DapStore { Some((session, client)) } - pub fn capabilities_by_id( - &self, - client_id: &DebugAdapterClientId, - cx: &mut ModelContext, - ) -> Capabilities { - if let Some((session, _)) = self.client_by_id(client_id, cx) { - session.read(cx).capabilities(client_id) - } else { - Capabilities::default() - } + pub fn capabilities_by_id(&self, client_id: &DebugAdapterClientId) -> Capabilities { + self.capabilities + .get(client_id) + .cloned() + .unwrap_or_default() } pub fn merge_capabilities_for_client( &mut self, + session_id: &DebugSessionId, client_id: &DebugAdapterClientId, other: &Capabilities, cx: &mut ModelContext, ) { - if let Some((session, _)) = self.client_by_id(client_id, cx) { - session.update(cx, |session, cx| { - session.update_capabilities( - client_id, - session.capabilities(client_id).merge(other.clone()), - cx, + if let Some(capabilities) = self.capabilities.get_mut(client_id) { + *capabilities = capabilities.merge(other.clone()); + cx.notify(); + + if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() { + let message = dap::proto_conversions::capabilities_to_proto( + &capabilities, + *project_id, + session_id.to_proto(), + client_id.to_proto(), ); - }); - cx.notify(); + downstream_client.send(message).log_err(); + } } } @@ -619,7 +622,7 @@ impl DapStore { client_id: &DebugAdapterClientId, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!( "Could not find debug client: {:?} for session {:?}", client_id, @@ -653,21 +656,7 @@ impl DapStore { .await?; this.update(&mut cx, |store, cx| { - session.update(cx, |session, cx| { - session.update_capabilities(&client_id, capabilities.clone(), cx); - }); - cx.notify(); - - if let Some((downstream_client, project_id)) = store.downstream_client.as_ref() { - let message = dap::proto_conversions::capabilities_to_proto( - &capabilities, - *project_id, - session_id.to_proto(), - client_id.to_proto(), - ); - - downstream_client.send(message).log_err(); - } + store.merge_capabilities_for_client(&session_id, &client_id, &capabilities, cx); }) }) } @@ -747,13 +736,15 @@ impl DapStore { client_id: &DebugAdapterClientId, cx: &mut ModelContext, ) -> Task>> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Client was not found"))); }; - let capabilities = session.read(cx).capabilities(client_id); - - if !capabilities.supports_modules_request.unwrap_or_default() { + if !self + .capabilities_by_id(client_id) + .supports_modules_request + .unwrap_or_default() + { return Task::ready(Ok(Vec::default())); } @@ -773,13 +764,12 @@ impl DapStore { client_id: &DebugAdapterClientId, cx: &mut ModelContext, ) -> Task>> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Client was not found"))); }; - let capabilities = session.read(cx).capabilities(client_id); - - if !capabilities + if !self + .capabilities_by_id(client_id) .supports_loaded_sources_request .unwrap_or_default() { @@ -842,25 +832,23 @@ impl DapStore { client_id: &DebugAdapterClientId, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); }; - let capabilities = session.read(cx).capabilities(client_id); - - cx.background_executor().spawn(async move { - let support_configuration_done_request = capabilities - .supports_configuration_done_request - .unwrap_or_default(); - - if support_configuration_done_request { + if self + .capabilities_by_id(client_id) + .supports_configuration_done_request + .unwrap_or_default() + { + cx.background_executor().spawn(async move { client .request::(ConfigurationDoneArguments) .await - } else { - Ok(()) - } - }) + }) + } else { + Task::ready(Ok(())) + } } pub fn respond_to_start_debugging( @@ -1021,12 +1009,11 @@ impl DapStore { granularity: SteppingGranularity, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); }; - let capabilities = session.read(cx).capabilities(client_id); - + let capabilities = self.capabilities_by_id(client_id); let supports_single_thread_execution_requests = capabilities .supports_single_thread_execution_requests .unwrap_or_default(); @@ -1052,12 +1039,11 @@ impl DapStore { granularity: SteppingGranularity, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); }; - let capabilities = session.read(cx).capabilities(client_id); - + let capabilities = self.capabilities_by_id(client_id); let supports_single_thread_execution_requests = capabilities .supports_single_thread_execution_requests .unwrap_or_default(); @@ -1084,12 +1070,11 @@ impl DapStore { granularity: SteppingGranularity, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); }; - let capabilities = session.read(cx).capabilities(client_id); - + let capabilities = self.capabilities_by_id(client_id); let supports_single_thread_execution_requests = capabilities .supports_single_thread_execution_requests .unwrap_or_default(); @@ -1115,19 +1100,11 @@ impl DapStore { granularity: SteppingGranularity, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); }; - let capabilities = session.read(cx).capabilities(client_id); - - if capabilities.supports_step_back.unwrap_or(false) { - return Task::ready(Err(anyhow!( - "Step back request isn't support for client_id: {:?}", - client_id - ))); - } - + let capabilities = self.capabilities_by_id(client_id); let supports_single_thread_execution_requests = capabilities .supports_single_thread_execution_requests .unwrap_or_default(); @@ -1135,15 +1112,19 @@ impl DapStore { .supports_stepping_granularity .unwrap_or_default(); - cx.background_executor().spawn(async move { - client - .request::(StepBackArguments { - thread_id, - granularity: supports_stepping_granularity.then(|| granularity), - single_thread: supports_single_thread_execution_requests.then(|| true), - }) - .await - }) + if capabilities.supports_step_back.unwrap_or_default() { + cx.background_executor().spawn(async move { + client + .request::(StepBackArguments { + thread_id, + granularity: supports_stepping_granularity.then(|| granularity), + single_thread: supports_single_thread_execution_requests.then(|| true), + }) + .await + }) + } else { + Task::ready(Ok(())) + } } pub fn variables( @@ -1238,7 +1219,7 @@ impl DapStore { }; let supports_set_expression = self - .capabilities_by_id(client_id, cx) + .capabilities_by_id(client_id) .supports_set_expression .unwrap_or_default(); @@ -1287,13 +1268,12 @@ impl DapStore { thread_ids: Option>, cx: &mut ModelContext, ) -> Task> { - let Some((session, client)) = self.client_by_id(client_id, cx) else { + let Some((_, client)) = self.client_by_id(client_id, cx) else { return Task::ready(Err(anyhow!("Could not find client: {:?}", client_id))); }; - let capabilities = session.read(cx).capabilities(client_id); - - if capabilities + if self + .capabilities_by_id(client_id) .supports_terminate_threads_request .unwrap_or_default() { @@ -1338,7 +1318,7 @@ impl DapStore { }; let supports_restart = self - .capabilities_by_id(client_id, cx) + .capabilities_by_id(client_id) .supports_restart_request .unwrap_or_default(); @@ -1410,7 +1390,7 @@ impl DapStore { cx.emit(DapStoreEvent::DebugClientShutdown(*client_id)); - let capabilities = session.read(cx).capabilities(client_id); + let capabilities = self.capabilities.remove(client_id).unwrap_or_default(); if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() { let request = proto::ShutdownDebugClient { @@ -1528,18 +1508,12 @@ impl DapStore { mut cx: AsyncAppContext, ) -> Result<()> { this.update(&mut cx, |dap_store, cx| { - let session_id = DebugSessionId::from_proto(envelope.payload.session_id); - if let Some(session) = dap_store.session_by_id(&session_id) { - session.update(cx, |session, cx| { - session.update_capabilities( - &DebugAdapterClientId::from_proto(envelope.payload.client_id), - dap::proto_conversions::capabilities_from_proto(&envelope.payload), - cx, - ); - }); - - cx.notify(); - } + dap_store.merge_capabilities_for_client( + &DebugSessionId::from_proto(envelope.payload.session_id), + &DebugAdapterClientId::from_proto(envelope.payload.client_id), + &dap::proto_conversions::capabilities_from_proto(&envelope.payload), + cx, + ); }) }