diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index 489866907f..b19a3633c7 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -33,6 +33,7 @@ use std::sync::Arc; use task::DebugTaskDefinition; use terminal_view::terminal_panel::TerminalPanel; use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*}; +use util::debug_panic; use workspace::{ Workspace, dock::{DockPosition, Panel, PanelEvent}, @@ -316,8 +317,20 @@ impl DebugPanel { .any(|item| item.read(cx).session_id(cx) == session_id) { // We already have an item for this session. + debug_panic!("We should never reuse session ids"); return; } + + this.sessions.retain(|session| { + session + .read(cx) + .mode() + .as_running() + .map_or(false, |running_state| { + !running_state.read(cx).session().read(cx).is_terminated() + }) + }); + let session_item = DebugSession::running( project, this.workspace.clone(), @@ -769,9 +782,6 @@ impl DebugPanel { this.restart_session(cx); }, )) - .disabled( - !capabilities.supports_restart_request.unwrap_or_default(), - ) .tooltip(move |window, cx| { Tooltip::text("Restart")(window, cx) }), diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index dce63fa4c0..049a9a72f9 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -792,10 +792,48 @@ fn create_new_session( this.update(cx, |_, cx| { cx.subscribe( &session, - move |this: &mut DapStore, _, event: &SessionStateEvent, cx| match event { + move |this: &mut DapStore, session, event: &SessionStateEvent, cx| match event { SessionStateEvent::Shutdown => { this.shutdown_session(session_id, cx).detach_and_log_err(cx); } + SessionStateEvent::Restart => { + let Some((config, binary)) = session.read_with(cx, |session, _| { + session + .configuration() + .map(|config| (config, session.binary().clone())) + }) else { + log::error!("Failed to get debug config from session"); + return; + }; + + let mut curr_session = session; + while let Some(parent_id) = curr_session.read(cx).parent_id() { + if let Some(parent_session) = this.sessions.get(&parent_id).cloned() { + curr_session = parent_session; + } else { + log::error!("Failed to get parent session from parent session id"); + break; + } + } + + let session_id = curr_session.read(cx).session_id(); + + let task = curr_session.update(cx, |session, cx| session.shutdown(cx)); + + cx.spawn(async move |this, cx| { + task.await; + + this.update(cx, |this, cx| { + this.sessions.remove(&session_id); + this.new_session(binary, config, None, cx) + })? + .1 + .await?; + + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } }, ) .detach(); diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 8d3ae43590..beaf5fd4e7 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -397,6 +397,7 @@ impl LocalMode { self.definition.initialize_args.clone().unwrap_or(json!({})), &mut raw.configuration, ); + // Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522 let launch = match raw.request { dap::StartDebuggingRequestArgumentsRequest::Launch => self.request( @@ -684,8 +685,9 @@ pub enum SessionEvent { Threads, } -pub(crate) enum SessionStateEvent { +pub(super) enum SessionStateEvent { Shutdown, + Restart, } impl EventEmitter for Session {} @@ -1362,6 +1364,18 @@ impl Session { &self.loaded_sources } + fn fallback_to_manual_restart( + &mut self, + res: Result<()>, + cx: &mut Context, + ) -> Option<()> { + if res.log_err().is_none() { + cx.emit(SessionStateEvent::Restart); + return None; + } + Some(()) + } + fn empty_response(&mut self, res: Result<()>, _cx: &mut Context) -> Option<()> { res.log_err()?; Some(()) @@ -1421,26 +1435,17 @@ impl Session { } pub fn restart(&mut self, args: Option, cx: &mut Context) { - if self.capabilities.supports_restart_request.unwrap_or(false) { + if self.capabilities.supports_restart_request.unwrap_or(false) && !self.is_terminated() { self.request( RestartCommand { raw: args.unwrap_or(Value::Null), }, - Self::empty_response, + Self::fallback_to_manual_restart, cx, ) .detach(); } else { - self.request( - DisconnectCommand { - restart: Some(false), - terminate_debuggee: Some(true), - suspend_debuggee: Some(false), - }, - Self::empty_response, - cx, - ) - .detach(); + cx.emit(SessionStateEvent::Restart); } } @@ -1475,8 +1480,14 @@ impl Session { cx.emit(SessionStateEvent::Shutdown); + let debug_client = self.adapter_client(); + cx.background_spawn(async move { let _ = task.await; + + if let Some(client) = debug_client { + client.shutdown().await.log_err(); + } }) }