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