aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-dap/src/client.rs28
-rw-r--r--helix-dap/src/lib.rs2
-rw-r--r--helix-dap/src/types.rs13
-rw-r--r--helix-term/src/commands/dap.rs2
-rw-r--r--helix-view/src/handlers/dap.rs63
5 files changed, 99 insertions, 9 deletions
diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs
index 10d93180..f6d8a069 100644
--- a/helix-dap/src/client.rs
+++ b/helix-dap/src/client.rs
@@ -1,4 +1,5 @@
use crate::{
+ requests::DisconnectArguments,
transport::{Payload, Request, Response, Transport},
types::*,
Error, Result, ThreadId,
@@ -31,6 +32,7 @@ pub struct Client {
_process: Option<Child>,
server_tx: UnboundedSender<Payload>,
request_counter: AtomicU64,
+ connection_type: Option<ConnectionType>,
pub caps: Option<DebuggerCapabilities>,
// thread_id -> frames
pub stack_frames: HashMap<ThreadId, Vec<StackFrame>>,
@@ -41,6 +43,12 @@ pub struct Client {
pub quirks: DebuggerQuirks,
}
+#[derive(Clone, Copy, Debug)]
+pub enum ConnectionType {
+ Launch,
+ Attach,
+}
+
impl Client {
// Spawn a process and communicate with it by either TCP or stdio
pub async fn process(
@@ -78,7 +86,7 @@ impl Client {
server_tx,
request_counter: AtomicU64::new(0),
caps: None,
- //
+ connection_type: None,
stack_frames: HashMap::new(),
thread_states: HashMap::new(),
thread_id: None,
@@ -207,6 +215,10 @@ impl Client {
self.id
}
+ pub fn connection_type(&self) -> Option<ConnectionType> {
+ self.connection_type
+ }
+
fn next_request_id(&self) -> u64 {
self.request_counter.fetch_add(1, Ordering::Relaxed)
}
@@ -334,15 +346,21 @@ impl Client {
Ok(())
}
- pub fn disconnect(&self) -> impl Future<Output = Result<Value>> {
- self.call::<requests::Disconnect>(())
+ pub fn disconnect(
+ &mut self,
+ args: Option<DisconnectArguments>,
+ ) -> impl Future<Output = Result<Value>> {
+ self.connection_type = None;
+ self.call::<requests::Disconnect>(args)
}
- pub fn launch(&self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
+ pub fn launch(&mut self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
+ self.connection_type = Some(ConnectionType::Launch);
self.call::<requests::Launch>(args)
}
- pub fn attach(&self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
+ pub fn attach(&mut self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
+ self.connection_type = Some(ConnectionType::Attach);
self.call::<requests::Attach>(args)
}
diff --git a/helix-dap/src/lib.rs b/helix-dap/src/lib.rs
index 24d7472b..21162cb8 100644
--- a/helix-dap/src/lib.rs
+++ b/helix-dap/src/lib.rs
@@ -2,7 +2,7 @@ mod client;
mod transport;
mod types;
-pub use client::Client;
+pub use client::{Client, ConnectionType};
pub use events::Event;
pub use transport::{Payload, Response, Transport};
pub use types::*;
diff --git a/helix-dap/src/types.rs b/helix-dap/src/types.rs
index 0a9ebe5e..c598790b 100644
--- a/helix-dap/src/types.rs
+++ b/helix-dap/src/types.rs
@@ -391,11 +391,22 @@ pub mod requests {
const COMMAND: &'static str = "attach";
}
+ #[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
+ #[serde(rename_all = "camelCase")]
+ pub struct DisconnectArguments {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub restart: Option<bool>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub terminate_debuggee: Option<bool>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub suspend_debuggee: Option<bool>,
+ }
+
#[derive(Debug)]
pub enum Disconnect {}
impl Request for Disconnect {
- type Arguments = ();
+ type Arguments = Option<DisconnectArguments>;
type Result = ();
const COMMAND: &'static str = "disconnect";
}
diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs
index b3166e39..b30dc8c0 100644
--- a/helix-term/src/commands/dap.rs
+++ b/helix-term/src/commands/dap.rs
@@ -539,7 +539,7 @@ pub fn dap_variables(cx: &mut Context) {
pub fn dap_terminate(cx: &mut Context) {
let debugger = debugger!(cx.editor);
- let request = debugger.disconnect();
+ let request = debugger.disconnect(None);
dap_callback(cx.jobs, request, |editor, _compositor, _response: ()| {
// editor.set_error(format!("Failed to disconnect: {}", e));
editor.debugger = None;
diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs
index 2e86871b..107c29be 100644
--- a/helix-view/src/handlers/dap.rs
+++ b/helix-view/src/handlers/dap.rs
@@ -1,7 +1,8 @@
use crate::editor::{Action, Breakpoint};
use crate::{align_view, Align, Editor};
+use dap::requests::DisconnectArguments;
use helix_core::Selection;
-use helix_dap::{self as dap, Client, Payload, Request, ThreadId};
+use helix_dap::{self as dap, Client, ConnectionType, Payload, Request, ThreadId};
use helix_lsp::block_on;
use log::warn;
use std::fmt::Write;
@@ -274,6 +275,66 @@ impl Editor {
self.set_status("Debugged application started");
}; // TODO: do we need to handle error?
}
+ Event::Terminated(terminated) => {
+ let restart_args = if let Some(terminated) = terminated {
+ terminated.restart
+ } else {
+ None
+ };
+
+ let disconnect_args = Some(DisconnectArguments {
+ restart: Some(restart_args.is_some()),
+ terminate_debuggee: None,
+ suspend_debuggee: None,
+ });
+
+ if let Err(err) = debugger.disconnect(disconnect_args).await {
+ self.set_error(format!(
+ "Cannot disconnect debugger upon terminated event receival {:?}",
+ err
+ ));
+ return false;
+ }
+
+ match restart_args {
+ Some(restart_args) => {
+ log::info!("Attempting to restart debug session.");
+ let connection_type = match debugger.connection_type() {
+ Some(connection_type) => connection_type,
+ None => {
+ self.set_error("No starting request found, to be used in restarting the debugging session.");
+ return false;
+ }
+ };
+
+ let relaunch_resp = if let ConnectionType::Launch = connection_type {
+ debugger.launch(restart_args).await
+ } else {
+ debugger.attach(restart_args).await
+ };
+
+ if let Err(err) = relaunch_resp {
+ self.set_error(format!(
+ "Failed to restart debugging session: {:?}",
+ err
+ ));
+ }
+ }
+ None => {
+ self.set_status(
+ "Terminated debugging session and disconnected debugger.",
+ );
+ }
+ }
+ }
+ Event::Exited(resp) => {
+ let exit_code = resp.exit_code;
+ if exit_code != 0 {
+ self.set_error(format!(
+ "Debuggee failed to exit successfully (exit code: {exit_code})."
+ ));
+ }
+ }
ev => {
log::warn!("Unhandled event {:?}", ev);
return false; // return early to skip render