Add more event types, simplify event decoding

This commit is contained in:
Blaž Hrastnik 2021-08-22 16:05:12 +09:00
parent 2aee5f02d0
commit 28658836ee
4 changed files with 158 additions and 40 deletions

View file

@ -3,7 +3,8 @@ mod transport;
mod types; mod types;
pub use client::Client; pub use client::Client;
pub use transport::{Event, Payload, Response, Transport}; pub use events::Event;
pub use transport::{Payload, Response, Transport};
pub use types::*; pub use types::*;
use thiserror::Error; use thiserror::Error;

View file

@ -1,4 +1,4 @@
use crate::{Error, Result}; use crate::{Error, Event, Result};
use anyhow::Context; use anyhow::Context;
use log::{error, info, warn}; use log::{error, info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -32,13 +32,6 @@ pub struct Response {
pub body: Option<Value>, pub body: Option<Value>,
} }
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Event {
// seq is omitted as unused and is not sent by some implementations
pub event: String,
pub body: Option<Value>,
}
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type", rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]
pub enum Payload { pub enum Payload {
@ -208,8 +201,8 @@ impl Transport {
client_tx.send(msg).expect("Failed to send"); client_tx.send(msg).expect("Failed to send");
Ok(()) Ok(())
} }
Payload::Event(Event { ref event, .. }) => { Payload::Event(ref event) => {
info!("<- DAP event {}", event); info!("<- DAP event {:?}", event);
client_tx.send(msg).expect("Failed to send"); client_tx.send(msg).expect("Failed to send");
Ok(()) Ok(())
} }

View file

@ -206,6 +206,21 @@ pub struct Variable {
pub memory_reference: Option<String>, pub memory_reference: Option<String>,
} }
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Module {
pub id: String, // TODO: || number
pub name: String,
pub path: Option<PathBuf>,
pub is_optimized: Option<bool>,
pub is_user_code: Option<bool>,
pub version: Option<String>,
pub symbol_status: Option<String>,
pub symbol_file_path: Option<String>,
pub date_time_stamp: Option<String>,
pub address_range: Option<String>,
}
pub mod requests { pub mod requests {
use super::*; use super::*;
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)] #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
@ -411,6 +426,69 @@ pub mod requests {
pub mod events { pub mod events {
use super::*; use super::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "event", content = "body")]
// seq is omitted as unused and is not sent by some implementations
pub enum Event {
Initialized,
Stopped(Stopped),
Continued(Continued),
Exited(Exited),
Terminated(Terminated),
Thread(Thread),
Output(Output),
Breakpoint(Breakpoint),
Module(Module),
LoadedSource(LoadedSource),
Process(Process),
Capabilities(Capabilities),
// ProgressStart(),
// ProgressUpdate(),
// ProgressEnd(),
// Invalidated(),
Memory(Memory),
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Stopped {
pub reason: String,
pub description: Option<String>,
pub thread_id: Option<usize>,
pub preserve_focus_hint: Option<bool>,
pub text: Option<String>,
pub all_threads_stopped: Option<bool>,
pub hit_breakpoint_ids: Option<Vec<usize>>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Continued {
pub thread_id: usize,
pub all_threads_continued: Option<bool>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Exited {
pub exit_code: usize,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Terminated {
pub restart: Option<Value>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Thread {
pub reason: String,
pub thread_id: usize,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Output { pub struct Output {
@ -426,13 +504,54 @@ pub mod events {
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Stopped { pub struct Breakpoint {
pub reason: String, pub reason: String,
pub description: Option<String>, pub breakpoint: super::Breakpoint,
pub thread_id: Option<usize>, }
pub preserve_focus_hint: Option<bool>,
pub text: Option<String>, #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub all_threads_stopped: Option<bool>, #[serde(rename_all = "camelCase")]
pub hit_breakpoint_ids: Option<Vec<usize>>, pub struct Module {
pub reason: String,
pub module: super::Module,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LoadedSource {
pub reason: String,
pub source: super::Source,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Process {
pub name: String,
pub system_process_id: Option<usize>,
pub is_local_process: Option<bool>,
pub start_method: String, // TODO: use enum
pub pointer_size: Option<usize>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Capabilities {
pub module: super::DebuggerCapabilities,
}
// #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
// #[serde(rename_all = "camelCase")]
// pub struct Invalidated {
// pub areas: Vec<InvalidatedArea>,
// pub thread_id: Option<usize>,
// pub stack_frame_id: Option<usize>,
// }
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Memory {
pub memory_reference: String,
pub offset: usize,
pub count: usize,
} }
} }

View file

@ -2,7 +2,6 @@ use helix_core::syntax;
use helix_dap::Payload; use helix_dap::Payload;
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{theme, Editor}; use helix_view::{theme, Editor};
use serde_json::from_value;
use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui}; use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
@ -251,40 +250,47 @@ impl Application {
} }
pub async fn handle_debugger_message(&mut self, payload: helix_dap::Payload) { pub async fn handle_debugger_message(&mut self, payload: helix_dap::Payload) {
use helix_dap::{events, Event};
let mut debugger = match self.editor.debugger.as_mut() { let mut debugger = match self.editor.debugger.as_mut() {
Some(debugger) => debugger, Some(debugger) => debugger,
None => return, None => return,
}; };
match payload { match payload {
Payload::Event(ev) => match &ev.event[..] { Payload::Event(ev) => match ev {
"stopped" => { Event::Stopped(events::Stopped {
thread_id,
description,
text,
reason,
all_threads_stopped,
..
}) => {
debugger.is_running = false; debugger.is_running = false;
let main = debugger let main = debugger
.threads() .threads()
.await .await
.ok() .ok()
.and_then(|threads| threads.get(0).cloned()); .and_then(|threads| threads.get(0).cloned());
if let Some(main) = main { if let Some(main) = main {
let (bt, _) = debugger.stack_trace(main.id).await.unwrap(); let (bt, _) = debugger.stack_trace(main.id).await.unwrap();
debugger.stack_pointer = bt.get(0).cloned(); debugger.stack_pointer = bt.get(0).cloned();
} }
let body: helix_dap::events::Stopped = let scope = match thread_id {
from_value(ev.body.expect("`stopped` event must have a body")).unwrap();
let scope = match body.thread_id {
Some(id) => format!("Thread {}", id), Some(id) => format!("Thread {}", id),
None => "Target".to_owned(), None => "Target".to_owned(),
}; };
let mut status = format!("{} stopped because of {}", scope, body.reason); let mut status = format!("{} stopped because of {}", scope, reason);
if let Some(desc) = body.description { if let Some(desc) = description {
status.push_str(&format!(" {}", desc)); status.push_str(&format!(" {}", desc));
} }
if let Some(text) = body.text { if let Some(text) = text {
status.push_str(&format!(" {}", text)); status.push_str(&format!(" {}", text));
} }
if body.all_threads_stopped == Some(true) { if all_threads_stopped.unwrap_or_default() {
status.push_str(" (all threads stopped)"); status.push_str(" (all threads stopped)");
} }
@ -302,31 +308,30 @@ impl Application {
.unwrap(); .unwrap();
} }
self.editor.set_status(status); self.editor.set_status(status);
self.render();
} }
"output" => { Event::Output(events::Output {
let body: helix_dap::events::Output = category, output, ..
from_value(ev.body.expect("`output` event must have a body")).unwrap(); }) => {
let prefix = match category {
let prefix = match body.category {
Some(category) => format!("Debug ({}):", category), Some(category) => format!("Debug ({}):", category),
None => "Debug:".to_owned(), None => "Debug:".to_owned(),
}; };
self.editor self.editor.set_status(format!("{} {}", prefix, output));
.set_status(format!("{} {}", prefix, body.output));
self.render();
} }
"initialized" => { Event::Initialized => {
self.editor self.editor
.set_status("Debugged application started".to_owned()); .set_status("Debugged application started".to_owned());
self.render();
} }
_ => {} ev => {
log::warn!("Unhandled event {:?}", ev);
return; // return early to skip render
}
}, },
Payload::Response(_) => unreachable!(), Payload::Response(_) => unreachable!(),
Payload::Request(_) => todo!(), Payload::Request(_) => todo!(),
} }
self.render();
} }
pub async fn handle_language_server_message( pub async fn handle_language_server_message(