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