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;
pub use client::Client;
pub use transport::{Event, Payload, Response, Transport};
pub use events::Event;
pub use transport::{Payload, Response, Transport};
pub use types::*;
use thiserror::Error;

View file

@ -1,4 +1,4 @@
use crate::{Error, Result};
use crate::{Error, Event, Result};
use anyhow::Context;
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
@ -32,13 +32,6 @@ pub struct Response {
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)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum Payload {
@ -208,8 +201,8 @@ impl Transport {
client_tx.send(msg).expect("Failed to send");
Ok(())
}
Payload::Event(Event { ref event, .. }) => {
info!("<- DAP event {}", event);
Payload::Event(ref event) => {
info!("<- DAP event {:?}", event);
client_tx.send(msg).expect("Failed to send");
Ok(())
}

View file

@ -206,6 +206,21 @@ pub struct Variable {
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 {
use super::*;
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
@ -411,6 +426,69 @@ pub mod requests {
pub mod events {
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)]
#[serde(rename_all = "camelCase")]
pub struct Output {
@ -426,13 +504,54 @@ pub mod events {
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Stopped {
pub struct Breakpoint {
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>>,
pub breakpoint: super::Breakpoint,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
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_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{theme, Editor};
use serde_json::from_value;
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) {
use helix_dap::{events, Event};
let mut debugger = match self.editor.debugger.as_mut() {
Some(debugger) => debugger,
None => return,
};
match payload {
Payload::Event(ev) => match &ev.event[..] {
"stopped" => {
Payload::Event(ev) => match ev {
Event::Stopped(events::Stopped {
thread_id,
description,
text,
reason,
all_threads_stopped,
..
}) => {
debugger.is_running = false;
let main = debugger
.threads()
.await
.ok()
.and_then(|threads| threads.get(0).cloned());
if let Some(main) = main {
let (bt, _) = debugger.stack_trace(main.id).await.unwrap();
debugger.stack_pointer = bt.get(0).cloned();
}
let body: helix_dap::events::Stopped =
from_value(ev.body.expect("`stopped` event must have a body")).unwrap();
let scope = match body.thread_id {
let scope = match thread_id {
Some(id) => format!("Thread {}", id),
None => "Target".to_owned(),
};
let mut status = format!("{} stopped because of {}", scope, body.reason);
if let Some(desc) = body.description {
let mut status = format!("{} stopped because of {}", scope, reason);
if let Some(desc) = description {
status.push_str(&format!(" {}", desc));
}
if let Some(text) = body.text {
if let Some(text) = 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)");
}
@ -302,31 +308,30 @@ impl Application {
.unwrap();
}
self.editor.set_status(status);
self.render();
}
"output" => {
let body: helix_dap::events::Output =
from_value(ev.body.expect("`output` event must have a body")).unwrap();
let prefix = match body.category {
Event::Output(events::Output {
category, output, ..
}) => {
let prefix = match category {
Some(category) => format!("Debug ({}):", category),
None => "Debug:".to_owned(),
};
self.editor
.set_status(format!("{} {}", prefix, body.output));
self.render();
self.editor.set_status(format!("{} {}", prefix, output));
}
"initialized" => {
Event::Initialized => {
self.editor
.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::Request(_) => todo!(),
}
self.render();
}
pub async fn handle_language_server_message(