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