1#![expect(clippy::result_large_err)]
2use crate::{
3 tests::{active_debug_session_panel, start_debug_session},
4 *,
5};
6use dap::requests::StackTrace;
7use editor::{DisplayPoint, display_map::DisplayRow};
8use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
9use project::{FakeFs, Project};
10use serde_json::json;
11use tests::{init_test, init_test_workspace};
12use util::path;
13
14#[gpui::test]
15async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestAppContext) {
16 init_test(cx);
17
18 let fs = FakeFs::new(executor.clone());
19
20 fs.insert_tree(
21 path!("/project"),
22 json!({
23 "main.rs": "First line\nSecond line\nThird line\nFourth line",
24 }),
25 )
26 .await;
27
28 let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
29 let workspace = init_test_workspace(&project, cx).await;
30 let cx = &mut VisualTestContext::from_window(*workspace, cx);
31 workspace
32 .update(cx, |workspace, window, cx| {
33 workspace.focus_panel::<DebugPanel>(window, cx);
34 })
35 .unwrap();
36
37 let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
38 let client = session.read_with(cx, |session, _| session.adapter_client().unwrap());
39
40 client.on_request::<StackTrace, _>(move |_, _| {
41 Ok(dap::StackTraceResponse {
42 stack_frames: Vec::default(),
43 total_frames: None,
44 })
45 });
46
47 client
48 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
49 category: None,
50 output: "First console output line before thread stopped!".to_string(),
51 data: None,
52 variables_reference: None,
53 source: None,
54 line: None,
55 column: None,
56 group: None,
57 location_reference: None,
58 }))
59 .await;
60
61 client
62 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
63 category: Some(dap::OutputEventCategory::Stdout),
64 output: "First output line before thread stopped!".to_string(),
65 data: None,
66 variables_reference: None,
67 source: None,
68 line: None,
69 column: None,
70 group: None,
71 location_reference: None,
72 }))
73 .await;
74
75 client
76 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
77 reason: dap::StoppedEventReason::Pause,
78 description: None,
79 thread_id: Some(1),
80 preserve_focus_hint: None,
81 text: None,
82 all_threads_stopped: None,
83 hit_breakpoint_ids: None,
84 }))
85 .await;
86
87 cx.run_until_parked();
88
89 let running_state =
90 active_debug_session_panel(workspace, cx).update_in(cx, |item, window, cx| {
91 cx.focus_self(window);
92 item.running_state().clone()
93 });
94
95 cx.run_until_parked();
96
97 // assert we have output from before the thread stopped
98 workspace
99 .update(cx, |workspace, _window, cx| {
100 let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
101 let active_debug_session_panel = debug_panel
102 .update(cx, |this, _| this.active_session())
103 .unwrap();
104
105 assert_eq!(
106 "First console output line before thread stopped!\nFirst output line before thread stopped!\n",
107 active_debug_session_panel.read(cx).running_state().read(cx).console().read(cx).editor().read(cx).text(cx).as_str()
108 );
109 })
110 .unwrap();
111
112 client
113 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
114 category: Some(dap::OutputEventCategory::Stdout),
115 output: "\tSecond output line after thread stopped!".to_string(),
116 data: None,
117 variables_reference: None,
118 source: None,
119 line: None,
120 column: None,
121 group: None,
122 location_reference: None,
123 }))
124 .await;
125
126 client
127 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
128 category: Some(dap::OutputEventCategory::Console),
129 output: "\tSecond console output line after thread stopped!".to_string(),
130 data: None,
131 variables_reference: None,
132 source: None,
133 line: None,
134 column: None,
135 group: None,
136 location_reference: None,
137 }))
138 .await;
139
140 cx.run_until_parked();
141 running_state.update(cx, |_, cx| {
142 cx.refresh_windows();
143 });
144 cx.run_until_parked();
145
146 // assert we have output from before and after the thread stopped
147 workspace
148 .update(cx, |workspace, _window, cx| {
149 let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
150 let active_session_panel = debug_panel
151 .update(cx, |this, _| this.active_session())
152 .unwrap();
153
154 assert_eq!(
155 "First console output line before thread stopped!\nFirst output line before thread stopped!\n\tSecond output line after thread stopped!\n\tSecond console output line after thread stopped!\n",
156 active_session_panel.read(cx).running_state().read(cx).console().read(cx).editor().read(cx).text(cx).as_str()
157 );
158 })
159 .unwrap();
160}
161
162#[gpui::test]
163async fn test_escape_code_processing(executor: BackgroundExecutor, cx: &mut TestAppContext) {
164 init_test(cx);
165
166 let fs = FakeFs::new(executor.clone());
167
168 fs.insert_tree(
169 path!("/project"),
170 json!({
171 "main.rs": "First line\nSecond line\nThird line\nFourth line",
172 }),
173 )
174 .await;
175
176 let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
177 let workspace = init_test_workspace(&project, cx).await;
178 let cx = &mut VisualTestContext::from_window(*workspace, cx);
179 workspace
180 .update(cx, |workspace, window, cx| {
181 workspace.focus_panel::<DebugPanel>(window, cx);
182 })
183 .unwrap();
184
185 let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
186 let client = session.read_with(cx, |session, _| session.adapter_client().unwrap());
187
188 client.on_request::<StackTrace, _>(move |_, _| {
189 Ok(dap::StackTraceResponse {
190 stack_frames: Vec::default(),
191 total_frames: None,
192 })
193 });
194
195 client
196 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
197 category: None,
198 output: "Checking latest version of JavaScript...".to_string(),
199 data: None,
200 variables_reference: None,
201 source: None,
202 line: None,
203 column: None,
204 group: None,
205 location_reference: None,
206 }))
207 .await;
208 client
209 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
210 category: None,
211 output: " \u{1b}[1m\u{1b}[38;2;173;127;168m▲ Next.js 15.1.5\u{1b}[39m\u{1b}[22m"
212 .to_string(),
213 data: None,
214 variables_reference: None,
215 source: None,
216 line: None,
217 column: None,
218 group: None,
219 location_reference: None,
220 }))
221 .await;
222 client
223 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
224 category: None,
225 output: " - Local: http://localhost:3000\n - Network: http://192.168.1.144:3000\n\n \u{1b}[32m\u{1b}[1m✓\u{1b}[22m\u{1b}[39m Starting..."
226 .to_string(),
227 data: None,
228 variables_reference: None,
229 source: None,
230 line: None,
231 column: None,
232 group: None,
233 location_reference: None,
234 }))
235 .await;
236 client
237 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
238 category: None,
239 output: "Something else...".to_string(),
240 data: None,
241 variables_reference: None,
242 source: None,
243 line: None,
244 column: None,
245 group: None,
246 location_reference: None,
247 }))
248 .await;
249 client
250 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
251 category: None,
252 output: " \u{1b}[32m\u{1b}[1m✓\u{1b}[22m\u{1b}[39m Ready in 1009ms\n".to_string(),
253 data: None,
254 variables_reference: None,
255 source: None,
256 line: None,
257 column: None,
258 group: None,
259 location_reference: None,
260 }))
261 .await;
262
263 client
264 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
265 category: None,
266 output: "\u{1b}[41m\u{1b}[37mBoth background and foreground!".to_string(),
267 data: None,
268 variables_reference: None,
269 source: None,
270 line: None,
271 column: None,
272 group: None,
273 location_reference: None,
274 }))
275 .await;
276 client
277 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
278 category: None,
279 output: "Even more...".to_string(),
280 data: None,
281 variables_reference: None,
282 source: None,
283 line: None,
284 column: None,
285 group: None,
286 location_reference: None,
287 }))
288 .await;
289
290 cx.run_until_parked();
291
292 let _running_state =
293 active_debug_session_panel(workspace, cx).update_in(cx, |item, window, cx| {
294 cx.focus_self(window);
295 item.running_state().update(cx, |this, cx| {
296 this.console()
297 .update(cx, |this, cx| this.update_output(window, cx));
298 });
299
300 item.running_state().clone()
301 });
302
303 cx.run_until_parked();
304
305 workspace
306 .update(cx, |workspace, window, cx| {
307 let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
308 let active_debug_session_panel = debug_panel
309 .update(cx, |this, _| this.active_session())
310 .unwrap();
311
312 let editor =
313 active_debug_session_panel
314 .read(cx)
315 .running_state()
316 .read(cx)
317 .console()
318 .read(cx)
319 .editor().clone();
320
321 assert_eq!(
322 "Checking latest version of JavaScript...\n ▲ Next.js 15.1.5\n - Local: http://localhost:3000\n - Network: http://192.168.1.144:3000\n\n ✓ Starting...\nSomething else...\n ✓ Ready in 1009ms\nBoth background and foreground!\nEven more...\n",
323 editor
324 .read(cx)
325 .text(cx)
326 .as_str()
327 );
328
329 let text_highlights = editor.update(cx, |editor, cx| {
330 let mut text_highlights = editor.all_text_highlights(window, cx).into_iter().flat_map(|(_, ranges)| ranges).collect::<Vec<_>>();
331 text_highlights.sort_by(|a, b| a.start.cmp(&b.start));
332 text_highlights
333 });
334 pretty_assertions::assert_eq!(
335 text_highlights,
336 [
337 DisplayPoint::new(DisplayRow(1), 3)..DisplayPoint::new(DisplayRow(1), 21),
338 DisplayPoint::new(DisplayRow(1), 21)..DisplayPoint::new(DisplayRow(2), 0),
339 DisplayPoint::new(DisplayRow(5), 1)..DisplayPoint::new(DisplayRow(5), 4),
340 DisplayPoint::new(DisplayRow(5), 4)..DisplayPoint::new(DisplayRow(6), 0),
341 DisplayPoint::new(DisplayRow(7), 1)..DisplayPoint::new(DisplayRow(7), 4),
342 DisplayPoint::new(DisplayRow(7), 4)..DisplayPoint::new(DisplayRow(8), 0),
343 DisplayPoint::new(DisplayRow(8), 0)..DisplayPoint::new(DisplayRow(9), 0),
344 ]
345 );
346
347 let background_highlights = editor.update(cx, |editor, cx| {
348 editor.all_text_background_highlights(window, cx).into_iter().map(|(range, _)| range).collect::<Vec<_>>()
349 });
350 pretty_assertions::assert_eq!(
351 background_highlights,
352 [
353 DisplayPoint::new(DisplayRow(8), 0)..DisplayPoint::new(DisplayRow(9), 0),
354 ]
355 )
356 })
357 .unwrap();
358}
359
360// #[gpui::test]
361// async fn test_grouped_output(executor: BackgroundExecutor, cx: &mut TestAppContext) {
362// init_test(cx);
363
364// let fs = FakeFs::new(executor.clone());
365
366// fs.insert_tree(
367// "/project",
368// json!({
369// "main.rs": "First line\nSecond line\nThird line\nFourth line",
370// }),
371// )
372// .await;
373
374// let project = Project::test(fs, ["/project".as_ref()], cx).await;
375// let workspace = init_test_workspace(&project, cx).await;
376// let cx = &mut VisualTestContext::from_window(*workspace, cx);
377
378// let task = project.update(cx, |project, cx| {
379// project.start_debug_session(
380// dap::test_config(dap::DebugRequestType::Launch, None, None),
381// cx,
382// )
383// });
384
385// let session = task.await.unwrap();
386// let client = session.update(cx, |session, _| session.adapter_client().unwrap());
387
388// client
389// .on_request::<StackTrace, _>(move |_, _| {
390// Ok(dap::StackTraceResponse {
391// stack_frames: Vec::default(),
392// total_frames: None,
393// })
394// })
395// .await;
396
397// client
398// .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
399// reason: dap::StoppedEventReason::Pause,
400// description: None,
401// thread_id: Some(1),
402// preserve_focus_hint: None,
403// text: None,
404// all_threads_stopped: None,
405// hit_breakpoint_ids: None,
406// }))
407// .await;
408
409// client
410// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
411// category: None,
412// output: "First line".to_string(),
413// data: None,
414// variables_reference: None,
415// source: None,
416// line: None,
417// column: None,
418// group: None,
419// location_reference: None,
420// }))
421// .await;
422
423// client
424// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
425// category: Some(dap::OutputEventCategory::Stdout),
426// output: "First group".to_string(),
427// data: None,
428// variables_reference: None,
429// source: None,
430// line: None,
431// column: None,
432// group: Some(dap::OutputEventGroup::Start),
433// location_reference: None,
434// }))
435// .await;
436
437// client
438// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
439// category: Some(dap::OutputEventCategory::Stdout),
440// output: "First item in group 1".to_string(),
441// data: None,
442// variables_reference: None,
443// source: None,
444// line: None,
445// column: None,
446// group: None,
447// location_reference: None,
448// }))
449// .await;
450
451// client
452// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
453// category: Some(dap::OutputEventCategory::Stdout),
454// output: "Second item in group 1".to_string(),
455// data: None,
456// variables_reference: None,
457// source: None,
458// line: None,
459// column: None,
460// group: None,
461// location_reference: None,
462// }))
463// .await;
464
465// client
466// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
467// category: Some(dap::OutputEventCategory::Stdout),
468// output: "Second group".to_string(),
469// data: None,
470// variables_reference: None,
471// source: None,
472// line: None,
473// column: None,
474// group: Some(dap::OutputEventGroup::Start),
475// location_reference: None,
476// }))
477// .await;
478
479// client
480// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
481// category: Some(dap::OutputEventCategory::Stdout),
482// output: "First item in group 2".to_string(),
483// data: None,
484// variables_reference: None,
485// source: None,
486// line: None,
487// column: None,
488// group: None,
489// location_reference: None,
490// }))
491// .await;
492
493// client
494// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
495// category: Some(dap::OutputEventCategory::Stdout),
496// output: "Second item in group 2".to_string(),
497// data: None,
498// variables_reference: None,
499// source: None,
500// line: None,
501// column: None,
502// group: None,
503// location_reference: None,
504// }))
505// .await;
506
507// client
508// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
509// category: Some(dap::OutputEventCategory::Stdout),
510// output: "End group 2".to_string(),
511// data: None,
512// variables_reference: None,
513// source: None,
514// line: None,
515// column: None,
516// group: Some(dap::OutputEventGroup::End),
517// location_reference: None,
518// }))
519// .await;
520
521// client
522// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
523// category: Some(dap::OutputEventCategory::Stdout),
524// output: "Third group".to_string(),
525// data: None,
526// variables_reference: None,
527// source: None,
528// line: None,
529// column: None,
530// group: Some(dap::OutputEventGroup::StartCollapsed),
531// location_reference: None,
532// }))
533// .await;
534
535// client
536// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
537// category: Some(dap::OutputEventCategory::Stdout),
538// output: "First item in group 3".to_string(),
539// data: None,
540// variables_reference: None,
541// source: None,
542// line: None,
543// column: None,
544// group: None,
545// location_reference: None,
546// }))
547// .await;
548
549// client
550// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
551// category: Some(dap::OutputEventCategory::Stdout),
552// output: "Second item in group 3".to_string(),
553// data: None,
554// variables_reference: None,
555// source: None,
556// line: None,
557// column: None,
558// group: None,
559// location_reference: None,
560// }))
561// .await;
562
563// client
564// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
565// category: Some(dap::OutputEventCategory::Stdout),
566// output: "End group 3".to_string(),
567// data: None,
568// variables_reference: None,
569// source: None,
570// line: None,
571// column: None,
572// group: Some(dap::OutputEventGroup::End),
573// location_reference: None,
574// }))
575// .await;
576
577// client
578// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
579// category: Some(dap::OutputEventCategory::Stdout),
580// output: "Third item in group 1".to_string(),
581// data: None,
582// variables_reference: None,
583// source: None,
584// line: None,
585// column: None,
586// group: None,
587// location_reference: None,
588// }))
589// .await;
590
591// client
592// .fake_event(dap::messages::Events::Output(dap::OutputEvent {
593// category: Some(dap::OutputEventCategory::Stdout),
594// output: "Second item".to_string(),
595// data: None,
596// variables_reference: None,
597// source: None,
598// line: None,
599// column: None,
600// group: Some(dap::OutputEventGroup::End),
601// location_reference: None,
602// }))
603// .await;
604
605// cx.run_until_parked();
606
607// active_debug_session_panel(workspace, cx).update(cx, |debug_panel_item, cx| {
608// debug_panel_item
609// .mode()
610// .as_running()
611// .unwrap()
612// .update(cx, |running_state, cx| {
613// running_state.console().update(cx, |console, cx| {
614// console.editor().update(cx, |editor, cx| {
615// pretty_assertions::assert_eq!(
616// "
617// First line
618// First group
619// First item in group 1
620// Second item in group 1
621// Second group
622// First item in group 2
623// Second item in group 2
624// End group 2
625// ⋯ End group 3
626// Third item in group 1
627// Second item
628// "
629// .unindent(),
630// editor.display_text(cx)
631// );
632// })
633// });
634// });
635// });
636
637// let shutdown_session = project.update(cx, |project, cx| {
638// project.dap_store().update(cx, |dap_store, cx| {
639// dap_store.shutdown_session(session.read(cx).session_id(), cx)
640// })
641// });
642
643// shutdown_session.await.unwrap();
644// }
645
646// todo(debugger): enable this again
647// #[gpui::test]
648// async fn test_evaluate_expression(executor: BackgroundExecutor, cx: &mut TestAppContext) {
649// init_test(cx);
650
651// const NEW_VALUE: &str = "{nested1: \"Nested 1 updated\", nested2: \"Nested 2 updated\"}";
652
653// let called_evaluate = Arc::new(AtomicBool::new(false));
654
655// let fs = FakeFs::new(executor.clone());
656
657// let test_file_content = r#"
658// const variable1 = {
659// nested1: "Nested 1",
660// nested2: "Nested 2",
661// };
662// const variable2 = "Value 2";
663// const variable3 = "Value 3";
664// "#
665// .unindent();
666
667// fs.insert_tree(
668// "/project",
669// json!({
670// "src": {
671// "test.js": test_file_content,
672// }
673// }),
674// )
675// .await;
676
677// let project = Project::test(fs, ["/project".as_ref()], cx).await;
678// let workspace = init_test_workspace(&project, cx).await;
679// let cx = &mut VisualTestContext::from_window(*workspace, cx);
680
681// let task = project.update(cx, |project, cx| {
682// project.start_debug_session(dap::test_config(None), cx)
683// });
684
685// let session = task.await.unwrap();
686// let client = session.update(cx, |session, _| session.adapter_client().unwrap());
687
688// client
689// .on_request::<Threads, _>(move |_, _| {
690// Ok(dap::ThreadsResponse {
691// threads: vec![dap::Thread {
692// id: 1,
693// name: "Thread 1".into(),
694// }],
695// })
696// })
697// .await;
698
699// let stack_frames = vec![StackFrame {
700// id: 1,
701// name: "Stack Frame 1".into(),
702// source: Some(dap::Source {
703// name: Some("test.js".into()),
704// path: Some("/project/src/test.js".into()),
705// source_reference: None,
706// presentation_hint: None,
707// origin: None,
708// sources: None,
709// adapter_data: None,
710// checksums: None,
711// }),
712// line: 3,
713// column: 1,
714// end_line: None,
715// end_column: None,
716// can_restart: None,
717// instruction_pointer_reference: None,
718// module_id: None,
719// presentation_hint: None,
720// }];
721
722// client
723// .on_request::<StackTrace, _>({
724// let stack_frames = Arc::new(stack_frames.clone());
725// move |_, args| {
726// assert_eq!(1, args.thread_id);
727
728// Ok(dap::StackTraceResponse {
729// stack_frames: (*stack_frames).clone(),
730// total_frames: None,
731// })
732// }
733// })
734// .await;
735
736// let scopes = vec![
737// Scope {
738// name: "Scope 1".into(),
739// presentation_hint: None,
740// variables_reference: 2,
741// named_variables: None,
742// indexed_variables: None,
743// expensive: false,
744// source: None,
745// line: None,
746// column: None,
747// end_line: None,
748// end_column: None,
749// },
750// Scope {
751// name: "Scope 2".into(),
752// presentation_hint: None,
753// variables_reference: 4,
754// named_variables: None,
755// indexed_variables: None,
756// expensive: false,
757// source: None,
758// line: None,
759// column: None,
760// end_line: None,
761// end_column: None,
762// },
763// ];
764
765// client
766// .on_request::<Scopes, _>({
767// let scopes = Arc::new(scopes.clone());
768// move |_, args| {
769// assert_eq!(1, args.frame_id);
770
771// Ok(dap::ScopesResponse {
772// scopes: (*scopes).clone(),
773// })
774// }
775// })
776// .await;
777
778// let scope1_variables = Arc::new(Mutex::new(vec![
779// Variable {
780// name: "variable1".into(),
781// value: "{nested1: \"Nested 1\", nested2: \"Nested 2\"}".into(),
782// type_: None,
783// presentation_hint: None,
784// evaluate_name: None,
785// variables_reference: 3,
786// named_variables: None,
787// indexed_variables: None,
788// memory_reference: None,
789// declaration_location_reference: None,
790// value_location_reference: None,
791// },
792// Variable {
793// name: "variable2".into(),
794// value: "Value 2".into(),
795// type_: None,
796// presentation_hint: None,
797// evaluate_name: None,
798// variables_reference: 0,
799// named_variables: None,
800// indexed_variables: None,
801// memory_reference: None,
802// declaration_location_reference: None,
803// value_location_reference: None,
804// },
805// ]));
806
807// let nested_variables = vec![
808// Variable {
809// name: "nested1".into(),
810// value: "Nested 1".into(),
811// type_: None,
812// presentation_hint: None,
813// evaluate_name: None,
814// variables_reference: 0,
815// named_variables: None,
816// indexed_variables: None,
817// memory_reference: None,
818// declaration_location_reference: None,
819// value_location_reference: None,
820// },
821// Variable {
822// name: "nested2".into(),
823// value: "Nested 2".into(),
824// type_: None,
825// presentation_hint: None,
826// evaluate_name: None,
827// variables_reference: 0,
828// named_variables: None,
829// indexed_variables: None,
830// memory_reference: None,
831// declaration_location_reference: None,
832// value_location_reference: None,
833// },
834// ];
835
836// let scope2_variables = vec![Variable {
837// name: "variable3".into(),
838// value: "Value 3".into(),
839// type_: None,
840// presentation_hint: None,
841// evaluate_name: None,
842// variables_reference: 0,
843// named_variables: None,
844// indexed_variables: None,
845// memory_reference: None,
846// declaration_location_reference: None,
847// value_location_reference: None,
848// }];
849
850// client
851// .on_request::<Variables, _>({
852// let scope1_variables = scope1_variables.clone();
853// let nested_variables = Arc::new(nested_variables.clone());
854// let scope2_variables = Arc::new(scope2_variables.clone());
855// move |_, args| match args.variables_reference {
856// 4 => Ok(dap::VariablesResponse {
857// variables: (*scope2_variables).clone(),
858// }),
859// 3 => Ok(dap::VariablesResponse {
860// variables: (*nested_variables).clone(),
861// }),
862// 2 => Ok(dap::VariablesResponse {
863// variables: scope1_variables.lock().unwrap().clone(),
864// }),
865// id => unreachable!("unexpected variables reference {id}"),
866// }
867// })
868// .await;
869
870// client
871// .on_request::<Evaluate, _>({
872// let called_evaluate = called_evaluate.clone();
873// let scope1_variables = scope1_variables.clone();
874// move |_, args| {
875// called_evaluate.store(true, Ordering::SeqCst);
876
877// assert_eq!(format!("$variable1 = {}", NEW_VALUE), args.expression);
878// assert_eq!(Some(1), args.frame_id);
879// assert_eq!(Some(dap::EvaluateArgumentsContext::Variables), args.context);
880
881// scope1_variables.lock().unwrap()[0].value = NEW_VALUE.to_string();
882
883// Ok(dap::EvaluateResponse {
884// result: NEW_VALUE.into(),
885// type_: None,
886// presentation_hint: None,
887// variables_reference: 0,
888// named_variables: None,
889// indexed_variables: None,
890// memory_reference: None,
891// value_location_reference: None,
892// })
893// }
894// })
895// .await;
896
897// client
898// .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
899// reason: dap::StoppedEventReason::Pause,
900// description: None,
901// thread_id: Some(1),
902// preserve_focus_hint: None,
903// text: None,
904// all_threads_stopped: None,
905// hit_breakpoint_ids: None,
906// }))
907// .await;
908
909// cx.run_until_parked();
910
911// // toggle nested variables for scope 1
912// active_debug_session_panel(workspace, cx).update(cx, |debug_panel_item, cx| {
913// debug_panel_item
914// .mode()
915// .as_running()
916// .unwrap()
917// .update(cx, |running_state, cx| {
918// running_state
919// .variable_list()
920// .update(cx, |variable_list, cx| {
921// variable_list.toggle_variable(
922// &VariablePath {
923// indices: Arc::from([scopes[0].variables_reference]),
924// },
925// cx,
926// );
927// });
928// });
929// });
930
931// cx.run_until_parked();
932
933// active_debug_session_panel(workspace, cx).update_in(cx, |debug_panel_item, window, cx| {
934// debug_panel_item
935// .mode()
936// .as_running()
937// .unwrap()
938// .update(cx, |running_state, cx| {
939// running_state.console().update(cx, |console, item_cx| {
940// console
941// .query_bar()
942// .update(item_cx, |query_bar, console_cx| {
943// query_bar.set_text(
944// format!("$variable1 = {}", NEW_VALUE),
945// window,
946// console_cx,
947// );
948// });
949
950// console.evaluate(&menu::Confirm, window, item_cx);
951// });
952// });
953// });
954
955// cx.run_until_parked();
956
957// active_debug_session_panel(workspace, cx).update(cx, |debug_panel_item, cx| {
958// assert_eq!(
959// "",
960// debug_panel_item
961// .mode()
962// .as_running()
963// .unwrap()
964// .read(cx)
965// .console()
966// .read(cx)
967// .query_bar()
968// .read(cx)
969// .text(cx)
970// .as_str()
971// );
972
973// assert_eq!(
974// format!("{}\n", NEW_VALUE),
975// debug_panel_item
976// .mode()
977// .as_running()
978// .unwrap()
979// .read(cx)
980// .console()
981// .read(cx)
982// .editor()
983// .read(cx)
984// .text(cx)
985// .as_str()
986// );
987
988// debug_panel_item
989// .mode()
990// .as_running()
991// .unwrap()
992// .update(cx, |running_state, cx| {
993// running_state
994// .variable_list()
995// .update(cx, |variable_list, _| {
996// let scope1_variables = scope1_variables.lock().unwrap().clone();
997
998// // scope 1
999// // assert_eq!(
1000// // vec![
1001// // VariableContainer {
1002// // container_reference: scopes[0].variables_reference,
1003// // variable: scope1_variables[0].clone(),
1004// // depth: 1,
1005// // },
1006// // VariableContainer {
1007// // container_reference: scope1_variables[0].variables_reference,
1008// // variable: nested_variables[0].clone(),
1009// // depth: 2,
1010// // },
1011// // VariableContainer {
1012// // container_reference: scope1_variables[0].variables_reference,
1013// // variable: nested_variables[1].clone(),
1014// // depth: 2,
1015// // },
1016// // VariableContainer {
1017// // container_reference: scopes[0].variables_reference,
1018// // variable: scope1_variables[1].clone(),
1019// // depth: 1,
1020// // },
1021// // ],
1022// // variable_list.variables_by_scope(1, 2).unwrap().variables()
1023// // );
1024
1025// // scope 2
1026// // assert_eq!(
1027// // vec![VariableContainer {
1028// // container_reference: scopes[1].variables_reference,
1029// // variable: scope2_variables[0].clone(),
1030// // depth: 1,
1031// // }],
1032// // variable_list.variables_by_scope(1, 4).unwrap().variables()
1033// // );
1034
1035// variable_list.assert_visual_entries(vec![
1036// "v Scope 1",
1037// " v variable1",
1038// " > nested1",
1039// " > nested2",
1040// " > variable2",
1041// ]);
1042
1043// // assert visual entries
1044// // assert_eq!(
1045// // vec![
1046// // VariableListEntry::Scope(scopes[0].clone()),
1047// // VariableListEntry::Variable {
1048// // depth: 1,
1049// // scope: Arc::new(scopes[0].clone()),
1050// // has_children: true,
1051// // variable: Arc::new(scope1_variables[0].clone()),
1052// // container_reference: scopes[0].variables_reference,
1053// // },
1054// // VariableListEntry::Variable {
1055// // depth: 2,
1056// // scope: Arc::new(scopes[0].clone()),
1057// // has_children: false,
1058// // variable: Arc::new(nested_variables[0].clone()),
1059// // container_reference: scope1_variables[0].variables_reference,
1060// // },
1061// // VariableListEntry::Variable {
1062// // depth: 2,
1063// // scope: Arc::new(scopes[0].clone()),
1064// // has_children: false,
1065// // variable: Arc::new(nested_variables[1].clone()),
1066// // container_reference: scope1_variables[0].variables_reference,
1067// // },
1068// // VariableListEntry::Variable {
1069// // depth: 1,
1070// // scope: Arc::new(scopes[0].clone()),
1071// // has_children: false,
1072// // variable: Arc::new(scope1_variables[1].clone()),
1073// // container_reference: scopes[0].variables_reference,
1074// // },
1075// // VariableListEntry::Scope(scopes[1].clone()),
1076// // ],
1077// // variable_list.entries().get(&1).unwrap().clone()
1078// // );
1079// });
1080// });
1081// });
1082
1083// assert!(
1084// called_evaluate.load(std::sync::atomic::Ordering::SeqCst),
1085// "Expected evaluate request to be called"
1086// );
1087
1088// let shutdown_session = project.update(cx, |project, cx| {
1089// project.dap_store().update(cx, |dap_store, cx| {
1090// dap_store.shutdown_session(&session.read(cx).session_id(), cx)
1091// })
1092// });
1093
1094// shutdown_session.await.unwrap();
1095// }