1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! # miden-debug-dap, a Rust implementation of the Debug Adapter Protocol
//!
//! ## Introduction
//!
//! This crate is a Rust implementation of the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)
//! (or DAP for short).
//!
//! The best way to think of DAP is to compare it to [LSP](https://microsoft.github.io/language-server-protocol/)
//! (Language Server Protocol) but for debuggers. The core idea is the same: a protocol that serves
//! as *lingua franca* for editors and debuggers to talk to each other. This means that an editor
//! that implements DAP can use a debugger that also implements DAP.
//!
//! In practice, the adapter might be separate from the actual debugger. For example, one could
//! implement an adapter that writes commands to the stdin of a gdb subprocess, then parses
//! the output it receives (this is why it's called an "adapter" - it adapts the debugger to
//! editors that know DAP).
//!
//! ## Minimal example
//!
//! To get started, create a binary project and add `miden-debug-dap` to your Cargo.toml:
//!
//! ```toml
//! [package]
//! name = "dummy-server"
//! version = "*"
//! edition = "2024"
//!
//! [dependencies]
//! miden-debug-dap = "*"
//! ```
//!
//! Our dummy server is going to read its input from a text file and write the output to stdout.
//!
//! ```rust
//! use std::fs::File;
//! use std::io::{BufReader, BufWriter};
//!
//! use thiserror::Error;
//!
//! use dap::prelude::*;
//!
//! #[derive(Error, Debug)]
//! enum MyAdapterError {
//! #[error("Unhandled command")]
//! UnhandledCommandError,
//!
//! #[error("Missing command")]
//! MissingCommandError,
//! }
//!
//! type DynResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
//!
//! fn main() -> DynResult<()> {
//! let output = BufWriter::new(std::io::stdout());
//! let f = File::open("testinput.txt")?;
//! let input = BufReader::new(f);
//! let mut server = Server::new(input, output);
//!
//! let req = match server.poll_request()? {
//! Some(req) => req,
//! None => return Err(Box::new(MyAdapterError::MissingCommandError)),
//! };
//! if let Command::Initialize(_) = req.command {
//! let rsp = req.success(
//! ResponseBody::Initialize(Some(types::Capabilities {
//! ..Default::default()
//! })),
//! );
//!
//! // When you call respond, send_event etc. the message will be wrapped
//! // in a base message with a appropriate seq number, so you don't have to keep track of that yourself
//! server.respond(rsp)?;
//!
//! server.send_event(Event::Initialized)?;
//! } else {
//! return Err(Box::new(MyAdapterError::UnhandledCommandError));
//! }
//!
//! // You can send events from other threads while the server is blocked
//! // polling for requests by grabbing a `ServerOutput` mutex:
//! let server_output = server.output.clone();
//! std::thread::spawn(move || {
//! std::thread::sleep(std::time::Duration::from_millis(500));
//!
//! let mut server_output = server_output.lock().unwrap();
//! server_output
//! .send_event(Event::Capabilities(events::CapabilitiesEventBody {
//! ..Default::default()
//! }))
//! .unwrap();
//! });
//!
//! // The thread will concurrently send an event while we are polling
//! // for the next request
//! let _ = server.poll_request()?;
//!
//! Ok(())
//! }
//! ```
pub use get_spec_version;