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