Add initial structure and types for debugger

This commit is contained in:
Tad Hardesty 2019-11-10 18:38:53 -08:00
parent 174e7c0c50
commit ddbb3e9b39
3 changed files with 194 additions and 0 deletions

View file

@ -0,0 +1,49 @@
//! Debug adapter protocol implementation for DreamSeeker.
//!
//! * https://microsoft.github.io/debug-adapter-protocol/
mod types;
use std::error::Error;
use io;
use self::types::*;
pub fn debugger_main<I: Iterator<Item=String>>(mut args: I) {
let mut dreamseeker_exe = None;
while let Some(arg) = args.next() {
if arg == "--dreamseeker-exe" {
dreamseeker_exe = Some(args.next().expect("must specify a value for --dreamseeker-exe"));
} else {
panic!("unknown argument {:?}", arg);
}
}
let mut debugger = Debugger {
dreamseeker_exe: dreamseeker_exe.expect("must provide argument `--dreamseeker-exe path/to/dreamseeker.exe`"),
};
io::run_forever(|message| debugger.handle_input(message));
}
struct Debugger {
dreamseeker_exe: String,
}
impl Debugger {
fn handle_input(&mut self, message: &str) {
// TODO: error handling
self.dispatch_input(message).expect("error in dispatch_input");
}
fn dispatch_input(&mut self, message: &str) -> Result<(), Box<dyn Error>> {
let protocol_message = serde_json::from_str::<ProtocolMessage>(message)?;
match protocol_message.type_.as_str() {
"request" => {
let request = serde_json::from_str::<Request>(message)?;
eprintln!("{:?}", request);
}
other => return Err(format!("unknown `type` field {:?}", other).into())
}
Ok(())
}
}

View file

@ -0,0 +1,133 @@
//! Serde types for the Debug Adapter Protocol.
//!
//! * https://microsoft.github.io/debug-adapter-protocol/specification
use std::collections::HashMap;
use serde_json::Value;
// ----------------------------------------------------------------------------
// Base Protocol
/// Base class of requests, responses, and events.
#[derive(Serialize, Deserialize, Debug)]
pub struct ProtocolMessage {
/// Sequence number (also known as message ID). For protocol messages of type 'request' this ID can be used to cancel the request.
pub seq: i64,
#[serde(rename = "type")]
/// Message type.
/// Values: 'request', 'response', 'event', etc.
pub type_: String,
}
/// A client or debug adapter initiated request.
#[derive(Serialize, Deserialize, Debug)]
pub struct Request {
#[serde(flatten)]
pub protocol_message: ProtocolMessage,
/// The command to execute.
pub command: String,
/// Object containing arguments for the command.
pub arguments: Option<Value>,
}
/// A debug adapter initiated event.
#[derive(Serialize, Deserialize, Debug)]
pub struct Event {
#[serde(flatten)]
pub protocol_message: ProtocolMessage,
/// Type of event.
pub event: String,
/// Event-specific information.
pub body: Option<Value>,
}
/// Response for a request.
#[derive(Serialize, Deserialize, Debug)]
pub struct Response {
#[serde(flatten)]
pub protocol_message: ProtocolMessage,
/**
* Sequence number of the corresponding request.
*/
pub request_seq: i64,
/**
* Outcome of the request.
* If true, the request was successful and the 'body' attribute may contain the result of the request.
* If the value is false, the attribute 'message' contains the error in short form and the 'body' may contain additional information (see 'ErrorResponse.body.error').
*/
pub success: bool,
/**
* The command requested.
*/
pub command: String,
/**
* Contains the raw error in short form if 'success' is false.
* This raw error might be interpreted by the frontend and is not shown in the UI.
* Some predefined values exist.
* Values:
* 'cancelled': request was cancelled.
* etc.
*/
pub message: Option<String>,
/**
* Contains request result if success is true and optional error details if success is false.
*/
pub body: Option<Value>,
}
/// On error (whenever success is false), the body can provide more details.
#[derive(Serialize, Deserialize, Debug)]
pub struct ErrorResponseBody {
/// An optional, structured error message.
pub error: Option<Message>,
}
// ----------------------------------------------------------------------------
// Types
#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
/**
* Unique identifier for the message.
*/
pub id: i64,
/**
* A format string for the message. Embedded variables have the form '{name}'.
* If variable name starts with an underscore character, the variable does not contain user data (PII) and can be safely used for telemetry purposes.
*/
pub format: String,
/**
* An object used as a dictionary for looking up the variables in the format string.
*/
pub variables: Option<HashMap<String, String>>,
/**
* If true send to telemetry.
*/
#[serde(rename = "sendTelemetry")]
pub send_telemetry: Option<bool>,
/**
* If true show user.
*/
#[serde(rename = "showUser")]
pub show_user: Option<bool>,
/**
* An optional url where additional information about this message can be found.
*/
pub url: Option<String>,
/**
* An optional label that is presented to the user as the UI for opening the url.
*/
#[serde(rename = "urlLabel")]
pub url_label: Option<String>,
}

View file

@ -27,6 +27,8 @@ mod find_references;
mod extras;
mod completion;
mod debugger;
use std::path::PathBuf;
use std::collections::{HashMap, HashSet, VecDeque};
use std::collections::hash_map::Entry;
@ -62,6 +64,16 @@ fn main() {
Err(e) => eprintln!("dir check failure: {}", e),
}
let mut args = std::env::args();
let _ = args.next(); // skip executable name
if let Some(arg) = args.next() {
if arg == "--debugger" {
return debugger::debugger_main(args);
} else {
panic!("unknown argument {:?}", arg);
}
}
let context = dm::Context::default();
let mut engine = Engine::new(&context);
io::run_forever(|message| engine.handle_input(message));