session.rs

   1use crate::debugger::breakpoint_store::BreakpointSessionState;
   2use crate::debugger::dap_command::{DataBreakpointContext, ReadMemory};
   3use crate::debugger::memory::{self, Memory, MemoryIterator, MemoryPageBuilder, PageAddress};
   4
   5use super::breakpoint_store::{
   6    BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint,
   7};
   8use super::dap_command::{
   9    self, Attach, ConfigurationDone, ContinueCommand, DataBreakpointInfoCommand, DisconnectCommand,
  10    EvaluateCommand, Initialize, Launch, LoadedSourcesCommand, LocalDapCommand, LocationsCommand,
  11    ModulesCommand, NextCommand, PauseCommand, RestartCommand, RestartStackFrameCommand,
  12    ScopesCommand, SetDataBreakpointsCommand, SetExceptionBreakpoints, SetVariableValueCommand,
  13    StackTraceCommand, StepBackCommand, StepCommand, StepInCommand, StepOutCommand,
  14    TerminateCommand, TerminateThreadsCommand, ThreadsCommand, VariablesCommand,
  15};
  16use super::dap_store::DapStore;
  17use anyhow::{Context as _, Result, anyhow};
  18use base64::Engine;
  19use collections::{HashMap, HashSet, IndexMap};
  20use dap::adapters::{DebugAdapterBinary, DebugAdapterName};
  21use dap::messages::Response;
  22use dap::requests::{Request, RunInTerminal, StartDebugging};
  23use dap::{
  24    Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, StackFrameId,
  25    SteppingGranularity, StoppedEvent, VariableReference,
  26    client::{DebugAdapterClient, SessionId},
  27    messages::{Events, Message},
  28};
  29use dap::{
  30    ExceptionBreakpointsFilter, ExceptionFilterOptions, OutputEvent, OutputEventCategory,
  31    RunInTerminalRequestArguments, StackFramePresentationHint, StartDebuggingRequestArguments,
  32    StartDebuggingRequestArgumentsRequest, VariablePresentationHint, WriteMemoryArguments,
  33};
  34use futures::SinkExt;
  35use futures::channel::mpsc::UnboundedSender;
  36use futures::channel::{mpsc, oneshot};
  37use futures::{FutureExt, future::Shared};
  38use gpui::{
  39    App, AppContext, AsyncApp, BackgroundExecutor, Context, Entity, EventEmitter, SharedString,
  40    Task, WeakEntity,
  41};
  42
  43use rpc::ErrorExt;
  44use serde_json::Value;
  45use smol::stream::StreamExt;
  46use std::any::TypeId;
  47use std::collections::BTreeMap;
  48use std::ops::RangeInclusive;
  49use std::u64;
  50use std::{
  51    any::Any,
  52    collections::hash_map::Entry,
  53    hash::{Hash, Hasher},
  54    path::Path,
  55    sync::Arc,
  56};
  57use task::TaskContext;
  58use text::{PointUtf16, ToPointUtf16};
  59use util::{ResultExt, debug_panic, maybe};
  60use worktree::Worktree;
  61
  62#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
  63#[repr(transparent)]
  64pub struct ThreadId(pub i64);
  65
  66impl From<i64> for ThreadId {
  67    fn from(id: i64) -> Self {
  68        Self(id)
  69    }
  70}
  71
  72#[derive(Clone, Debug)]
  73pub struct StackFrame {
  74    pub dap: dap::StackFrame,
  75    pub scopes: Vec<dap::Scope>,
  76}
  77
  78impl From<dap::StackFrame> for StackFrame {
  79    fn from(stack_frame: dap::StackFrame) -> Self {
  80        Self {
  81            scopes: vec![],
  82            dap: stack_frame,
  83        }
  84    }
  85}
  86
  87#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
  88pub enum ThreadStatus {
  89    #[default]
  90    Running,
  91    Stopped,
  92    Stepping,
  93    Exited,
  94    Ended,
  95}
  96
  97impl ThreadStatus {
  98    pub fn label(&self) -> &'static str {
  99        match self {
 100            ThreadStatus::Running => "Running",
 101            ThreadStatus::Stopped => "Stopped",
 102            ThreadStatus::Stepping => "Stepping",
 103            ThreadStatus::Exited => "Exited",
 104            ThreadStatus::Ended => "Ended",
 105        }
 106    }
 107}
 108
 109#[derive(Debug)]
 110pub struct Thread {
 111    dap: dap::Thread,
 112    stack_frames: Vec<StackFrame>,
 113    stack_frames_error: Option<anyhow::Error>,
 114    _has_stopped: bool,
 115}
 116
 117impl From<dap::Thread> for Thread {
 118    fn from(dap: dap::Thread) -> Self {
 119        Self {
 120            dap,
 121            stack_frames: Default::default(),
 122            stack_frames_error: None,
 123            _has_stopped: false,
 124        }
 125    }
 126}
 127
 128#[derive(Debug, Clone, PartialEq)]
 129pub struct Watcher {
 130    pub expression: SharedString,
 131    pub value: SharedString,
 132    pub variables_reference: u64,
 133    pub presentation_hint: Option<VariablePresentationHint>,
 134}
 135
 136#[derive(Debug, Clone, PartialEq)]
 137pub struct DataBreakpointState {
 138    pub dap: dap::DataBreakpoint,
 139    pub is_enabled: bool,
 140    pub context: Arc<DataBreakpointContext>,
 141}
 142
 143pub enum SessionState {
 144    /// Represents a session that is building/initializing
 145    /// even if a session doesn't have a pre build task this state
 146    /// is used to run all the async tasks that are required to start the session
 147    Booting(Option<Task<Result<()>>>),
 148    Running(RunningMode),
 149}
 150
 151#[derive(Clone)]
 152pub struct RunningMode {
 153    client: Arc<DebugAdapterClient>,
 154    binary: DebugAdapterBinary,
 155    tmp_breakpoint: Option<SourceBreakpoint>,
 156    worktree: WeakEntity<Worktree>,
 157    executor: BackgroundExecutor,
 158    is_started: bool,
 159    has_ever_stopped: bool,
 160    messages_tx: UnboundedSender<Message>,
 161}
 162
 163#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
 164pub struct SessionQuirks {
 165    pub compact: bool,
 166    pub prefer_thread_name: bool,
 167}
 168
 169fn client_source(abs_path: &Path) -> dap::Source {
 170    dap::Source {
 171        name: abs_path
 172            .file_name()
 173            .map(|filename| filename.to_string_lossy().to_string()),
 174        path: Some(abs_path.to_string_lossy().to_string()),
 175        source_reference: None,
 176        presentation_hint: None,
 177        origin: None,
 178        sources: None,
 179        adapter_data: None,
 180        checksums: None,
 181    }
 182}
 183
 184impl RunningMode {
 185    async fn new(
 186        session_id: SessionId,
 187        parent_session: Option<Entity<Session>>,
 188        worktree: WeakEntity<Worktree>,
 189        binary: DebugAdapterBinary,
 190        messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
 191        cx: &mut AsyncApp,
 192    ) -> Result<Self> {
 193        let message_handler = Box::new({
 194            let messages_tx = messages_tx.clone();
 195            move |message| {
 196                messages_tx.unbounded_send(message).ok();
 197            }
 198        });
 199
 200        let client = if let Some(client) = parent_session
 201            .and_then(|session| cx.update(|cx| session.read(cx).adapter_client()).ok())
 202            .flatten()
 203        {
 204            client
 205                .create_child_connection(session_id, binary.clone(), message_handler, cx)
 206                .await?
 207        } else {
 208            DebugAdapterClient::start(session_id, binary.clone(), message_handler, cx).await?
 209        };
 210
 211        Ok(Self {
 212            client: Arc::new(client),
 213            worktree,
 214            tmp_breakpoint: None,
 215            binary,
 216            executor: cx.background_executor().clone(),
 217            is_started: false,
 218            has_ever_stopped: false,
 219            messages_tx,
 220        })
 221    }
 222
 223    pub(crate) fn worktree(&self) -> &WeakEntity<Worktree> {
 224        &self.worktree
 225    }
 226
 227    fn unset_breakpoints_from_paths(&self, paths: &Vec<Arc<Path>>, cx: &mut App) -> Task<()> {
 228        let tasks: Vec<_> = paths
 229            .into_iter()
 230            .map(|path| {
 231                self.request(dap_command::SetBreakpoints {
 232                    source: client_source(path),
 233                    source_modified: None,
 234                    breakpoints: vec![],
 235                })
 236            })
 237            .collect();
 238
 239        cx.background_spawn(async move {
 240            futures::future::join_all(tasks)
 241                .await
 242                .iter()
 243                .for_each(|res| match res {
 244                    Ok(_) => {}
 245                    Err(err) => {
 246                        log::warn!("Set breakpoints request failed: {}", err);
 247                    }
 248                });
 249        })
 250    }
 251
 252    fn send_breakpoints_from_path(
 253        &self,
 254        abs_path: Arc<Path>,
 255        reason: BreakpointUpdatedReason,
 256        breakpoint_store: &Entity<BreakpointStore>,
 257        cx: &mut App,
 258    ) -> Task<()> {
 259        let breakpoints =
 260            breakpoint_store
 261                .read(cx)
 262                .source_breakpoints_from_path(&abs_path, cx)
 263                .into_iter()
 264                .filter(|bp| bp.state.is_enabled())
 265                .chain(self.tmp_breakpoint.iter().filter_map(|breakpoint| {
 266                    breakpoint.path.eq(&abs_path).then(|| breakpoint.clone())
 267                }))
 268                .map(Into::into)
 269                .collect();
 270
 271        let raw_breakpoints = breakpoint_store
 272            .read(cx)
 273            .breakpoints_from_path(&abs_path)
 274            .into_iter()
 275            .filter(|bp| bp.bp.state.is_enabled())
 276            .collect::<Vec<_>>();
 277
 278        let task = self.request(dap_command::SetBreakpoints {
 279            source: client_source(&abs_path),
 280            source_modified: Some(matches!(reason, BreakpointUpdatedReason::FileSaved)),
 281            breakpoints,
 282        });
 283        let session_id = self.client.id();
 284        let breakpoint_store = breakpoint_store.downgrade();
 285        cx.spawn(async move |cx| match cx.background_spawn(task).await {
 286            Ok(breakpoints) => {
 287                let breakpoints =
 288                    breakpoints
 289                        .into_iter()
 290                        .zip(raw_breakpoints)
 291                        .filter_map(|(dap_bp, zed_bp)| {
 292                            Some((
 293                                zed_bp,
 294                                BreakpointSessionState {
 295                                    id: dap_bp.id?,
 296                                    verified: dap_bp.verified,
 297                                },
 298                            ))
 299                        });
 300                breakpoint_store
 301                    .update(cx, |this, _| {
 302                        this.mark_breakpoints_verified(session_id, &abs_path, breakpoints);
 303                    })
 304                    .ok();
 305            }
 306            Err(err) => log::warn!("Set breakpoints request failed for path: {}", err),
 307        })
 308    }
 309
 310    fn send_exception_breakpoints(
 311        &self,
 312        filters: Vec<ExceptionBreakpointsFilter>,
 313        supports_filter_options: bool,
 314    ) -> Task<Result<Vec<dap::Breakpoint>>> {
 315        let arg = if supports_filter_options {
 316            SetExceptionBreakpoints::WithOptions {
 317                filters: filters
 318                    .into_iter()
 319                    .map(|filter| ExceptionFilterOptions {
 320                        filter_id: filter.filter,
 321                        condition: None,
 322                        mode: None,
 323                    })
 324                    .collect(),
 325            }
 326        } else {
 327            SetExceptionBreakpoints::Plain {
 328                filters: filters.into_iter().map(|filter| filter.filter).collect(),
 329            }
 330        };
 331        self.request(arg)
 332    }
 333
 334    fn send_source_breakpoints(
 335        &self,
 336        ignore_breakpoints: bool,
 337        breakpoint_store: &Entity<BreakpointStore>,
 338        cx: &App,
 339    ) -> Task<HashMap<Arc<Path>, anyhow::Error>> {
 340        let mut breakpoint_tasks = Vec::new();
 341        let breakpoints = breakpoint_store.read(cx).all_source_breakpoints(cx);
 342        let mut raw_breakpoints = breakpoint_store.read_with(cx, |this, _| this.all_breakpoints());
 343        debug_assert_eq!(raw_breakpoints.len(), breakpoints.len());
 344        let session_id = self.client.id();
 345        for (path, breakpoints) in breakpoints {
 346            let breakpoints = if ignore_breakpoints {
 347                vec![]
 348            } else {
 349                breakpoints
 350                    .into_iter()
 351                    .filter(|bp| bp.state.is_enabled())
 352                    .map(Into::into)
 353                    .collect()
 354            };
 355
 356            let raw_breakpoints = raw_breakpoints
 357                .remove(&path)
 358                .unwrap_or_default()
 359                .into_iter()
 360                .filter(|bp| bp.bp.state.is_enabled());
 361            let error_path = path.clone();
 362            let send_request = self
 363                .request(dap_command::SetBreakpoints {
 364                    source: client_source(&path),
 365                    source_modified: Some(false),
 366                    breakpoints,
 367                })
 368                .map(|result| result.map_err(move |e| (error_path, e)));
 369
 370            let task = cx.spawn({
 371                let breakpoint_store = breakpoint_store.downgrade();
 372                async move |cx| {
 373                    let breakpoints = cx.background_spawn(send_request).await?;
 374
 375                    let breakpoints = breakpoints.into_iter().zip(raw_breakpoints).filter_map(
 376                        |(dap_bp, zed_bp)| {
 377                            Some((
 378                                zed_bp,
 379                                BreakpointSessionState {
 380                                    id: dap_bp.id?,
 381                                    verified: dap_bp.verified,
 382                                },
 383                            ))
 384                        },
 385                    );
 386                    breakpoint_store
 387                        .update(cx, |this, _| {
 388                            this.mark_breakpoints_verified(session_id, &path, breakpoints);
 389                        })
 390                        .ok();
 391
 392                    Ok(())
 393                }
 394            });
 395            breakpoint_tasks.push(task);
 396        }
 397
 398        cx.background_spawn(async move {
 399            futures::future::join_all(breakpoint_tasks)
 400                .await
 401                .into_iter()
 402                .filter_map(Result::err)
 403                .collect::<HashMap<_, _>>()
 404        })
 405    }
 406
 407    fn initialize_sequence(
 408        &self,
 409        capabilities: &Capabilities,
 410        initialized_rx: oneshot::Receiver<()>,
 411        dap_store: WeakEntity<DapStore>,
 412        cx: &mut Context<Session>,
 413    ) -> Task<Result<()>> {
 414        let raw = self.binary.request_args.clone();
 415
 416        // Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
 417        let launch = match raw.request {
 418            dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(Launch {
 419                raw: raw.configuration,
 420            }),
 421            dap::StartDebuggingRequestArgumentsRequest::Attach => self.request(Attach {
 422                raw: raw.configuration,
 423            }),
 424        };
 425
 426        let configuration_done_supported = ConfigurationDone::is_supported(capabilities);
 427        // From spec (on initialization sequence):
 428        // client sends a setExceptionBreakpoints request if one or more exceptionBreakpointFilters have been defined (or if supportsConfigurationDoneRequest is not true)
 429        //
 430        // Thus we should send setExceptionBreakpoints even if `exceptionFilters` variable is empty (as long as there were some options in the first place).
 431        let should_send_exception_breakpoints = capabilities
 432            .exception_breakpoint_filters
 433            .as_ref()
 434            .is_some_and(|filters| !filters.is_empty())
 435            || !configuration_done_supported;
 436        let supports_exception_filters = capabilities
 437            .supports_exception_filter_options
 438            .unwrap_or_default();
 439        let this = self.clone();
 440        let worktree = self.worktree().clone();
 441        let mut filters = capabilities
 442            .exception_breakpoint_filters
 443            .clone()
 444            .unwrap_or_default();
 445        let configuration_sequence = cx.spawn({
 446            async move |session, cx| {
 447                let adapter_name = session.read_with(cx, |this, _| this.adapter())?;
 448                let (breakpoint_store, adapter_defaults) =
 449                    dap_store.read_with(cx, |dap_store, _| {
 450                        (
 451                            dap_store.breakpoint_store().clone(),
 452                            dap_store.adapter_options(&adapter_name),
 453                        )
 454                    })?;
 455                initialized_rx.await?;
 456                let errors_by_path = cx
 457                    .update(|cx| this.send_source_breakpoints(false, &breakpoint_store, cx))?
 458                    .await;
 459
 460                dap_store.update(cx, |_, cx| {
 461                    let Some(worktree) = worktree.upgrade() else {
 462                        return;
 463                    };
 464
 465                    for (path, error) in &errors_by_path {
 466                        log::error!("failed to set breakpoints for {path:?}: {error}");
 467                    }
 468
 469                    if let Some(failed_path) = errors_by_path.keys().next() {
 470                        let failed_path = failed_path
 471                            .strip_prefix(worktree.read(cx).abs_path())
 472                            .unwrap_or(failed_path)
 473                            .display();
 474                        let message = format!(
 475                            "Failed to set breakpoints for {failed_path}{}",
 476                            match errors_by_path.len() {
 477                                0 => unreachable!(),
 478                                1 => "".into(),
 479                                2 => " and 1 other path".into(),
 480                                n => format!(" and {} other paths", n - 1),
 481                            }
 482                        );
 483                        cx.emit(super::dap_store::DapStoreEvent::Notification(message));
 484                    }
 485                })?;
 486
 487                if should_send_exception_breakpoints {
 488                    _ = session.update(cx, |this, _| {
 489                        filters.retain(|filter| {
 490                            let is_enabled = if let Some(defaults) = adapter_defaults.as_ref() {
 491                                defaults
 492                                    .exception_breakpoints
 493                                    .get(&filter.filter)
 494                                    .map(|options| options.enabled)
 495                                    .unwrap_or_else(|| filter.default.unwrap_or_default())
 496                            } else {
 497                                filter.default.unwrap_or_default()
 498                            };
 499                            this.exception_breakpoints
 500                                .entry(filter.filter.clone())
 501                                .or_insert_with(|| (filter.clone(), is_enabled));
 502                            is_enabled
 503                        });
 504                    });
 505
 506                    this.send_exception_breakpoints(filters, supports_exception_filters)
 507                        .await
 508                        .ok();
 509                }
 510
 511                let ret = if configuration_done_supported {
 512                    this.request(ConfigurationDone {})
 513                } else {
 514                    Task::ready(Ok(()))
 515                }
 516                .await;
 517                ret
 518            }
 519        });
 520
 521        let task = cx.background_spawn(futures::future::try_join(launch, configuration_sequence));
 522
 523        cx.spawn(async move |this, cx| {
 524            let result = task.await;
 525
 526            this.update(cx, |this, cx| {
 527                if let Some(this) = this.as_running_mut() {
 528                    this.is_started = true;
 529                    cx.notify();
 530                }
 531            })
 532            .ok();
 533
 534            result?;
 535            anyhow::Ok(())
 536        })
 537    }
 538
 539    fn reconnect_for_ssh(&self, cx: &mut AsyncApp) -> Option<Task<Result<()>>> {
 540        let client = self.client.clone();
 541        let messages_tx = self.messages_tx.clone();
 542        let message_handler = Box::new(move |message| {
 543            messages_tx.unbounded_send(message).ok();
 544        });
 545        if client.should_reconnect_for_ssh() {
 546            Some(cx.spawn(async move |cx| {
 547                client.connect(message_handler, cx).await?;
 548                anyhow::Ok(())
 549            }))
 550        } else {
 551            None
 552        }
 553    }
 554
 555    fn request<R: LocalDapCommand>(&self, request: R) -> Task<Result<R::Response>>
 556    where
 557        <R::DapRequest as dap::requests::Request>::Response: 'static,
 558        <R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
 559    {
 560        let request = Arc::new(request);
 561
 562        let request_clone = request.clone();
 563        let connection = self.client.clone();
 564        self.executor.spawn(async move {
 565            let args = request_clone.to_dap();
 566            let response = connection.request::<R::DapRequest>(args).await?;
 567            request.response_from_dap(response)
 568        })
 569    }
 570}
 571
 572impl SessionState {
 573    pub(super) fn request_dap<R: LocalDapCommand>(&self, request: R) -> Task<Result<R::Response>>
 574    where
 575        <R::DapRequest as dap::requests::Request>::Response: 'static,
 576        <R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
 577    {
 578        match self {
 579            SessionState::Running(debug_adapter_client) => debug_adapter_client.request(request),
 580            SessionState::Booting(_) => Task::ready(Err(anyhow!(
 581                "no adapter running to send request: {request:?}"
 582            ))),
 583        }
 584    }
 585
 586    /// Did this debug session stop at least once?
 587    pub(crate) fn has_ever_stopped(&self) -> bool {
 588        match self {
 589            SessionState::Booting(_) => false,
 590            SessionState::Running(running_mode) => running_mode.has_ever_stopped,
 591        }
 592    }
 593
 594    fn stopped(&mut self) {
 595        if let SessionState::Running(running) = self {
 596            running.has_ever_stopped = true;
 597        }
 598    }
 599}
 600
 601#[derive(Default)]
 602struct ThreadStates {
 603    global_state: Option<ThreadStatus>,
 604    known_thread_states: IndexMap<ThreadId, ThreadStatus>,
 605}
 606
 607impl ThreadStates {
 608    fn stop_all_threads(&mut self) {
 609        self.global_state = Some(ThreadStatus::Stopped);
 610        self.known_thread_states.clear();
 611    }
 612
 613    fn exit_all_threads(&mut self) {
 614        self.global_state = Some(ThreadStatus::Exited);
 615        self.known_thread_states.clear();
 616    }
 617
 618    fn continue_all_threads(&mut self) {
 619        self.global_state = Some(ThreadStatus::Running);
 620        self.known_thread_states.clear();
 621    }
 622
 623    fn stop_thread(&mut self, thread_id: ThreadId) {
 624        self.known_thread_states
 625            .insert(thread_id, ThreadStatus::Stopped);
 626    }
 627
 628    fn continue_thread(&mut self, thread_id: ThreadId) {
 629        self.known_thread_states
 630            .insert(thread_id, ThreadStatus::Running);
 631    }
 632
 633    fn process_step(&mut self, thread_id: ThreadId) {
 634        self.known_thread_states
 635            .insert(thread_id, ThreadStatus::Stepping);
 636    }
 637
 638    fn thread_status(&self, thread_id: ThreadId) -> ThreadStatus {
 639        self.thread_state(thread_id)
 640            .unwrap_or(ThreadStatus::Running)
 641    }
 642
 643    fn thread_state(&self, thread_id: ThreadId) -> Option<ThreadStatus> {
 644        self.known_thread_states
 645            .get(&thread_id)
 646            .copied()
 647            .or(self.global_state)
 648    }
 649
 650    fn exit_thread(&mut self, thread_id: ThreadId) {
 651        self.known_thread_states
 652            .insert(thread_id, ThreadStatus::Exited);
 653    }
 654
 655    fn any_stopped_thread(&self) -> bool {
 656        self.global_state
 657            .is_some_and(|state| state == ThreadStatus::Stopped)
 658            || self
 659                .known_thread_states
 660                .values()
 661                .any(|status| *status == ThreadStatus::Stopped)
 662    }
 663}
 664const MAX_TRACKED_OUTPUT_EVENTS: usize = 5000;
 665
 666type IsEnabled = bool;
 667
 668#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd, Eq, Ord)]
 669pub struct OutputToken(pub usize);
 670/// Represents a current state of a single debug adapter and provides ways to mutate it.
 671pub struct Session {
 672    pub mode: SessionState,
 673    id: SessionId,
 674    label: Option<SharedString>,
 675    adapter: DebugAdapterName,
 676    pub(super) capabilities: Capabilities,
 677    child_session_ids: HashSet<SessionId>,
 678    parent_session: Option<Entity<Session>>,
 679    modules: Vec<dap::Module>,
 680    loaded_sources: Vec<dap::Source>,
 681    output_token: OutputToken,
 682    output: Box<circular_buffer::CircularBuffer<MAX_TRACKED_OUTPUT_EVENTS, dap::OutputEvent>>,
 683    threads: IndexMap<ThreadId, Thread>,
 684    thread_states: ThreadStates,
 685    watchers: HashMap<SharedString, Watcher>,
 686    variables: HashMap<VariableReference, Vec<dap::Variable>>,
 687    stack_frames: IndexMap<StackFrameId, StackFrame>,
 688    locations: HashMap<u64, dap::LocationsResponse>,
 689    is_session_terminated: bool,
 690    requests: HashMap<TypeId, HashMap<RequestSlot, Shared<Task<Option<()>>>>>,
 691    pub(crate) breakpoint_store: Entity<BreakpointStore>,
 692    ignore_breakpoints: bool,
 693    exception_breakpoints: BTreeMap<String, (ExceptionBreakpointsFilter, IsEnabled)>,
 694    data_breakpoints: BTreeMap<String, DataBreakpointState>,
 695    background_tasks: Vec<Task<()>>,
 696    restart_task: Option<Task<()>>,
 697    task_context: TaskContext,
 698    memory: memory::Memory,
 699    quirks: SessionQuirks,
 700}
 701
 702trait CacheableCommand: Any + Send + Sync {
 703    fn dyn_eq(&self, rhs: &dyn CacheableCommand) -> bool;
 704    fn dyn_hash(&self, hasher: &mut dyn Hasher);
 705    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
 706}
 707
 708impl<T> CacheableCommand for T
 709where
 710    T: LocalDapCommand + PartialEq + Eq + Hash,
 711{
 712    fn dyn_eq(&self, rhs: &dyn CacheableCommand) -> bool {
 713        (rhs as &dyn Any).downcast_ref::<Self>() == Some(self)
 714    }
 715
 716    fn dyn_hash(&self, mut hasher: &mut dyn Hasher) {
 717        T::hash(self, &mut hasher);
 718    }
 719
 720    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
 721        self
 722    }
 723}
 724
 725pub(crate) struct RequestSlot(Arc<dyn CacheableCommand>);
 726
 727impl<T: LocalDapCommand + PartialEq + Eq + Hash> From<T> for RequestSlot {
 728    fn from(request: T) -> Self {
 729        Self(Arc::new(request))
 730    }
 731}
 732
 733impl PartialEq for RequestSlot {
 734    fn eq(&self, other: &Self) -> bool {
 735        self.0.dyn_eq(other.0.as_ref())
 736    }
 737}
 738
 739impl Eq for RequestSlot {}
 740
 741impl Hash for RequestSlot {
 742    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 743        self.0.dyn_hash(state);
 744        (&*self.0 as &dyn Any).type_id().hash(state)
 745    }
 746}
 747
 748#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 749pub struct CompletionsQuery {
 750    pub query: String,
 751    pub column: u64,
 752    pub line: Option<u64>,
 753    pub frame_id: Option<u64>,
 754}
 755
 756impl CompletionsQuery {
 757    pub fn new(
 758        buffer: &language::Buffer,
 759        cursor_position: language::Anchor,
 760        frame_id: Option<u64>,
 761    ) -> Self {
 762        let PointUtf16 { row, column } = cursor_position.to_point_utf16(&buffer.snapshot());
 763        Self {
 764            query: buffer.text(),
 765            column: column as u64,
 766            frame_id,
 767            line: Some(row as u64),
 768        }
 769    }
 770}
 771
 772#[derive(Debug)]
 773pub enum SessionEvent {
 774    Modules,
 775    LoadedSources,
 776    Stopped(Option<ThreadId>),
 777    StackTrace,
 778    Variables,
 779    Watchers,
 780    Threads,
 781    InvalidateInlineValue,
 782    CapabilitiesLoaded,
 783    RunInTerminal {
 784        request: RunInTerminalRequestArguments,
 785        sender: mpsc::Sender<Result<u32>>,
 786    },
 787    DataBreakpointInfo,
 788    ConsoleOutput,
 789}
 790
 791#[derive(Clone, Debug, PartialEq, Eq)]
 792pub enum SessionStateEvent {
 793    Running,
 794    Shutdown,
 795    Restart,
 796    SpawnChildSession {
 797        request: StartDebuggingRequestArguments,
 798    },
 799}
 800
 801impl EventEmitter<SessionEvent> for Session {}
 802impl EventEmitter<SessionStateEvent> for Session {}
 803
 804// local session will send breakpoint updates to DAP for all new breakpoints
 805// remote side will only send breakpoint updates when it is a breakpoint created by that peer
 806// BreakpointStore notifies session on breakpoint changes
 807impl Session {
 808    pub(crate) fn new(
 809        breakpoint_store: Entity<BreakpointStore>,
 810        session_id: SessionId,
 811        parent_session: Option<Entity<Session>>,
 812        label: Option<SharedString>,
 813        adapter: DebugAdapterName,
 814        task_context: TaskContext,
 815        quirks: SessionQuirks,
 816        cx: &mut App,
 817    ) -> Entity<Self> {
 818        cx.new::<Self>(|cx| {
 819            cx.subscribe(&breakpoint_store, |this, store, event, cx| match event {
 820                BreakpointStoreEvent::BreakpointsUpdated(path, reason) => {
 821                    if let Some(local) = (!this.ignore_breakpoints)
 822                        .then(|| this.as_running_mut())
 823                        .flatten()
 824                    {
 825                        local
 826                            .send_breakpoints_from_path(path.clone(), *reason, &store, cx)
 827                            .detach();
 828                    };
 829                }
 830                BreakpointStoreEvent::BreakpointsCleared(paths) => {
 831                    if let Some(local) = (!this.ignore_breakpoints)
 832                        .then(|| this.as_running_mut())
 833                        .flatten()
 834                    {
 835                        local.unset_breakpoints_from_paths(paths, cx).detach();
 836                    }
 837                }
 838                BreakpointStoreEvent::SetDebugLine | BreakpointStoreEvent::ClearDebugLines => {}
 839            })
 840            .detach();
 841
 842            let this = Self {
 843                mode: SessionState::Booting(None),
 844                id: session_id,
 845                child_session_ids: HashSet::default(),
 846                parent_session,
 847                capabilities: Capabilities::default(),
 848                watchers: HashMap::default(),
 849                variables: Default::default(),
 850                stack_frames: Default::default(),
 851                thread_states: ThreadStates::default(),
 852                output_token: OutputToken(0),
 853                output: circular_buffer::CircularBuffer::boxed(),
 854                requests: HashMap::default(),
 855                modules: Vec::default(),
 856                loaded_sources: Vec::default(),
 857                threads: IndexMap::default(),
 858                background_tasks: Vec::default(),
 859                restart_task: None,
 860                locations: Default::default(),
 861                is_session_terminated: false,
 862                ignore_breakpoints: false,
 863                breakpoint_store,
 864                data_breakpoints: Default::default(),
 865                exception_breakpoints: Default::default(),
 866                label,
 867                adapter,
 868                task_context,
 869                memory: memory::Memory::new(),
 870                quirks,
 871            };
 872
 873            this
 874        })
 875    }
 876
 877    pub fn task_context(&self) -> &TaskContext {
 878        &self.task_context
 879    }
 880
 881    pub fn worktree(&self) -> Option<Entity<Worktree>> {
 882        match &self.mode {
 883            SessionState::Booting(_) => None,
 884            SessionState::Running(local_mode) => local_mode.worktree.upgrade(),
 885        }
 886    }
 887
 888    pub fn boot(
 889        &mut self,
 890        binary: DebugAdapterBinary,
 891        worktree: Entity<Worktree>,
 892        dap_store: WeakEntity<DapStore>,
 893        cx: &mut Context<Self>,
 894    ) -> Task<Result<()>> {
 895        let (message_tx, mut message_rx) = futures::channel::mpsc::unbounded();
 896        let (initialized_tx, initialized_rx) = futures::channel::oneshot::channel();
 897
 898        let background_tasks = vec![cx.spawn(async move |this: WeakEntity<Session>, cx| {
 899            let mut initialized_tx = Some(initialized_tx);
 900            while let Some(message) = message_rx.next().await {
 901                if let Message::Event(event) = message {
 902                    if let Events::Initialized(_) = *event {
 903                        if let Some(tx) = initialized_tx.take() {
 904                            tx.send(()).ok();
 905                        }
 906                    } else {
 907                        let Ok(_) = this.update(cx, |session, cx| {
 908                            session.handle_dap_event(event, cx);
 909                        }) else {
 910                            break;
 911                        };
 912                    }
 913                } else if let Message::Request(request) = message {
 914                    let Ok(_) = this.update(cx, |this, cx| {
 915                        if request.command == StartDebugging::COMMAND {
 916                            this.handle_start_debugging_request(request, cx)
 917                                .detach_and_log_err(cx);
 918                        } else if request.command == RunInTerminal::COMMAND {
 919                            this.handle_run_in_terminal_request(request, cx)
 920                                .detach_and_log_err(cx);
 921                        }
 922                    }) else {
 923                        break;
 924                    };
 925                }
 926            }
 927        })];
 928        self.background_tasks = background_tasks;
 929        let id = self.id;
 930        let parent_session = self.parent_session.clone();
 931
 932        cx.spawn(async move |this, cx| {
 933            let mode = RunningMode::new(
 934                id,
 935                parent_session,
 936                worktree.downgrade(),
 937                binary.clone(),
 938                message_tx,
 939                cx,
 940            )
 941            .await?;
 942            this.update(cx, |this, cx| {
 943                match &mut this.mode {
 944                    SessionState::Booting(task) if task.is_some() => {
 945                        task.take().unwrap().detach_and_log_err(cx);
 946                    }
 947                    SessionState::Booting(_) => {}
 948                    SessionState::Running(_) => {
 949                        debug_panic!("Attempting to boot a session that is already running");
 950                    }
 951                };
 952                this.mode = SessionState::Running(mode);
 953                cx.emit(SessionStateEvent::Running);
 954            })?;
 955
 956            this.update(cx, |session, cx| session.request_initialize(cx))?
 957                .await?;
 958
 959            let result = this
 960                .update(cx, |session, cx| {
 961                    session.initialize_sequence(initialized_rx, dap_store.clone(), cx)
 962                })?
 963                .await;
 964
 965            if result.is_err() {
 966                let mut console = this.update(cx, |session, cx| session.console_output(cx))?;
 967
 968                console
 969                    .send(format!(
 970                        "Tried to launch debugger with: {}",
 971                        serde_json::to_string_pretty(&binary.request_args.configuration)
 972                            .unwrap_or_default(),
 973                    ))
 974                    .await
 975                    .ok();
 976            }
 977
 978            result
 979        })
 980    }
 981
 982    pub fn session_id(&self) -> SessionId {
 983        self.id
 984    }
 985
 986    pub fn child_session_ids(&self) -> HashSet<SessionId> {
 987        self.child_session_ids.clone()
 988    }
 989
 990    pub fn add_child_session_id(&mut self, session_id: SessionId) {
 991        self.child_session_ids.insert(session_id);
 992    }
 993
 994    pub fn remove_child_session_id(&mut self, session_id: SessionId) {
 995        self.child_session_ids.remove(&session_id);
 996    }
 997
 998    pub fn parent_id(&self, cx: &App) -> Option<SessionId> {
 999        self.parent_session
1000            .as_ref()
1001            .map(|session| session.read(cx).id)
1002    }
1003
1004    pub fn parent_session(&self) -> Option<&Entity<Self>> {
1005        self.parent_session.as_ref()
1006    }
1007
1008    pub fn on_app_quit(&mut self, cx: &mut Context<Self>) -> Task<()> {
1009        let Some(client) = self.adapter_client() else {
1010            return Task::ready(());
1011        };
1012
1013        let supports_terminate = self
1014            .capabilities
1015            .support_terminate_debuggee
1016            .unwrap_or(false);
1017
1018        cx.background_spawn(async move {
1019            if supports_terminate {
1020                client
1021                    .request::<dap::requests::Terminate>(dap::TerminateArguments {
1022                        restart: Some(false),
1023                    })
1024                    .await
1025                    .ok();
1026            } else {
1027                client
1028                    .request::<dap::requests::Disconnect>(dap::DisconnectArguments {
1029                        restart: Some(false),
1030                        terminate_debuggee: Some(true),
1031                        suspend_debuggee: Some(false),
1032                    })
1033                    .await
1034                    .ok();
1035            }
1036        })
1037    }
1038
1039    pub fn capabilities(&self) -> &Capabilities {
1040        &self.capabilities
1041    }
1042
1043    pub fn binary(&self) -> Option<&DebugAdapterBinary> {
1044        match &self.mode {
1045            SessionState::Booting(_) => None,
1046            SessionState::Running(running_mode) => Some(&running_mode.binary),
1047        }
1048    }
1049
1050    pub fn adapter(&self) -> DebugAdapterName {
1051        self.adapter.clone()
1052    }
1053
1054    pub fn label(&self) -> Option<SharedString> {
1055        self.label.clone()
1056    }
1057
1058    pub fn is_terminated(&self) -> bool {
1059        self.is_session_terminated
1060    }
1061
1062    pub fn console_output(&mut self, cx: &mut Context<Self>) -> mpsc::UnboundedSender<String> {
1063        let (tx, mut rx) = mpsc::unbounded();
1064
1065        cx.spawn(async move |this, cx| {
1066            while let Some(output) = rx.next().await {
1067                this.update(cx, |this, _| {
1068                    let event = dap::OutputEvent {
1069                        category: None,
1070                        output,
1071                        group: None,
1072                        variables_reference: None,
1073                        source: None,
1074                        line: None,
1075                        column: None,
1076                        data: None,
1077                        location_reference: None,
1078                    };
1079                    this.push_output(event);
1080                })?;
1081            }
1082            anyhow::Ok(())
1083        })
1084        .detach();
1085
1086        tx
1087    }
1088
1089    pub fn is_started(&self) -> bool {
1090        match &self.mode {
1091            SessionState::Booting(_) => false,
1092            SessionState::Running(running) => running.is_started,
1093        }
1094    }
1095
1096    pub fn is_building(&self) -> bool {
1097        matches!(self.mode, SessionState::Booting(_))
1098    }
1099
1100    pub fn as_running_mut(&mut self) -> Option<&mut RunningMode> {
1101        match &mut self.mode {
1102            SessionState::Running(local_mode) => Some(local_mode),
1103            SessionState::Booting(_) => None,
1104        }
1105    }
1106
1107    pub fn as_running(&self) -> Option<&RunningMode> {
1108        match &self.mode {
1109            SessionState::Running(local_mode) => Some(local_mode),
1110            SessionState::Booting(_) => None,
1111        }
1112    }
1113
1114    fn handle_start_debugging_request(
1115        &mut self,
1116        request: dap::messages::Request,
1117        cx: &mut Context<Self>,
1118    ) -> Task<Result<()>> {
1119        let request_seq = request.seq;
1120
1121        let launch_request: Option<Result<StartDebuggingRequestArguments, _>> = request
1122            .arguments
1123            .as_ref()
1124            .map(|value| serde_json::from_value(value.clone()));
1125
1126        let mut success = true;
1127        if let Some(Ok(request)) = launch_request {
1128            cx.emit(SessionStateEvent::SpawnChildSession { request });
1129        } else {
1130            log::error!(
1131                "Failed to parse launch request arguments: {:?}",
1132                request.arguments
1133            );
1134            success = false;
1135        }
1136
1137        cx.spawn(async move |this, cx| {
1138            this.update(cx, |this, cx| {
1139                this.respond_to_client(
1140                    request_seq,
1141                    success,
1142                    StartDebugging::COMMAND.to_string(),
1143                    None,
1144                    cx,
1145                )
1146            })?
1147            .await
1148        })
1149    }
1150
1151    fn handle_run_in_terminal_request(
1152        &mut self,
1153        request: dap::messages::Request,
1154        cx: &mut Context<Self>,
1155    ) -> Task<Result<()>> {
1156        let request_args = match serde_json::from_value::<RunInTerminalRequestArguments>(
1157            request.arguments.unwrap_or_default(),
1158        ) {
1159            Ok(args) => args,
1160            Err(error) => {
1161                return cx.spawn(async move |session, cx| {
1162                    let error = serde_json::to_value(dap::ErrorResponse {
1163                        error: Some(dap::Message {
1164                            id: request.seq,
1165                            format: error.to_string(),
1166                            variables: None,
1167                            send_telemetry: None,
1168                            show_user: None,
1169                            url: None,
1170                            url_label: None,
1171                        }),
1172                    })
1173                    .ok();
1174
1175                    session
1176                        .update(cx, |this, cx| {
1177                            this.respond_to_client(
1178                                request.seq,
1179                                false,
1180                                StartDebugging::COMMAND.to_string(),
1181                                error,
1182                                cx,
1183                            )
1184                        })?
1185                        .await?;
1186
1187                    Err(anyhow!("Failed to parse RunInTerminalRequestArguments"))
1188                });
1189            }
1190        };
1191
1192        let seq = request.seq;
1193
1194        let (tx, mut rx) = mpsc::channel::<Result<u32>>(1);
1195        cx.emit(SessionEvent::RunInTerminal {
1196            request: request_args,
1197            sender: tx,
1198        });
1199        cx.notify();
1200
1201        cx.spawn(async move |session, cx| {
1202            let result = util::maybe!(async move {
1203                rx.next().await.ok_or_else(|| {
1204                    anyhow!("failed to receive response from spawn terminal".to_string())
1205                })?
1206            })
1207            .await;
1208            let (success, body) = match result {
1209                Ok(pid) => (
1210                    true,
1211                    serde_json::to_value(dap::RunInTerminalResponse {
1212                        process_id: None,
1213                        shell_process_id: Some(pid as u64),
1214                    })
1215                    .ok(),
1216                ),
1217                Err(error) => (
1218                    false,
1219                    serde_json::to_value(dap::ErrorResponse {
1220                        error: Some(dap::Message {
1221                            id: seq,
1222                            format: error.to_string(),
1223                            variables: None,
1224                            send_telemetry: None,
1225                            show_user: None,
1226                            url: None,
1227                            url_label: None,
1228                        }),
1229                    })
1230                    .ok(),
1231                ),
1232            };
1233
1234            session
1235                .update(cx, |session, cx| {
1236                    session.respond_to_client(
1237                        seq,
1238                        success,
1239                        RunInTerminal::COMMAND.to_string(),
1240                        body,
1241                        cx,
1242                    )
1243                })?
1244                .await
1245        })
1246    }
1247
1248    pub(super) fn request_initialize(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
1249        let adapter_id = self.adapter().to_string();
1250        let request = Initialize { adapter_id };
1251
1252        let SessionState::Running(running) = &self.mode else {
1253            return Task::ready(Err(anyhow!(
1254                "Cannot send initialize request, task still building"
1255            )));
1256        };
1257        let mut response = running.request(request.clone());
1258
1259        cx.spawn(async move |this, cx| {
1260            loop {
1261                let capabilities = response.await;
1262                match capabilities {
1263                    Err(e) => {
1264                        let Ok(Some(reconnect)) = this.update(cx, |this, cx| {
1265                            this.as_running()
1266                                .and_then(|running| running.reconnect_for_ssh(&mut cx.to_async()))
1267                        }) else {
1268                            return Err(e);
1269                        };
1270                        log::info!("Failed to connect to debug adapter: {}, retrying...", e);
1271                        reconnect.await?;
1272
1273                        let Ok(Some(r)) = this.update(cx, |this, _| {
1274                            this.as_running()
1275                                .map(|running| running.request(request.clone()))
1276                        }) else {
1277                            return Err(e);
1278                        };
1279                        response = r
1280                    }
1281                    Ok(capabilities) => {
1282                        this.update(cx, |session, cx| {
1283                            session.capabilities = capabilities;
1284
1285                            cx.emit(SessionEvent::CapabilitiesLoaded);
1286                        })?;
1287                        return Ok(());
1288                    }
1289                }
1290            }
1291        })
1292    }
1293
1294    pub(super) fn initialize_sequence(
1295        &mut self,
1296        initialize_rx: oneshot::Receiver<()>,
1297        dap_store: WeakEntity<DapStore>,
1298        cx: &mut Context<Self>,
1299    ) -> Task<Result<()>> {
1300        match &self.mode {
1301            SessionState::Running(local_mode) => {
1302                local_mode.initialize_sequence(&self.capabilities, initialize_rx, dap_store, cx)
1303            }
1304            SessionState::Booting(_) => {
1305                Task::ready(Err(anyhow!("cannot initialize, still building")))
1306            }
1307        }
1308    }
1309
1310    pub fn run_to_position(
1311        &mut self,
1312        breakpoint: SourceBreakpoint,
1313        active_thread_id: ThreadId,
1314        cx: &mut Context<Self>,
1315    ) {
1316        match &mut self.mode {
1317            SessionState::Running(local_mode) => {
1318                if !matches!(
1319                    self.thread_states.thread_state(active_thread_id),
1320                    Some(ThreadStatus::Stopped)
1321                ) {
1322                    return;
1323                };
1324                let path = breakpoint.path.clone();
1325                local_mode.tmp_breakpoint = Some(breakpoint);
1326                let task = local_mode.send_breakpoints_from_path(
1327                    path,
1328                    BreakpointUpdatedReason::Toggled,
1329                    &self.breakpoint_store,
1330                    cx,
1331                );
1332
1333                cx.spawn(async move |this, cx| {
1334                    task.await;
1335                    this.update(cx, |this, cx| {
1336                        this.continue_thread(active_thread_id, cx);
1337                    })
1338                })
1339                .detach();
1340            }
1341            SessionState::Booting(_) => {}
1342        }
1343    }
1344
1345    pub fn has_new_output(&self, last_update: OutputToken) -> bool {
1346        self.output_token.0.checked_sub(last_update.0).unwrap_or(0) != 0
1347    }
1348
1349    pub fn output(
1350        &self,
1351        since: OutputToken,
1352    ) -> (impl Iterator<Item = &dap::OutputEvent>, OutputToken) {
1353        if self.output_token.0 == 0 {
1354            return (self.output.range(0..0), OutputToken(0));
1355        };
1356
1357        let events_since = self.output_token.0.checked_sub(since.0).unwrap_or(0);
1358
1359        let clamped_events_since = events_since.clamp(0, self.output.len());
1360        (
1361            self.output
1362                .range(self.output.len() - clamped_events_since..),
1363            self.output_token,
1364        )
1365    }
1366
1367    pub fn respond_to_client(
1368        &self,
1369        request_seq: u64,
1370        success: bool,
1371        command: String,
1372        body: Option<serde_json::Value>,
1373        cx: &mut Context<Self>,
1374    ) -> Task<Result<()>> {
1375        let Some(local_session) = self.as_running() else {
1376            unreachable!("Cannot respond to remote client");
1377        };
1378        let client = local_session.client.clone();
1379
1380        cx.background_spawn(async move {
1381            client
1382                .send_message(Message::Response(Response {
1383                    body,
1384                    success,
1385                    command,
1386                    seq: request_seq + 1,
1387                    request_seq,
1388                    message: None,
1389                }))
1390                .await
1391        })
1392    }
1393
1394    fn handle_stopped_event(&mut self, event: StoppedEvent, cx: &mut Context<Self>) {
1395        self.mode.stopped();
1396        // todo(debugger): Find a clean way to get around the clone
1397        let breakpoint_store = self.breakpoint_store.clone();
1398        if let Some((local, path)) = self.as_running_mut().and_then(|local| {
1399            let breakpoint = local.tmp_breakpoint.take()?;
1400            let path = breakpoint.path.clone();
1401            Some((local, path))
1402        }) {
1403            local
1404                .send_breakpoints_from_path(
1405                    path,
1406                    BreakpointUpdatedReason::Toggled,
1407                    &breakpoint_store,
1408                    cx,
1409                )
1410                .detach();
1411        };
1412
1413        if event.all_threads_stopped.unwrap_or_default() || event.thread_id.is_none() {
1414            self.thread_states.stop_all_threads();
1415            self.invalidate_command_type::<StackTraceCommand>();
1416        }
1417
1418        // Event if we stopped all threads we still need to insert the thread_id
1419        // to our own data
1420        if let Some(thread_id) = event.thread_id {
1421            self.thread_states.stop_thread(ThreadId(thread_id));
1422
1423            self.invalidate_state(
1424                &StackTraceCommand {
1425                    thread_id,
1426                    start_frame: None,
1427                    levels: None,
1428                }
1429                .into(),
1430            );
1431        }
1432
1433        self.invalidate_generic();
1434        self.threads.clear();
1435        self.variables.clear();
1436        cx.emit(SessionEvent::Stopped(
1437            event
1438                .thread_id
1439                .map(Into::into)
1440                .filter(|_| !event.preserve_focus_hint.unwrap_or(false)),
1441        ));
1442        cx.emit(SessionEvent::InvalidateInlineValue);
1443        cx.notify();
1444    }
1445
1446    pub(crate) fn handle_dap_event(&mut self, event: Box<Events>, cx: &mut Context<Self>) {
1447        match *event {
1448            Events::Initialized(_) => {
1449                debug_assert!(
1450                    false,
1451                    "Initialized event should have been handled in LocalMode"
1452                );
1453            }
1454            Events::Stopped(event) => self.handle_stopped_event(event, cx),
1455            Events::Continued(event) => {
1456                if event.all_threads_continued.unwrap_or_default() {
1457                    self.thread_states.continue_all_threads();
1458                    self.breakpoint_store.update(cx, |store, cx| {
1459                        store.remove_active_position(Some(self.session_id()), cx)
1460                    });
1461                } else {
1462                    self.thread_states
1463                        .continue_thread(ThreadId(event.thread_id));
1464                }
1465                // todo(debugger): We should be able to get away with only invalidating generic if all threads were continued
1466                self.invalidate_generic();
1467            }
1468            Events::Exited(_event) => {
1469                self.clear_active_debug_line(cx);
1470            }
1471            Events::Terminated(_) => {
1472                self.shutdown(cx).detach();
1473            }
1474            Events::Thread(event) => {
1475                let thread_id = ThreadId(event.thread_id);
1476
1477                match event.reason {
1478                    dap::ThreadEventReason::Started => {
1479                        self.thread_states.continue_thread(thread_id);
1480                    }
1481                    dap::ThreadEventReason::Exited => {
1482                        self.thread_states.exit_thread(thread_id);
1483                    }
1484                    reason => {
1485                        log::error!("Unhandled thread event reason {:?}", reason);
1486                    }
1487                }
1488                self.invalidate_state(&ThreadsCommand.into());
1489                cx.notify();
1490            }
1491            Events::Output(event) => {
1492                if event
1493                    .category
1494                    .as_ref()
1495                    .is_some_and(|category| *category == OutputEventCategory::Telemetry)
1496                {
1497                    return;
1498                }
1499
1500                self.push_output(event);
1501                cx.notify();
1502            }
1503            Events::Breakpoint(event) => self.breakpoint_store.update(cx, |store, _| {
1504                store.update_session_breakpoint(self.session_id(), event.reason, event.breakpoint);
1505            }),
1506            Events::Module(event) => {
1507                match event.reason {
1508                    dap::ModuleEventReason::New => {
1509                        self.modules.push(event.module);
1510                    }
1511                    dap::ModuleEventReason::Changed => {
1512                        if let Some(module) = self
1513                            .modules
1514                            .iter_mut()
1515                            .find(|other| event.module.id == other.id)
1516                        {
1517                            *module = event.module;
1518                        }
1519                    }
1520                    dap::ModuleEventReason::Removed => {
1521                        self.modules.retain(|other| event.module.id != other.id);
1522                    }
1523                }
1524
1525                // todo(debugger): We should only send the invalidate command to downstream clients.
1526                // self.invalidate_state(&ModulesCommand.into());
1527            }
1528            Events::LoadedSource(_) => {
1529                self.invalidate_state(&LoadedSourcesCommand.into());
1530            }
1531            Events::Capabilities(event) => {
1532                self.capabilities = self.capabilities.merge(event.capabilities);
1533
1534                // The adapter might've enabled new exception breakpoints (or disabled existing ones).
1535                let recent_filters = self
1536                    .capabilities
1537                    .exception_breakpoint_filters
1538                    .iter()
1539                    .flatten()
1540                    .map(|filter| (filter.filter.clone(), filter.clone()))
1541                    .collect::<BTreeMap<_, _>>();
1542                for filter in recent_filters.values() {
1543                    let default = filter.default.unwrap_or_default();
1544                    self.exception_breakpoints
1545                        .entry(filter.filter.clone())
1546                        .or_insert_with(|| (filter.clone(), default));
1547                }
1548                self.exception_breakpoints
1549                    .retain(|k, _| recent_filters.contains_key(k));
1550                if self.is_started() {
1551                    self.send_exception_breakpoints(cx);
1552                }
1553
1554                // Remove the ones that no longer exist.
1555                cx.notify();
1556            }
1557            Events::Memory(_) => {}
1558            Events::Process(_) => {}
1559            Events::ProgressEnd(_) => {}
1560            Events::ProgressStart(_) => {}
1561            Events::ProgressUpdate(_) => {}
1562            Events::Invalidated(_) => {}
1563            Events::Other(_) => {}
1564        }
1565    }
1566
1567    /// Ensure that there's a request in flight for the given command, and if not, send it. Use this to run requests that are idempotent.
1568    fn fetch<T: LocalDapCommand + PartialEq + Eq + Hash>(
1569        &mut self,
1570        request: T,
1571        process_result: impl FnOnce(&mut Self, Result<T::Response>, &mut Context<Self>) + 'static,
1572        cx: &mut Context<Self>,
1573    ) {
1574        const {
1575            assert!(
1576                T::CACHEABLE,
1577                "Only requests marked as cacheable should invoke `fetch`"
1578            );
1579        }
1580
1581        if !self.thread_states.any_stopped_thread()
1582            && request.type_id() != TypeId::of::<ThreadsCommand>()
1583            || self.is_session_terminated
1584        {
1585            return;
1586        }
1587
1588        let request_map = self
1589            .requests
1590            .entry(std::any::TypeId::of::<T>())
1591            .or_default();
1592
1593        if let Entry::Vacant(vacant) = request_map.entry(request.into()) {
1594            let command = vacant.key().0.clone().as_any_arc().downcast::<T>().unwrap();
1595
1596            let task = Self::request_inner::<Arc<T>>(
1597                &self.capabilities,
1598                &self.mode,
1599                command,
1600                |this, result, cx| {
1601                    process_result(this, result, cx);
1602                    None
1603                },
1604                cx,
1605            );
1606            let task = cx
1607                .background_executor()
1608                .spawn(async move {
1609                    let _ = task.await?;
1610                    Some(())
1611                })
1612                .shared();
1613
1614            vacant.insert(task);
1615            cx.notify();
1616        }
1617    }
1618
1619    fn request_inner<T: LocalDapCommand + PartialEq + Eq + Hash>(
1620        capabilities: &Capabilities,
1621        mode: &SessionState,
1622        request: T,
1623        process_result: impl FnOnce(
1624            &mut Self,
1625            Result<T::Response>,
1626            &mut Context<Self>,
1627        ) -> Option<T::Response>
1628        + 'static,
1629        cx: &mut Context<Self>,
1630    ) -> Task<Option<T::Response>> {
1631        if !T::is_supported(capabilities) {
1632            log::warn!(
1633                "Attempted to send a DAP request that isn't supported: {:?}",
1634                request
1635            );
1636            let error = Err(anyhow::Error::msg(
1637                "Couldn't complete request because it's not supported",
1638            ));
1639            return cx.spawn(async move |this, cx| {
1640                this.update(cx, |this, cx| process_result(this, error, cx))
1641                    .ok()
1642                    .flatten()
1643            });
1644        }
1645
1646        let request = mode.request_dap(request);
1647        cx.spawn(async move |this, cx| {
1648            let result = request.await;
1649            this.update(cx, |this, cx| process_result(this, result, cx))
1650                .ok()
1651                .flatten()
1652        })
1653    }
1654
1655    fn request<T: LocalDapCommand + PartialEq + Eq + Hash>(
1656        &self,
1657        request: T,
1658        process_result: impl FnOnce(
1659            &mut Self,
1660            Result<T::Response>,
1661            &mut Context<Self>,
1662        ) -> Option<T::Response>
1663        + 'static,
1664        cx: &mut Context<Self>,
1665    ) -> Task<Option<T::Response>> {
1666        Self::request_inner(&self.capabilities, &self.mode, request, process_result, cx)
1667    }
1668
1669    fn invalidate_command_type<Command: LocalDapCommand>(&mut self) {
1670        self.requests.remove(&std::any::TypeId::of::<Command>());
1671    }
1672
1673    fn invalidate_generic(&mut self) {
1674        self.invalidate_command_type::<ModulesCommand>();
1675        self.invalidate_command_type::<LoadedSourcesCommand>();
1676        self.invalidate_command_type::<ThreadsCommand>();
1677        self.invalidate_command_type::<DataBreakpointInfoCommand>();
1678        self.invalidate_command_type::<ReadMemory>();
1679        let executor = self.as_running().map(|running| running.executor.clone());
1680        if let Some(executor) = executor {
1681            self.memory.clear(&executor);
1682        }
1683    }
1684
1685    fn invalidate_state(&mut self, key: &RequestSlot) {
1686        self.requests
1687            .entry((&*key.0 as &dyn Any).type_id())
1688            .and_modify(|request_map| {
1689                request_map.remove(key);
1690            });
1691    }
1692
1693    fn push_output(&mut self, event: OutputEvent) {
1694        self.output.push_back(event);
1695        self.output_token.0 += 1;
1696    }
1697
1698    pub fn any_stopped_thread(&self) -> bool {
1699        self.thread_states.any_stopped_thread()
1700    }
1701
1702    pub fn thread_status(&self, thread_id: ThreadId) -> ThreadStatus {
1703        self.thread_states.thread_status(thread_id)
1704    }
1705
1706    pub fn threads(&mut self, cx: &mut Context<Self>) -> Vec<(dap::Thread, ThreadStatus)> {
1707        self.fetch(
1708            dap_command::ThreadsCommand,
1709            |this, result, cx| {
1710                let Some(result) = result.log_err() else {
1711                    return;
1712                };
1713
1714                this.threads = result
1715                    .into_iter()
1716                    .map(|thread| (ThreadId(thread.id), Thread::from(thread.clone())))
1717                    .collect();
1718
1719                this.invalidate_command_type::<StackTraceCommand>();
1720                cx.emit(SessionEvent::Threads);
1721                cx.notify();
1722            },
1723            cx,
1724        );
1725
1726        self.threads
1727            .values()
1728            .map(|thread| {
1729                (
1730                    thread.dap.clone(),
1731                    self.thread_states.thread_status(ThreadId(thread.dap.id)),
1732                )
1733            })
1734            .collect()
1735    }
1736
1737    pub fn modules(&mut self, cx: &mut Context<Self>) -> &[Module] {
1738        self.fetch(
1739            dap_command::ModulesCommand,
1740            |this, result, cx| {
1741                let Some(result) = result.log_err() else {
1742                    return;
1743                };
1744
1745                this.modules = result;
1746                cx.emit(SessionEvent::Modules);
1747                cx.notify();
1748            },
1749            cx,
1750        );
1751
1752        &self.modules
1753    }
1754
1755    // CodeLLDB returns the size of a pointed-to-memory, which we can use to make the experience of go-to-memory better.
1756    pub fn data_access_size(
1757        &mut self,
1758        frame_id: Option<u64>,
1759        evaluate_name: &str,
1760        cx: &mut Context<Self>,
1761    ) -> Task<Option<u64>> {
1762        let request = self.request(
1763            EvaluateCommand {
1764                expression: format!("?${{sizeof({evaluate_name})}}"),
1765                frame_id,
1766
1767                context: Some(EvaluateArgumentsContext::Repl),
1768                source: None,
1769            },
1770            |_, response, _| response.ok(),
1771            cx,
1772        );
1773        cx.background_spawn(async move {
1774            let result = request.await?;
1775            result.result.parse().ok()
1776        })
1777    }
1778
1779    pub fn memory_reference_of_expr(
1780        &mut self,
1781        frame_id: Option<u64>,
1782        expression: String,
1783        cx: &mut Context<Self>,
1784    ) -> Task<Option<(String, Option<String>)>> {
1785        let request = self.request(
1786            EvaluateCommand {
1787                expression,
1788                frame_id,
1789
1790                context: Some(EvaluateArgumentsContext::Repl),
1791                source: None,
1792            },
1793            |_, response, _| response.ok(),
1794            cx,
1795        );
1796        cx.background_spawn(async move {
1797            let result = request.await?;
1798            result
1799                .memory_reference
1800                .map(|reference| (reference, result.type_))
1801        })
1802    }
1803
1804    pub fn write_memory(&mut self, address: u64, data: &[u8], cx: &mut Context<Self>) {
1805        let data = base64::engine::general_purpose::STANDARD.encode(data);
1806        self.request(
1807            WriteMemoryArguments {
1808                memory_reference: address.to_string(),
1809                data,
1810                allow_partial: None,
1811                offset: None,
1812            },
1813            |this, response, cx| {
1814                this.memory.clear(cx.background_executor());
1815                this.invalidate_command_type::<ReadMemory>();
1816                this.invalidate_command_type::<VariablesCommand>();
1817                cx.emit(SessionEvent::Variables);
1818                response.ok()
1819            },
1820            cx,
1821        )
1822        .detach();
1823    }
1824    pub fn read_memory(
1825        &mut self,
1826        range: RangeInclusive<u64>,
1827        cx: &mut Context<Self>,
1828    ) -> MemoryIterator {
1829        // This function is a bit more involved when it comes to fetching data.
1830        // Since we attempt to read memory in pages, we need to account for some parts
1831        // of memory being unreadable. Therefore, we start off by fetching a page per request.
1832        // In case that fails, we try to re-fetch smaller regions until we have the full range.
1833        let page_range = Memory::memory_range_to_page_range(range.clone());
1834        for page_address in PageAddress::iter_range(page_range) {
1835            self.read_single_page_memory(page_address, cx);
1836        }
1837        self.memory.memory_range(range)
1838    }
1839
1840    fn read_single_page_memory(&mut self, page_start: PageAddress, cx: &mut Context<Self>) {
1841        _ = maybe!({
1842            let builder = self.memory.build_page(page_start)?;
1843
1844            self.memory_read_fetch_page_recursive(builder, cx);
1845            Some(())
1846        });
1847    }
1848    fn memory_read_fetch_page_recursive(
1849        &mut self,
1850        mut builder: MemoryPageBuilder,
1851        cx: &mut Context<Self>,
1852    ) {
1853        let Some(next_request) = builder.next_request() else {
1854            // We're done fetching. Let's grab the page and insert it into our memory store.
1855            let (address, contents) = builder.build();
1856            self.memory.insert_page(address, contents);
1857
1858            return;
1859        };
1860        let size = next_request.size;
1861        self.fetch(
1862            ReadMemory {
1863                memory_reference: format!("0x{:X}", next_request.address),
1864                offset: Some(0),
1865                count: next_request.size,
1866            },
1867            move |this, memory, cx| {
1868                if let Ok(memory) = memory {
1869                    builder.known(memory.content);
1870                    if let Some(unknown) = memory.unreadable_bytes {
1871                        builder.unknown(unknown);
1872                    }
1873                    // This is the recursive bit: if we're not yet done with
1874                    // the whole page, we'll kick off a new request with smaller range.
1875                    // Note that this function is recursive only conceptually;
1876                    // since it kicks off a new request with callback, we don't need to worry about stack overflow.
1877                    this.memory_read_fetch_page_recursive(builder, cx);
1878                } else {
1879                    builder.unknown(size);
1880                }
1881            },
1882            cx,
1883        );
1884    }
1885
1886    pub fn ignore_breakpoints(&self) -> bool {
1887        self.ignore_breakpoints
1888    }
1889
1890    pub fn toggle_ignore_breakpoints(
1891        &mut self,
1892        cx: &mut App,
1893    ) -> Task<HashMap<Arc<Path>, anyhow::Error>> {
1894        self.set_ignore_breakpoints(!self.ignore_breakpoints, cx)
1895    }
1896
1897    pub(crate) fn set_ignore_breakpoints(
1898        &mut self,
1899        ignore: bool,
1900        cx: &mut App,
1901    ) -> Task<HashMap<Arc<Path>, anyhow::Error>> {
1902        if self.ignore_breakpoints == ignore {
1903            return Task::ready(HashMap::default());
1904        }
1905
1906        self.ignore_breakpoints = ignore;
1907
1908        if let Some(local) = self.as_running() {
1909            local.send_source_breakpoints(ignore, &self.breakpoint_store, cx)
1910        } else {
1911            // todo(debugger): We need to propagate this change to downstream sessions and send a message to upstream sessions
1912            unimplemented!()
1913        }
1914    }
1915
1916    pub fn data_breakpoints(&self) -> impl Iterator<Item = &DataBreakpointState> {
1917        self.data_breakpoints.values()
1918    }
1919
1920    pub fn exception_breakpoints(
1921        &self,
1922    ) -> impl Iterator<Item = &(ExceptionBreakpointsFilter, IsEnabled)> {
1923        self.exception_breakpoints.values()
1924    }
1925
1926    pub fn toggle_exception_breakpoint(&mut self, id: &str, cx: &App) {
1927        if let Some((_, is_enabled)) = self.exception_breakpoints.get_mut(id) {
1928            *is_enabled = !*is_enabled;
1929            self.send_exception_breakpoints(cx);
1930        }
1931    }
1932
1933    fn send_exception_breakpoints(&mut self, cx: &App) {
1934        if let Some(local) = self.as_running() {
1935            let exception_filters = self
1936                .exception_breakpoints
1937                .values()
1938                .filter_map(|(filter, is_enabled)| is_enabled.then(|| filter.clone()))
1939                .collect();
1940
1941            let supports_exception_filters = self
1942                .capabilities
1943                .supports_exception_filter_options
1944                .unwrap_or_default();
1945            local
1946                .send_exception_breakpoints(exception_filters, supports_exception_filters)
1947                .detach_and_log_err(cx);
1948        } else {
1949            debug_assert!(false, "Not implemented");
1950        }
1951    }
1952
1953    pub fn toggle_data_breakpoint(&mut self, id: &str, cx: &mut Context<'_, Session>) {
1954        if let Some(state) = self.data_breakpoints.get_mut(id) {
1955            state.is_enabled = !state.is_enabled;
1956            self.send_exception_breakpoints(cx);
1957        }
1958    }
1959
1960    fn send_data_breakpoints(&mut self, cx: &mut Context<Self>) {
1961        if let Some(mode) = self.as_running() {
1962            let breakpoints = self
1963                .data_breakpoints
1964                .values()
1965                .filter_map(|state| state.is_enabled.then(|| state.dap.clone()))
1966                .collect();
1967            let command = SetDataBreakpointsCommand { breakpoints };
1968            mode.request(command).detach_and_log_err(cx);
1969        }
1970    }
1971
1972    pub fn create_data_breakpoint(
1973        &mut self,
1974        context: Arc<DataBreakpointContext>,
1975        data_id: String,
1976        dap: dap::DataBreakpoint,
1977        cx: &mut Context<Self>,
1978    ) {
1979        if self.data_breakpoints.remove(&data_id).is_none() {
1980            self.data_breakpoints.insert(
1981                data_id,
1982                DataBreakpointState {
1983                    dap,
1984                    is_enabled: true,
1985                    context,
1986                },
1987            );
1988        }
1989        self.send_data_breakpoints(cx);
1990    }
1991
1992    pub fn breakpoints_enabled(&self) -> bool {
1993        self.ignore_breakpoints
1994    }
1995
1996    pub fn loaded_sources(&mut self, cx: &mut Context<Self>) -> &[Source] {
1997        self.fetch(
1998            dap_command::LoadedSourcesCommand,
1999            |this, result, cx| {
2000                let Some(result) = result.log_err() else {
2001                    return;
2002                };
2003                this.loaded_sources = result;
2004                cx.emit(SessionEvent::LoadedSources);
2005                cx.notify();
2006            },
2007            cx,
2008        );
2009
2010        &self.loaded_sources
2011    }
2012
2013    fn fallback_to_manual_restart(
2014        &mut self,
2015        res: Result<()>,
2016        cx: &mut Context<Self>,
2017    ) -> Option<()> {
2018        if res.log_err().is_none() {
2019            cx.emit(SessionStateEvent::Restart);
2020            return None;
2021        }
2022        Some(())
2023    }
2024
2025    fn empty_response(&mut self, res: Result<()>, _cx: &mut Context<Self>) -> Option<()> {
2026        res.log_err()?;
2027        Some(())
2028    }
2029
2030    fn on_step_response<T: LocalDapCommand + PartialEq + Eq + Hash>(
2031        thread_id: ThreadId,
2032    ) -> impl FnOnce(&mut Self, Result<T::Response>, &mut Context<Self>) -> Option<T::Response> + 'static
2033    {
2034        move |this, response, cx| match response.log_err() {
2035            Some(response) => {
2036                this.breakpoint_store.update(cx, |store, cx| {
2037                    store.remove_active_position(Some(this.session_id()), cx)
2038                });
2039                Some(response)
2040            }
2041            None => {
2042                this.thread_states.stop_thread(thread_id);
2043                cx.notify();
2044                None
2045            }
2046        }
2047    }
2048
2049    fn clear_active_debug_line_response(
2050        &mut self,
2051        response: Result<()>,
2052        cx: &mut Context<Session>,
2053    ) -> Option<()> {
2054        response.log_err()?;
2055        self.clear_active_debug_line(cx);
2056        Some(())
2057    }
2058
2059    fn clear_active_debug_line(&mut self, cx: &mut Context<Session>) {
2060        self.breakpoint_store.update(cx, |store, cx| {
2061            store.remove_active_position(Some(self.id), cx)
2062        });
2063    }
2064
2065    pub fn pause_thread(&mut self, thread_id: ThreadId, cx: &mut Context<Self>) {
2066        self.request(
2067            PauseCommand {
2068                thread_id: thread_id.0,
2069            },
2070            Self::empty_response,
2071            cx,
2072        )
2073        .detach();
2074    }
2075
2076    pub fn restart_stack_frame(&mut self, stack_frame_id: u64, cx: &mut Context<Self>) {
2077        self.request(
2078            RestartStackFrameCommand { stack_frame_id },
2079            Self::empty_response,
2080            cx,
2081        )
2082        .detach();
2083    }
2084
2085    pub fn restart(&mut self, args: Option<Value>, cx: &mut Context<Self>) {
2086        if self.restart_task.is_some() || self.as_running().is_none() {
2087            return;
2088        }
2089
2090        let supports_dap_restart =
2091            self.capabilities.supports_restart_request.unwrap_or(false) && !self.is_terminated();
2092
2093        self.restart_task = Some(cx.spawn(async move |this, cx| {
2094            let _ = this.update(cx, |session, cx| {
2095                if supports_dap_restart {
2096                    session
2097                        .request(
2098                            RestartCommand {
2099                                raw: args.unwrap_or(Value::Null),
2100                            },
2101                            Self::fallback_to_manual_restart,
2102                            cx,
2103                        )
2104                        .detach();
2105                } else {
2106                    cx.emit(SessionStateEvent::Restart);
2107                }
2108            });
2109        }));
2110    }
2111
2112    pub fn shutdown(&mut self, cx: &mut Context<Self>) -> Task<()> {
2113        if self.is_session_terminated {
2114            return Task::ready(());
2115        }
2116
2117        self.is_session_terminated = true;
2118        self.thread_states.exit_all_threads();
2119        cx.notify();
2120
2121        let task = match &mut self.mode {
2122            SessionState::Running(_) => {
2123                if self
2124                    .capabilities
2125                    .supports_terminate_request
2126                    .unwrap_or_default()
2127                {
2128                    self.request(
2129                        TerminateCommand {
2130                            restart: Some(false),
2131                        },
2132                        Self::clear_active_debug_line_response,
2133                        cx,
2134                    )
2135                } else {
2136                    self.request(
2137                        DisconnectCommand {
2138                            restart: Some(false),
2139                            terminate_debuggee: Some(true),
2140                            suspend_debuggee: Some(false),
2141                        },
2142                        Self::clear_active_debug_line_response,
2143                        cx,
2144                    )
2145                }
2146            }
2147            SessionState::Booting(build_task) => {
2148                build_task.take();
2149                Task::ready(Some(()))
2150            }
2151        };
2152
2153        cx.emit(SessionStateEvent::Shutdown);
2154
2155        cx.spawn(async move |this, cx| {
2156            task.await;
2157            let _ = this.update(cx, |this, _| {
2158                if let Some(adapter_client) = this.adapter_client() {
2159                    adapter_client.kill();
2160                }
2161            });
2162        })
2163    }
2164
2165    pub fn completions(
2166        &mut self,
2167        query: CompletionsQuery,
2168        cx: &mut Context<Self>,
2169    ) -> Task<Result<Vec<dap::CompletionItem>>> {
2170        let task = self.request(query, |_, result, _| result.log_err(), cx);
2171
2172        cx.background_executor().spawn(async move {
2173            anyhow::Ok(
2174                task.await
2175                    .map(|response| response.targets)
2176                    .context("failed to fetch completions")?,
2177            )
2178        })
2179    }
2180
2181    pub fn continue_thread(&mut self, thread_id: ThreadId, cx: &mut Context<Self>) {
2182        let supports_single_thread_execution_requests =
2183            self.capabilities.supports_single_thread_execution_requests;
2184        self.thread_states.continue_thread(thread_id);
2185        self.request(
2186            ContinueCommand {
2187                args: ContinueArguments {
2188                    thread_id: thread_id.0,
2189                    single_thread: supports_single_thread_execution_requests,
2190                },
2191            },
2192            Self::on_step_response::<ContinueCommand>(thread_id),
2193            cx,
2194        )
2195        .detach();
2196    }
2197
2198    pub fn adapter_client(&self) -> Option<Arc<DebugAdapterClient>> {
2199        match self.mode {
2200            SessionState::Running(ref local) => Some(local.client.clone()),
2201            SessionState::Booting(_) => None,
2202        }
2203    }
2204
2205    pub fn has_ever_stopped(&self) -> bool {
2206        self.mode.has_ever_stopped()
2207    }
2208    pub fn step_over(
2209        &mut self,
2210        thread_id: ThreadId,
2211        granularity: SteppingGranularity,
2212        cx: &mut Context<Self>,
2213    ) {
2214        let supports_single_thread_execution_requests =
2215            self.capabilities.supports_single_thread_execution_requests;
2216        let supports_stepping_granularity = self
2217            .capabilities
2218            .supports_stepping_granularity
2219            .unwrap_or_default();
2220
2221        let command = NextCommand {
2222            inner: StepCommand {
2223                thread_id: thread_id.0,
2224                granularity: supports_stepping_granularity.then(|| granularity),
2225                single_thread: supports_single_thread_execution_requests,
2226            },
2227        };
2228
2229        self.thread_states.process_step(thread_id);
2230        self.request(
2231            command,
2232            Self::on_step_response::<NextCommand>(thread_id),
2233            cx,
2234        )
2235        .detach();
2236    }
2237
2238    pub fn step_in(
2239        &mut self,
2240        thread_id: ThreadId,
2241        granularity: SteppingGranularity,
2242        cx: &mut Context<Self>,
2243    ) {
2244        let supports_single_thread_execution_requests =
2245            self.capabilities.supports_single_thread_execution_requests;
2246        let supports_stepping_granularity = self
2247            .capabilities
2248            .supports_stepping_granularity
2249            .unwrap_or_default();
2250
2251        let command = StepInCommand {
2252            inner: StepCommand {
2253                thread_id: thread_id.0,
2254                granularity: supports_stepping_granularity.then(|| granularity),
2255                single_thread: supports_single_thread_execution_requests,
2256            },
2257        };
2258
2259        self.thread_states.process_step(thread_id);
2260        self.request(
2261            command,
2262            Self::on_step_response::<StepInCommand>(thread_id),
2263            cx,
2264        )
2265        .detach();
2266    }
2267
2268    pub fn step_out(
2269        &mut self,
2270        thread_id: ThreadId,
2271        granularity: SteppingGranularity,
2272        cx: &mut Context<Self>,
2273    ) {
2274        let supports_single_thread_execution_requests =
2275            self.capabilities.supports_single_thread_execution_requests;
2276        let supports_stepping_granularity = self
2277            .capabilities
2278            .supports_stepping_granularity
2279            .unwrap_or_default();
2280
2281        let command = StepOutCommand {
2282            inner: StepCommand {
2283                thread_id: thread_id.0,
2284                granularity: supports_stepping_granularity.then(|| granularity),
2285                single_thread: supports_single_thread_execution_requests,
2286            },
2287        };
2288
2289        self.thread_states.process_step(thread_id);
2290        self.request(
2291            command,
2292            Self::on_step_response::<StepOutCommand>(thread_id),
2293            cx,
2294        )
2295        .detach();
2296    }
2297
2298    pub fn step_back(
2299        &mut self,
2300        thread_id: ThreadId,
2301        granularity: SteppingGranularity,
2302        cx: &mut Context<Self>,
2303    ) {
2304        let supports_single_thread_execution_requests =
2305            self.capabilities.supports_single_thread_execution_requests;
2306        let supports_stepping_granularity = self
2307            .capabilities
2308            .supports_stepping_granularity
2309            .unwrap_or_default();
2310
2311        let command = StepBackCommand {
2312            inner: StepCommand {
2313                thread_id: thread_id.0,
2314                granularity: supports_stepping_granularity.then(|| granularity),
2315                single_thread: supports_single_thread_execution_requests,
2316            },
2317        };
2318
2319        self.thread_states.process_step(thread_id);
2320
2321        self.request(
2322            command,
2323            Self::on_step_response::<StepBackCommand>(thread_id),
2324            cx,
2325        )
2326        .detach();
2327    }
2328
2329    pub fn stack_frames(
2330        &mut self,
2331        thread_id: ThreadId,
2332        cx: &mut Context<Self>,
2333    ) -> Result<Vec<StackFrame>> {
2334        if self.thread_states.thread_status(thread_id) == ThreadStatus::Stopped
2335            && self.requests.contains_key(&ThreadsCommand.type_id())
2336            && self.threads.contains_key(&thread_id)
2337        // ^ todo(debugger): We need a better way to check that we're not querying stale data
2338        // We could still be using an old thread id and have sent a new thread's request
2339        // This isn't the biggest concern right now because it hasn't caused any issues outside of tests
2340        // But it very well could cause a minor bug in the future that is hard to track down
2341        {
2342            self.fetch(
2343                super::dap_command::StackTraceCommand {
2344                    thread_id: thread_id.0,
2345                    start_frame: None,
2346                    levels: None,
2347                },
2348                move |this, stack_frames, cx| {
2349                    let entry =
2350                        this.threads
2351                            .entry(thread_id)
2352                            .and_modify(|thread| match &stack_frames {
2353                                Ok(stack_frames) => {
2354                                    thread.stack_frames = stack_frames
2355                                        .iter()
2356                                        .cloned()
2357                                        .map(StackFrame::from)
2358                                        .collect();
2359                                    thread.stack_frames_error = None;
2360                                }
2361                                Err(error) => {
2362                                    thread.stack_frames.clear();
2363                                    thread.stack_frames_error = Some(error.cloned());
2364                                }
2365                            });
2366                    debug_assert!(
2367                        matches!(entry, indexmap::map::Entry::Occupied(_)),
2368                        "Sent request for thread_id that doesn't exist"
2369                    );
2370                    if let Ok(stack_frames) = stack_frames {
2371                        this.stack_frames.extend(
2372                            stack_frames
2373                                .into_iter()
2374                                .filter(|frame| {
2375                                    // Workaround for JavaScript debug adapter sending out "fake" stack frames for delineating await points. This is fine,
2376                                    // except that they always use an id of 0 for it, which collides with other (valid) stack frames.
2377                                    !(frame.id == 0
2378                                        && frame.line == 0
2379                                        && frame.column == 0
2380                                        && frame.presentation_hint
2381                                            == Some(StackFramePresentationHint::Label))
2382                                })
2383                                .map(|frame| (frame.id, StackFrame::from(frame))),
2384                        );
2385                    }
2386
2387                    this.invalidate_command_type::<ScopesCommand>();
2388                    this.invalidate_command_type::<VariablesCommand>();
2389
2390                    cx.emit(SessionEvent::StackTrace);
2391                },
2392                cx,
2393            );
2394        }
2395
2396        match self.threads.get(&thread_id) {
2397            Some(thread) => {
2398                if let Some(error) = &thread.stack_frames_error {
2399                    Err(error.cloned())
2400                } else {
2401                    Ok(thread.stack_frames.clone())
2402                }
2403            }
2404            None => Ok(Vec::new()),
2405        }
2406    }
2407
2408    pub fn scopes(&mut self, stack_frame_id: u64, cx: &mut Context<Self>) -> &[dap::Scope] {
2409        if self.requests.contains_key(&TypeId::of::<ThreadsCommand>())
2410            && self
2411                .requests
2412                .contains_key(&TypeId::of::<StackTraceCommand>())
2413        {
2414            self.fetch(
2415                ScopesCommand { stack_frame_id },
2416                move |this, scopes, cx| {
2417                    let Some(scopes) = scopes.log_err() else {
2418                        return
2419                    };
2420
2421                    for scope in scopes.iter() {
2422                        this.variables(scope.variables_reference, cx);
2423                    }
2424
2425                    let entry = this
2426                        .stack_frames
2427                        .entry(stack_frame_id)
2428                        .and_modify(|stack_frame| {
2429                            stack_frame.scopes = scopes;
2430                        });
2431
2432                    cx.emit(SessionEvent::Variables);
2433
2434                    debug_assert!(
2435                        matches!(entry, indexmap::map::Entry::Occupied(_)),
2436                        "Sent scopes request for stack_frame_id that doesn't exist or hasn't been fetched"
2437                    );
2438                },
2439                cx,
2440            );
2441        }
2442
2443        self.stack_frames
2444            .get(&stack_frame_id)
2445            .map(|frame| frame.scopes.as_slice())
2446            .unwrap_or_default()
2447    }
2448
2449    pub fn variables_by_stack_frame_id(
2450        &self,
2451        stack_frame_id: StackFrameId,
2452        globals: bool,
2453        locals: bool,
2454    ) -> Vec<dap::Variable> {
2455        let Some(stack_frame) = self.stack_frames.get(&stack_frame_id) else {
2456            return Vec::new();
2457        };
2458
2459        stack_frame
2460            .scopes
2461            .iter()
2462            .filter(|scope| {
2463                (scope.name.to_lowercase().contains("local") && locals)
2464                    || (scope.name.to_lowercase().contains("global") && globals)
2465            })
2466            .filter_map(|scope| self.variables.get(&scope.variables_reference))
2467            .flatten()
2468            .cloned()
2469            .collect()
2470    }
2471
2472    pub fn watchers(&self) -> &HashMap<SharedString, Watcher> {
2473        &self.watchers
2474    }
2475
2476    pub fn add_watcher(
2477        &mut self,
2478        expression: SharedString,
2479        frame_id: u64,
2480        cx: &mut Context<Self>,
2481    ) -> Task<Result<()>> {
2482        let request = self.mode.request_dap(EvaluateCommand {
2483            expression: expression.to_string(),
2484            context: Some(EvaluateArgumentsContext::Watch),
2485            frame_id: Some(frame_id),
2486            source: None,
2487        });
2488
2489        cx.spawn(async move |this, cx| {
2490            let response = request.await?;
2491
2492            this.update(cx, |session, cx| {
2493                session.watchers.insert(
2494                    expression.clone(),
2495                    Watcher {
2496                        expression,
2497                        value: response.result.into(),
2498                        variables_reference: response.variables_reference,
2499                        presentation_hint: response.presentation_hint,
2500                    },
2501                );
2502                cx.emit(SessionEvent::Watchers);
2503            })
2504        })
2505    }
2506
2507    pub fn refresh_watchers(&mut self, frame_id: u64, cx: &mut Context<Self>) {
2508        let watches = self.watchers.clone();
2509        for (_, watch) in watches.into_iter() {
2510            self.add_watcher(watch.expression.clone(), frame_id, cx)
2511                .detach();
2512        }
2513    }
2514
2515    pub fn remove_watcher(&mut self, expression: SharedString) {
2516        self.watchers.remove(&expression);
2517    }
2518
2519    pub fn variables(
2520        &mut self,
2521        variables_reference: VariableReference,
2522        cx: &mut Context<Self>,
2523    ) -> Vec<dap::Variable> {
2524        let command = VariablesCommand {
2525            variables_reference,
2526            filter: None,
2527            start: None,
2528            count: None,
2529            format: None,
2530        };
2531
2532        self.fetch(
2533            command,
2534            move |this, variables, cx| {
2535                let Some(variables) = variables.log_err() else {
2536                    return;
2537                };
2538
2539                this.variables.insert(variables_reference, variables);
2540
2541                cx.emit(SessionEvent::Variables);
2542                cx.emit(SessionEvent::InvalidateInlineValue);
2543            },
2544            cx,
2545        );
2546
2547        self.variables
2548            .get(&variables_reference)
2549            .cloned()
2550            .unwrap_or_default()
2551    }
2552
2553    pub fn data_breakpoint_info(
2554        &mut self,
2555        context: Arc<DataBreakpointContext>,
2556        mode: Option<String>,
2557        cx: &mut Context<Self>,
2558    ) -> Task<Option<dap::DataBreakpointInfoResponse>> {
2559        let command = DataBreakpointInfoCommand {
2560            context: context.clone(),
2561            mode,
2562        };
2563
2564        self.request(command, |_, response, _| response.ok(), cx)
2565    }
2566
2567    pub fn set_variable_value(
2568        &mut self,
2569        stack_frame_id: u64,
2570        variables_reference: u64,
2571        name: String,
2572        value: String,
2573        cx: &mut Context<Self>,
2574    ) {
2575        if self.capabilities.supports_set_variable.unwrap_or_default() {
2576            self.request(
2577                SetVariableValueCommand {
2578                    name,
2579                    value,
2580                    variables_reference,
2581                },
2582                move |this, response, cx| {
2583                    let response = response.log_err()?;
2584                    this.invalidate_command_type::<VariablesCommand>();
2585                    this.invalidate_command_type::<ReadMemory>();
2586                    this.memory.clear(cx.background_executor());
2587                    this.refresh_watchers(stack_frame_id, cx);
2588                    cx.emit(SessionEvent::Variables);
2589                    Some(response)
2590                },
2591                cx,
2592            )
2593            .detach();
2594        }
2595    }
2596
2597    pub fn evaluate(
2598        &mut self,
2599        expression: String,
2600        context: Option<EvaluateArgumentsContext>,
2601        frame_id: Option<u64>,
2602        source: Option<Source>,
2603        cx: &mut Context<Self>,
2604    ) -> Task<()> {
2605        let event = dap::OutputEvent {
2606            category: None,
2607            output: format!("> {expression}"),
2608            group: None,
2609            variables_reference: None,
2610            source: None,
2611            line: None,
2612            column: None,
2613            data: None,
2614            location_reference: None,
2615        };
2616        self.push_output(event);
2617        let request = self.mode.request_dap(EvaluateCommand {
2618            expression,
2619            context,
2620            frame_id,
2621            source,
2622        });
2623        cx.spawn(async move |this, cx| {
2624            let response = request.await;
2625            this.update(cx, |this, cx| {
2626                this.memory.clear(cx.background_executor());
2627                this.invalidate_command_type::<ReadMemory>();
2628                match response {
2629                    Ok(response) => {
2630                        let event = dap::OutputEvent {
2631                            category: None,
2632                            output: format!("< {}", &response.result),
2633                            group: None,
2634                            variables_reference: Some(response.variables_reference),
2635                            source: None,
2636                            line: None,
2637                            column: None,
2638                            data: None,
2639                            location_reference: None,
2640                        };
2641                        this.push_output(event);
2642                    }
2643                    Err(e) => {
2644                        let event = dap::OutputEvent {
2645                            category: None,
2646                            output: format!("{}", e),
2647                            group: None,
2648                            variables_reference: None,
2649                            source: None,
2650                            line: None,
2651                            column: None,
2652                            data: None,
2653                            location_reference: None,
2654                        };
2655                        this.push_output(event);
2656                    }
2657                };
2658                cx.notify();
2659            })
2660            .ok();
2661        })
2662    }
2663
2664    pub fn location(
2665        &mut self,
2666        reference: u64,
2667        cx: &mut Context<Self>,
2668    ) -> Option<dap::LocationsResponse> {
2669        self.fetch(
2670            LocationsCommand { reference },
2671            move |this, response, _| {
2672                let Some(response) = response.log_err() else {
2673                    return;
2674                };
2675                this.locations.insert(reference, response);
2676            },
2677            cx,
2678        );
2679        self.locations.get(&reference).cloned()
2680    }
2681
2682    pub fn is_attached(&self) -> bool {
2683        let SessionState::Running(local_mode) = &self.mode else {
2684            return false;
2685        };
2686        local_mode.binary.request_args.request == StartDebuggingRequestArgumentsRequest::Attach
2687    }
2688
2689    pub fn disconnect_client(&mut self, cx: &mut Context<Self>) {
2690        let command = DisconnectCommand {
2691            restart: Some(false),
2692            terminate_debuggee: Some(false),
2693            suspend_debuggee: Some(false),
2694        };
2695
2696        self.request(command, Self::empty_response, cx).detach()
2697    }
2698
2699    pub fn terminate_threads(&mut self, thread_ids: Option<Vec<ThreadId>>, cx: &mut Context<Self>) {
2700        if self
2701            .capabilities
2702            .supports_terminate_threads_request
2703            .unwrap_or_default()
2704        {
2705            self.request(
2706                TerminateThreadsCommand {
2707                    thread_ids: thread_ids.map(|ids| ids.into_iter().map(|id| id.0).collect()),
2708                },
2709                Self::clear_active_debug_line_response,
2710                cx,
2711            )
2712            .detach();
2713        } else {
2714            self.shutdown(cx).detach();
2715        }
2716    }
2717
2718    pub fn thread_state(&self, thread_id: ThreadId) -> Option<ThreadStatus> {
2719        self.thread_states.thread_state(thread_id)
2720    }
2721
2722    pub fn quirks(&self) -> SessionQuirks {
2723        self.quirks
2724    }
2725}