1use std::sync::Arc;
2
3use anyhow::{Context as _, Ok, Result};
4use base64::Engine;
5use dap::{
6 Capabilities, ContinueArguments, ExceptionFilterOptions, InitializeRequestArguments,
7 InitializeRequestArgumentsPathFormat, NextArguments, SetVariableResponse, SourceBreakpoint,
8 StepInArguments, StepOutArguments, SteppingGranularity, ValueFormat, Variable,
9 VariablesArgumentsFilter,
10 client::SessionId,
11 proto_conversions::ProtoConversion,
12 requests::{Continue, Next},
13};
14
15use rpc::proto;
16use serde_json::Value;
17use util::ResultExt;
18
19pub trait LocalDapCommand: 'static + Send + Sync + std::fmt::Debug {
20 type Response: 'static + Send + std::fmt::Debug;
21 type DapRequest: 'static + Send + dap::requests::Request;
22 /// Is this request idempotent? Is it safe to cache the response for as long as the execution environment is unchanged?
23 const CACHEABLE: bool = false;
24
25 fn is_supported(_capabilities: &Capabilities) -> bool {
26 true
27 }
28
29 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments;
30
31 fn response_from_dap(
32 &self,
33 message: <Self::DapRequest as dap::requests::Request>::Response,
34 ) -> Result<Self::Response>;
35}
36
37pub trait DapCommand: LocalDapCommand {
38 type ProtoRequest: 'static + Send;
39 type ProtoResponse: 'static + Send;
40
41 #[allow(dead_code)]
42 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId;
43
44 #[allow(dead_code)]
45 fn from_proto(request: &Self::ProtoRequest) -> Self;
46
47 #[allow(unused)]
48 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest;
49
50 #[allow(dead_code)]
51 fn response_to_proto(
52 debug_client_id: SessionId,
53 message: Self::Response,
54 ) -> Self::ProtoResponse;
55
56 #[allow(unused)]
57 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response>;
58}
59
60impl<T: LocalDapCommand> LocalDapCommand for Arc<T> {
61 type Response = T::Response;
62 type DapRequest = T::DapRequest;
63
64 fn is_supported(capabilities: &Capabilities) -> bool {
65 T::is_supported(capabilities)
66 }
67
68 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
69 T::to_dap(self)
70 }
71
72 fn response_from_dap(
73 &self,
74 message: <Self::DapRequest as dap::requests::Request>::Response,
75 ) -> Result<Self::Response> {
76 T::response_from_dap(self, message)
77 }
78}
79
80impl<T: DapCommand> DapCommand for Arc<T> {
81 type ProtoRequest = T::ProtoRequest;
82 type ProtoResponse = T::ProtoResponse;
83
84 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
85 T::client_id_from_proto(request)
86 }
87
88 fn from_proto(request: &Self::ProtoRequest) -> Self {
89 Arc::new(T::from_proto(request))
90 }
91
92 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
93 T::to_proto(self, debug_client_id, upstream_project_id)
94 }
95
96 fn response_to_proto(
97 debug_client_id: SessionId,
98 message: Self::Response,
99 ) -> Self::ProtoResponse {
100 T::response_to_proto(debug_client_id, message)
101 }
102
103 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
104 T::response_from_proto(self, message)
105 }
106}
107
108#[derive(Debug, Hash, PartialEq, Eq)]
109pub struct StepCommand {
110 pub thread_id: i64,
111 pub granularity: Option<SteppingGranularity>,
112 pub single_thread: Option<bool>,
113}
114
115impl StepCommand {
116 fn from_proto(message: proto::DapNextRequest) -> Self {
117 const LINE: i32 = proto::SteppingGranularity::Line as i32;
118 const INSTRUCTION: i32 = proto::SteppingGranularity::Instruction as i32;
119
120 let granularity = message.granularity.map(|granularity| match granularity {
121 LINE => SteppingGranularity::Line,
122 INSTRUCTION => SteppingGranularity::Instruction,
123 _ => SteppingGranularity::Statement,
124 });
125
126 Self {
127 thread_id: message.thread_id,
128 granularity,
129 single_thread: message.single_thread,
130 }
131 }
132}
133
134#[derive(Debug, Hash, PartialEq, Eq)]
135pub(crate) struct NextCommand {
136 pub inner: StepCommand,
137}
138
139impl LocalDapCommand for NextCommand {
140 type Response = <Next as dap::requests::Request>::Response;
141 type DapRequest = Next;
142
143 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
144 NextArguments {
145 thread_id: self.inner.thread_id,
146 single_thread: self.inner.single_thread,
147 granularity: self.inner.granularity,
148 }
149 }
150 fn response_from_dap(
151 &self,
152 _message: <Self::DapRequest as dap::requests::Request>::Response,
153 ) -> Result<Self::Response> {
154 Ok(())
155 }
156}
157
158impl DapCommand for NextCommand {
159 type ProtoRequest = proto::DapNextRequest;
160 type ProtoResponse = proto::Ack;
161
162 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
163 SessionId::from_proto(request.client_id)
164 }
165
166 fn from_proto(request: &Self::ProtoRequest) -> Self {
167 Self {
168 inner: StepCommand::from_proto(request.clone()),
169 }
170 }
171
172 fn response_to_proto(
173 _debug_client_id: SessionId,
174 _message: Self::Response,
175 ) -> Self::ProtoResponse {
176 proto::Ack {}
177 }
178
179 fn to_proto(
180 &self,
181 debug_client_id: SessionId,
182 upstream_project_id: u64,
183 ) -> proto::DapNextRequest {
184 proto::DapNextRequest {
185 project_id: upstream_project_id,
186 client_id: debug_client_id.to_proto(),
187 thread_id: self.inner.thread_id,
188 single_thread: self.inner.single_thread,
189 granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
190 }
191 }
192
193 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
194 Ok(())
195 }
196}
197
198#[derive(Debug, Hash, PartialEq, Eq)]
199pub(crate) struct StepInCommand {
200 pub inner: StepCommand,
201}
202
203impl LocalDapCommand for StepInCommand {
204 type Response = <dap::requests::StepIn as dap::requests::Request>::Response;
205 type DapRequest = dap::requests::StepIn;
206
207 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
208 StepInArguments {
209 thread_id: self.inner.thread_id,
210 single_thread: self.inner.single_thread,
211 target_id: None,
212 granularity: self.inner.granularity,
213 }
214 }
215
216 fn response_from_dap(
217 &self,
218 _message: <Self::DapRequest as dap::requests::Request>::Response,
219 ) -> Result<Self::Response> {
220 Ok(())
221 }
222}
223
224impl DapCommand for StepInCommand {
225 type ProtoRequest = proto::DapStepInRequest;
226 type ProtoResponse = proto::Ack;
227
228 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
229 SessionId::from_proto(request.client_id)
230 }
231
232 fn from_proto(request: &Self::ProtoRequest) -> Self {
233 Self {
234 inner: StepCommand::from_proto(proto::DapNextRequest {
235 project_id: request.project_id,
236 client_id: request.client_id,
237 thread_id: request.thread_id,
238 single_thread: request.single_thread,
239 granularity: request.granularity,
240 }),
241 }
242 }
243
244 fn response_to_proto(
245 _debug_client_id: SessionId,
246 _message: Self::Response,
247 ) -> Self::ProtoResponse {
248 proto::Ack {}
249 }
250
251 fn to_proto(
252 &self,
253 debug_client_id: SessionId,
254 upstream_project_id: u64,
255 ) -> proto::DapStepInRequest {
256 proto::DapStepInRequest {
257 project_id: upstream_project_id,
258 client_id: debug_client_id.to_proto(),
259 thread_id: self.inner.thread_id,
260 single_thread: self.inner.single_thread,
261 granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
262 target_id: None,
263 }
264 }
265
266 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
267 Ok(())
268 }
269}
270
271#[derive(Debug, Hash, PartialEq, Eq)]
272pub(crate) struct StepOutCommand {
273 pub inner: StepCommand,
274}
275
276impl LocalDapCommand for StepOutCommand {
277 type Response = <dap::requests::StepOut as dap::requests::Request>::Response;
278 type DapRequest = dap::requests::StepOut;
279
280 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
281 StepOutArguments {
282 thread_id: self.inner.thread_id,
283 single_thread: self.inner.single_thread,
284 granularity: self.inner.granularity,
285 }
286 }
287
288 fn response_from_dap(
289 &self,
290 _message: <Self::DapRequest as dap::requests::Request>::Response,
291 ) -> Result<Self::Response> {
292 Ok(())
293 }
294}
295
296impl DapCommand for StepOutCommand {
297 type ProtoRequest = proto::DapStepOutRequest;
298 type ProtoResponse = proto::Ack;
299
300 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
301 SessionId::from_proto(request.client_id)
302 }
303
304 fn from_proto(request: &Self::ProtoRequest) -> Self {
305 Self {
306 inner: StepCommand::from_proto(proto::DapNextRequest {
307 project_id: request.project_id,
308 client_id: request.client_id,
309 thread_id: request.thread_id,
310 single_thread: request.single_thread,
311 granularity: request.granularity,
312 }),
313 }
314 }
315
316 fn response_to_proto(
317 _debug_client_id: SessionId,
318 _message: Self::Response,
319 ) -> Self::ProtoResponse {
320 proto::Ack {}
321 }
322
323 fn to_proto(
324 &self,
325 debug_client_id: SessionId,
326 upstream_project_id: u64,
327 ) -> proto::DapStepOutRequest {
328 proto::DapStepOutRequest {
329 project_id: upstream_project_id,
330 client_id: debug_client_id.to_proto(),
331 thread_id: self.inner.thread_id,
332 single_thread: self.inner.single_thread,
333 granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
334 }
335 }
336
337 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
338 Ok(())
339 }
340}
341
342#[derive(Debug, Hash, PartialEq, Eq)]
343pub(crate) struct StepBackCommand {
344 pub inner: StepCommand,
345}
346impl LocalDapCommand for StepBackCommand {
347 type Response = <dap::requests::StepBack as dap::requests::Request>::Response;
348 type DapRequest = dap::requests::StepBack;
349
350 fn is_supported(capabilities: &Capabilities) -> bool {
351 capabilities.supports_step_back.unwrap_or_default()
352 }
353
354 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
355 dap::StepBackArguments {
356 thread_id: self.inner.thread_id,
357 single_thread: self.inner.single_thread,
358 granularity: self.inner.granularity,
359 }
360 }
361
362 fn response_from_dap(
363 &self,
364 _message: <Self::DapRequest as dap::requests::Request>::Response,
365 ) -> Result<Self::Response> {
366 Ok(())
367 }
368}
369
370impl DapCommand for StepBackCommand {
371 type ProtoRequest = proto::DapStepBackRequest;
372 type ProtoResponse = proto::Ack;
373
374 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
375 SessionId::from_proto(request.client_id)
376 }
377
378 fn from_proto(request: &Self::ProtoRequest) -> Self {
379 Self {
380 inner: StepCommand::from_proto(proto::DapNextRequest {
381 project_id: request.project_id,
382 client_id: request.client_id,
383 thread_id: request.thread_id,
384 single_thread: request.single_thread,
385 granularity: request.granularity,
386 }),
387 }
388 }
389
390 fn response_to_proto(
391 _debug_client_id: SessionId,
392 _message: Self::Response,
393 ) -> Self::ProtoResponse {
394 proto::Ack {}
395 }
396
397 fn to_proto(
398 &self,
399 debug_client_id: SessionId,
400 upstream_project_id: u64,
401 ) -> proto::DapStepBackRequest {
402 proto::DapStepBackRequest {
403 project_id: upstream_project_id,
404 client_id: debug_client_id.to_proto(),
405 thread_id: self.inner.thread_id,
406 single_thread: self.inner.single_thread,
407 granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
408 }
409 }
410
411 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
412 Ok(())
413 }
414}
415
416#[derive(Debug, Hash, PartialEq, Eq)]
417pub(crate) struct ContinueCommand {
418 pub args: ContinueArguments,
419}
420
421impl LocalDapCommand for ContinueCommand {
422 type Response = <Continue as dap::requests::Request>::Response;
423 type DapRequest = Continue;
424
425 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
426 self.args.clone()
427 }
428
429 fn response_from_dap(
430 &self,
431 message: <Self::DapRequest as dap::requests::Request>::Response,
432 ) -> Result<Self::Response> {
433 Ok(message)
434 }
435}
436
437impl DapCommand for ContinueCommand {
438 type ProtoRequest = proto::DapContinueRequest;
439 type ProtoResponse = proto::DapContinueResponse;
440
441 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
442 SessionId::from_proto(request.client_id)
443 }
444
445 fn to_proto(
446 &self,
447 debug_client_id: SessionId,
448 upstream_project_id: u64,
449 ) -> proto::DapContinueRequest {
450 proto::DapContinueRequest {
451 project_id: upstream_project_id,
452 client_id: debug_client_id.to_proto(),
453 thread_id: self.args.thread_id,
454 single_thread: self.args.single_thread,
455 }
456 }
457
458 fn from_proto(request: &Self::ProtoRequest) -> Self {
459 Self {
460 args: ContinueArguments {
461 thread_id: request.thread_id,
462 single_thread: request.single_thread,
463 },
464 }
465 }
466
467 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
468 Ok(Self::Response {
469 all_threads_continued: message.all_threads_continued,
470 })
471 }
472
473 fn response_to_proto(
474 debug_client_id: SessionId,
475 message: Self::Response,
476 ) -> Self::ProtoResponse {
477 proto::DapContinueResponse {
478 client_id: debug_client_id.to_proto(),
479 all_threads_continued: message.all_threads_continued,
480 }
481 }
482}
483
484#[derive(Debug, Hash, PartialEq, Eq)]
485pub(crate) struct PauseCommand {
486 pub thread_id: i64,
487}
488
489impl LocalDapCommand for PauseCommand {
490 type Response = <dap::requests::Pause as dap::requests::Request>::Response;
491 type DapRequest = dap::requests::Pause;
492 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
493 dap::PauseArguments {
494 thread_id: self.thread_id,
495 }
496 }
497
498 fn response_from_dap(
499 &self,
500 _message: <Self::DapRequest as dap::requests::Request>::Response,
501 ) -> Result<Self::Response> {
502 Ok(())
503 }
504}
505
506impl DapCommand for PauseCommand {
507 type ProtoRequest = proto::DapPauseRequest;
508 type ProtoResponse = proto::Ack;
509
510 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
511 SessionId::from_proto(request.client_id)
512 }
513
514 fn from_proto(request: &Self::ProtoRequest) -> Self {
515 Self {
516 thread_id: request.thread_id,
517 }
518 }
519
520 fn to_proto(
521 &self,
522 debug_client_id: SessionId,
523 upstream_project_id: u64,
524 ) -> proto::DapPauseRequest {
525 proto::DapPauseRequest {
526 project_id: upstream_project_id,
527 client_id: debug_client_id.to_proto(),
528 thread_id: self.thread_id,
529 }
530 }
531
532 fn response_to_proto(
533 _debug_client_id: SessionId,
534 _message: Self::Response,
535 ) -> Self::ProtoResponse {
536 proto::Ack {}
537 }
538
539 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
540 Ok(())
541 }
542}
543
544#[derive(Debug, Hash, PartialEq, Eq)]
545pub(crate) struct DisconnectCommand {
546 pub restart: Option<bool>,
547 pub terminate_debuggee: Option<bool>,
548 pub suspend_debuggee: Option<bool>,
549}
550
551impl LocalDapCommand for DisconnectCommand {
552 type Response = <dap::requests::Disconnect as dap::requests::Request>::Response;
553 type DapRequest = dap::requests::Disconnect;
554
555 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
556 dap::DisconnectArguments {
557 restart: self.restart,
558 terminate_debuggee: self.terminate_debuggee,
559 suspend_debuggee: self.suspend_debuggee,
560 }
561 }
562
563 fn response_from_dap(
564 &self,
565 _message: <Self::DapRequest as dap::requests::Request>::Response,
566 ) -> Result<Self::Response> {
567 Ok(())
568 }
569}
570
571impl DapCommand for DisconnectCommand {
572 type ProtoRequest = proto::DapDisconnectRequest;
573 type ProtoResponse = proto::Ack;
574
575 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
576 SessionId::from_proto(request.client_id)
577 }
578
579 fn from_proto(request: &Self::ProtoRequest) -> Self {
580 Self {
581 restart: request.restart,
582 terminate_debuggee: request.terminate_debuggee,
583 suspend_debuggee: request.suspend_debuggee,
584 }
585 }
586
587 fn to_proto(
588 &self,
589 debug_client_id: SessionId,
590 upstream_project_id: u64,
591 ) -> proto::DapDisconnectRequest {
592 proto::DapDisconnectRequest {
593 project_id: upstream_project_id,
594 client_id: debug_client_id.to_proto(),
595 restart: self.restart,
596 terminate_debuggee: self.terminate_debuggee,
597 suspend_debuggee: self.suspend_debuggee,
598 }
599 }
600
601 fn response_to_proto(
602 _debug_client_id: SessionId,
603 _message: Self::Response,
604 ) -> Self::ProtoResponse {
605 proto::Ack {}
606 }
607
608 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
609 Ok(())
610 }
611}
612
613#[derive(Debug, Hash, PartialEq, Eq)]
614pub(crate) struct TerminateThreadsCommand {
615 pub thread_ids: Option<Vec<i64>>,
616}
617
618impl LocalDapCommand for TerminateThreadsCommand {
619 type Response = <dap::requests::TerminateThreads as dap::requests::Request>::Response;
620 type DapRequest = dap::requests::TerminateThreads;
621
622 fn is_supported(capabilities: &Capabilities) -> bool {
623 capabilities
624 .supports_terminate_threads_request
625 .unwrap_or_default()
626 }
627
628 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
629 dap::TerminateThreadsArguments {
630 thread_ids: self.thread_ids.clone(),
631 }
632 }
633
634 fn response_from_dap(
635 &self,
636 _message: <Self::DapRequest as dap::requests::Request>::Response,
637 ) -> Result<Self::Response> {
638 Ok(())
639 }
640}
641
642impl DapCommand for TerminateThreadsCommand {
643 type ProtoRequest = proto::DapTerminateThreadsRequest;
644 type ProtoResponse = proto::Ack;
645
646 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
647 SessionId::from_proto(request.client_id)
648 }
649
650 fn from_proto(request: &Self::ProtoRequest) -> Self {
651 let thread_ids = if request.thread_ids.is_empty() {
652 None
653 } else {
654 Some(request.thread_ids.clone())
655 };
656
657 Self { thread_ids }
658 }
659
660 fn to_proto(
661 &self,
662 debug_client_id: SessionId,
663 upstream_project_id: u64,
664 ) -> proto::DapTerminateThreadsRequest {
665 proto::DapTerminateThreadsRequest {
666 project_id: upstream_project_id,
667 client_id: debug_client_id.to_proto(),
668 thread_ids: self.thread_ids.clone().unwrap_or_default(),
669 }
670 }
671
672 fn response_to_proto(
673 _debug_client_id: SessionId,
674 _message: Self::Response,
675 ) -> Self::ProtoResponse {
676 proto::Ack {}
677 }
678
679 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
680 Ok(())
681 }
682}
683
684#[derive(Debug, Hash, PartialEq, Eq)]
685pub(crate) struct TerminateCommand {
686 pub restart: Option<bool>,
687}
688
689impl LocalDapCommand for TerminateCommand {
690 type Response = <dap::requests::Terminate as dap::requests::Request>::Response;
691 type DapRequest = dap::requests::Terminate;
692
693 fn is_supported(capabilities: &Capabilities) -> bool {
694 capabilities.supports_terminate_request.unwrap_or_default()
695 }
696 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
697 dap::TerminateArguments {
698 restart: self.restart,
699 }
700 }
701
702 fn response_from_dap(
703 &self,
704 _message: <Self::DapRequest as dap::requests::Request>::Response,
705 ) -> Result<Self::Response> {
706 Ok(())
707 }
708}
709
710impl DapCommand for TerminateCommand {
711 type ProtoRequest = proto::DapTerminateRequest;
712 type ProtoResponse = proto::Ack;
713
714 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
715 SessionId::from_proto(request.client_id)
716 }
717
718 fn from_proto(request: &Self::ProtoRequest) -> Self {
719 Self {
720 restart: request.restart,
721 }
722 }
723
724 fn to_proto(
725 &self,
726 debug_client_id: SessionId,
727 upstream_project_id: u64,
728 ) -> proto::DapTerminateRequest {
729 proto::DapTerminateRequest {
730 project_id: upstream_project_id,
731 client_id: debug_client_id.to_proto(),
732 restart: self.restart,
733 }
734 }
735
736 fn response_to_proto(
737 _debug_client_id: SessionId,
738 _message: Self::Response,
739 ) -> Self::ProtoResponse {
740 proto::Ack {}
741 }
742
743 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
744 Ok(())
745 }
746}
747
748#[derive(Debug, Hash, PartialEq, Eq)]
749pub(crate) struct RestartCommand {
750 pub raw: serde_json::Value,
751}
752
753impl LocalDapCommand for RestartCommand {
754 type Response = <dap::requests::Restart as dap::requests::Request>::Response;
755 type DapRequest = dap::requests::Restart;
756
757 fn is_supported(capabilities: &Capabilities) -> bool {
758 capabilities.supports_restart_request.unwrap_or_default()
759 }
760
761 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
762 dap::RestartArguments {
763 raw: self.raw.clone(),
764 }
765 }
766
767 fn response_from_dap(
768 &self,
769 _message: <Self::DapRequest as dap::requests::Request>::Response,
770 ) -> Result<Self::Response> {
771 Ok(())
772 }
773}
774
775impl DapCommand for RestartCommand {
776 type ProtoRequest = proto::DapRestartRequest;
777 type ProtoResponse = proto::Ack;
778
779 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
780 SessionId::from_proto(request.client_id)
781 }
782
783 fn from_proto(request: &Self::ProtoRequest) -> Self {
784 Self {
785 raw: serde_json::from_slice(&request.raw_args)
786 .log_err()
787 .unwrap_or(serde_json::Value::Null),
788 }
789 }
790
791 fn to_proto(
792 &self,
793 debug_client_id: SessionId,
794 upstream_project_id: u64,
795 ) -> proto::DapRestartRequest {
796 let raw_args = serde_json::to_vec(&self.raw).log_err().unwrap_or_default();
797
798 proto::DapRestartRequest {
799 project_id: upstream_project_id,
800 client_id: debug_client_id.to_proto(),
801 raw_args,
802 }
803 }
804
805 fn response_to_proto(
806 _debug_client_id: SessionId,
807 _message: Self::Response,
808 ) -> Self::ProtoResponse {
809 proto::Ack {}
810 }
811
812 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
813 Ok(())
814 }
815}
816
817#[derive(Clone, Debug, Hash, PartialEq, Eq)]
818pub struct VariablesCommand {
819 pub variables_reference: u64,
820 pub filter: Option<VariablesArgumentsFilter>,
821 pub start: Option<u64>,
822 pub count: Option<u64>,
823 pub format: Option<ValueFormat>,
824}
825
826impl LocalDapCommand for VariablesCommand {
827 type Response = Vec<Variable>;
828 type DapRequest = dap::requests::Variables;
829 const CACHEABLE: bool = true;
830
831 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
832 dap::VariablesArguments {
833 variables_reference: self.variables_reference,
834 filter: self.filter,
835 start: self.start,
836 count: self.count,
837 format: self.format.clone(),
838 }
839 }
840
841 fn response_from_dap(
842 &self,
843 message: <Self::DapRequest as dap::requests::Request>::Response,
844 ) -> Result<Self::Response> {
845 Ok(message.variables)
846 }
847}
848
849impl DapCommand for VariablesCommand {
850 type ProtoRequest = proto::VariablesRequest;
851 type ProtoResponse = proto::DapVariables;
852
853 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
854 SessionId::from_proto(request.client_id)
855 }
856
857 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
858 proto::VariablesRequest {
859 project_id: upstream_project_id,
860 client_id: debug_client_id.to_proto(),
861 variables_reference: self.variables_reference,
862 filter: None,
863 start: self.start,
864 count: self.count,
865 format: None,
866 }
867 }
868
869 fn from_proto(request: &Self::ProtoRequest) -> Self {
870 Self {
871 variables_reference: request.variables_reference,
872 filter: None,
873 start: request.start,
874 count: request.count,
875 format: None,
876 }
877 }
878
879 fn response_to_proto(
880 debug_client_id: SessionId,
881 message: Self::Response,
882 ) -> Self::ProtoResponse {
883 proto::DapVariables {
884 client_id: debug_client_id.to_proto(),
885 variables: message.to_proto(),
886 }
887 }
888
889 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
890 Ok(Vec::from_proto(message.variables))
891 }
892}
893
894#[derive(Debug, Hash, PartialEq, Eq)]
895pub(crate) struct SetVariableValueCommand {
896 pub name: String,
897 pub value: String,
898 pub variables_reference: u64,
899}
900impl LocalDapCommand for SetVariableValueCommand {
901 type Response = SetVariableResponse;
902 type DapRequest = dap::requests::SetVariable;
903 fn is_supported(capabilities: &Capabilities) -> bool {
904 capabilities.supports_set_variable.unwrap_or_default()
905 }
906 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
907 dap::SetVariableArguments {
908 format: None,
909 name: self.name.clone(),
910 value: self.value.clone(),
911 variables_reference: self.variables_reference,
912 }
913 }
914 fn response_from_dap(
915 &self,
916 message: <Self::DapRequest as dap::requests::Request>::Response,
917 ) -> Result<Self::Response> {
918 Ok(message)
919 }
920}
921
922impl DapCommand for SetVariableValueCommand {
923 type ProtoRequest = proto::DapSetVariableValueRequest;
924 type ProtoResponse = proto::DapSetVariableValueResponse;
925
926 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
927 SessionId::from_proto(request.client_id)
928 }
929
930 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
931 proto::DapSetVariableValueRequest {
932 project_id: upstream_project_id,
933 client_id: debug_client_id.to_proto(),
934 variables_reference: self.variables_reference,
935 value: self.value.clone(),
936 name: self.name.clone(),
937 }
938 }
939
940 fn from_proto(request: &Self::ProtoRequest) -> Self {
941 Self {
942 variables_reference: request.variables_reference,
943 name: request.name.clone(),
944 value: request.value.clone(),
945 }
946 }
947
948 fn response_to_proto(
949 debug_client_id: SessionId,
950 message: Self::Response,
951 ) -> Self::ProtoResponse {
952 proto::DapSetVariableValueResponse {
953 client_id: debug_client_id.to_proto(),
954 value: message.value,
955 variable_type: message.type_,
956 named_variables: message.named_variables,
957 variables_reference: message.variables_reference,
958 indexed_variables: message.indexed_variables,
959 memory_reference: message.memory_reference,
960 }
961 }
962
963 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
964 Ok(SetVariableResponse {
965 value: message.value,
966 type_: message.variable_type,
967 variables_reference: message.variables_reference,
968 named_variables: message.named_variables,
969 indexed_variables: message.indexed_variables,
970 memory_reference: message.memory_reference,
971 value_location_reference: None, // TODO
972 })
973 }
974}
975
976#[derive(Debug, Clone, Hash, PartialEq, Eq)]
977pub(crate) struct RestartStackFrameCommand {
978 pub stack_frame_id: u64,
979}
980
981impl LocalDapCommand for RestartStackFrameCommand {
982 type Response = <dap::requests::RestartFrame as dap::requests::Request>::Response;
983 type DapRequest = dap::requests::RestartFrame;
984
985 fn is_supported(capabilities: &Capabilities) -> bool {
986 capabilities.supports_restart_frame.unwrap_or_default()
987 }
988
989 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
990 dap::RestartFrameArguments {
991 frame_id: self.stack_frame_id,
992 }
993 }
994
995 fn response_from_dap(
996 &self,
997 _message: <Self::DapRequest as dap::requests::Request>::Response,
998 ) -> Result<Self::Response> {
999 Ok(())
1000 }
1001}
1002
1003impl DapCommand for RestartStackFrameCommand {
1004 type ProtoRequest = proto::DapRestartStackFrameRequest;
1005 type ProtoResponse = proto::Ack;
1006
1007 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1008 SessionId::from_proto(request.client_id)
1009 }
1010
1011 fn from_proto(request: &Self::ProtoRequest) -> Self {
1012 Self {
1013 stack_frame_id: request.stack_frame_id,
1014 }
1015 }
1016
1017 fn to_proto(
1018 &self,
1019 debug_client_id: SessionId,
1020 upstream_project_id: u64,
1021 ) -> proto::DapRestartStackFrameRequest {
1022 proto::DapRestartStackFrameRequest {
1023 project_id: upstream_project_id,
1024 client_id: debug_client_id.to_proto(),
1025 stack_frame_id: self.stack_frame_id,
1026 }
1027 }
1028
1029 fn response_to_proto(
1030 _debug_client_id: SessionId,
1031 _message: Self::Response,
1032 ) -> Self::ProtoResponse {
1033 proto::Ack {}
1034 }
1035
1036 fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
1037 Ok(())
1038 }
1039}
1040
1041#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1042pub(crate) struct ModulesCommand;
1043
1044impl LocalDapCommand for ModulesCommand {
1045 type Response = Vec<dap::Module>;
1046 type DapRequest = dap::requests::Modules;
1047 const CACHEABLE: bool = true;
1048
1049 fn is_supported(capabilities: &Capabilities) -> bool {
1050 capabilities.supports_modules_request.unwrap_or_default()
1051 }
1052
1053 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1054 dap::ModulesArguments {
1055 start_module: None,
1056 module_count: None,
1057 }
1058 }
1059
1060 fn response_from_dap(
1061 &self,
1062 message: <Self::DapRequest as dap::requests::Request>::Response,
1063 ) -> Result<Self::Response> {
1064 Ok(message.modules)
1065 }
1066}
1067
1068impl DapCommand for ModulesCommand {
1069 type ProtoRequest = proto::DapModulesRequest;
1070 type ProtoResponse = proto::DapModulesResponse;
1071
1072 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1073 SessionId::from_proto(request.client_id)
1074 }
1075
1076 fn from_proto(_request: &Self::ProtoRequest) -> Self {
1077 Self {}
1078 }
1079
1080 fn to_proto(
1081 &self,
1082 debug_client_id: SessionId,
1083 upstream_project_id: u64,
1084 ) -> proto::DapModulesRequest {
1085 proto::DapModulesRequest {
1086 project_id: upstream_project_id,
1087 client_id: debug_client_id.to_proto(),
1088 }
1089 }
1090
1091 fn response_to_proto(
1092 debug_client_id: SessionId,
1093 message: Self::Response,
1094 ) -> Self::ProtoResponse {
1095 proto::DapModulesResponse {
1096 modules: message
1097 .into_iter()
1098 .map(|module| module.to_proto())
1099 .collect(),
1100 client_id: debug_client_id.to_proto(),
1101 }
1102 }
1103
1104 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1105 Ok(message
1106 .modules
1107 .into_iter()
1108 .filter_map(|module| dap::Module::from_proto(module).ok())
1109 .collect())
1110 }
1111}
1112
1113#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1114pub(crate) struct LoadedSourcesCommand;
1115
1116impl LocalDapCommand for LoadedSourcesCommand {
1117 type Response = Vec<dap::Source>;
1118 type DapRequest = dap::requests::LoadedSources;
1119 const CACHEABLE: bool = true;
1120
1121 fn is_supported(capabilities: &Capabilities) -> bool {
1122 capabilities
1123 .supports_loaded_sources_request
1124 .unwrap_or_default()
1125 }
1126 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1127 dap::LoadedSourcesArguments {}
1128 }
1129
1130 fn response_from_dap(
1131 &self,
1132 message: <Self::DapRequest as dap::requests::Request>::Response,
1133 ) -> Result<Self::Response> {
1134 Ok(message.sources)
1135 }
1136}
1137
1138impl DapCommand for LoadedSourcesCommand {
1139 type ProtoRequest = proto::DapLoadedSourcesRequest;
1140 type ProtoResponse = proto::DapLoadedSourcesResponse;
1141
1142 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1143 SessionId::from_proto(request.client_id)
1144 }
1145
1146 fn from_proto(_request: &Self::ProtoRequest) -> Self {
1147 Self {}
1148 }
1149
1150 fn to_proto(
1151 &self,
1152 debug_client_id: SessionId,
1153 upstream_project_id: u64,
1154 ) -> proto::DapLoadedSourcesRequest {
1155 proto::DapLoadedSourcesRequest {
1156 project_id: upstream_project_id,
1157 client_id: debug_client_id.to_proto(),
1158 }
1159 }
1160
1161 fn response_to_proto(
1162 debug_client_id: SessionId,
1163 message: Self::Response,
1164 ) -> Self::ProtoResponse {
1165 proto::DapLoadedSourcesResponse {
1166 sources: message
1167 .into_iter()
1168 .map(|source| source.to_proto())
1169 .collect(),
1170 client_id: debug_client_id.to_proto(),
1171 }
1172 }
1173
1174 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1175 Ok(message
1176 .sources
1177 .into_iter()
1178 .map(dap::Source::from_proto)
1179 .collect())
1180 }
1181}
1182
1183#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1184pub(crate) struct StackTraceCommand {
1185 pub thread_id: i64,
1186 pub start_frame: Option<u64>,
1187 pub levels: Option<u64>,
1188}
1189
1190impl LocalDapCommand for StackTraceCommand {
1191 type Response = Vec<dap::StackFrame>;
1192 type DapRequest = dap::requests::StackTrace;
1193 const CACHEABLE: bool = true;
1194
1195 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1196 dap::StackTraceArguments {
1197 thread_id: self.thread_id,
1198 start_frame: self.start_frame,
1199 levels: self.levels,
1200 format: None,
1201 }
1202 }
1203
1204 fn response_from_dap(
1205 &self,
1206 message: <Self::DapRequest as dap::requests::Request>::Response,
1207 ) -> Result<Self::Response> {
1208 Ok(message.stack_frames)
1209 }
1210}
1211
1212impl DapCommand for StackTraceCommand {
1213 type ProtoRequest = proto::DapStackTraceRequest;
1214 type ProtoResponse = proto::DapStackTraceResponse;
1215
1216 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1217 proto::DapStackTraceRequest {
1218 project_id: upstream_project_id,
1219 client_id: debug_client_id.to_proto(),
1220 thread_id: self.thread_id,
1221 start_frame: self.start_frame,
1222 stack_trace_levels: self.levels,
1223 }
1224 }
1225
1226 fn from_proto(request: &Self::ProtoRequest) -> Self {
1227 Self {
1228 thread_id: request.thread_id,
1229 start_frame: request.start_frame,
1230 levels: request.stack_trace_levels,
1231 }
1232 }
1233
1234 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1235 SessionId::from_proto(request.client_id)
1236 }
1237
1238 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1239 Ok(message
1240 .frames
1241 .into_iter()
1242 .map(dap::StackFrame::from_proto)
1243 .collect())
1244 }
1245
1246 fn response_to_proto(
1247 _debug_client_id: SessionId,
1248 message: Self::Response,
1249 ) -> Self::ProtoResponse {
1250 proto::DapStackTraceResponse {
1251 frames: message.to_proto(),
1252 }
1253 }
1254}
1255
1256#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1257pub(crate) struct ScopesCommand {
1258 pub stack_frame_id: u64,
1259}
1260
1261impl LocalDapCommand for ScopesCommand {
1262 type Response = Vec<dap::Scope>;
1263 type DapRequest = dap::requests::Scopes;
1264 const CACHEABLE: bool = true;
1265
1266 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1267 dap::ScopesArguments {
1268 frame_id: self.stack_frame_id,
1269 }
1270 }
1271
1272 fn response_from_dap(
1273 &self,
1274 message: <Self::DapRequest as dap::requests::Request>::Response,
1275 ) -> Result<Self::Response> {
1276 Ok(message.scopes)
1277 }
1278}
1279
1280impl DapCommand for ScopesCommand {
1281 type ProtoRequest = proto::DapScopesRequest;
1282 type ProtoResponse = proto::DapScopesResponse;
1283
1284 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1285 proto::DapScopesRequest {
1286 project_id: upstream_project_id,
1287 client_id: debug_client_id.to_proto(),
1288 stack_frame_id: self.stack_frame_id,
1289 }
1290 }
1291
1292 fn from_proto(request: &Self::ProtoRequest) -> Self {
1293 Self {
1294 stack_frame_id: request.stack_frame_id,
1295 }
1296 }
1297
1298 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1299 SessionId::from_proto(request.client_id)
1300 }
1301
1302 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1303 Ok(Vec::from_proto(message.scopes))
1304 }
1305
1306 fn response_to_proto(
1307 _debug_client_id: SessionId,
1308 message: Self::Response,
1309 ) -> Self::ProtoResponse {
1310 proto::DapScopesResponse {
1311 scopes: message.to_proto(),
1312 }
1313 }
1314}
1315
1316impl LocalDapCommand for super::session::CompletionsQuery {
1317 type Response = dap::CompletionsResponse;
1318 type DapRequest = dap::requests::Completions;
1319 const CACHEABLE: bool = true;
1320
1321 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1322 dap::CompletionsArguments {
1323 text: self.query.clone(),
1324 frame_id: self.frame_id,
1325 column: self.column,
1326 line: None,
1327 }
1328 }
1329
1330 fn response_from_dap(
1331 &self,
1332 message: <Self::DapRequest as dap::requests::Request>::Response,
1333 ) -> Result<Self::Response> {
1334 Ok(message)
1335 }
1336
1337 fn is_supported(capabilities: &Capabilities) -> bool {
1338 capabilities
1339 .supports_completions_request
1340 .unwrap_or_default()
1341 }
1342}
1343
1344impl DapCommand for super::session::CompletionsQuery {
1345 type ProtoRequest = proto::DapCompletionRequest;
1346 type ProtoResponse = proto::DapCompletionResponse;
1347
1348 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1349 proto::DapCompletionRequest {
1350 client_id: debug_client_id.to_proto(),
1351 project_id: upstream_project_id,
1352 frame_id: self.frame_id,
1353 query: self.query.clone(),
1354 column: self.column,
1355 line: self.line,
1356 }
1357 }
1358
1359 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1360 SessionId::from_proto(request.client_id)
1361 }
1362
1363 fn from_proto(request: &Self::ProtoRequest) -> Self {
1364 Self {
1365 query: request.query.clone(),
1366 frame_id: request.frame_id,
1367 column: request.column,
1368 line: request.line,
1369 }
1370 }
1371
1372 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1373 Ok(dap::CompletionsResponse {
1374 targets: Vec::from_proto(message.completions),
1375 })
1376 }
1377
1378 fn response_to_proto(
1379 _debug_client_id: SessionId,
1380 message: Self::Response,
1381 ) -> Self::ProtoResponse {
1382 proto::DapCompletionResponse {
1383 client_id: _debug_client_id.to_proto(),
1384 completions: message.targets.to_proto(),
1385 }
1386 }
1387}
1388
1389#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1390pub(crate) struct EvaluateCommand {
1391 pub expression: String,
1392 pub frame_id: Option<u64>,
1393 pub context: Option<dap::EvaluateArgumentsContext>,
1394 pub source: Option<dap::Source>,
1395}
1396
1397impl LocalDapCommand for EvaluateCommand {
1398 type Response = dap::EvaluateResponse;
1399 type DapRequest = dap::requests::Evaluate;
1400 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1401 dap::EvaluateArguments {
1402 expression: self.expression.clone(),
1403 frame_id: self.frame_id,
1404 context: self.context.clone(),
1405 source: self.source.clone(),
1406 line: None,
1407 column: None,
1408 format: None,
1409 }
1410 }
1411
1412 fn response_from_dap(
1413 &self,
1414 message: <Self::DapRequest as dap::requests::Request>::Response,
1415 ) -> Result<Self::Response> {
1416 Ok(message)
1417 }
1418}
1419impl DapCommand for EvaluateCommand {
1420 type ProtoRequest = proto::DapEvaluateRequest;
1421 type ProtoResponse = proto::DapEvaluateResponse;
1422
1423 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1424 proto::DapEvaluateRequest {
1425 client_id: debug_client_id.to_proto(),
1426 project_id: upstream_project_id,
1427 expression: self.expression.clone(),
1428 frame_id: self.frame_id,
1429 context: self
1430 .context
1431 .clone()
1432 .map(|context| context.to_proto().into()),
1433 }
1434 }
1435
1436 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1437 SessionId::from_proto(request.client_id)
1438 }
1439
1440 fn from_proto(request: &Self::ProtoRequest) -> Self {
1441 Self {
1442 expression: request.expression.clone(),
1443 frame_id: request.frame_id,
1444 context: Some(dap::EvaluateArgumentsContext::from_proto(request.context())),
1445 source: None,
1446 }
1447 }
1448
1449 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1450 Ok(dap::EvaluateResponse {
1451 result: message.result.clone(),
1452 type_: message.evaluate_type.clone(),
1453 presentation_hint: None,
1454 variables_reference: message.variable_reference,
1455 named_variables: message.named_variables,
1456 indexed_variables: message.indexed_variables,
1457 memory_reference: message.memory_reference,
1458 value_location_reference: None, //TODO
1459 })
1460 }
1461
1462 fn response_to_proto(
1463 _debug_client_id: SessionId,
1464 message: Self::Response,
1465 ) -> Self::ProtoResponse {
1466 proto::DapEvaluateResponse {
1467 result: message.result,
1468 evaluate_type: message.type_,
1469 variable_reference: message.variables_reference,
1470 named_variables: message.named_variables,
1471 indexed_variables: message.indexed_variables,
1472 memory_reference: message.memory_reference,
1473 }
1474 }
1475}
1476
1477#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1478pub(crate) struct ThreadsCommand;
1479
1480impl LocalDapCommand for ThreadsCommand {
1481 type Response = Vec<dap::Thread>;
1482 type DapRequest = dap::requests::Threads;
1483 const CACHEABLE: bool = true;
1484
1485 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1486 dap::ThreadsArgument {}
1487 }
1488
1489 fn response_from_dap(
1490 &self,
1491 message: <Self::DapRequest as dap::requests::Request>::Response,
1492 ) -> Result<Self::Response> {
1493 Ok(message.threads)
1494 }
1495}
1496
1497impl DapCommand for ThreadsCommand {
1498 type ProtoRequest = proto::DapThreadsRequest;
1499 type ProtoResponse = proto::DapThreadsResponse;
1500
1501 fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1502 proto::DapThreadsRequest {
1503 project_id: upstream_project_id,
1504 client_id: debug_client_id.to_proto(),
1505 }
1506 }
1507
1508 fn from_proto(_request: &Self::ProtoRequest) -> Self {
1509 Self {}
1510 }
1511
1512 fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1513 SessionId::from_proto(request.client_id)
1514 }
1515
1516 fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1517 Ok(Vec::from_proto(message.threads))
1518 }
1519
1520 fn response_to_proto(
1521 _debug_client_id: SessionId,
1522 message: Self::Response,
1523 ) -> Self::ProtoResponse {
1524 proto::DapThreadsResponse {
1525 threads: message.to_proto(),
1526 }
1527 }
1528}
1529
1530#[derive(Clone, Debug, Hash, PartialEq)]
1531pub(super) struct Initialize {
1532 pub(super) adapter_id: String,
1533}
1534
1535fn dap_client_capabilities(adapter_id: String) -> InitializeRequestArguments {
1536 InitializeRequestArguments {
1537 client_id: Some("zed".to_owned()),
1538 client_name: Some("Zed".to_owned()),
1539 adapter_id,
1540 locale: Some("en-US".to_owned()),
1541 path_format: Some(InitializeRequestArgumentsPathFormat::Path),
1542 supports_variable_type: Some(true),
1543 supports_variable_paging: Some(false),
1544 supports_run_in_terminal_request: Some(true),
1545 supports_memory_references: Some(true),
1546 supports_progress_reporting: Some(false),
1547 supports_invalidated_event: Some(false),
1548 lines_start_at1: Some(true),
1549 columns_start_at1: Some(true),
1550 supports_memory_event: Some(false),
1551 supports_args_can_be_interpreted_by_shell: Some(false),
1552 supports_start_debugging_request: Some(true),
1553 supports_ansistyling: Some(true),
1554 }
1555}
1556
1557impl LocalDapCommand for Initialize {
1558 type Response = Capabilities;
1559 type DapRequest = dap::requests::Initialize;
1560
1561 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1562 dap_client_capabilities(self.adapter_id.clone())
1563 }
1564
1565 fn response_from_dap(
1566 &self,
1567 message: <Self::DapRequest as dap::requests::Request>::Response,
1568 ) -> Result<Self::Response> {
1569 Ok(message)
1570 }
1571}
1572
1573#[derive(Clone, Debug, Hash, PartialEq)]
1574pub(super) struct ConfigurationDone {}
1575
1576impl LocalDapCommand for ConfigurationDone {
1577 type Response = ();
1578 type DapRequest = dap::requests::ConfigurationDone;
1579
1580 fn is_supported(capabilities: &Capabilities) -> bool {
1581 capabilities
1582 .supports_configuration_done_request
1583 .unwrap_or_default()
1584 }
1585
1586 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1587 dap::ConfigurationDoneArguments {}
1588 }
1589
1590 fn response_from_dap(
1591 &self,
1592 message: <Self::DapRequest as dap::requests::Request>::Response,
1593 ) -> Result<Self::Response> {
1594 Ok(message)
1595 }
1596}
1597
1598#[derive(Clone, Debug, Hash, PartialEq)]
1599pub(super) struct Launch {
1600 pub(super) raw: Value,
1601}
1602
1603impl LocalDapCommand for Launch {
1604 type Response = ();
1605 type DapRequest = dap::requests::Launch;
1606
1607 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1608 dap::LaunchRequestArguments {
1609 raw: self.raw.clone(),
1610 }
1611 }
1612
1613 fn response_from_dap(
1614 &self,
1615 message: <Self::DapRequest as dap::requests::Request>::Response,
1616 ) -> Result<Self::Response> {
1617 Ok(message)
1618 }
1619}
1620
1621#[derive(Clone, Debug, Hash, PartialEq)]
1622pub(super) struct Attach {
1623 pub(super) raw: Value,
1624}
1625
1626impl LocalDapCommand for Attach {
1627 type Response = ();
1628 type DapRequest = dap::requests::Attach;
1629
1630 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1631 dap::AttachRequestArguments {
1632 raw: self.raw.clone(),
1633 }
1634 }
1635
1636 fn response_from_dap(
1637 &self,
1638 message: <Self::DapRequest as dap::requests::Request>::Response,
1639 ) -> Result<Self::Response> {
1640 Ok(message)
1641 }
1642}
1643
1644#[derive(Clone, Debug, Hash, PartialEq)]
1645pub(super) struct SetBreakpoints {
1646 pub(super) source: dap::Source,
1647 pub(super) breakpoints: Vec<SourceBreakpoint>,
1648 pub(super) source_modified: Option<bool>,
1649}
1650
1651impl LocalDapCommand for SetBreakpoints {
1652 type Response = Vec<dap::Breakpoint>;
1653 type DapRequest = dap::requests::SetBreakpoints;
1654
1655 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1656 dap::SetBreakpointsArguments {
1657 lines: None,
1658 source_modified: self.source_modified,
1659 source: self.source.clone(),
1660 breakpoints: Some(self.breakpoints.clone()),
1661 }
1662 }
1663
1664 fn response_from_dap(
1665 &self,
1666 message: <Self::DapRequest as dap::requests::Request>::Response,
1667 ) -> Result<Self::Response> {
1668 Ok(message.breakpoints)
1669 }
1670}
1671
1672#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1673pub enum DataBreakpointContext {
1674 Variable {
1675 variables_reference: u64,
1676 name: String,
1677 bytes: Option<u64>,
1678 },
1679 Expression {
1680 expression: String,
1681 frame_id: Option<u64>,
1682 },
1683 Address {
1684 address: String,
1685 bytes: Option<u64>,
1686 },
1687}
1688
1689impl DataBreakpointContext {
1690 pub fn human_readable_label(&self) -> String {
1691 match self {
1692 DataBreakpointContext::Variable { name, .. } => format!("Variable: {}", name),
1693 DataBreakpointContext::Expression { expression, .. } => {
1694 format!("Expression: {}", expression)
1695 }
1696 DataBreakpointContext::Address { address, bytes } => {
1697 let mut label = format!("Address: {}", address);
1698 if let Some(bytes) = bytes {
1699 label.push_str(&format!(
1700 " ({} byte{})",
1701 bytes,
1702 if *bytes == 1 { "" } else { "s" }
1703 ));
1704 }
1705 label
1706 }
1707 }
1708 }
1709}
1710
1711#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1712pub(crate) struct DataBreakpointInfoCommand {
1713 pub context: Arc<DataBreakpointContext>,
1714 pub mode: Option<String>,
1715}
1716
1717impl LocalDapCommand for DataBreakpointInfoCommand {
1718 type Response = dap::DataBreakpointInfoResponse;
1719 type DapRequest = dap::requests::DataBreakpointInfo;
1720 const CACHEABLE: bool = true;
1721
1722 // todo(debugger): We should expand this trait in the future to take a &self
1723 // Depending on this command is_supported could be differentb
1724 fn is_supported(capabilities: &Capabilities) -> bool {
1725 capabilities.supports_data_breakpoints.unwrap_or(false)
1726 }
1727
1728 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1729 let (variables_reference, name, frame_id, as_address, bytes) = match &*self.context {
1730 DataBreakpointContext::Variable {
1731 variables_reference,
1732 name,
1733 bytes,
1734 } => (
1735 Some(*variables_reference),
1736 name.clone(),
1737 None,
1738 Some(false),
1739 *bytes,
1740 ),
1741 DataBreakpointContext::Expression {
1742 expression,
1743 frame_id,
1744 } => (None, expression.clone(), *frame_id, Some(false), None),
1745 DataBreakpointContext::Address { address, bytes } => {
1746 (None, address.clone(), None, Some(true), *bytes)
1747 }
1748 };
1749
1750 dap::DataBreakpointInfoArguments {
1751 variables_reference,
1752 name,
1753 frame_id,
1754 bytes,
1755 as_address,
1756 mode: self.mode.clone(),
1757 }
1758 }
1759
1760 fn response_from_dap(
1761 &self,
1762 message: <Self::DapRequest as dap::requests::Request>::Response,
1763 ) -> Result<Self::Response> {
1764 Ok(message)
1765 }
1766}
1767
1768#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1769pub(crate) struct SetDataBreakpointsCommand {
1770 pub breakpoints: Vec<dap::DataBreakpoint>,
1771}
1772
1773impl LocalDapCommand for SetDataBreakpointsCommand {
1774 type Response = Vec<dap::Breakpoint>;
1775 type DapRequest = dap::requests::SetDataBreakpoints;
1776
1777 fn is_supported(capabilities: &Capabilities) -> bool {
1778 capabilities.supports_data_breakpoints.unwrap_or(false)
1779 }
1780
1781 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1782 dap::SetDataBreakpointsArguments {
1783 breakpoints: self.breakpoints.clone(),
1784 }
1785 }
1786
1787 fn response_from_dap(
1788 &self,
1789 message: <Self::DapRequest as dap::requests::Request>::Response,
1790 ) -> Result<Self::Response> {
1791 Ok(message.breakpoints)
1792 }
1793}
1794
1795#[derive(Clone, Debug, Hash, PartialEq)]
1796pub(super) enum SetExceptionBreakpoints {
1797 Plain {
1798 filters: Vec<String>,
1799 },
1800 WithOptions {
1801 filters: Vec<ExceptionFilterOptions>,
1802 },
1803}
1804
1805impl LocalDapCommand for SetExceptionBreakpoints {
1806 type Response = Vec<dap::Breakpoint>;
1807 type DapRequest = dap::requests::SetExceptionBreakpoints;
1808
1809 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1810 match self {
1811 SetExceptionBreakpoints::Plain { filters } => dap::SetExceptionBreakpointsArguments {
1812 filters: filters.clone(),
1813 exception_options: None,
1814 filter_options: None,
1815 },
1816 SetExceptionBreakpoints::WithOptions { filters } => {
1817 dap::SetExceptionBreakpointsArguments {
1818 filters: vec![],
1819 filter_options: Some(filters.clone()),
1820 exception_options: None,
1821 }
1822 }
1823 }
1824 }
1825
1826 fn response_from_dap(
1827 &self,
1828 message: <Self::DapRequest as dap::requests::Request>::Response,
1829 ) -> Result<Self::Response> {
1830 Ok(message.breakpoints.unwrap_or_default())
1831 }
1832}
1833
1834#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1835pub(super) struct LocationsCommand {
1836 pub(super) reference: u64,
1837}
1838
1839impl LocalDapCommand for LocationsCommand {
1840 type Response = dap::LocationsResponse;
1841 type DapRequest = dap::requests::Locations;
1842 const CACHEABLE: bool = true;
1843
1844 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1845 dap::LocationsArguments {
1846 location_reference: self.reference,
1847 }
1848 }
1849
1850 fn response_from_dap(
1851 &self,
1852 message: <Self::DapRequest as dap::requests::Request>::Response,
1853 ) -> Result<Self::Response> {
1854 Ok(message)
1855 }
1856}
1857
1858impl DapCommand for LocationsCommand {
1859 type ProtoRequest = proto::DapLocationsRequest;
1860 type ProtoResponse = proto::DapLocationsResponse;
1861
1862 fn client_id_from_proto(message: &Self::ProtoRequest) -> SessionId {
1863 SessionId::from_proto(message.session_id)
1864 }
1865
1866 fn from_proto(message: &Self::ProtoRequest) -> Self {
1867 Self {
1868 reference: message.location_reference,
1869 }
1870 }
1871
1872 fn to_proto(&self, session_id: SessionId, project_id: u64) -> Self::ProtoRequest {
1873 proto::DapLocationsRequest {
1874 project_id,
1875 session_id: session_id.to_proto(),
1876 location_reference: self.reference,
1877 }
1878 }
1879
1880 fn response_to_proto(_: SessionId, response: Self::Response) -> Self::ProtoResponse {
1881 proto::DapLocationsResponse {
1882 source: Some(response.source.to_proto()),
1883 line: response.line,
1884 column: response.column,
1885 end_line: response.end_line,
1886 end_column: response.end_column,
1887 }
1888 }
1889
1890 fn response_from_proto(&self, response: Self::ProtoResponse) -> Result<Self::Response> {
1891 Ok(dap::LocationsResponse {
1892 source: response
1893 .source
1894 .map(<dap::Source as ProtoConversion>::from_proto)
1895 .context("Missing `source` field in Locations proto")?,
1896 line: response.line,
1897 column: response.column,
1898 end_line: response.end_line,
1899 end_column: response.end_column,
1900 })
1901 }
1902}
1903
1904#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1905pub(crate) struct ReadMemory {
1906 pub(crate) memory_reference: String,
1907 pub(crate) offset: Option<u64>,
1908 pub(crate) count: u64,
1909}
1910
1911#[derive(Clone, Debug, PartialEq)]
1912pub(crate) struct ReadMemoryResponse {
1913 pub(super) address: Arc<str>,
1914 pub(super) unreadable_bytes: Option<u64>,
1915 pub(super) content: Arc<[u8]>,
1916}
1917
1918impl LocalDapCommand for ReadMemory {
1919 type Response = ReadMemoryResponse;
1920 type DapRequest = dap::requests::ReadMemory;
1921 const CACHEABLE: bool = true;
1922
1923 fn is_supported(capabilities: &Capabilities) -> bool {
1924 capabilities
1925 .supports_read_memory_request
1926 .unwrap_or_default()
1927 }
1928 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1929 dap::ReadMemoryArguments {
1930 memory_reference: self.memory_reference.clone(),
1931 offset: self.offset,
1932 count: self.count,
1933 }
1934 }
1935
1936 fn response_from_dap(
1937 &self,
1938 message: <Self::DapRequest as dap::requests::Request>::Response,
1939 ) -> Result<Self::Response> {
1940 let data = if let Some(data) = message.data {
1941 base64::engine::general_purpose::STANDARD
1942 .decode(data)
1943 .log_err()
1944 .context("parsing base64 data from DAP's ReadMemory response")?
1945 } else {
1946 vec![]
1947 };
1948
1949 Ok(ReadMemoryResponse {
1950 address: message.address.into(),
1951 content: data.into(),
1952 unreadable_bytes: message.unreadable_bytes,
1953 })
1954 }
1955}
1956
1957impl LocalDapCommand for dap::WriteMemoryArguments {
1958 type Response = dap::WriteMemoryResponse;
1959 type DapRequest = dap::requests::WriteMemory;
1960 fn is_supported(capabilities: &Capabilities) -> bool {
1961 capabilities
1962 .supports_write_memory_request
1963 .unwrap_or_default()
1964 }
1965 fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1966 self.clone()
1967 }
1968
1969 fn response_from_dap(
1970 &self,
1971 message: <Self::DapRequest as dap::requests::Request>::Response,
1972 ) -> Result<Self::Response> {
1973 Ok(message)
1974 }
1975}