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 task::DebugTaskDefinition;
|
||||||
use terminal_view::terminal_panel::TerminalPanel;
|
use terminal_view::terminal_panel::TerminalPanel;
|
||||||
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
||||||
|
use util::debug_panic;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
Workspace,
|
Workspace,
|
||||||
dock::{DockPosition, Panel, PanelEvent},
|
dock::{DockPosition, Panel, PanelEvent},
|
||||||
|
@ -316,8 +317,20 @@ impl DebugPanel {
|
||||||
.any(|item| item.read(cx).session_id(cx) == session_id)
|
.any(|item| item.read(cx).session_id(cx) == session_id)
|
||||||
{
|
{
|
||||||
// We already have an item for this session.
|
// We already have an item for this session.
|
||||||
|
debug_panic!("We should never reuse session ids");
|
||||||
return;
|
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(
|
let session_item = DebugSession::running(
|
||||||
project,
|
project,
|
||||||
this.workspace.clone(),
|
this.workspace.clone(),
|
||||||
|
@ -769,9 +782,6 @@ impl DebugPanel {
|
||||||
this.restart_session(cx);
|
this.restart_session(cx);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.disabled(
|
|
||||||
!capabilities.supports_restart_request.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.tooltip(move |window, cx| {
|
.tooltip(move |window, cx| {
|
||||||
Tooltip::text("Restart")(window, cx)
|
Tooltip::text("Restart")(window, cx)
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -792,10 +792,48 @@ fn create_new_session(
|
||||||
this.update(cx, |_, cx| {
|
this.update(cx, |_, cx| {
|
||||||
cx.subscribe(
|
cx.subscribe(
|
||||||
&session,
|
&session,
|
||||||
move |this: &mut DapStore, _, event: &SessionStateEvent, cx| match event {
|
move |this: &mut DapStore, session, event: &SessionStateEvent, cx| match event {
|
||||||
SessionStateEvent::Shutdown => {
|
SessionStateEvent::Shutdown => {
|
||||||
this.shutdown_session(session_id, cx).detach_and_log_err(cx);
|
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();
|
.detach();
|
||||||
|
|
|
@ -397,6 +397,7 @@ impl LocalMode {
|
||||||
self.definition.initialize_args.clone().unwrap_or(json!({})),
|
self.definition.initialize_args.clone().unwrap_or(json!({})),
|
||||||
&mut raw.configuration,
|
&mut raw.configuration,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
|
// Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
|
||||||
let launch = match raw.request {
|
let launch = match raw.request {
|
||||||
dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(
|
dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(
|
||||||
|
@ -684,8 +685,9 @@ pub enum SessionEvent {
|
||||||
Threads,
|
Threads,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum SessionStateEvent {
|
pub(super) enum SessionStateEvent {
|
||||||
Shutdown,
|
Shutdown,
|
||||||
|
Restart,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<SessionEvent> for Session {}
|
impl EventEmitter<SessionEvent> for Session {}
|
||||||
|
@ -1362,6 +1364,18 @@ impl Session {
|
||||||
&self.loaded_sources
|
&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<()> {
|
fn empty_response(&mut self, res: Result<()>, _cx: &mut Context<Self>) -> Option<()> {
|
||||||
res.log_err()?;
|
res.log_err()?;
|
||||||
Some(())
|
Some(())
|
||||||
|
@ -1421,26 +1435,17 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restart(&mut self, args: Option<Value>, cx: &mut Context<Self>) {
|
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(
|
self.request(
|
||||||
RestartCommand {
|
RestartCommand {
|
||||||
raw: args.unwrap_or(Value::Null),
|
raw: args.unwrap_or(Value::Null),
|
||||||
},
|
},
|
||||||
Self::empty_response,
|
Self::fallback_to_manual_restart,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.detach();
|
.detach();
|
||||||
} else {
|
} else {
|
||||||
self.request(
|
cx.emit(SessionStateEvent::Restart);
|
||||||
DisconnectCommand {
|
|
||||||
restart: Some(false),
|
|
||||||
terminate_debuggee: Some(true),
|
|
||||||
suspend_debuggee: Some(false),
|
|
||||||
},
|
|
||||||
Self::empty_response,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,8 +1480,14 @@ impl Session {
|
||||||
|
|
||||||
cx.emit(SessionStateEvent::Shutdown);
|
cx.emit(SessionStateEvent::Shutdown);
|
||||||
|
|
||||||
|
let debug_client = self.adapter_client();
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
let _ = task.await;
|
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