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