|
1 | | -use anyhow::Result; |
2 | | -use connection::Connection; |
3 | | -use dap::events::{Event, StoppedEventBody}; |
4 | | -use dap::prelude::{Command, Request, ResponseBody}; |
5 | | -use dap::responses::{ |
6 | | - EvaluateResponse, ScopesResponse, SetBreakpointsResponse, StackTraceResponse, ThreadsResponse, |
7 | | - VariablesResponse, |
8 | | -}; |
9 | | -use dap::types::{Breakpoint, Capabilities, Source, StackFrame, StoppedEventReason, Thread}; |
10 | | -use tracing::trace; |
11 | | - |
12 | 1 | mod connection; |
| 2 | +mod debugger; |
13 | 3 |
|
14 | | -// TODO: add vm, add handlers for requests. |
15 | | -pub struct CairoDebugger { |
16 | | - connection: Connection, |
17 | | -} |
18 | | - |
19 | | -enum ServerResponse { |
20 | | - Success(ResponseBody), |
21 | | - Error(String), |
22 | | - Event(Event), |
23 | | - SuccessThenEvent(ResponseBody, Event), |
24 | | -} |
25 | | - |
26 | | -impl CairoDebugger { |
27 | | - pub fn connect() -> Result<Self> { |
28 | | - let connection = Connection::new()?; |
29 | | - Ok(Self { connection }) |
30 | | - } |
31 | | - |
32 | | - pub fn run(&mut self) -> Result<()> { |
33 | | - while let Ok(req) = self.connection.next_request() { |
34 | | - match handle_request(&req) { |
35 | | - ServerResponse::Success(body) => self.connection.send_success(req, body)?, |
36 | | - ServerResponse::Error(msg) => self.connection.send_error(req, &msg)?, |
37 | | - ServerResponse::Event(event) => self.connection.send_event(event)?, |
38 | | - ServerResponse::SuccessThenEvent(body, event) => { |
39 | | - self.connection.send_success(req, body)?; |
40 | | - self.connection.send_event(event)?; |
41 | | - } |
42 | | - } |
43 | | - } |
44 | | - |
45 | | - Ok(()) |
46 | | - } |
47 | | -} |
48 | | - |
49 | | -fn handle_request(request: &Request) -> ServerResponse { |
50 | | - match &request.command { |
51 | | - // We have not yet decided if we want to support these. |
52 | | - Command::BreakpointLocations(_) |
53 | | - | Command::Cancel(_) |
54 | | - | Command::Completions(_) |
55 | | - | Command::DataBreakpointInfo(_) |
56 | | - | Command::Disassemble(_) |
57 | | - | Command::Disconnect(_) |
58 | | - | Command::Goto(_) |
59 | | - | Command::ExceptionInfo(_) |
60 | | - | Command::GotoTargets(_) |
61 | | - | Command::LoadedSources |
62 | | - | Command::Modules(_) |
63 | | - | Command::ReadMemory(_) |
64 | | - | Command::RestartFrame(_) |
65 | | - | Command::SetDataBreakpoints(_) |
66 | | - | Command::Restart(_) |
67 | | - | Command::SetExceptionBreakpoints(_) |
68 | | - | Command::TerminateThreads(_) |
69 | | - | Command::Terminate(_) |
70 | | - | Command::StepInTargets(_) |
71 | | - | Command::SetVariable(_) |
72 | | - | Command::SetInstructionBreakpoints(_) |
73 | | - | Command::SetExpression(_) |
74 | | - | Command::WriteMemory(_) => { |
75 | | - // If we receive these with current capabilities, it is the client's fault. |
76 | | - let msg = format!("Received an unsupported request: {request:?}"); |
77 | | - ServerResponse::Error(msg) |
78 | | - } |
79 | | - |
80 | | - // These may be supported after the MVP. |
81 | | - // Nonetheless, if we receive these with current capabilities, |
82 | | - // it is the client's fault. |
83 | | - Command::ReverseContinue(_) => { |
84 | | - ServerResponse::Error("Step back is not yet supported".into()) |
85 | | - } |
86 | | - Command::StepBack(_) => ServerResponse::Error("Step back is not yet supported".into()), |
87 | | - Command::SetFunctionBreakpoints(_) => { |
88 | | - ServerResponse::Error("Set function breakpoints is not yet supported".into()) |
89 | | - } |
90 | | - |
91 | | - // It makes no sense to send `attach` in the current architecture. |
92 | | - Command::Attach(_) => ServerResponse::Error("Attach is not supported".into()), |
93 | | - |
94 | | - // Supported requests. |
95 | | - Command::Initialize(args) => { |
96 | | - trace!("Initialized a client: {:?}", args.client_name); |
97 | | - |
98 | | - ServerResponse::Success(ResponseBody::Initialize(Capabilities { |
99 | | - supports_configuration_done_request: Some(true), |
100 | | - ..Default::default() |
101 | | - })) |
102 | | - } |
103 | | - Command::ConfigurationDone => { |
104 | | - trace!("Configuration done"); |
105 | | - ServerResponse::Success(ResponseBody::ConfigurationDone) |
106 | | - } |
107 | | - Command::Continue(_) => { |
108 | | - todo!() |
109 | | - } |
110 | | - Command::Launch(_) => { |
111 | | - // Start running the Cairo program here. |
112 | | - ServerResponse::SuccessThenEvent(ResponseBody::Launch, Event::Initialized) |
113 | | - } |
114 | | - Command::Next(_) => { |
115 | | - todo!() |
116 | | - } |
117 | | - Command::Pause(_) => ServerResponse::Event(Event::Stopped(StoppedEventBody { |
118 | | - reason: StoppedEventReason::Pause, |
119 | | - thread_id: Some(0), |
120 | | - description: None, |
121 | | - preserve_focus_hint: None, |
122 | | - text: None, |
123 | | - all_threads_stopped: Some(true), |
124 | | - hit_breakpoint_ids: None, |
125 | | - })), |
126 | | - Command::SetBreakpoints(args) => { |
127 | | - let mut response_bps = Vec::new(); |
128 | | - if let Some(requested_bps) = &args.breakpoints { |
129 | | - for bp in requested_bps { |
130 | | - // For now accept every breakpoint as valid |
131 | | - response_bps.push(Breakpoint { |
132 | | - verified: true, |
133 | | - source: Some(args.source.clone()), |
134 | | - line: Some(bp.line), |
135 | | - ..Default::default() |
136 | | - }); |
137 | | - } |
138 | | - } |
139 | | - ServerResponse::Success(ResponseBody::SetBreakpoints(SetBreakpointsResponse { |
140 | | - breakpoints: response_bps, |
141 | | - })) |
142 | | - } |
143 | | - Command::Source(_) => { |
144 | | - todo!() |
145 | | - } |
146 | | - Command::StackTrace(_) => { |
147 | | - ServerResponse::Success(ResponseBody::StackTrace(StackTraceResponse { |
148 | | - stack_frames: vec![StackFrame { |
149 | | - id: 1, |
150 | | - name: "test".to_string(), |
151 | | - // Replace it with the actual source path. |
152 | | - // Otherwise, the debugger will crush after returning this response. |
153 | | - source: Some(Source { name: None, path: None, ..Default::default() }), |
154 | | - line: 1, |
155 | | - column: 1, |
156 | | - ..Default::default() |
157 | | - }], |
158 | | - total_frames: Some(1), |
159 | | - })) |
160 | | - } |
161 | | - Command::StepIn(_) => { |
162 | | - todo!() |
163 | | - } |
164 | | - Command::StepOut(_) => { |
165 | | - todo!() |
166 | | - } |
167 | | - |
168 | | - Command::Evaluate(_) => { |
169 | | - ServerResponse::Success(ResponseBody::Evaluate(EvaluateResponse { |
170 | | - // Return whatever since we cannot opt out of supporting this request. |
171 | | - result: "".to_string(), |
172 | | - type_field: None, |
173 | | - presentation_hint: None, |
174 | | - variables_reference: 0, |
175 | | - named_variables: None, |
176 | | - indexed_variables: None, |
177 | | - memory_reference: None, |
178 | | - })) |
179 | | - } |
180 | | - Command::Threads => { |
181 | | - ServerResponse::Success(ResponseBody::Threads(ThreadsResponse { |
182 | | - // Return a single thread. |
183 | | - threads: vec![Thread { id: 0, name: "".to_string() }], |
184 | | - })) |
185 | | - } |
186 | | - Command::Variables(_) => { |
187 | | - ServerResponse::Success(ResponseBody::Variables(VariablesResponse { |
188 | | - // Return no variables. |
189 | | - variables: vec![], |
190 | | - })) |
191 | | - } |
192 | | - Command::Scopes(_) => { |
193 | | - // Return no scopes. |
194 | | - ServerResponse::Success(ResponseBody::Scopes(ScopesResponse { scopes: vec![] })) |
195 | | - } |
196 | | - } |
197 | | -} |
| 4 | +pub use debugger::CairoDebugger; |
0 commit comments