debugger: Enable manually restarting a session when a DAP server doesn't support restarting (#28908)
This PR also fixes the unexpected behavior of clicking restart when a session is terminated and nothing happens. And we fixed a small bug where `DebugClientAdapter.shutdown()` was never called. Release Notes: - N/A --------- Co-authored-by: Cole Miller <m@cole-miller.net>
This commit is contained in:
parent
21946691a4
commit
78c856cb75
3 changed files with 76 additions and 17 deletions
|
@ -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)
|
||||
}),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<SessionEvent> for Session {}
|
||||
|
@ -1362,6 +1364,18 @@ impl Session {
|
|||
&self.loaded_sources
|
||||
}
|
||||
|
||||
fn fallback_to_manual_restart(
|
||||
&mut self,
|
||||
res: Result<()>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<()> {
|
||||
if res.log_err().is_none() {
|
||||
cx.emit(SessionStateEvent::Restart);
|
||||
return None;
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn empty_response(&mut self, res: Result<()>, _cx: &mut Context<Self>) -> Option<()> {
|
||||
res.log_err()?;
|
||||
Some(())
|
||||
|
@ -1421,26 +1435,17 @@ impl Session {
|
|||
}
|
||||
|
||||
pub fn restart(&mut self, args: Option<Value>, cx: &mut Context<Self>) {
|
||||
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();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue