Debugger UI: Dynamic session contents (#28033)
Closes #ISSUE Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
parent
fdaf2a27bf
commit
22b937f27f
14 changed files with 663 additions and 537 deletions
|
@ -30,9 +30,8 @@ use task::DebugTaskDefinition;
|
|||
use terminal_view::terminal_panel::TerminalPanel;
|
||||
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
||||
use workspace::{
|
||||
Pane, Workspace,
|
||||
Workspace,
|
||||
dock::{DockPosition, Panel, PanelEvent},
|
||||
pane,
|
||||
};
|
||||
|
||||
pub enum DebugPanelEvent {
|
||||
|
@ -55,11 +54,13 @@ pub enum DebugPanelEvent {
|
|||
actions!(debug_panel, [ToggleFocus]);
|
||||
pub struct DebugPanel {
|
||||
size: Pixels,
|
||||
pane: Entity<Pane>,
|
||||
sessions: Vec<Entity<DebugSession>>,
|
||||
active_session: Option<Entity<DebugSession>>,
|
||||
/// This represents the last debug definition that was created in the new session modal
|
||||
pub(crate) past_debug_definition: Option<DebugTaskDefinition>,
|
||||
project: WeakEntity<Project>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
focus_handle: FocusHandle,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
|
@ -72,36 +73,17 @@ impl DebugPanel {
|
|||
cx.new(|cx| {
|
||||
let project = workspace.project().clone();
|
||||
let dap_store = project.read(cx).dap_store();
|
||||
let pane = cx.new(|cx| {
|
||||
let mut pane = Pane::new(
|
||||
workspace.weak_handle(),
|
||||
project.clone(),
|
||||
Default::default(),
|
||||
None,
|
||||
gpui::NoAction.boxed_clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
pane.set_can_split(None);
|
||||
pane.set_can_navigate(true, cx);
|
||||
pane.display_nav_history_buttons(None);
|
||||
pane.set_should_display_tab_bar(|_window, _cx| false);
|
||||
pane.set_close_pane_if_empty(true, cx);
|
||||
|
||||
pane
|
||||
});
|
||||
|
||||
let _subscriptions = vec![
|
||||
cx.observe(&pane, |_, _, cx| cx.notify()),
|
||||
cx.subscribe_in(&pane, window, Self::handle_pane_event),
|
||||
cx.subscribe_in(&dap_store, window, Self::handle_dap_store_event),
|
||||
];
|
||||
let _subscriptions =
|
||||
vec![cx.subscribe_in(&dap_store, window, Self::handle_dap_store_event)];
|
||||
|
||||
let debug_panel = Self {
|
||||
pane,
|
||||
size: px(300.),
|
||||
sessions: vec![],
|
||||
active_session: None,
|
||||
_subscriptions,
|
||||
past_debug_definition: None,
|
||||
focus_handle: cx.focus_handle(),
|
||||
project: project.downgrade(),
|
||||
workspace: workspace.weak_handle(),
|
||||
};
|
||||
|
@ -130,7 +112,7 @@ impl DebugPanel {
|
|||
cx.observe(&debug_panel, |_, debug_panel, cx| {
|
||||
let (has_active_session, supports_restart, support_step_back) = debug_panel
|
||||
.update(cx, |this, cx| {
|
||||
this.active_session(cx)
|
||||
this.active_session()
|
||||
.map(|item| {
|
||||
let running = item.read(cx).mode().as_running().cloned();
|
||||
|
||||
|
@ -192,11 +174,8 @@ impl DebugPanel {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn active_session(&self, cx: &App) -> Option<Entity<DebugSession>> {
|
||||
self.pane
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.and_then(|panel| panel.downcast::<DebugSession>())
|
||||
pub fn active_session(&self) -> Option<Entity<DebugSession>> {
|
||||
self.active_session.clone()
|
||||
}
|
||||
|
||||
pub fn debug_panel_items_by_client(
|
||||
|
@ -204,10 +183,8 @@ impl DebugPanel {
|
|||
client_id: &SessionId,
|
||||
cx: &Context<Self>,
|
||||
) -> Vec<Entity<DebugSession>> {
|
||||
self.pane
|
||||
.read(cx)
|
||||
.items()
|
||||
.filter_map(|item| item.downcast::<DebugSession>())
|
||||
self.sessions
|
||||
.iter()
|
||||
.filter(|item| item.read(cx).session_id(cx) == Some(*client_id))
|
||||
.map(|item| item.clone())
|
||||
.collect()
|
||||
|
@ -218,15 +195,14 @@ impl DebugPanel {
|
|||
client_id: SessionId,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<Entity<DebugSession>> {
|
||||
self.pane
|
||||
.read(cx)
|
||||
.items()
|
||||
.filter_map(|item| item.downcast::<DebugSession>())
|
||||
self.sessions
|
||||
.iter()
|
||||
.find(|item| {
|
||||
let item = item.read(cx);
|
||||
|
||||
item.session_id(cx) == Some(client_id)
|
||||
})
|
||||
.cloned()
|
||||
}
|
||||
|
||||
fn handle_dap_store_event(
|
||||
|
@ -248,10 +224,11 @@ impl DebugPanel {
|
|||
return log::error!("Debug Panel out lived it's weak reference to Project");
|
||||
};
|
||||
|
||||
if self.pane.read_with(cx, |pane, cx| {
|
||||
pane.items_of_type::<DebugSession>()
|
||||
.any(|item| item.read(cx).session_id(cx) == Some(*session_id))
|
||||
}) {
|
||||
if self
|
||||
.sessions
|
||||
.iter()
|
||||
.any(|item| item.read(cx).session_id(cx) == Some(*session_id))
|
||||
{
|
||||
// We already have an item for this session.
|
||||
return;
|
||||
}
|
||||
|
@ -264,11 +241,8 @@ impl DebugPanel {
|
|||
cx,
|
||||
);
|
||||
|
||||
self.pane.update(cx, |pane, cx| {
|
||||
pane.add_item(Box::new(session_item), true, true, None, window, cx);
|
||||
window.focus(&pane.focus_handle(cx));
|
||||
cx.notify();
|
||||
});
|
||||
self.sessions.push(session_item.clone());
|
||||
self.activate_session(session_item, window, cx);
|
||||
}
|
||||
dap_store::DapStoreEvent::RunInTerminal {
|
||||
title,
|
||||
|
@ -362,63 +336,9 @@ impl DebugPanel {
|
|||
})
|
||||
}
|
||||
|
||||
fn handle_pane_event(
|
||||
&mut self,
|
||||
_: &Entity<Pane>,
|
||||
event: &pane::Event,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
pane::Event::Remove { .. } => cx.emit(PanelEvent::Close),
|
||||
pane::Event::ZoomIn => cx.emit(PanelEvent::ZoomIn),
|
||||
pane::Event::ZoomOut => cx.emit(PanelEvent::ZoomOut),
|
||||
pane::Event::AddItem { item } => {
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
item.added_to_pane(workspace, self.pane.clone(), window, cx)
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
pane::Event::RemovedItem { item } => {
|
||||
if let Some(debug_session) = item.downcast::<DebugSession>() {
|
||||
debug_session.update(cx, |session, cx| {
|
||||
session.shutdown(cx);
|
||||
})
|
||||
}
|
||||
}
|
||||
pane::Event::ActivateItem {
|
||||
local: _,
|
||||
focus_changed,
|
||||
} => {
|
||||
if *focus_changed {
|
||||
if let Some(debug_session) = self
|
||||
.pane
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.and_then(|item| item.downcast::<DebugSession>())
|
||||
{
|
||||
if let Some(running) = debug_session
|
||||
.read_with(cx, |session, _| session.mode().as_running().cloned())
|
||||
{
|
||||
running.update(cx, |running, cx| {
|
||||
running.go_to_selected_stack_frame(window, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn top_controls_strip(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Div> {
|
||||
let active_session = self
|
||||
.pane
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.and_then(|item| item.downcast::<DebugSession>());
|
||||
let active_session = self.active_session.clone();
|
||||
|
||||
Some(
|
||||
h_flex()
|
||||
.border_b_1()
|
||||
|
@ -609,34 +529,29 @@ impl DebugPanel {
|
|||
},
|
||||
)
|
||||
.when_some(active_session.as_ref(), |this, session| {
|
||||
let pane = self.pane.downgrade();
|
||||
let sessions = self.sessions.clone();
|
||||
let weak = cx.weak_entity();
|
||||
let label = session.read(cx).label(cx);
|
||||
this.child(DropdownMenu::new(
|
||||
"debugger-session-list",
|
||||
label,
|
||||
ContextMenu::build(window, cx, move |mut this, _, cx| {
|
||||
let sessions = pane
|
||||
.read_with(cx, |pane, _| {
|
||||
pane.items().map(|item| item.boxed_clone()).collect()
|
||||
})
|
||||
.ok()
|
||||
.unwrap_or_else(Vec::new);
|
||||
for (index, item) in sessions.into_iter().enumerate() {
|
||||
if let Some(session) = item.downcast::<DebugSession>() {
|
||||
let pane = pane.clone();
|
||||
this = this.entry(
|
||||
session.read(cx).label(cx),
|
||||
None,
|
||||
move |window, cx| {
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.activate_item(
|
||||
index, true, true, window, cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
},
|
||||
);
|
||||
}
|
||||
for item in sessions {
|
||||
let weak = weak.clone();
|
||||
this = this.entry(
|
||||
session.read(cx).label(cx),
|
||||
None,
|
||||
move |window, cx| {
|
||||
weak.update(cx, |panel, cx| {
|
||||
panel.activate_session(
|
||||
item.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
},
|
||||
);
|
||||
}
|
||||
this
|
||||
}),
|
||||
|
@ -680,6 +595,25 @@ impl DebugPanel {
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn activate_session(
|
||||
&mut self,
|
||||
session_item: Entity<DebugSession>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
debug_assert!(self.sessions.contains(&session_item));
|
||||
session_item.focus_handle(cx).focus(window);
|
||||
session_item.update(cx, |this, cx| {
|
||||
if let Some(running) = this.mode().as_running() {
|
||||
running.update(cx, |this, cx| {
|
||||
this.go_to_selected_stack_frame(window, cx);
|
||||
});
|
||||
}
|
||||
});
|
||||
self.active_session = Some(session_item);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PanelEvent> for DebugPanel {}
|
||||
|
@ -687,16 +621,12 @@ impl EventEmitter<DebugPanelEvent> for DebugPanel {}
|
|||
impl EventEmitter<project::Event> for DebugPanel {}
|
||||
|
||||
impl Focusable for DebugPanel {
|
||||
fn focus_handle(&self, cx: &App) -> FocusHandle {
|
||||
self.pane.focus_handle(cx)
|
||||
fn focus_handle(&self, _: &App) -> FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Panel for DebugPanel {
|
||||
fn pane(&self) -> Option<Entity<Pane>> {
|
||||
Some(self.pane.clone())
|
||||
}
|
||||
|
||||
fn persistent_name() -> &'static str {
|
||||
"DebugPanel"
|
||||
}
|
||||
|
@ -753,7 +683,9 @@ impl Panel for DebugPanel {
|
|||
|
||||
impl Render for DebugPanel {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let has_sessions = self.pane.read(cx).items_len() > 0;
|
||||
let has_sessions = self.sessions.len() > 0;
|
||||
debug_assert_eq!(has_sessions, self.active_session.is_some());
|
||||
|
||||
v_flex()
|
||||
.size_full()
|
||||
.key_context("DebugPanel")
|
||||
|
@ -761,7 +693,7 @@ impl Render for DebugPanel {
|
|||
.track_focus(&self.focus_handle(cx))
|
||||
.map(|this| {
|
||||
if has_sessions {
|
||||
this.child(self.pane.clone())
|
||||
this.children(self.active_session.clone())
|
||||
} else {
|
||||
this.child(
|
||||
v_flex()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue