1use std::{path::Path, sync::Arc};
2
3use dap::{Scope, StackFrame, Variable, requests::Variables};
4use editor::{Editor, EditorMode, MultiBuffer};
5use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
6use language::{
7 Language, LanguageConfig, LanguageMatcher, rust_lang, tree_sitter_python,
8 tree_sitter_typescript,
9};
10use project::{FakeFs, Project};
11use serde_json::json;
12use unindent::Unindent as _;
13use util::{path, rel_path::rel_path};
14
15use crate::{
16 debugger_panel::DebugPanel,
17 tests::{active_debug_session_panel, init_test, init_test_workspace, start_debug_session},
18};
19
20#[gpui::test]
21async fn test_rust_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
22 init_test(cx);
23
24 fn stack_frame_for_line(line: u64) -> dap::StackFrame {
25 StackFrame {
26 id: 1,
27 name: "Stack Frame 1".into(),
28 source: Some(dap::Source {
29 name: Some("main.rs".into()),
30 path: Some(path!("/project/main.rs").into()),
31 source_reference: None,
32 presentation_hint: None,
33 origin: None,
34 sources: None,
35 adapter_data: None,
36 checksums: None,
37 }),
38 line,
39 column: 1,
40 end_line: None,
41 end_column: None,
42 can_restart: None,
43 instruction_pointer_reference: None,
44 module_id: None,
45 presentation_hint: None,
46 }
47 }
48
49 let fs = FakeFs::new(executor.clone());
50 let source_code = r#"
51static mut GLOBAL: usize = 1;
52
53fn main() {
54 let x = 10;
55 let value = 42;
56 let y = 4;
57 let tester = {
58 let y = 10;
59 let y = 5;
60 let b = 3;
61 vec![y, 20, 30]
62 };
63
64 let caller = || {
65 let x = 3;
66 println!("x={}", x);
67 };
68
69 caller();
70
71 unsafe {
72 GLOBAL = 2;
73 }
74
75 let result = value * 2 * x;
76 println!("Simple test executed: value={}, result={}", value, result);
77 assert!(true);
78}
79"#
80 .unindent();
81 fs.insert_tree(path!("/project"), json!({ "main.rs": source_code }))
82 .await;
83
84 let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
85 let workspace = init_test_workspace(&project, cx).await;
86 workspace
87 .update(cx, |workspace, window, cx| {
88 workspace.focus_panel::<DebugPanel>(window, cx);
89 })
90 .unwrap();
91 let cx = &mut VisualTestContext::from_window(*workspace, cx);
92
93 let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
94 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
95
96 client.on_request::<dap::requests::Threads, _>(move |_, _| {
97 Ok(dap::ThreadsResponse {
98 threads: vec![dap::Thread {
99 id: 1,
100 name: "Thread 1".into(),
101 }],
102 })
103 });
104
105 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
106 Ok(dap::StackTraceResponse {
107 stack_frames: vec![stack_frame_for_line(4)],
108 total_frames: None,
109 })
110 });
111
112 client.on_request::<dap::requests::Evaluate, _>(move |_, args| {
113 assert_eq!("GLOBAL", args.expression);
114 Ok(dap::EvaluateResponse {
115 result: "1".into(),
116 type_: None,
117 presentation_hint: None,
118 variables_reference: 0,
119 named_variables: None,
120 indexed_variables: None,
121 memory_reference: None,
122 value_location_reference: None,
123 })
124 });
125
126 let local_variables = vec![
127 Variable {
128 name: "x".into(),
129 value: "10".into(),
130 type_: None,
131 presentation_hint: None,
132 evaluate_name: None,
133 variables_reference: 0,
134 named_variables: None,
135 indexed_variables: None,
136 memory_reference: None,
137 declaration_location_reference: None,
138 value_location_reference: None,
139 },
140 Variable {
141 name: "y".into(),
142 value: "4".into(),
143 type_: None,
144 presentation_hint: None,
145 evaluate_name: None,
146 variables_reference: 0,
147 named_variables: None,
148 indexed_variables: None,
149 memory_reference: None,
150 declaration_location_reference: None,
151 value_location_reference: None,
152 },
153 Variable {
154 name: "value".into(),
155 value: "42".into(),
156 type_: None,
157 presentation_hint: None,
158 evaluate_name: None,
159 variables_reference: 0,
160 named_variables: None,
161 indexed_variables: None,
162 memory_reference: None,
163 declaration_location_reference: None,
164 value_location_reference: None,
165 },
166 ];
167
168 client.on_request::<Variables, _>({
169 let local_variables = Arc::new(local_variables.clone());
170 move |_, _| {
171 Ok(dap::VariablesResponse {
172 variables: (*local_variables).clone(),
173 })
174 }
175 });
176
177 client.on_request::<dap::requests::Scopes, _>(move |_, _| {
178 Ok(dap::ScopesResponse {
179 scopes: vec![Scope {
180 name: "Locale".into(),
181 presentation_hint: None,
182 variables_reference: 2,
183 named_variables: None,
184 indexed_variables: None,
185 expensive: false,
186 source: None,
187 line: None,
188 column: None,
189 end_line: None,
190 end_column: None,
191 }],
192 })
193 });
194
195 client
196 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
197 reason: dap::StoppedEventReason::Pause,
198 description: None,
199 thread_id: Some(1),
200 preserve_focus_hint: None,
201 text: None,
202 all_threads_stopped: None,
203 hit_breakpoint_ids: None,
204 }))
205 .await;
206
207 cx.run_until_parked();
208
209 let project_path = Path::new(path!("/project"));
210 let worktree = project
211 .update(cx, |project, cx| project.find_worktree(project_path, cx))
212 .expect("This worktree should exist in project")
213 .0;
214
215 let worktree_id = workspace
216 .update(cx, |_, _, cx| worktree.read(cx).id())
217 .unwrap();
218
219 let buffer = project
220 .update(cx, |project, cx| {
221 project.open_buffer((worktree_id, rel_path("main.rs")), cx)
222 })
223 .await
224 .unwrap();
225
226 buffer.update(cx, |buffer, cx| {
227 buffer.set_language(Some(rust_lang()), cx);
228 });
229
230 let (editor, cx) = cx.add_window_view(|window, cx| {
231 Editor::new(
232 EditorMode::full(),
233 MultiBuffer::build_from_buffer(buffer, cx),
234 Some(project),
235 window,
236 cx,
237 )
238 });
239
240 active_debug_session_panel(workspace, cx).update_in(cx, |_, window, cx| {
241 cx.focus_self(window);
242 });
243 cx.run_until_parked();
244
245 editor.update(cx, |editor, cx| editor.refresh_inline_values(cx));
246
247 cx.run_until_parked();
248
249 editor.update_in(cx, |editor, window, cx| {
250 pretty_assertions::assert_eq!(
251 r#"
252 static mut GLOBAL: usize = 1;
253
254 fn main() {
255 let x: 10 = 10;
256 let value = 42;
257 let y = 4;
258 let tester = {
259 let y = 10;
260 let y = 5;
261 let b = 3;
262 vec![y, 20, 30]
263 };
264
265 let caller = || {
266 let x = 3;
267 println!("x={}", x);
268 };
269
270 caller();
271
272 unsafe {
273 GLOBAL = 2;
274 }
275
276 let result = value * 2 * x;
277 println!("Simple test executed: value={}, result={}", value, result);
278 assert!(true);
279 }
280 "#
281 .unindent(),
282 editor.snapshot(window, cx).text()
283 );
284 });
285
286 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
287 Ok(dap::StackTraceResponse {
288 stack_frames: vec![stack_frame_for_line(5)],
289 total_frames: None,
290 })
291 });
292 client
293 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
294 reason: dap::StoppedEventReason::Pause,
295 description: None,
296 thread_id: Some(1),
297 preserve_focus_hint: None,
298 text: None,
299 all_threads_stopped: None,
300 hit_breakpoint_ids: None,
301 }))
302 .await;
303
304 cx.run_until_parked();
305
306 editor.update_in(cx, |editor, window, cx| {
307 pretty_assertions::assert_eq!(
308 r#"
309 static mut GLOBAL: usize = 1;
310
311 fn main() {
312 let x: 10 = 10;
313 let value: 42 = 42;
314 let y = 4;
315 let tester = {
316 let y = 10;
317 let y = 5;
318 let b = 3;
319 vec![y, 20, 30]
320 };
321
322 let caller = || {
323 let x = 3;
324 println!("x={}", x);
325 };
326
327 caller();
328
329 unsafe {
330 GLOBAL = 2;
331 }
332
333 let result = value * 2 * x;
334 println!("Simple test executed: value={}, result={}", value, result);
335 assert!(true);
336 }
337 "#
338 .unindent(),
339 editor.snapshot(window, cx).text()
340 );
341 });
342
343 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
344 Ok(dap::StackTraceResponse {
345 stack_frames: vec![stack_frame_for_line(6)],
346 total_frames: None,
347 })
348 });
349 client
350 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
351 reason: dap::StoppedEventReason::Pause,
352 description: None,
353 thread_id: Some(1),
354 preserve_focus_hint: None,
355 text: None,
356 all_threads_stopped: None,
357 hit_breakpoint_ids: None,
358 }))
359 .await;
360
361 cx.run_until_parked();
362
363 editor.update_in(cx, |editor, window, cx| {
364 pretty_assertions::assert_eq!(
365 r#"
366 static mut GLOBAL: usize = 1;
367
368 fn main() {
369 let x: 10 = 10;
370 let value: 42 = 42;
371 let y: 4 = 4;
372 let tester = {
373 let y = 10;
374 let y = 5;
375 let b = 3;
376 vec![y, 20, 30]
377 };
378
379 let caller = || {
380 let x = 3;
381 println!("x={}", x);
382 };
383
384 caller();
385
386 unsafe {
387 GLOBAL = 2;
388 }
389
390 let result = value * 2 * x;
391 println!("Simple test executed: value={}, result={}", value, result);
392 assert!(true);
393 }
394 "#
395 .unindent(),
396 editor.snapshot(window, cx).text()
397 );
398 });
399
400 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
401 Ok(dap::StackTraceResponse {
402 stack_frames: vec![stack_frame_for_line(7)],
403 total_frames: None,
404 })
405 });
406 client
407 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
408 reason: dap::StoppedEventReason::Pause,
409 description: None,
410 thread_id: Some(1),
411 preserve_focus_hint: None,
412 text: None,
413 all_threads_stopped: None,
414 hit_breakpoint_ids: None,
415 }))
416 .await;
417
418 cx.run_until_parked();
419
420 editor.update_in(cx, |editor, window, cx| {
421 pretty_assertions::assert_eq!(
422 r#"
423 static mut GLOBAL: usize = 1;
424
425 fn main() {
426 let x: 10 = 10;
427 let value: 42 = 42;
428 let y: 4 = 4;
429 let tester = {
430 let y = 10;
431 let y = 5;
432 let b = 3;
433 vec![y, 20, 30]
434 };
435
436 let caller = || {
437 let x = 3;
438 println!("x={}", x);
439 };
440
441 caller();
442
443 unsafe {
444 GLOBAL = 2;
445 }
446
447 let result = value * 2 * x;
448 println!("Simple test executed: value={}, result={}", value, result);
449 assert!(true);
450 }
451 "#
452 .unindent(),
453 editor.snapshot(window, cx).text()
454 );
455 });
456
457 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
458 Ok(dap::StackTraceResponse {
459 stack_frames: vec![stack_frame_for_line(8)],
460 total_frames: None,
461 })
462 });
463 client
464 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
465 reason: dap::StoppedEventReason::Pause,
466 description: None,
467 thread_id: Some(1),
468 preserve_focus_hint: None,
469 text: None,
470 all_threads_stopped: None,
471 hit_breakpoint_ids: None,
472 }))
473 .await;
474
475 cx.run_until_parked();
476
477 editor.update_in(cx, |editor, window, cx| {
478 pretty_assertions::assert_eq!(
479 r#"
480 static mut GLOBAL: usize = 1;
481
482 fn main() {
483 let x: 10 = 10;
484 let value: 42 = 42;
485 let y: 4 = 4;
486 let tester = {
487 let y: 4 = 10;
488 let y = 5;
489 let b = 3;
490 vec![y, 20, 30]
491 };
492
493 let caller = || {
494 let x = 3;
495 println!("x={}", x);
496 };
497
498 caller();
499
500 unsafe {
501 GLOBAL = 2;
502 }
503
504 let result = value * 2 * x;
505 println!("Simple test executed: value={}, result={}", value, result);
506 assert!(true);
507 }
508 "#
509 .unindent(),
510 editor.snapshot(window, cx).text()
511 );
512 });
513
514 let local_variables = vec![
515 Variable {
516 name: "x".into(),
517 value: "10".into(),
518 type_: None,
519 presentation_hint: None,
520 evaluate_name: None,
521 variables_reference: 0,
522 named_variables: None,
523 indexed_variables: None,
524 memory_reference: None,
525 declaration_location_reference: None,
526 value_location_reference: None,
527 },
528 Variable {
529 name: "y".into(),
530 value: "10".into(),
531 type_: None,
532 presentation_hint: None,
533 evaluate_name: None,
534 variables_reference: 0,
535 named_variables: None,
536 indexed_variables: None,
537 memory_reference: None,
538 declaration_location_reference: None,
539 value_location_reference: None,
540 },
541 Variable {
542 name: "value".into(),
543 value: "42".into(),
544 type_: None,
545 presentation_hint: None,
546 evaluate_name: None,
547 variables_reference: 0,
548 named_variables: None,
549 indexed_variables: None,
550 memory_reference: None,
551 declaration_location_reference: None,
552 value_location_reference: None,
553 },
554 ];
555
556 client.on_request::<Variables, _>({
557 let local_variables = Arc::new(local_variables.clone());
558 move |_, _| {
559 Ok(dap::VariablesResponse {
560 variables: (*local_variables).clone(),
561 })
562 }
563 });
564 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
565 Ok(dap::StackTraceResponse {
566 stack_frames: vec![stack_frame_for_line(9)],
567 total_frames: None,
568 })
569 });
570 client
571 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
572 reason: dap::StoppedEventReason::Pause,
573 description: None,
574 thread_id: Some(1),
575 preserve_focus_hint: None,
576 text: None,
577 all_threads_stopped: None,
578 hit_breakpoint_ids: None,
579 }))
580 .await;
581
582 cx.run_until_parked();
583
584 editor.update_in(cx, |editor, window, cx| {
585 pretty_assertions::assert_eq!(
586 r#"
587 static mut GLOBAL: usize = 1;
588
589 fn main() {
590 let x: 10 = 10;
591 let value: 42 = 42;
592 let y: 10 = 4;
593 let tester = {
594 let y: 10 = 10;
595 let y: 10 = 5;
596 let b = 3;
597 vec![y, 20, 30]
598 };
599
600 let caller = || {
601 let x = 3;
602 println!("x={}", x);
603 };
604
605 caller();
606
607 unsafe {
608 GLOBAL = 2;
609 }
610
611 let result = value * 2 * x;
612 println!("Simple test executed: value={}, result={}", value, result);
613 assert!(true);
614 }
615 "#
616 .unindent(),
617 editor.snapshot(window, cx).text()
618 );
619 });
620
621 let local_variables = vec![
622 Variable {
623 name: "x".into(),
624 value: "10".into(),
625 type_: None,
626 presentation_hint: None,
627 evaluate_name: None,
628 variables_reference: 0,
629 named_variables: None,
630 indexed_variables: None,
631 memory_reference: None,
632 declaration_location_reference: None,
633 value_location_reference: None,
634 },
635 Variable {
636 name: "y".into(),
637 value: "5".into(),
638 type_: None,
639 presentation_hint: None,
640 evaluate_name: None,
641 variables_reference: 0,
642 named_variables: None,
643 indexed_variables: None,
644 memory_reference: None,
645 declaration_location_reference: None,
646 value_location_reference: None,
647 },
648 Variable {
649 name: "value".into(),
650 value: "42".into(),
651 type_: None,
652 presentation_hint: None,
653 evaluate_name: None,
654 variables_reference: 0,
655 named_variables: None,
656 indexed_variables: None,
657 memory_reference: None,
658 declaration_location_reference: None,
659 value_location_reference: None,
660 },
661 ];
662
663 client.on_request::<Variables, _>({
664 let local_variables = Arc::new(local_variables.clone());
665 move |_, _| {
666 Ok(dap::VariablesResponse {
667 variables: (*local_variables).clone(),
668 })
669 }
670 });
671 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
672 Ok(dap::StackTraceResponse {
673 stack_frames: vec![stack_frame_for_line(10)],
674 total_frames: None,
675 })
676 });
677 client
678 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
679 reason: dap::StoppedEventReason::Pause,
680 description: None,
681 thread_id: Some(1),
682 preserve_focus_hint: None,
683 text: None,
684 all_threads_stopped: None,
685 hit_breakpoint_ids: None,
686 }))
687 .await;
688
689 cx.run_until_parked();
690
691 editor.update_in(cx, |editor, window, cx| {
692 pretty_assertions::assert_eq!(
693 r#"
694 static mut GLOBAL: usize = 1;
695
696 fn main() {
697 let x: 10 = 10;
698 let value: 42 = 42;
699 let y: 5 = 4;
700 let tester = {
701 let y: 5 = 10;
702 let y: 5 = 5;
703 let b = 3;
704 vec![y, 20, 30]
705 };
706
707 let caller = || {
708 let x = 3;
709 println!("x={}", x);
710 };
711
712 caller();
713
714 unsafe {
715 GLOBAL = 2;
716 }
717
718 let result = value * 2 * x;
719 println!("Simple test executed: value={}, result={}", value, result);
720 assert!(true);
721 }
722 "#
723 .unindent(),
724 editor.snapshot(window, cx).text()
725 );
726 });
727
728 let local_variables = vec![
729 Variable {
730 name: "x".into(),
731 value: "10".into(),
732 type_: None,
733 presentation_hint: None,
734 evaluate_name: None,
735 variables_reference: 0,
736 named_variables: None,
737 indexed_variables: None,
738 memory_reference: None,
739 declaration_location_reference: None,
740 value_location_reference: None,
741 },
742 Variable {
743 name: "y".into(),
744 value: "5".into(),
745 type_: None,
746 presentation_hint: None,
747 evaluate_name: None,
748 variables_reference: 0,
749 named_variables: None,
750 indexed_variables: None,
751 memory_reference: None,
752 declaration_location_reference: None,
753 value_location_reference: None,
754 },
755 Variable {
756 name: "value".into(),
757 value: "42".into(),
758 type_: None,
759 presentation_hint: None,
760 evaluate_name: None,
761 variables_reference: 0,
762 named_variables: None,
763 indexed_variables: None,
764 memory_reference: None,
765 declaration_location_reference: None,
766 value_location_reference: None,
767 },
768 Variable {
769 name: "b".into(),
770 value: "3".into(),
771 type_: None,
772 presentation_hint: None,
773 evaluate_name: None,
774 variables_reference: 0,
775 named_variables: None,
776 indexed_variables: None,
777 memory_reference: None,
778 declaration_location_reference: None,
779 value_location_reference: None,
780 },
781 ];
782 client.on_request::<Variables, _>({
783 let local_variables = Arc::new(local_variables.clone());
784 move |_, _| {
785 Ok(dap::VariablesResponse {
786 variables: (*local_variables).clone(),
787 })
788 }
789 });
790 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
791 Ok(dap::StackTraceResponse {
792 stack_frames: vec![stack_frame_for_line(11)],
793 total_frames: None,
794 })
795 });
796 client
797 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
798 reason: dap::StoppedEventReason::Pause,
799 description: None,
800 thread_id: Some(1),
801 preserve_focus_hint: None,
802 text: None,
803 all_threads_stopped: None,
804 hit_breakpoint_ids: None,
805 }))
806 .await;
807
808 cx.run_until_parked();
809
810 editor.update_in(cx, |editor, window, cx| {
811 pretty_assertions::assert_eq!(
812 r#"
813 static mut GLOBAL: usize = 1;
814
815 fn main() {
816 let x: 10 = 10;
817 let value: 42 = 42;
818 let y: 5 = 4;
819 let tester = {
820 let y: 5 = 10;
821 let y: 5 = 5;
822 let b: 3 = 3;
823 vec![y: 5, 20, 30]
824 };
825
826 let caller = || {
827 let x = 3;
828 println!("x={}", x);
829 };
830
831 caller();
832
833 unsafe {
834 GLOBAL = 2;
835 }
836
837 let result = value * 2 * x;
838 println!("Simple test executed: value={}, result={}", value, result);
839 assert!(true);
840 }
841 "#
842 .unindent(),
843 editor.snapshot(window, cx).text()
844 );
845 });
846
847 let local_variables = vec![
848 Variable {
849 name: "x".into(),
850 value: "10".into(),
851 type_: None,
852 presentation_hint: None,
853 evaluate_name: None,
854 variables_reference: 0,
855 named_variables: None,
856 indexed_variables: None,
857 memory_reference: None,
858 declaration_location_reference: None,
859 value_location_reference: None,
860 },
861 Variable {
862 name: "y".into(),
863 value: "4".into(),
864 type_: None,
865 presentation_hint: None,
866 evaluate_name: None,
867 variables_reference: 0,
868 named_variables: None,
869 indexed_variables: None,
870 memory_reference: None,
871 declaration_location_reference: None,
872 value_location_reference: None,
873 },
874 Variable {
875 name: "value".into(),
876 value: "42".into(),
877 type_: None,
878 presentation_hint: None,
879 evaluate_name: None,
880 variables_reference: 0,
881 named_variables: None,
882 indexed_variables: None,
883 memory_reference: None,
884 declaration_location_reference: None,
885 value_location_reference: None,
886 },
887 Variable {
888 name: "tester".into(),
889 value: "size=3".into(),
890 type_: None,
891 presentation_hint: None,
892 evaluate_name: None,
893 variables_reference: 0,
894 named_variables: None,
895 indexed_variables: None,
896 memory_reference: None,
897 declaration_location_reference: None,
898 value_location_reference: None,
899 },
900 ];
901 client.on_request::<Variables, _>({
902 let local_variables = Arc::new(local_variables.clone());
903 move |_, _| {
904 Ok(dap::VariablesResponse {
905 variables: (*local_variables).clone(),
906 })
907 }
908 });
909 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
910 Ok(dap::StackTraceResponse {
911 stack_frames: vec![stack_frame_for_line(14)],
912 total_frames: None,
913 })
914 });
915 client
916 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
917 reason: dap::StoppedEventReason::Pause,
918 description: None,
919 thread_id: Some(1),
920 preserve_focus_hint: None,
921 text: None,
922 all_threads_stopped: None,
923 hit_breakpoint_ids: None,
924 }))
925 .await;
926
927 cx.run_until_parked();
928
929 editor.update_in(cx, |editor, window, cx| {
930 pretty_assertions::assert_eq!(
931 r#"
932 static mut GLOBAL: usize = 1;
933
934 fn main() {
935 let x: 10 = 10;
936 let value: 42 = 42;
937 let y: 4 = 4;
938 let tester: size=3 = {
939 let y = 10;
940 let y = 5;
941 let b = 3;
942 vec![y, 20, 30]
943 };
944
945 let caller = || {
946 let x = 3;
947 println!("x={}", x);
948 };
949
950 caller();
951
952 unsafe {
953 GLOBAL = 2;
954 }
955
956 let result = value * 2 * x;
957 println!("Simple test executed: value={}, result={}", value, result);
958 assert!(true);
959 }
960 "#
961 .unindent(),
962 editor.snapshot(window, cx).text()
963 );
964 });
965
966 let local_variables = vec![
967 Variable {
968 name: "x".into(),
969 value: "10".into(),
970 type_: None,
971 presentation_hint: None,
972 evaluate_name: None,
973 variables_reference: 0,
974 named_variables: None,
975 indexed_variables: None,
976 memory_reference: None,
977 declaration_location_reference: None,
978 value_location_reference: None,
979 },
980 Variable {
981 name: "y".into(),
982 value: "4".into(),
983 type_: None,
984 presentation_hint: None,
985 evaluate_name: None,
986 variables_reference: 0,
987 named_variables: None,
988 indexed_variables: None,
989 memory_reference: None,
990 declaration_location_reference: None,
991 value_location_reference: None,
992 },
993 Variable {
994 name: "value".into(),
995 value: "42".into(),
996 type_: None,
997 presentation_hint: None,
998 evaluate_name: None,
999 variables_reference: 0,
1000 named_variables: None,
1001 indexed_variables: None,
1002 memory_reference: None,
1003 declaration_location_reference: None,
1004 value_location_reference: None,
1005 },
1006 Variable {
1007 name: "tester".into(),
1008 value: "size=3".into(),
1009 type_: None,
1010 presentation_hint: None,
1011 evaluate_name: None,
1012 variables_reference: 0,
1013 named_variables: None,
1014 indexed_variables: None,
1015 memory_reference: None,
1016 declaration_location_reference: None,
1017 value_location_reference: None,
1018 },
1019 Variable {
1020 name: "caller".into(),
1021 value: "<not available>".into(),
1022 type_: None,
1023 presentation_hint: None,
1024 evaluate_name: None,
1025 variables_reference: 0,
1026 named_variables: None,
1027 indexed_variables: None,
1028 memory_reference: None,
1029 declaration_location_reference: None,
1030 value_location_reference: None,
1031 },
1032 ];
1033 client.on_request::<Variables, _>({
1034 let local_variables = Arc::new(local_variables.clone());
1035 move |_, _| {
1036 Ok(dap::VariablesResponse {
1037 variables: (*local_variables).clone(),
1038 })
1039 }
1040 });
1041 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
1042 Ok(dap::StackTraceResponse {
1043 stack_frames: vec![stack_frame_for_line(19)],
1044 total_frames: None,
1045 })
1046 });
1047 client
1048 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
1049 reason: dap::StoppedEventReason::Pause,
1050 description: None,
1051 thread_id: Some(1),
1052 preserve_focus_hint: None,
1053 text: None,
1054 all_threads_stopped: None,
1055 hit_breakpoint_ids: None,
1056 }))
1057 .await;
1058
1059 cx.run_until_parked();
1060
1061 editor.update_in(cx, |editor, window, cx| {
1062 pretty_assertions::assert_eq!(
1063 r#"
1064 static mut GLOBAL: usize = 1;
1065
1066 fn main() {
1067 let x: 10 = 10;
1068 let value: 42 = 42;
1069 let y: 4 = 4;
1070 let tester: size=3 = {
1071 let y = 10;
1072 let y = 5;
1073 let b = 3;
1074 vec![y, 20, 30]
1075 };
1076
1077 let caller: <not available> = || {
1078 let x = 3;
1079 println!("x={}", x);
1080 };
1081
1082 caller();
1083
1084 unsafe {
1085 GLOBAL = 2;
1086 }
1087
1088 let result = value * 2 * x;
1089 println!("Simple test executed: value={}, result={}", value, result);
1090 assert!(true);
1091 }
1092 "#
1093 .unindent(),
1094 editor.snapshot(window, cx).text()
1095 );
1096 });
1097
1098 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
1099 Ok(dap::StackTraceResponse {
1100 stack_frames: vec![stack_frame_for_line(15)],
1101 total_frames: None,
1102 })
1103 });
1104 client
1105 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
1106 reason: dap::StoppedEventReason::Pause,
1107 description: None,
1108 thread_id: Some(1),
1109 preserve_focus_hint: None,
1110 text: None,
1111 all_threads_stopped: None,
1112 hit_breakpoint_ids: None,
1113 }))
1114 .await;
1115
1116 cx.run_until_parked();
1117
1118 editor.update_in(cx, |editor, window, cx| {
1119 pretty_assertions::assert_eq!(
1120 r#"
1121 static mut GLOBAL: usize = 1;
1122
1123 fn main() {
1124 let x: 10 = 10;
1125 let value: 42 = 42;
1126 let y: 4 = 4;
1127 let tester: size=3 = {
1128 let y = 10;
1129 let y = 5;
1130 let b = 3;
1131 vec![y, 20, 30]
1132 };
1133
1134 let caller: <not available> = || {
1135 let x: 10 = 3;
1136 println!("x={}", x);
1137 };
1138
1139 caller();
1140
1141 unsafe {
1142 GLOBAL = 2;
1143 }
1144
1145 let result = value * 2 * x;
1146 println!("Simple test executed: value={}, result={}", value, result);
1147 assert!(true);
1148 }
1149 "#
1150 .unindent(),
1151 editor.snapshot(window, cx).text()
1152 );
1153 });
1154
1155 let local_variables = vec![Variable {
1156 name: "x".into(),
1157 value: "3".into(),
1158 type_: None,
1159 presentation_hint: None,
1160 evaluate_name: None,
1161 variables_reference: 0,
1162 named_variables: None,
1163 indexed_variables: None,
1164 memory_reference: None,
1165 declaration_location_reference: None,
1166 value_location_reference: None,
1167 }];
1168 client.on_request::<Variables, _>({
1169 let local_variables = Arc::new(local_variables.clone());
1170 move |_, _| {
1171 Ok(dap::VariablesResponse {
1172 variables: (*local_variables).clone(),
1173 })
1174 }
1175 });
1176 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
1177 Ok(dap::StackTraceResponse {
1178 stack_frames: vec![stack_frame_for_line(16)],
1179 total_frames: None,
1180 })
1181 });
1182 client
1183 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
1184 reason: dap::StoppedEventReason::Pause,
1185 description: None,
1186 thread_id: Some(1),
1187 preserve_focus_hint: None,
1188 text: None,
1189 all_threads_stopped: None,
1190 hit_breakpoint_ids: None,
1191 }))
1192 .await;
1193
1194 cx.run_until_parked();
1195
1196 editor.update_in(cx, |editor, window, cx| {
1197 pretty_assertions::assert_eq!(
1198 r#"
1199 static mut GLOBAL: usize = 1;
1200
1201 fn main() {
1202 let x: 3 = 10;
1203 let value = 42;
1204 let y = 4;
1205 let tester = {
1206 let y = 10;
1207 let y = 5;
1208 let b = 3;
1209 vec![y, 20, 30]
1210 };
1211
1212 let caller = || {
1213 let x: 3 = 3;
1214 println!("x={}", x: 3);
1215 };
1216
1217 caller();
1218
1219 unsafe {
1220 GLOBAL = 2;
1221 }
1222
1223 let result = value * 2 * x;
1224 println!("Simple test executed: value={}, result={}", value, result);
1225 assert!(true);
1226 }
1227 "#
1228 .unindent(),
1229 editor.snapshot(window, cx).text()
1230 );
1231 });
1232
1233 let local_variables = vec![
1234 Variable {
1235 name: "x".into(),
1236 value: "10".into(),
1237 type_: None,
1238 presentation_hint: None,
1239 evaluate_name: None,
1240 variables_reference: 0,
1241 named_variables: None,
1242 indexed_variables: None,
1243 memory_reference: None,
1244 declaration_location_reference: None,
1245 value_location_reference: None,
1246 },
1247 Variable {
1248 name: "y".into(),
1249 value: "4".into(),
1250 type_: None,
1251 presentation_hint: None,
1252 evaluate_name: None,
1253 variables_reference: 0,
1254 named_variables: None,
1255 indexed_variables: None,
1256 memory_reference: None,
1257 declaration_location_reference: None,
1258 value_location_reference: None,
1259 },
1260 Variable {
1261 name: "value".into(),
1262 value: "42".into(),
1263 type_: None,
1264 presentation_hint: None,
1265 evaluate_name: None,
1266 variables_reference: 0,
1267 named_variables: None,
1268 indexed_variables: None,
1269 memory_reference: None,
1270 declaration_location_reference: None,
1271 value_location_reference: None,
1272 },
1273 Variable {
1274 name: "tester".into(),
1275 value: "size=3".into(),
1276 type_: None,
1277 presentation_hint: None,
1278 evaluate_name: None,
1279 variables_reference: 0,
1280 named_variables: None,
1281 indexed_variables: None,
1282 memory_reference: None,
1283 declaration_location_reference: None,
1284 value_location_reference: None,
1285 },
1286 Variable {
1287 name: "caller".into(),
1288 value: "<not available>".into(),
1289 type_: None,
1290 presentation_hint: None,
1291 evaluate_name: None,
1292 variables_reference: 0,
1293 named_variables: None,
1294 indexed_variables: None,
1295 memory_reference: None,
1296 declaration_location_reference: None,
1297 value_location_reference: None,
1298 },
1299 ];
1300 client.on_request::<Variables, _>({
1301 let local_variables = Arc::new(local_variables.clone());
1302 move |_, _| {
1303 Ok(dap::VariablesResponse {
1304 variables: (*local_variables).clone(),
1305 })
1306 }
1307 });
1308 client.on_request::<dap::requests::Evaluate, _>(move |_, args| {
1309 assert_eq!("GLOBAL", args.expression);
1310 Ok(dap::EvaluateResponse {
1311 result: "2".into(),
1312 type_: None,
1313 presentation_hint: None,
1314 variables_reference: 0,
1315 named_variables: None,
1316 indexed_variables: None,
1317 memory_reference: None,
1318 value_location_reference: None,
1319 })
1320 });
1321 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
1322 Ok(dap::StackTraceResponse {
1323 stack_frames: vec![stack_frame_for_line(25)],
1324 total_frames: None,
1325 })
1326 });
1327 client
1328 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
1329 reason: dap::StoppedEventReason::Pause,
1330 description: None,
1331 thread_id: Some(1),
1332 preserve_focus_hint: None,
1333 text: None,
1334 all_threads_stopped: None,
1335 hit_breakpoint_ids: None,
1336 }))
1337 .await;
1338
1339 cx.run_until_parked();
1340
1341 editor.update_in(cx, |editor, window, cx| {
1342 pretty_assertions::assert_eq!(
1343 r#"
1344 static mut GLOBAL: usize = 1;
1345
1346 fn main() {
1347 let x: 10 = 10;
1348 let value: 42 = 42;
1349 let y: 4 = 4;
1350 let tester: size=3 = {
1351 let y = 10;
1352 let y = 5;
1353 let b = 3;
1354 vec![y, 20, 30]
1355 };
1356
1357 let caller: <not available> = || {
1358 let x = 3;
1359 println!("x={}", x);
1360 };
1361
1362 caller();
1363
1364 unsafe {
1365 GLOBAL = 2;
1366 }
1367
1368 let result = value: 42 * 2 * x: 10;
1369 println!("Simple test executed: value={}, result={}", value, result);
1370 assert!(true);
1371 }
1372 "#
1373 .unindent(),
1374 editor.snapshot(window, cx).text()
1375 );
1376 });
1377
1378 let local_variables = vec![
1379 Variable {
1380 name: "x".into(),
1381 value: "10".into(),
1382 type_: None,
1383 presentation_hint: None,
1384 evaluate_name: None,
1385 variables_reference: 0,
1386 named_variables: None,
1387 indexed_variables: None,
1388 memory_reference: None,
1389 declaration_location_reference: None,
1390 value_location_reference: None,
1391 },
1392 Variable {
1393 name: "y".into(),
1394 value: "4".into(),
1395 type_: None,
1396 presentation_hint: None,
1397 evaluate_name: None,
1398 variables_reference: 0,
1399 named_variables: None,
1400 indexed_variables: None,
1401 memory_reference: None,
1402 declaration_location_reference: None,
1403 value_location_reference: None,
1404 },
1405 Variable {
1406 name: "value".into(),
1407 value: "42".into(),
1408 type_: None,
1409 presentation_hint: None,
1410 evaluate_name: None,
1411 variables_reference: 0,
1412 named_variables: None,
1413 indexed_variables: None,
1414 memory_reference: None,
1415 declaration_location_reference: None,
1416 value_location_reference: None,
1417 },
1418 Variable {
1419 name: "tester".into(),
1420 value: "size=3".into(),
1421 type_: None,
1422 presentation_hint: None,
1423 evaluate_name: None,
1424 variables_reference: 0,
1425 named_variables: None,
1426 indexed_variables: None,
1427 memory_reference: None,
1428 declaration_location_reference: None,
1429 value_location_reference: None,
1430 },
1431 Variable {
1432 name: "caller".into(),
1433 value: "<not available>".into(),
1434 type_: None,
1435 presentation_hint: None,
1436 evaluate_name: None,
1437 variables_reference: 0,
1438 named_variables: None,
1439 indexed_variables: None,
1440 memory_reference: None,
1441 declaration_location_reference: None,
1442 value_location_reference: None,
1443 },
1444 Variable {
1445 name: "result".into(),
1446 value: "840".into(),
1447 type_: None,
1448 presentation_hint: None,
1449 evaluate_name: None,
1450 variables_reference: 0,
1451 named_variables: None,
1452 indexed_variables: None,
1453 memory_reference: None,
1454 declaration_location_reference: None,
1455 value_location_reference: None,
1456 },
1457 ];
1458 client.on_request::<Variables, _>({
1459 let local_variables = Arc::new(local_variables.clone());
1460 move |_, _| {
1461 Ok(dap::VariablesResponse {
1462 variables: (*local_variables).clone(),
1463 })
1464 }
1465 });
1466 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
1467 Ok(dap::StackTraceResponse {
1468 stack_frames: vec![stack_frame_for_line(26)],
1469 total_frames: None,
1470 })
1471 });
1472 client
1473 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
1474 reason: dap::StoppedEventReason::Pause,
1475 description: None,
1476 thread_id: Some(1),
1477 preserve_focus_hint: None,
1478 text: None,
1479 all_threads_stopped: None,
1480 hit_breakpoint_ids: None,
1481 }))
1482 .await;
1483
1484 cx.run_until_parked();
1485
1486 editor.update_in(cx, |editor, window, cx| {
1487 pretty_assertions::assert_eq!(
1488 r#"
1489 static mut GLOBAL: usize = 1;
1490
1491 fn main() {
1492 let x: 10 = 10;
1493 let value: 42 = 42;
1494 let y: 4 = 4;
1495 let tester: size=3 = {
1496 let y = 10;
1497 let y = 5;
1498 let b = 3;
1499 vec![y, 20, 30]
1500 };
1501
1502 let caller: <not available> = || {
1503 let x = 3;
1504 println!("x={}", x);
1505 };
1506
1507 caller();
1508
1509 unsafe {
1510 GLOBAL = 2;
1511 }
1512
1513 let result: 840 = value: 42 * 2 * x: 10;
1514 println!("Simple test executed: value={}, result={}", value: 42, result: 840);
1515 assert!(true);
1516 }
1517 "#
1518 .unindent(),
1519 editor.snapshot(window, cx).text()
1520 );
1521 });
1522}
1523
1524#[gpui::test]
1525async fn test_python_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
1526 init_test(cx);
1527
1528 let fs = FakeFs::new(executor.clone());
1529 let source_code = r#"
1530def process_data(untyped_param, typed_param: int, another_typed: str):
1531 # Local variables
1532 x = 10
1533 result = typed_param * 2
1534 text = "Hello, " + another_typed
1535
1536 # For loop with range
1537 sum_value = 0
1538 for i in range(5):
1539 sum_value += i
1540
1541 # Final result
1542 final_result = x + result + sum_value
1543 return final_result
1544"#
1545 .unindent();
1546 fs.insert_tree(path!("/project"), json!({ "main.py": source_code }))
1547 .await;
1548
1549 let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
1550 let workspace = init_test_workspace(&project, cx).await;
1551 workspace
1552 .update(cx, |workspace, window, cx| {
1553 workspace.focus_panel::<DebugPanel>(window, cx);
1554 })
1555 .unwrap();
1556 let cx = &mut VisualTestContext::from_window(*workspace, cx);
1557
1558 let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
1559 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
1560
1561 let project_path = Path::new(path!("/project"));
1562 let worktree = project
1563 .update(cx, |project, cx| project.find_worktree(project_path, cx))
1564 .expect("This worktree should exist in project")
1565 .0;
1566
1567 let worktree_id = workspace
1568 .update(cx, |_, _, cx| worktree.read(cx).id())
1569 .unwrap();
1570
1571 let buffer = project
1572 .update(cx, |project, cx| {
1573 project.open_buffer((worktree_id, rel_path("main.py")), cx)
1574 })
1575 .await
1576 .unwrap();
1577
1578 buffer.update(cx, |buffer, cx| {
1579 buffer.set_language(Some(Arc::new(python_lang())), cx);
1580 });
1581
1582 let (editor, cx) = cx.add_window_view(|window, cx| {
1583 Editor::new(
1584 EditorMode::full(),
1585 MultiBuffer::build_from_buffer(buffer, cx),
1586 Some(project),
1587 window,
1588 cx,
1589 )
1590 });
1591
1592 editor.update(cx, |editor, cx| editor.refresh_inline_values(cx));
1593
1594 client.on_request::<dap::requests::Threads, _>(move |_, _| {
1595 Ok(dap::ThreadsResponse {
1596 threads: vec![dap::Thread {
1597 id: 1,
1598 name: "Thread 1".into(),
1599 }],
1600 })
1601 });
1602
1603 client.on_request::<dap::requests::StackTrace, _>(move |_, args| {
1604 assert_eq!(args.thread_id, 1);
1605 Ok(dap::StackTraceResponse {
1606 stack_frames: vec![StackFrame {
1607 id: 1,
1608 name: "Stack Frame 1".into(),
1609 source: Some(dap::Source {
1610 name: Some("main.py".into()),
1611 path: Some(path!("/project/main.py").into()),
1612 source_reference: None,
1613 presentation_hint: None,
1614 origin: None,
1615 sources: None,
1616 adapter_data: None,
1617 checksums: None,
1618 }),
1619 line: 12,
1620 column: 1,
1621 end_line: None,
1622 end_column: None,
1623 can_restart: None,
1624 instruction_pointer_reference: None,
1625 module_id: None,
1626 presentation_hint: None,
1627 }],
1628 total_frames: None,
1629 })
1630 });
1631
1632 client.on_request::<dap::requests::Scopes, _>(move |_, _| {
1633 Ok(dap::ScopesResponse {
1634 scopes: vec![
1635 Scope {
1636 name: "Local".into(),
1637 presentation_hint: None,
1638 variables_reference: 1,
1639 named_variables: None,
1640 indexed_variables: None,
1641 expensive: false,
1642 source: None,
1643 line: None,
1644 column: None,
1645 end_line: None,
1646 end_column: None,
1647 },
1648 Scope {
1649 name: "Global".into(),
1650 presentation_hint: None,
1651 variables_reference: 2,
1652 named_variables: None,
1653 indexed_variables: None,
1654 expensive: false,
1655 source: None,
1656 line: None,
1657 column: None,
1658 end_line: None,
1659 end_column: None,
1660 },
1661 ],
1662 })
1663 });
1664
1665 client.on_request::<Variables, _>(move |_, args| match args.variables_reference {
1666 1 => Ok(dap::VariablesResponse {
1667 variables: vec![
1668 Variable {
1669 name: "untyped_param".into(),
1670 value: "test_value".into(),
1671 type_: Some("str".into()),
1672 presentation_hint: None,
1673 evaluate_name: None,
1674 variables_reference: 0,
1675 named_variables: None,
1676 indexed_variables: None,
1677 memory_reference: None,
1678 declaration_location_reference: None,
1679 value_location_reference: None,
1680 },
1681 Variable {
1682 name: "typed_param".into(),
1683 value: "42".into(),
1684 type_: Some("int".into()),
1685 presentation_hint: None,
1686 evaluate_name: None,
1687 variables_reference: 0,
1688 named_variables: None,
1689 indexed_variables: None,
1690 memory_reference: None,
1691 declaration_location_reference: None,
1692 value_location_reference: None,
1693 },
1694 Variable {
1695 name: "another_typed".into(),
1696 value: "world".into(),
1697 type_: Some("str".into()),
1698 presentation_hint: None,
1699 evaluate_name: None,
1700 variables_reference: 0,
1701 named_variables: None,
1702 indexed_variables: None,
1703 memory_reference: None,
1704 declaration_location_reference: None,
1705 value_location_reference: None,
1706 },
1707 Variable {
1708 name: "x".into(),
1709 value: "10".into(),
1710 type_: Some("int".into()),
1711 presentation_hint: None,
1712 evaluate_name: None,
1713 variables_reference: 0,
1714 named_variables: None,
1715 indexed_variables: None,
1716 memory_reference: None,
1717 declaration_location_reference: None,
1718 value_location_reference: None,
1719 },
1720 Variable {
1721 name: "result".into(),
1722 value: "84".into(),
1723 type_: Some("int".into()),
1724 presentation_hint: None,
1725 evaluate_name: None,
1726 variables_reference: 0,
1727 named_variables: None,
1728 indexed_variables: None,
1729 memory_reference: None,
1730 declaration_location_reference: None,
1731 value_location_reference: None,
1732 },
1733 Variable {
1734 name: "text".into(),
1735 value: "Hello, world".into(),
1736 type_: Some("str".into()),
1737 presentation_hint: None,
1738 evaluate_name: None,
1739 variables_reference: 0,
1740 named_variables: None,
1741 indexed_variables: None,
1742 memory_reference: None,
1743 declaration_location_reference: None,
1744 value_location_reference: None,
1745 },
1746 Variable {
1747 name: "sum_value".into(),
1748 value: "10".into(),
1749 type_: Some("int".into()),
1750 presentation_hint: None,
1751 evaluate_name: None,
1752 variables_reference: 0,
1753 named_variables: None,
1754 indexed_variables: None,
1755 memory_reference: None,
1756 declaration_location_reference: None,
1757 value_location_reference: None,
1758 },
1759 Variable {
1760 name: "i".into(),
1761 value: "4".into(),
1762 type_: Some("int".into()),
1763 presentation_hint: None,
1764 evaluate_name: None,
1765 variables_reference: 0,
1766 named_variables: None,
1767 indexed_variables: None,
1768 memory_reference: None,
1769 declaration_location_reference: None,
1770 value_location_reference: None,
1771 },
1772 Variable {
1773 name: "final_result".into(),
1774 value: "104".into(),
1775 type_: Some("int".into()),
1776 presentation_hint: None,
1777 evaluate_name: None,
1778 variables_reference: 0,
1779 named_variables: None,
1780 indexed_variables: None,
1781 memory_reference: None,
1782 declaration_location_reference: None,
1783 value_location_reference: None,
1784 },
1785 ],
1786 }),
1787 _ => Ok(dap::VariablesResponse { variables: vec![] }),
1788 });
1789
1790 client
1791 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
1792 reason: dap::StoppedEventReason::Pause,
1793 description: None,
1794 thread_id: Some(1),
1795 preserve_focus_hint: None,
1796 text: None,
1797 all_threads_stopped: None,
1798 hit_breakpoint_ids: None,
1799 }))
1800 .await;
1801
1802 cx.run_until_parked();
1803
1804 editor.update_in(cx, |editor, window, cx| {
1805 pretty_assertions::assert_eq!(
1806 r#"
1807 def process_data(untyped_param: test_value, typed_param: 42: int, another_typed: world: str):
1808 # Local variables
1809 x: 10 = 10
1810 result: 84 = typed_param: 42 * 2
1811 text: Hello, world = "Hello, " + another_typed: world
1812
1813 # For loop with range
1814 sum_value: 10 = 0
1815 for i: 4 in range(5):
1816 sum_value += i
1817
1818 # Final result
1819 final_result = x + result + sum_value
1820 return final_result
1821 "#
1822 .unindent(),
1823 editor.snapshot(window, cx).text()
1824 );
1825 });
1826}
1827
1828fn python_lang() -> Language {
1829 let debug_variables_query = include_str!("../../../languages/src/python/debugger.scm");
1830 Language::new(
1831 LanguageConfig {
1832 name: "Python".into(),
1833 matcher: LanguageMatcher {
1834 path_suffixes: vec!["py".to_string()],
1835 ..Default::default()
1836 },
1837 ..Default::default()
1838 },
1839 Some(tree_sitter_python::LANGUAGE.into()),
1840 )
1841 .with_debug_variables_query(debug_variables_query)
1842 .unwrap()
1843}
1844
1845fn go_lang() -> Arc<Language> {
1846 let debug_variables_query = include_str!("../../../languages/src/go/debugger.scm");
1847 Arc::new(
1848 Language::new(
1849 LanguageConfig {
1850 name: "Go".into(),
1851 matcher: LanguageMatcher {
1852 path_suffixes: vec!["go".to_string()],
1853 ..Default::default()
1854 },
1855 ..Default::default()
1856 },
1857 Some(tree_sitter_go::LANGUAGE.into()),
1858 )
1859 .with_debug_variables_query(debug_variables_query)
1860 .unwrap(),
1861 )
1862}
1863
1864/// Test utility function for inline values testing
1865///
1866/// # Arguments
1867/// * `variables` - List of tuples containing (variable_name, variable_value)
1868/// * `before` - Source code before inline values are applied
1869/// * `after` - Expected source code after inline values are applied
1870/// * `language` - Language configuration to use for parsing
1871/// * `executor` - Background executor for async operations
1872/// * `cx` - Test app context
1873async fn test_inline_values_util(
1874 local_variables: &[(&str, &str)],
1875 global_variables: &[(&str, &str)],
1876 before: &str,
1877 after: &str,
1878 active_debug_line: Option<usize>,
1879 language: Arc<Language>,
1880 executor: BackgroundExecutor,
1881 cx: &mut TestAppContext,
1882) {
1883 init_test(cx);
1884
1885 let lines_count = before.lines().count();
1886 let stop_line =
1887 active_debug_line.unwrap_or_else(|| if lines_count > 6 { 6 } else { lines_count - 1 });
1888
1889 let fs = FakeFs::new(executor.clone());
1890 fs.insert_tree(path!("/project"), json!({ "main.rs": before.to_string() }))
1891 .await;
1892
1893 let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
1894 let workspace = init_test_workspace(&project, cx).await;
1895 workspace
1896 .update(cx, |workspace, window, cx| {
1897 workspace.focus_panel::<DebugPanel>(window, cx);
1898 })
1899 .unwrap();
1900 let cx = &mut VisualTestContext::from_window(*workspace, cx);
1901
1902 let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
1903 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
1904
1905 client.on_request::<dap::requests::Threads, _>(|_, _| {
1906 Ok(dap::ThreadsResponse {
1907 threads: vec![dap::Thread {
1908 id: 1,
1909 name: "main".into(),
1910 }],
1911 })
1912 });
1913
1914 client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
1915 Ok(dap::StackTraceResponse {
1916 stack_frames: vec![dap::StackFrame {
1917 id: 1,
1918 name: "main".into(),
1919 source: Some(dap::Source {
1920 name: Some("main.rs".into()),
1921 path: Some(path!("/project/main.rs").into()),
1922 source_reference: None,
1923 presentation_hint: None,
1924 origin: None,
1925 sources: None,
1926 adapter_data: None,
1927 checksums: None,
1928 }),
1929 line: stop_line as u64,
1930 column: 1,
1931 end_line: None,
1932 end_column: None,
1933 can_restart: None,
1934 instruction_pointer_reference: None,
1935 module_id: None,
1936 presentation_hint: None,
1937 }],
1938 total_frames: None,
1939 })
1940 });
1941
1942 let local_vars: Vec<Variable> = local_variables
1943 .iter()
1944 .map(|(name, value)| Variable {
1945 name: (*name).into(),
1946 value: (*value).into(),
1947 type_: None,
1948 presentation_hint: None,
1949 evaluate_name: None,
1950 variables_reference: 0,
1951 named_variables: None,
1952 indexed_variables: None,
1953 memory_reference: None,
1954 declaration_location_reference: None,
1955 value_location_reference: None,
1956 })
1957 .collect();
1958
1959 let global_vars: Vec<Variable> = global_variables
1960 .iter()
1961 .map(|(name, value)| Variable {
1962 name: (*name).into(),
1963 value: (*value).into(),
1964 type_: None,
1965 presentation_hint: None,
1966 evaluate_name: None,
1967 variables_reference: 0,
1968 named_variables: None,
1969 indexed_variables: None,
1970 memory_reference: None,
1971 declaration_location_reference: None,
1972 value_location_reference: None,
1973 })
1974 .collect();
1975
1976 client.on_request::<Variables, _>({
1977 let local_vars = Arc::new(local_vars.clone());
1978 let global_vars = Arc::new(global_vars.clone());
1979 move |_, args| {
1980 let variables = match args.variables_reference {
1981 2 => (*local_vars).clone(),
1982 3 => (*global_vars).clone(),
1983 _ => vec![],
1984 };
1985 Ok(dap::VariablesResponse { variables })
1986 }
1987 });
1988
1989 client.on_request::<dap::requests::Scopes, _>(move |_, _| {
1990 Ok(dap::ScopesResponse {
1991 scopes: vec![
1992 Scope {
1993 name: "Local".into(),
1994 presentation_hint: None,
1995 variables_reference: 2,
1996 named_variables: None,
1997 indexed_variables: None,
1998 expensive: false,
1999 source: None,
2000 line: None,
2001 column: None,
2002 end_line: None,
2003 end_column: None,
2004 },
2005 Scope {
2006 name: "Global".into(),
2007 presentation_hint: None,
2008 variables_reference: 3,
2009 named_variables: None,
2010 indexed_variables: None,
2011 expensive: false,
2012 source: None,
2013 line: None,
2014 column: None,
2015 end_line: None,
2016 end_column: None,
2017 },
2018 ],
2019 })
2020 });
2021
2022 if !global_variables.is_empty() {
2023 let global_evaluate_map: std::collections::HashMap<String, String> = global_variables
2024 .iter()
2025 .map(|(name, value)| (name.to_string(), value.to_string()))
2026 .collect();
2027
2028 client.on_request::<dap::requests::Evaluate, _>(move |_, args| {
2029 let value = global_evaluate_map
2030 .get(&args.expression)
2031 .unwrap_or(&"undefined".to_string())
2032 .clone();
2033
2034 Ok(dap::EvaluateResponse {
2035 result: value,
2036 type_: None,
2037 presentation_hint: None,
2038 variables_reference: 0,
2039 named_variables: None,
2040 indexed_variables: None,
2041 memory_reference: None,
2042 value_location_reference: None,
2043 })
2044 });
2045 }
2046
2047 client
2048 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
2049 reason: dap::StoppedEventReason::Pause,
2050 description: None,
2051 thread_id: Some(1),
2052 preserve_focus_hint: None,
2053 text: None,
2054 all_threads_stopped: None,
2055 hit_breakpoint_ids: None,
2056 }))
2057 .await;
2058
2059 cx.run_until_parked();
2060
2061 let project_path = Path::new(path!("/project"));
2062 let worktree = project
2063 .update(cx, |project, cx| project.find_worktree(project_path, cx))
2064 .expect("This worktree should exist in project")
2065 .0;
2066
2067 let worktree_id = workspace
2068 .update(cx, |_, _, cx| worktree.read(cx).id())
2069 .unwrap();
2070
2071 let buffer = project
2072 .update(cx, |project, cx| {
2073 project.open_buffer((worktree_id, rel_path("main.rs")), cx)
2074 })
2075 .await
2076 .unwrap();
2077
2078 buffer.update(cx, |buffer, cx| {
2079 buffer.set_language(Some(language), cx);
2080 });
2081
2082 let (editor, cx) = cx.add_window_view(|window, cx| {
2083 Editor::new(
2084 EditorMode::full(),
2085 MultiBuffer::build_from_buffer(buffer, cx),
2086 Some(project),
2087 window,
2088 cx,
2089 )
2090 });
2091
2092 active_debug_session_panel(workspace, cx).update_in(cx, |_, window, cx| {
2093 cx.focus_self(window);
2094 });
2095 cx.run_until_parked();
2096
2097 editor.update(cx, |editor, cx| editor.refresh_inline_values(cx));
2098
2099 cx.run_until_parked();
2100
2101 editor.update_in(cx, |editor, window, cx| {
2102 pretty_assertions::assert_eq!(after, editor.snapshot(window, cx).text());
2103 });
2104}
2105
2106#[gpui::test]
2107async fn test_inline_values_example(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2108 let variables = [("x", "10"), ("y", "20"), ("result", "30")];
2109
2110 let before = r#"
2111fn main() {
2112 let x = 10;
2113 let y = 20;
2114 let result = x + y;
2115 println!("Result: {}", result);
2116}
2117"#
2118 .unindent();
2119
2120 let after = r#"
2121fn main() {
2122 let x: 10 = 10;
2123 let y: 20 = 20;
2124 let result: 30 = x: 10 + y: 20;
2125 println!("Result: {}", result: 30);
2126}
2127"#
2128 .unindent();
2129
2130 test_inline_values_util(
2131 &variables,
2132 &[],
2133 &before,
2134 &after,
2135 None,
2136 rust_lang(),
2137 executor,
2138 cx,
2139 )
2140 .await;
2141}
2142
2143#[gpui::test]
2144async fn test_inline_values_with_globals(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2145 let variables = [("x", "5"), ("y", "10")];
2146
2147 let before = r#"
2148static mut GLOBAL_COUNTER: usize = 42;
2149
2150fn main() {
2151 let x = 5;
2152 let y = 10;
2153 unsafe {
2154 GLOBAL_COUNTER += 1;
2155 }
2156 println!("x={}, y={}, global={}", x, y, unsafe { GLOBAL_COUNTER });
2157}
2158"#
2159 .unindent();
2160
2161 let after = r#"
2162static mut GLOBAL_COUNTER: 42: usize = 42;
2163
2164fn main() {
2165 let x: 5 = 5;
2166 let y: 10 = 10;
2167 unsafe {
2168 GLOBAL_COUNTER += 1;
2169 }
2170 println!("x={}, y={}, global={}", x, y, unsafe { GLOBAL_COUNTER });
2171}
2172"#
2173 .unindent();
2174
2175 test_inline_values_util(
2176 &variables,
2177 &[("GLOBAL_COUNTER", "42")],
2178 &before,
2179 &after,
2180 None,
2181 rust_lang(),
2182 executor,
2183 cx,
2184 )
2185 .await;
2186}
2187
2188#[gpui::test]
2189async fn test_go_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2190 let variables = [("x", "42"), ("y", "hello")];
2191
2192 let before = r#"
2193package main
2194
2195var globalCounter int = 100
2196
2197func main() {
2198 x := 42
2199 y := "hello"
2200 z := x + 10
2201 println(x, y, z)
2202}
2203"#
2204 .unindent();
2205
2206 let after = r#"
2207package main
2208
2209var globalCounter: 100 int = 100
2210
2211func main() {
2212 x: 42 := 42
2213 y := "hello"
2214 z := x + 10
2215 println(x, y, z)
2216}
2217"#
2218 .unindent();
2219
2220 test_inline_values_util(
2221 &variables,
2222 &[("globalCounter", "100")],
2223 &before,
2224 &after,
2225 None,
2226 go_lang(),
2227 executor,
2228 cx,
2229 )
2230 .await;
2231}
2232
2233#[gpui::test]
2234async fn test_trim_multi_line_inline_value(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2235 let variables = [("y", "hello\n world")];
2236
2237 let before = r#"
2238fn main() {
2239 let y = "hello\n world";
2240}
2241"#
2242 .unindent();
2243
2244 let after = r#"
2245fn main() {
2246 let y: hello… = "hello\n world";
2247}
2248"#
2249 .unindent();
2250
2251 test_inline_values_util(
2252 &variables,
2253 &[],
2254 &before,
2255 &after,
2256 None,
2257 rust_lang(),
2258 executor,
2259 cx,
2260 )
2261 .await;
2262}
2263
2264fn javascript_lang() -> Arc<Language> {
2265 let debug_variables_query = include_str!("../../../languages/src/javascript/debugger.scm");
2266 Arc::new(
2267 Language::new(
2268 LanguageConfig {
2269 name: "JavaScript".into(),
2270 matcher: LanguageMatcher {
2271 path_suffixes: vec!["js".to_string()],
2272 ..Default::default()
2273 },
2274 ..Default::default()
2275 },
2276 Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
2277 )
2278 .with_debug_variables_query(debug_variables_query)
2279 .unwrap(),
2280 )
2281}
2282
2283fn typescript_lang() -> Arc<Language> {
2284 let debug_variables_query = include_str!("../../../languages/src/typescript/debugger.scm");
2285 Arc::new(
2286 Language::new(
2287 LanguageConfig {
2288 name: "TypeScript".into(),
2289 matcher: LanguageMatcher {
2290 path_suffixes: vec!["ts".to_string()],
2291 ..Default::default()
2292 },
2293 ..Default::default()
2294 },
2295 Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
2296 )
2297 .with_debug_variables_query(debug_variables_query)
2298 .unwrap(),
2299 )
2300}
2301
2302fn tsx_lang() -> Arc<Language> {
2303 let debug_variables_query = include_str!("../../../languages/src/tsx/debugger.scm");
2304 Arc::new(
2305 Language::new(
2306 LanguageConfig {
2307 name: "TSX".into(),
2308 matcher: LanguageMatcher {
2309 path_suffixes: vec!["tsx".to_string()],
2310 ..Default::default()
2311 },
2312 ..Default::default()
2313 },
2314 Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
2315 )
2316 .with_debug_variables_query(debug_variables_query)
2317 .unwrap(),
2318 )
2319}
2320
2321#[gpui::test]
2322async fn test_javascript_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2323 let variables = [
2324 ("x", "10"),
2325 ("y", "20"),
2326 ("sum", "30"),
2327 ("message", "Hello"),
2328 ];
2329
2330 let before = r#"
2331function calculate() {
2332 const x = 10;
2333 const y = 20;
2334 const sum = x + y;
2335 const message = "Hello";
2336 console.log(message, "Sum:", sum);
2337}
2338"#
2339 .unindent();
2340
2341 let after = r#"
2342function calculate() {
2343 const x: 10 = 10;
2344 const y: 20 = 20;
2345 const sum: 30 = x: 10 + y: 20;
2346 const message: Hello = "Hello";
2347 console.log(message, "Sum:", sum);
2348}
2349"#
2350 .unindent();
2351
2352 test_inline_values_util(
2353 &variables,
2354 &[],
2355 &before,
2356 &after,
2357 None,
2358 javascript_lang(),
2359 executor,
2360 cx,
2361 )
2362 .await;
2363}
2364
2365#[gpui::test]
2366async fn test_typescript_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2367 let variables = [
2368 ("count", "42"),
2369 ("name", "Alice"),
2370 ("result", "84"),
2371 ("i", "3"),
2372 ];
2373
2374 let before = r#"
2375function processData(count: number, name: string): number {
2376 let result = count * 2;
2377 for (let i = 0; i < 5; i++) {
2378 console.log(i);
2379 }
2380 return result;
2381}
2382"#
2383 .unindent();
2384
2385 let after = r#"
2386function processData(count: number, name: string): number {
2387 let result: 84 = count: 42 * 2;
2388 for (let i: 3 = 0; i: 3 < 5; i: 3++) {
2389 console.log(i);
2390 }
2391 return result: 84;
2392}
2393"#
2394 .unindent();
2395
2396 test_inline_values_util(
2397 &variables,
2398 &[],
2399 &before,
2400 &after,
2401 None,
2402 typescript_lang(),
2403 executor,
2404 cx,
2405 )
2406 .await;
2407}
2408
2409#[gpui::test]
2410async fn test_tsx_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2411 let variables = [("count", "5"), ("message", "Hello React")];
2412
2413 let before = r#"
2414const Counter = () => {
2415 const count = 5;
2416 const message = "Hello React";
2417 return (
2418 <div>
2419 <p>{message}</p>
2420 <span>{count}</span>
2421 </div>
2422 );
2423};
2424"#
2425 .unindent();
2426
2427 let after = r#"
2428const Counter = () => {
2429 const count: 5 = 5;
2430 const message: Hello React = "Hello React";
2431 return (
2432 <div>
2433 <p>{message: Hello React}</p>
2434 <span>{count}</span>
2435 </div>
2436 );
2437};
2438"#
2439 .unindent();
2440
2441 test_inline_values_util(
2442 &variables,
2443 &[],
2444 &before,
2445 &after,
2446 None,
2447 tsx_lang(),
2448 executor,
2449 cx,
2450 )
2451 .await;
2452}
2453
2454#[gpui::test]
2455async fn test_javascript_arrow_functions(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2456 let variables = [("x", "42"), ("result", "84")];
2457
2458 let before = r#"
2459const double = (x) => {
2460 const result = x * 2;
2461 return result;
2462};
2463"#
2464 .unindent();
2465
2466 let after = r#"
2467const double = (x) => {
2468 const result: 84 = x: 42 * 2;
2469 return result: 84;
2470};
2471"#
2472 .unindent();
2473
2474 test_inline_values_util(
2475 &variables,
2476 &[],
2477 &before,
2478 &after,
2479 None,
2480 javascript_lang(),
2481 executor,
2482 cx,
2483 )
2484 .await;
2485}
2486
2487#[gpui::test]
2488async fn test_typescript_for_in_loop(executor: BackgroundExecutor, cx: &mut TestAppContext) {
2489 let variables = [("key", "name"), ("obj", "{name: 'test'}")];
2490
2491 let before = r#"
2492function iterate() {
2493 const obj = {name: 'test'};
2494 for (const key in obj) {
2495 console.log(key);
2496 }
2497}
2498"#
2499 .unindent();
2500
2501 let after = r#"
2502function iterate() {
2503 const obj: {name: 'test'} = {name: 'test'};
2504 for (const key: name in obj) {
2505 console.log(key);
2506 }
2507}
2508"#
2509 .unindent();
2510
2511 test_inline_values_util(
2512 &variables,
2513 &[],
2514 &before,
2515 &after,
2516 None,
2517 typescript_lang(),
2518 executor,
2519 cx,
2520 )
2521 .await;
2522}