debugger: Get stack frame list working with historic snapshot feature (#44303)

Remco Smits and Anthony Eid created

This PR fixes an issue where the stack frame list would not update when
viewing a historic snapshot.
We now also show the right active debug line based on the currently
selected history.


https://github.com/user-attachments/assets/baccd078-23ed-4db3-9959-f83dc2be8309

Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>

Change summary

crates/debugger_ui/src/session/running/loaded_source_list.rs |  4 
crates/debugger_ui/src/session/running/module_list.rs        |  4 
crates/debugger_ui/src/session/running/stack_frame_list.rs   |  4 
crates/debugger_ui/src/session/running/variable_list.rs      |  7 +
crates/project/src/debugger/session.rs                       | 19 ++---
5 files changed, 22 insertions(+), 16 deletions(-)

Detailed changes

crates/debugger_ui/src/session/running/loaded_source_list.rs 🔗

@@ -17,7 +17,9 @@ impl LoadedSourceList {
         let list = ListState::new(0, gpui::ListAlignment::Top, px(1000.));
 
         let _subscription = cx.subscribe(&session, |this, _, event, cx| match event {
-            SessionEvent::Stopped(_) | SessionEvent::LoadedSources => {
+            SessionEvent::Stopped(_)
+            | SessionEvent::HistoricSnapshotSelected
+            | SessionEvent::LoadedSources => {
                 this.invalidate = true;
                 cx.notify();
             }

crates/debugger_ui/src/session/running/module_list.rs 🔗

@@ -32,7 +32,9 @@ impl ModuleList {
         let focus_handle = cx.focus_handle();
 
         let _subscription = cx.subscribe(&session, |this, _, event, cx| match event {
-            SessionEvent::Stopped(_) | SessionEvent::Modules => {
+            SessionEvent::Stopped(_)
+            | SessionEvent::HistoricSnapshotSelected
+            | SessionEvent::Modules => {
                 if this._rebuild_task.is_some() {
                     this.schedule_rebuild(cx);
                 }

crates/debugger_ui/src/session/running/stack_frame_list.rs 🔗

@@ -97,7 +97,9 @@ impl StackFrameList {
                 SessionEvent::Threads => {
                     this.schedule_refresh(false, window, cx);
                 }
-                SessionEvent::Stopped(..) | SessionEvent::StackTrace => {
+                SessionEvent::Stopped(..)
+                | SessionEvent::StackTrace
+                | SessionEvent::HistoricSnapshotSelected => {
                     this.schedule_refresh(true, window, cx);
                 }
                 _ => {}

crates/debugger_ui/src/session/running/variable_list.rs 🔗

@@ -217,6 +217,12 @@ impl VariableList {
         let _subscriptions = vec![
             cx.subscribe(&stack_frame_list, Self::handle_stack_frame_list_events),
             cx.subscribe(&session, |this, _, event, cx| match event {
+                SessionEvent::HistoricSnapshotSelected => {
+                    this.selection.take();
+                    this.edited_path.take();
+                    this.selected_stack_frame_id.take();
+                    this.build_entries(cx);
+                }
                 SessionEvent::Stopped(_) => {
                     this.selection.take();
                     this.edited_path.take();
@@ -225,7 +231,6 @@ impl VariableList {
                 SessionEvent::Variables | SessionEvent::Watchers => {
                     this.build_entries(cx);
                 }
-
                 _ => {}
             }),
             cx.on_focus_out(&focus_handle, window, |this, _, _, cx| {

crates/project/src/debugger/session.rs 🔗

@@ -808,6 +808,7 @@ pub enum SessionEvent {
     },
     DataBreakpointInfo,
     ConsoleOutput,
+    HistoricSnapshotSelected,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -1447,7 +1448,7 @@ impl Session {
         self.selected_snapshot_index = ix;
 
         if ix.is_some() {
-            cx.emit(SessionEvent::Stopped(None));
+            cx.emit(SessionEvent::HistoricSnapshotSelected);
         }
 
         cx.notify();
@@ -1668,16 +1669,10 @@ impl Session {
             );
         }
 
-        if self.selected_snapshot_index.is_some() {
-            return;
-        }
-
-        if self.is_session_terminated {
-            return;
-        }
-
-        if !self.active_snapshot.thread_states.any_stopped_thread()
-            && request.type_id() != TypeId::of::<ThreadsCommand>()
+        if (!self.active_snapshot.thread_states.any_stopped_thread()
+            && request.type_id() != TypeId::of::<ThreadsCommand>())
+            || self.selected_snapshot_index.is_some()
+            || self.is_session_terminated
         {
             return;
         }
@@ -2505,7 +2500,7 @@ impl Session {
             );
         }
 
-        match self.active_snapshot.threads.get(&thread_id) {
+        match self.session_state().threads.get(&thread_id) {
             Some(thread) => {
                 if let Some(error) = &thread.stack_frames_error {
                     Err(anyhow!(error.to_string()))