debugger: Make historic snapshot button a dropdown menu (#44307)
This allows users to select any snapshot in the debugger history feature and go back to the active session snapshot. We also change variable names to use hsitoric snapshot instead of history and move the snapshot icon to the back of the debugger top control strip. https://github.com/user-attachments/assets/805de8d0-30c1-4719-8af7-2d47e1df1da4 Release Notes: - N/A Co-authored-by: Anthony Eid <hello@anthonyeid.me>
This commit is contained in:
co-authored by
Anthony Eid
parent
4577e1bf8f
commit
ef76f07b1e
@@ -17,9 +17,9 @@ use dap::{client::SessionId, debugger_settings::DebuggerSettings};
|
||||
use editor::{Editor, MultiBufferOffset, ToPoint};
|
||||
use feature_flags::{FeatureFlag, FeatureFlagAppExt as _};
|
||||
use gpui::{
|
||||
Action, App, AsyncWindowContext, ClipboardItem, Context, DismissEvent, Entity, EntityId,
|
||||
EventEmitter, FocusHandle, Focusable, MouseButton, MouseDownEvent, Point, Subscription, Task,
|
||||
WeakEntity, anchored, deferred,
|
||||
Action, App, AsyncWindowContext, ClipboardItem, Context, Corner, DismissEvent, Entity,
|
||||
EntityId, EventEmitter, FocusHandle, Focusable, MouseButton, MouseDownEvent, Point,
|
||||
Subscription, Task, WeakEntity, anchored, deferred,
|
||||
};
|
||||
|
||||
use itertools::Itertools as _;
|
||||
@@ -32,7 +32,9 @@ use settings::Settings;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
use task::{DebugScenario, TaskContext};
|
||||
use tree_sitter::{Query, StreamingIterator as _};
|
||||
use ui::{ContextMenu, Divider, PopoverMenuHandle, Tab, Tooltip, prelude::*};
|
||||
use ui::{
|
||||
ContextMenu, Divider, PopoverMenu, PopoverMenuHandle, SplitButton, Tab, Tooltip, prelude::*,
|
||||
};
|
||||
use util::rel_path::RelPath;
|
||||
use util::{ResultExt, debug_panic, maybe};
|
||||
use workspace::SplitDirection;
|
||||
@@ -669,6 +671,12 @@ impl DebugPanel {
|
||||
)
|
||||
};
|
||||
|
||||
let thread_status = active_session
|
||||
.as_ref()
|
||||
.map(|session| session.read(cx).running_state())
|
||||
.and_then(|state| state.read(cx).thread_status(cx))
|
||||
.unwrap_or(project::debugger::session::ThreadStatus::Exited);
|
||||
|
||||
Some(
|
||||
div.w_full()
|
||||
.py_1()
|
||||
@@ -686,10 +694,6 @@ impl DebugPanel {
|
||||
.as_ref()
|
||||
.map(|session| session.read(cx).running_state()),
|
||||
|this, running_state| {
|
||||
let thread_status =
|
||||
running_state.read(cx).thread_status(cx).unwrap_or(
|
||||
project::debugger::session::ThreadStatus::Exited,
|
||||
);
|
||||
let capabilities = running_state.read(cx).capabilities(cx);
|
||||
let supports_detach =
|
||||
running_state.read(cx).session().read(cx).is_attached();
|
||||
@@ -812,34 +816,6 @@ impl DebugPanel {
|
||||
}
|
||||
}),
|
||||
)
|
||||
.when(cx.has_flag::<DebuggerHistoryFeatureFlag>(), |this| {
|
||||
this.child(
|
||||
IconButton::new(
|
||||
"debug-back-in-history",
|
||||
IconName::HistoryRerun,
|
||||
)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(
|
||||
window.listener_for(
|
||||
running_state,
|
||||
|this, _, _window, cx| {
|
||||
this.session().update(cx, |session, cx| {
|
||||
let ix = session
|
||||
.active_history()
|
||||
.unwrap_or_else(|| {
|
||||
session.history().len()
|
||||
});
|
||||
|
||||
session.go_back_to_history(
|
||||
Some(ix.saturating_sub(1)),
|
||||
cx,
|
||||
);
|
||||
})
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
.child(Divider::vertical())
|
||||
.child(
|
||||
IconButton::new("debug-restart", IconName::RotateCcw)
|
||||
@@ -906,36 +882,53 @@ impl DebugPanel {
|
||||
}
|
||||
}),
|
||||
)
|
||||
.when(supports_detach, |div| {
|
||||
div.child(
|
||||
IconButton::new(
|
||||
"debug-disconnect",
|
||||
IconName::DebugDetach,
|
||||
)
|
||||
.disabled(
|
||||
thread_status != ThreadStatus::Stopped
|
||||
&& thread_status != ThreadStatus::Running,
|
||||
)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
running_state,
|
||||
|this, _, _, cx| {
|
||||
this.detach_client(cx);
|
||||
},
|
||||
))
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |_window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Detach",
|
||||
&Detach,
|
||||
&focus_handle,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
.when(
|
||||
supports_detach,
|
||||
|div| {
|
||||
div.child(
|
||||
IconButton::new(
|
||||
"debug-disconnect",
|
||||
IconName::DebugDetach,
|
||||
cx.has_flag::<DebuggerHistoryFeatureFlag>(),
|
||||
|this| {
|
||||
this.child(Divider::vertical()).child(
|
||||
SplitButton::new(
|
||||
self.render_history_button(
|
||||
&running_state,
|
||||
thread_status,
|
||||
window,
|
||||
),
|
||||
self.render_history_toggle_button(
|
||||
thread_status,
|
||||
&running_state,
|
||||
)
|
||||
.into_any_element(),
|
||||
)
|
||||
.disabled(
|
||||
thread_status != ThreadStatus::Stopped
|
||||
&& thread_status != ThreadStatus::Running,
|
||||
)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(
|
||||
running_state,
|
||||
|this, _, _, cx| {
|
||||
this.detach_client(cx);
|
||||
},
|
||||
))
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |_window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Detach",
|
||||
&Detach,
|
||||
&focus_handle,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}),
|
||||
.style(ui::SplitButtonStyle::Outlined),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -1352,6 +1345,97 @@ impl DebugPanel {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn render_history_button(
|
||||
&self,
|
||||
running_state: &Entity<RunningState>,
|
||||
thread_status: ThreadStatus,
|
||||
window: &mut Window,
|
||||
) -> IconButton {
|
||||
IconButton::new("debug-back-in-history", IconName::HistoryRerun)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(window.listener_for(running_state, |this, _, _window, cx| {
|
||||
this.session().update(cx, |session, cx| {
|
||||
let ix = session
|
||||
.active_snapshot_index()
|
||||
.unwrap_or_else(|| session.historic_snapshots().len());
|
||||
|
||||
session.select_historic_snapshot(Some(ix.saturating_sub(1)), cx);
|
||||
})
|
||||
}))
|
||||
.disabled(
|
||||
thread_status == ThreadStatus::Running || thread_status == ThreadStatus::Stepping,
|
||||
)
|
||||
}
|
||||
|
||||
fn render_history_toggle_button(
|
||||
&self,
|
||||
thread_status: ThreadStatus,
|
||||
running_state: &Entity<RunningState>,
|
||||
) -> impl IntoElement {
|
||||
PopoverMenu::new("debug-back-in-history-menu")
|
||||
.trigger(
|
||||
ui::ButtonLike::new_rounded_right("debug-back-in-history-menu-trigger")
|
||||
.layer(ui::ElevationIndex::ModalSurface)
|
||||
.size(ui::ButtonSize::None)
|
||||
.child(
|
||||
div()
|
||||
.px_1()
|
||||
.child(Icon::new(IconName::ChevronDown).size(IconSize::XSmall)),
|
||||
)
|
||||
.disabled(
|
||||
thread_status == ThreadStatus::Running
|
||||
|| thread_status == ThreadStatus::Stepping,
|
||||
),
|
||||
)
|
||||
.menu({
|
||||
let running_state = running_state.clone();
|
||||
move |window, cx| {
|
||||
let handler =
|
||||
|ix: Option<usize>, running_state: Entity<RunningState>, cx: &mut App| {
|
||||
running_state.update(cx, |state, cx| {
|
||||
state.session().update(cx, |session, cx| {
|
||||
session.select_historic_snapshot(ix, cx);
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
let running_state = running_state.clone();
|
||||
Some(ContextMenu::build(
|
||||
window,
|
||||
cx,
|
||||
move |mut context_menu, _window, cx| {
|
||||
let history = running_state
|
||||
.read(cx)
|
||||
.session()
|
||||
.read(cx)
|
||||
.historic_snapshots();
|
||||
|
||||
context_menu = context_menu.entry("Current State", None, {
|
||||
let running_state = running_state.clone();
|
||||
move |_window, cx| {
|
||||
handler(None, running_state.clone(), cx);
|
||||
}
|
||||
});
|
||||
context_menu = context_menu.separator();
|
||||
|
||||
for (ix, _) in history.iter().enumerate().rev() {
|
||||
context_menu =
|
||||
context_menu.entry(format!("history-{}", ix + 1), None, {
|
||||
let running_state = running_state.clone();
|
||||
move |_window, cx| {
|
||||
handler(Some(ix), running_state.clone(), cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
context_menu
|
||||
},
|
||||
))
|
||||
}
|
||||
})
|
||||
.anchor(Corner::TopRight)
|
||||
}
|
||||
}
|
||||
|
||||
async fn register_session_inner(
|
||||
|
||||
@@ -227,7 +227,6 @@ impl StackFrameList {
|
||||
}
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
this.build_entries(select_first, window, cx);
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user