console.rs

   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// }