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