on master help sign in
Add more event types, simplify event decoding
2865883Blaž Hrastnik
helix-dap/src/lib.rs+2−1
@@ -3,7 +3,8 @@ mod transport;
3mod types;
3mod types;
4
4
5pub use client::Client;
5pub use client::Client;
6+pub use events::Event;
6−pub use transport::{Event, Payload, Response, Transport};
7+pub use transport::{Payload, Response, Transport};
7pub use types::*;
8pub use types::*;
8
9
9use thiserror::Error;
10use thiserror::Error;
helix-dap/src/transport.rs+3−10
@@ -1,4 +1,4 @@
1−use crate::{Error, Result};
1+use crate::{Error, Event, Result};
2use anyhow::Context;
2use anyhow::Context;
3use log::{error, info, warn};
3use log::{error, info, warn};
4use serde::{Deserialize, Serialize};
4use serde::{Deserialize, Serialize};
@@ -32,13 +32,6 @@ pub struct Response {
32 pub body: Option<Value>,
32 pub body: Option<Value>,
33}
33}
34
34
35−#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
36−pub struct Event {
37− // seq is omitted as unused and is not sent by some implementations
38− pub event: String,
39− pub body: Option<Value>,
40−}
41−
42#[derive(Debug, Clone, Deserialize, Serialize)]
35#[derive(Debug, Clone, Deserialize, Serialize)]
43#[serde(tag = "type", rename_all = "camelCase")]
36#[serde(tag = "type", rename_all = "camelCase")]
44pub enum Payload {
37pub enum Payload {
@@ -208,8 +201,8 @@ impl Transport {
208 client_tx.send(msg).expect("Failed to send");
201 client_tx.send(msg).expect("Failed to send");
209 Ok(())
202 Ok(())
210 }
203 }
211− Payload::Event(Event { ref event, .. }) => {
204+ Payload::Event(ref event) => {
212− info!("<- DAP event {}", event);
205+ info!("<- DAP event {:?}", event);
213 client_tx.send(msg).expect("Failed to send");
206 client_tx.send(msg).expect("Failed to send");
214 Ok(())
207 Ok(())
215 }
208 }
helix-dap/src/types.rs+126−7
@@ -206,6 +206,21 @@ pub struct Variable {
206 pub memory_reference: Option<String>,
206 pub memory_reference: Option<String>,
207}
207}
208
208
209+#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
210+#[serde(rename_all = "camelCase")]
211+pub struct Module {
212+ pub id: String, // TODO: || number
213+ pub name: String,
214+ pub path: Option<PathBuf>,
215+ pub is_optimized: Option<bool>,
216+ pub is_user_code: Option<bool>,
217+ pub version: Option<String>,
218+ pub symbol_status: Option<String>,
219+ pub symbol_file_path: Option<String>,
220+ pub date_time_stamp: Option<String>,
221+ pub address_range: Option<String>,
222+}
223+
209pub mod requests {
224pub mod requests {
210 use super::*;
225 use super::*;
211 #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
226 #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
@@ -411,6 +426,69 @@ pub mod requests {
411
426
412pub mod events {
427pub mod events {
413 use super::*;
428 use super::*;
429+
430+ #[derive(Debug, Clone, Serialize, Deserialize)]
431+ #[serde(rename_all = "camelCase")]
432+ #[serde(tag = "event", content = "body")]
433+ // seq is omitted as unused and is not sent by some implementations
434+ pub enum Event {
435+ Initialized,
436+ Stopped(Stopped),
437+ Continued(Continued),
438+ Exited(Exited),
439+ Terminated(Terminated),
440+ Thread(Thread),
441+ Output(Output),
442+ Breakpoint(Breakpoint),
443+ Module(Module),
444+ LoadedSource(LoadedSource),
445+ Process(Process),
446+ Capabilities(Capabilities),
447+ // ProgressStart(),
448+ // ProgressUpdate(),
449+ // ProgressEnd(),
450+ // Invalidated(),
451+ Memory(Memory),
452+ }
453+
454+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
455+ #[serde(rename_all = "camelCase")]
456+ pub struct Stopped {
457+ pub reason: String,
458+ pub description: Option<String>,
459+ pub thread_id: Option<usize>,
460+ pub preserve_focus_hint: Option<bool>,
461+ pub text: Option<String>,
462+ pub all_threads_stopped: Option<bool>,
463+ pub hit_breakpoint_ids: Option<Vec<usize>>,
464+ }
465+
466+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
467+ #[serde(rename_all = "camelCase")]
468+ pub struct Continued {
469+ pub thread_id: usize,
470+ pub all_threads_continued: Option<bool>,
471+ }
472+
473+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
474+ #[serde(rename_all = "camelCase")]
475+ pub struct Exited {
476+ pub exit_code: usize,
477+ }
478+
479+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
480+ #[serde(rename_all = "camelCase")]
481+ pub struct Terminated {
482+ pub restart: Option<Value>,
483+ }
484+
485+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
486+ #[serde(rename_all = "camelCase")]
487+ pub struct Thread {
488+ pub reason: String,
489+ pub thread_id: usize,
490+ }
491+
414 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
492 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
415 #[serde(rename_all = "camelCase")]
493 #[serde(rename_all = "camelCase")]
416 pub struct Output {
494 pub struct Output {
@@ -426,13 +504,54 @@ pub mod events {
426
504
427 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
505 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
428 #[serde(rename_all = "camelCase")]
506 #[serde(rename_all = "camelCase")]
429− pub struct Stopped {
507+ pub struct Breakpoint {
430 pub reason: String,
508 pub reason: String,
431− pub description: Option<String>,
509+ pub breakpoint: super::Breakpoint,
510+ }
511+
512+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
513+ #[serde(rename_all = "camelCase")]
514+ pub struct Module {
515+ pub reason: String,
516+ pub module: super::Module,
517+ }
518+
519+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
520+ #[serde(rename_all = "camelCase")]
521+ pub struct LoadedSource {
522+ pub reason: String,
523+ pub source: super::Source,
524+ }
525+
526+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
527+ #[serde(rename_all = "camelCase")]
528+ pub struct Process {
529+ pub name: String,
432− pub thread_id: Option<usize>,
530+ pub system_process_id: Option<usize>,
433− pub preserve_focus_hint: Option<bool>,
531+ pub is_local_process: Option<bool>,
434− pub text: Option<String>,
532+ pub start_method: String, // TODO: use enum
435− pub all_threads_stopped: Option<bool>,
533+ pub pointer_size: Option<usize>,
436− pub hit_breakpoint_ids: Option<Vec<usize>>,
534+ }
535+
536+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
537+ #[serde(rename_all = "camelCase")]
538+ pub struct Capabilities {
539+ pub module: super::DebuggerCapabilities,
540+ }
541+
542+ // #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
543+ // #[serde(rename_all = "camelCase")]
544+ // pub struct Invalidated {
545+ // pub areas: Vec<InvalidatedArea>,
546+ // pub thread_id: Option<usize>,
547+ // pub stack_frame_id: Option<usize>,
548+ // }
549+
550+ #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
551+ #[serde(rename_all = "camelCase")]
552+ pub struct Memory {
553+ pub memory_reference: String,
554+ pub offset: usize,
555+ pub count: usize,
437 }
556 }
438}
557}
helix-term/src/application.rs+27−22
@@ -2,7 +2,6 @@ use helix_core::syntax;
2use helix_dap::Payload;
2use helix_dap::Payload;
3use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
3use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
4use helix_view::{theme, Editor};
4use helix_view::{theme, Editor};
5−use serde_json::from_value;
6
5
7use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
6use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
8
7
@@ -251,40 +250,47 @@ impl Application {
251 }
250 }
252
251
253 pub async fn handle_debugger_message(&mut self, payload: helix_dap::Payload) {
252 pub async fn handle_debugger_message(&mut self, payload: helix_dap::Payload) {
253+ use helix_dap::{events, Event};
254 let mut debugger = match self.editor.debugger.as_mut() {
254 let mut debugger = match self.editor.debugger.as_mut() {
255 Some(debugger) => debugger,
255 Some(debugger) => debugger,
256 None => return,
256 None => return,
257 };
257 };
258
258
259 match payload {
259 match payload {
260− Payload::Event(ev) => match &ev.event[..] {
260+ Payload::Event(ev) => match ev {
261− "stopped" => {
261+ Event::Stopped(events::Stopped {
262+ thread_id,
263+ description,
264+ text,
265+ reason,
266+ all_threads_stopped,
267+ ..
268+ }) => {
262 debugger.is_running = false;
269 debugger.is_running = false;
263 let main = debugger
270 let main = debugger
264 .threads()
271 .threads()
265 .await
272 .await
266 .ok()
273 .ok()
267 .and_then(|threads| threads.get(0).cloned());
274 .and_then(|threads| threads.get(0).cloned());
275+
268 if let Some(main) = main {
276 if let Some(main) = main {
269 let (bt, _) = debugger.stack_trace(main.id).await.unwrap();
277 let (bt, _) = debugger.stack_trace(main.id).await.unwrap();
270 debugger.stack_pointer = bt.get(0).cloned();
278 debugger.stack_pointer = bt.get(0).cloned();
271 }
279 }
272
280
273− let body: helix_dap::events::Stopped =
274− from_value(ev.body.expect("`stopped` event must have a body")).unwrap();
275− let scope = match body.thread_id {
281+ let scope = match thread_id {
276 Some(id) => format!("Thread {}", id),
282 Some(id) => format!("Thread {}", id),
277 None => "Target".to_owned(),
283 None => "Target".to_owned(),
278 };
284 };
279
285
280− let mut status = format!("{} stopped because of {}", scope, body.reason);
286+ let mut status = format!("{} stopped because of {}", scope, reason);
281− if let Some(desc) = body.description {
287+ if let Some(desc) = description {
282 status.push_str(&format!(" {}", desc));
288 status.push_str(&format!(" {}", desc));
283 }
289 }
284− if let Some(text) = body.text {
290+ if let Some(text) = text {
285 status.push_str(&format!(" {}", text));
291 status.push_str(&format!(" {}", text));
286 }
292 }
287− if body.all_threads_stopped == Some(true) {
293+ if all_threads_stopped.unwrap_or_default() {
288 status.push_str(" (all threads stopped)");
294 status.push_str(" (all threads stopped)");
289 }
295 }
290
296
@@ -302,31 +308,30 @@ impl Application {
302 .unwrap();
308 .unwrap();
303 }
309 }
304 self.editor.set_status(status);
310 self.editor.set_status(status);
305− self.render();
306 }
311 }
312+ Event::Output(events::Output {
307− "output" => {
313+ category, output, ..
308− let body: helix_dap::events::Output =
314+ }) => {
309− from_value(ev.body.expect("`output` event must have a body")).unwrap();
310−
311− let prefix = match body.category {
315+ let prefix = match category {
312 Some(category) => format!("Debug ({}):", category),
316 Some(category) => format!("Debug ({}):", category),
313 None => "Debug:".to_owned(),
317 None => "Debug:".to_owned(),
314 };
318 };
315
319
316− self.editor
317− .set_status(format!("{} {}", prefix, body.output));
320+ self.editor.set_status(format!("{} {}", prefix, output));
318− self.render();
319 }
321 }
320− "initialized" => {
322+ Event::Initialized => {
321 self.editor
323 self.editor
322 .set_status("Debugged application started".to_owned());
324 .set_status("Debugged application started".to_owned());
323− self.render();
324 }
325 }
325− _ => {}
326+ ev => {
327+ log::warn!("Unhandled event {:?}", ev);
328+ return; // return early to skip render
329+ }
326 },
330 },
327 Payload::Response(_) => unreachable!(),
331 Payload::Response(_) => unreachable!(),
328 Payload::Request(_) => todo!(),
332 Payload::Request(_) => todo!(),
329 }
333 }
334+ self.render();
330 }
335 }
331
336
332 pub async fn handle_language_server_message(
337 pub async fn handle_language_server_message(