Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | helix-dap-types/src/lib.rs | 57 | ||||
| -rw-r--r-- | helix-dap/src/client.rs | 24 | ||||
| -rw-r--r-- | helix-dap/src/lib.rs | 61 | ||||
| -rw-r--r-- | helix-view/src/handlers/dap.rs | 40 |
4 files changed, 177 insertions, 5 deletions
diff --git a/helix-dap-types/src/lib.rs b/helix-dap-types/src/lib.rs index 11eda181..cee06aa5 100644 --- a/helix-dap-types/src/lib.rs +++ b/helix-dap-types/src/lib.rs @@ -923,6 +923,63 @@ pub mod events { } #[derive(Debug)] + pub enum ProgressStart {} + + impl Event for ProgressStart { + type Body = ProgressStartBody; + const EVENT: &'static str = "progressStart"; + } + + #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct ProgressStartBody { + pub progress_id: String, + pub title: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub request_id: Option<u64>, + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option<u8>, + } + + #[derive(Debug)] + pub enum ProgressUpdate {} + + impl Event for ProgressUpdate { + type Body = ProgressUpdateBody; + const EVENT: &'static str = "progressUpdate"; + } + + #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct ProgressUpdateBody { + pub progress_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option<u8>, + } + + #[derive(Debug)] + pub enum ProgressEnd {} + + impl Event for ProgressEnd { + type Body = ProgressEndBody; + const EVENT: &'static str = "progressEnd"; + } + + #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct ProgressEndBody { + pub progress_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option<String>, + } + + #[derive(Debug)] pub enum Breakpoint {} impl Event for Breakpoint { diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index bef0556c..1ecd949f 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -2,7 +2,7 @@ use crate::{ registry::DebugAdapterId, requests::{DisconnectArguments, TerminateArguments}, transport::{Payload, Request, Response, Transport}, - Error, Result, + Error, ProgressMap, ProgressState, Result, }; use helix_core::syntax::config::{DebugAdapterConfig, DebuggerQuirks}; use helix_dap_types::*; @@ -40,6 +40,7 @@ pub struct Client { // thread_id -> frames pub stack_frames: HashMap<ThreadId, Vec<StackFrame>>, pub thread_states: ThreadStates, + pub progress: ProgressMap, pub thread_id: Option<ThreadId>, /// Currently active frame for the current thread. pub active_frame: Option<usize>, @@ -89,6 +90,7 @@ impl Client { socket: None, stack_frames: HashMap::new(), thread_states: HashMap::new(), + progress: HashMap::new(), thread_id: None, active_frame: None, quirks: DebuggerQuirks::default(), @@ -348,6 +350,24 @@ impl Client { self.caps.as_ref().expect("debugger not yet initialized!") } + pub fn progress_start(&mut self, event: events::ProgressStartBody) -> String { + let status = ProgressState::new(event.title, event.message, event.percentage); + let status_line = status.status_line(); + self.progress.insert(event.progress_id, status); + status_line + } + + pub fn progress_update(&mut self, event: events::ProgressUpdateBody) -> Option<String> { + let status = self.progress.get_mut(&event.progress_id)?; + status.update(event.message, event.percentage); + Some(status.status_line()) + } + + pub fn progress_end(&mut self, event: events::ProgressEndBody) -> Option<String> { + let status = self.progress.remove(&event.progress_id)?; + Some(status.end_status_line(event.message.as_deref())) + } + pub async fn initialize(&mut self, adapter_id: String) -> Result<()> { let args = requests::InitializeArguments { client_id: Some("hx".to_owned()), @@ -361,7 +381,7 @@ impl Client { supports_variable_paging: Some(false), supports_run_in_terminal_request: Some(true), supports_memory_references: Some(false), - supports_progress_reporting: Some(false), + supports_progress_reporting: Some(true), supports_invalidated_event: Some(false), }; diff --git a/helix-dap/src/lib.rs b/helix-dap/src/lib.rs index 907ff965..745abc9f 100644 --- a/helix-dap/src/lib.rs +++ b/helix-dap/src/lib.rs @@ -7,6 +7,7 @@ pub use helix_dap_types::*; pub use transport::{Payload, Response, Transport}; use serde::de::DeserializeOwned; +use std::collections::HashMap; use thiserror::Error; #[derive(Error, Debug)] @@ -75,9 +76,9 @@ pub enum Event { LoadedSource(<events::LoadedSource as events::Event>::Body), Process(<events::Process as events::Event>::Body), Capabilities(<events::Capabilities as events::Event>::Body), - // ProgressStart(), - // ProgressUpdate(), - // ProgressEnd(), + ProgressStart(<events::ProgressStart as events::Event>::Body), + ProgressUpdate(<events::ProgressUpdate as events::Event>::Body), + ProgressEnd(<events::ProgressEnd as events::Event>::Body), // Invalidated(), Memory(<events::Memory as events::Event>::Body), } @@ -100,6 +101,9 @@ impl Event { events::LoadedSource::EVENT => Self::LoadedSource(parse_value(body)?), events::Process::EVENT => Self::Process(parse_value(body)?), events::Capabilities::EVENT => Self::Capabilities(parse_value(body)?), + events::ProgressStart::EVENT => Self::ProgressStart(parse_value(body)?), + events::ProgressUpdate::EVENT => Self::ProgressUpdate(parse_value(body)?), + events::ProgressEnd::EVENT => Self::ProgressEnd(parse_value(body)?), events::Memory::EVENT => Self::Memory(parse_value(body)?), _ => return Err(Error::Unhandled), }; @@ -114,3 +118,54 @@ where { serde_json::from_value(value).map_err(|err| err.into()) } + +#[derive(Debug, Clone)] +pub struct ProgressState { + title: String, + message: Option<String>, + percentage: Option<u8>, +} + +impl ProgressState { + pub fn new(title: String, message: Option<String>, percentage: Option<u8>) -> Self { + Self { + title, + message, + percentage, + } + } + + pub fn update(&mut self, message: Option<String>, percentage: Option<u8>) { + if let Some(message) = message { + self.message = Some(message); + } + if let Some(percentage) = percentage { + self.percentage = Some(percentage); + } + } + + pub fn status_line(&self) -> String { + let mut status = format!("Debug: {}", self.title); + if let Some(message) = self.message.as_deref() { + status.push_str(" - "); + status.push_str(message); + } + if let Some(percentage) = self.percentage { + status.push_str(&format!(" ({}%)", percentage)); + } + status + } + + pub fn end_status_line(&self, message: Option<&str>) -> String { + let mut status = format!("Debug: {}", self.title); + if let Some(message) = message.or(self.message.as_deref()) { + status.push_str(" - "); + status.push_str(message); + } else { + status.push_str(" finished"); + } + status + } +} + +pub type ProgressMap = HashMap<String, ProgressState>; diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index b913ce8e..f8f3c1b8 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -332,6 +332,46 @@ impl Editor { log::info!("{}", output); self.set_status(format!("{} {}", prefix, output)); } + Event::ProgressStart(body) => { + let status = { + let debugger = match self.debug_adapters.get_client_mut(id) { + Some(debugger) => debugger, + None => return false, + }; + + debugger.progress_start(body) + }; + + self.set_status(status); + } + Event::ProgressUpdate(body) => { + let status = { + let debugger = match self.debug_adapters.get_client_mut(id) { + Some(debugger) => debugger, + None => return false, + }; + + debugger.progress_update(body) + }; + + if let Some(status) = status { + self.set_status(status); + } + } + Event::ProgressEnd(body) => { + let status = { + let debugger = match self.debug_adapters.get_client_mut(id) { + Some(debugger) => debugger, + None => return false, + }; + + debugger.progress_end(body) + }; + + if let Some(status) = status { + self.set_status(status); + } + } Event::Initialized(_) => { self.set_status("Debugger initialized..."); let debugger = match self.debug_adapters.get_client_mut(id) { |