Start improving support for keyboard-driven debugging (#29380)
Closes #ISSUE Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <peterosiewicz@gmail.com> Co-authored-by: Anthony Eid <hello@anthonyeid.me>
This commit is contained in:
parent
7f5c874a38
commit
7623fce4b4
10 changed files with 307 additions and 45 deletions
|
@ -693,7 +693,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"context": "GitPanel || ProjectPanel || CollabPanel || OutlinePanel || ChatPanel || VimControl || EmptyPane || SharedScreen || MarkdownPreview || KeyContextView",
|
"context": "GitPanel || ProjectPanel || CollabPanel || OutlinePanel || ChatPanel || VimControl || EmptyPane || SharedScreen || MarkdownPreview || KeyContextView || DebugPanel",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
// window related commands (ctrl-w X)
|
// window related commands (ctrl-w X)
|
||||||
"ctrl-w": null,
|
"ctrl-w": null,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::persistence::DebuggerPaneItem;
|
use crate::persistence::DebuggerPaneItem;
|
||||||
use crate::{
|
use crate::{
|
||||||
ClearAllBreakpoints, Continue, CreateDebuggingSession, Disconnect, Pause, Restart, StepBack,
|
ClearAllBreakpoints, Continue, CreateDebuggingSession, Disconnect, FocusBreakpointList,
|
||||||
StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
|
FocusConsole, FocusFrames, FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables,
|
||||||
|
Pause, Restart, StepBack, StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints,
|
||||||
|
persistence,
|
||||||
};
|
};
|
||||||
use crate::{new_session_modal::NewSessionModal, session::DebugSession};
|
use crate::{new_session_modal::NewSessionModal, session::DebugSession};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
|
@ -38,6 +40,7 @@ use task::{
|
||||||
};
|
};
|
||||||
use terminal_view::TerminalView;
|
use terminal_view::TerminalView;
|
||||||
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
||||||
|
use workspace::SplitDirection;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
Pane, Workspace,
|
Pane, Workspace,
|
||||||
dock::{DockPosition, Panel, PanelEvent},
|
dock::{DockPosition, Panel, PanelEvent},
|
||||||
|
@ -790,6 +793,7 @@ impl DebugPanel {
|
||||||
|
|
||||||
fn top_controls_strip(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Div> {
|
fn top_controls_strip(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Div> {
|
||||||
let active_session = self.active_session.clone();
|
let active_session = self.active_session.clone();
|
||||||
|
let focus_handle = self.focus_handle.clone();
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
@ -821,8 +825,17 @@ impl DebugPanel {
|
||||||
this.pause_thread(cx);
|
this.pause_thread(cx);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Pause program")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Pause program",
|
||||||
|
&Pause,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -835,8 +848,17 @@ impl DebugPanel {
|
||||||
|this, _, _window, cx| this.continue_thread(cx),
|
|this, _, _window, cx| this.continue_thread(cx),
|
||||||
))
|
))
|
||||||
.disabled(thread_status != ThreadStatus::Stopped)
|
.disabled(thread_status != ThreadStatus::Stopped)
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Continue program")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Continue program",
|
||||||
|
&Continue,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -852,8 +874,17 @@ impl DebugPanel {
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.disabled(thread_status != ThreadStatus::Stopped)
|
.disabled(thread_status != ThreadStatus::Stopped)
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Step over")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Step over",
|
||||||
|
&StepOver,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
@ -867,8 +898,17 @@ impl DebugPanel {
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.disabled(thread_status != ThreadStatus::Stopped)
|
.disabled(thread_status != ThreadStatus::Stopped)
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Step out")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Step out",
|
||||||
|
&StepOut,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
@ -882,8 +922,17 @@ impl DebugPanel {
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.disabled(thread_status != ThreadStatus::Stopped)
|
.disabled(thread_status != ThreadStatus::Stopped)
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Step in")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Step in",
|
||||||
|
&StepInto,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(Divider::vertical())
|
.child(Divider::vertical())
|
||||||
|
@ -916,8 +965,17 @@ impl DebugPanel {
|
||||||
this.toggle_ignore_breakpoints(cx);
|
this.toggle_ignore_breakpoints(cx);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Disable all breakpoints")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Disable all breakpoints",
|
||||||
|
&ToggleIgnoreBreakpoints,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(Divider::vertical())
|
.child(Divider::vertical())
|
||||||
|
@ -930,8 +988,17 @@ impl DebugPanel {
|
||||||
this.restart_session(cx);
|
this.restart_session(cx);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.tooltip(move |window, cx| {
|
.tooltip({
|
||||||
Tooltip::text("Restart")(window, cx)
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Restart",
|
||||||
|
&Restart,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
@ -948,15 +1015,24 @@ impl DebugPanel {
|
||||||
&& thread_status != ThreadStatus::Running,
|
&& thread_status != ThreadStatus::Running,
|
||||||
)
|
)
|
||||||
.tooltip({
|
.tooltip({
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
let label = if capabilities
|
let label = if capabilities
|
||||||
.supports_terminate_threads_request
|
.supports_terminate_threads_request
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
{
|
{
|
||||||
"Terminate Thread"
|
"Terminate Thread"
|
||||||
} else {
|
} else {
|
||||||
"Terminate all Threads"
|
"Terminate All Threads"
|
||||||
};
|
};
|
||||||
move |window, cx| Tooltip::text(label)(window, cx)
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
label,
|
||||||
|
&Stop,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -1006,19 +1082,57 @@ impl DebugPanel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.tooltip(|window, cx| {
|
.tooltip({
|
||||||
Tooltip::for_action(
|
let focus_handle = focus_handle.clone();
|
||||||
"New Debug Session",
|
move |window, cx| {
|
||||||
&CreateDebuggingSession,
|
Tooltip::for_action_in(
|
||||||
window,
|
"New Debug Session",
|
||||||
cx,
|
&CreateDebuggingSession,
|
||||||
)
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn activate_pane_in_direction(
|
||||||
|
&mut self,
|
||||||
|
direction: SplitDirection,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
if let Some(session) = self.active_session() {
|
||||||
|
session.update(cx, |session, cx| {
|
||||||
|
if let Some(running) = session.mode().as_running() {
|
||||||
|
running.update(cx, |running, cx| {
|
||||||
|
running.activate_pane_in_direction(direction, window, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate_item(
|
||||||
|
&mut self,
|
||||||
|
item: DebuggerPaneItem,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
if let Some(session) = self.active_session() {
|
||||||
|
session.update(cx, |session, cx| {
|
||||||
|
if let Some(running) = session.mode().as_running() {
|
||||||
|
running.update(cx, |running, cx| {
|
||||||
|
running.activate_item(item, window, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn activate_session(
|
fn activate_session(
|
||||||
&mut self,
|
&mut self,
|
||||||
session_item: Entity<DebugSession>,
|
session_item: Entity<DebugSession>,
|
||||||
|
@ -1111,6 +1225,7 @@ impl Panel for DebugPanel {
|
||||||
impl Render for DebugPanel {
|
impl Render for DebugPanel {
|
||||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
let has_sessions = self.sessions.len() > 0;
|
let has_sessions = self.sessions.len() > 0;
|
||||||
|
let this = cx.weak_entity();
|
||||||
debug_assert_eq!(has_sessions, self.active_session.is_some());
|
debug_assert_eq!(has_sessions, self.active_session.is_some());
|
||||||
|
|
||||||
if self
|
if self
|
||||||
|
@ -1128,6 +1243,105 @@ impl Render for DebugPanel {
|
||||||
.key_context("DebugPanel")
|
.key_context("DebugPanel")
|
||||||
.child(h_flex().children(self.top_controls_strip(window, cx)))
|
.child(h_flex().children(self.top_controls_strip(window, cx)))
|
||||||
.track_focus(&self.focus_handle(cx))
|
.track_focus(&self.focus_handle(cx))
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &workspace::ActivatePaneLeft, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_pane_in_direction(SplitDirection::Left, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &workspace::ActivatePaneRight, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_pane_in_direction(SplitDirection::Right, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &workspace::ActivatePaneUp, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_pane_in_direction(SplitDirection::Up, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &workspace::ActivatePaneDown, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_pane_in_direction(SplitDirection::Down, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusConsole, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::Console, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusVariables, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::Variables, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusBreakpointList, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::BreakpointList, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusFrames, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::Frames, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusModules, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::Modules, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusLoadedSources, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::LoadedSources, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let this = this.clone();
|
||||||
|
move |_: &FocusTerminal, window, cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.activate_item(DebuggerPaneItem::Terminal, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
.when(self.active_session.is_some(), |this| {
|
.when(self.active_session.is_some(), |this| {
|
||||||
this.on_mouse_down(
|
this.on_mouse_down(
|
||||||
MouseButton::Right,
|
MouseButton::Right,
|
||||||
|
|
|
@ -35,6 +35,13 @@ actions!(
|
||||||
ToggleIgnoreBreakpoints,
|
ToggleIgnoreBreakpoints,
|
||||||
ClearAllBreakpoints,
|
ClearAllBreakpoints,
|
||||||
CreateDebuggingSession,
|
CreateDebuggingSession,
|
||||||
|
FocusConsole,
|
||||||
|
FocusVariables,
|
||||||
|
FocusBreakpointList,
|
||||||
|
FocusFrames,
|
||||||
|
FocusModules,
|
||||||
|
FocusLoadedSources,
|
||||||
|
FocusTerminal,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ use ui::{
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use variable_list::VariableList;
|
use variable_list::VariableList;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
ActivePaneDecorator, DraggedTab, Item, ItemHandle, Member, Pane, PaneGroup, Workspace,
|
ActivePaneDecorator, DraggedTab, Item, ItemHandle, Member, Pane, PaneGroup, SplitDirection,
|
||||||
item::TabContentParams, move_item, pane::Event,
|
Workspace, item::TabContentParams, move_item, pane::Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct RunningState {
|
pub struct RunningState {
|
||||||
|
@ -57,6 +57,7 @@ pub struct RunningState {
|
||||||
_console: Entity<Console>,
|
_console: Entity<Console>,
|
||||||
breakpoint_list: Entity<BreakpointList>,
|
breakpoint_list: Entity<BreakpointList>,
|
||||||
panes: PaneGroup,
|
panes: PaneGroup,
|
||||||
|
active_pane: Option<Entity<Pane>>,
|
||||||
pane_close_subscriptions: HashMap<EntityId, Subscription>,
|
pane_close_subscriptions: HashMap<EntityId, Subscription>,
|
||||||
_schedule_serialize: Option<Task<()>>,
|
_schedule_serialize: Option<Task<()>>,
|
||||||
}
|
}
|
||||||
|
@ -167,8 +168,14 @@ impl Item for SubView {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for SubView {
|
impl Render for SubView {
|
||||||
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
v_flex().size_full().child(self.inner.clone())
|
v_flex()
|
||||||
|
.size_full()
|
||||||
|
.when(self.pane_focus_handle.contains_focused(window, cx), |el| {
|
||||||
|
// TODO better way of showing focus?
|
||||||
|
el.border_1().border_color(gpui::red())
|
||||||
|
})
|
||||||
|
.child(self.inner.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,6 +583,7 @@ impl RunningState {
|
||||||
stack_frame_list,
|
stack_frame_list,
|
||||||
session_id,
|
session_id,
|
||||||
panes,
|
panes,
|
||||||
|
active_pane: None,
|
||||||
module_list,
|
module_list,
|
||||||
_console: console,
|
_console: console,
|
||||||
breakpoint_list,
|
breakpoint_list,
|
||||||
|
@ -616,7 +624,7 @@ impl RunningState {
|
||||||
fn create_sub_view(
|
fn create_sub_view(
|
||||||
&self,
|
&self,
|
||||||
item_kind: DebuggerPaneItem,
|
item_kind: DebuggerPaneItem,
|
||||||
pane: &Entity<Pane>,
|
_pane: &Entity<Pane>,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Box<dyn ItemHandle> {
|
) -> Box<dyn ItemHandle> {
|
||||||
match item_kind {
|
match item_kind {
|
||||||
|
@ -624,7 +632,7 @@ impl RunningState {
|
||||||
let weak_console = self._console.clone().downgrade();
|
let weak_console = self._console.clone().downgrade();
|
||||||
|
|
||||||
Box::new(SubView::new(
|
Box::new(SubView::new(
|
||||||
pane.focus_handle(cx),
|
self._console.focus_handle(cx),
|
||||||
self._console.clone().into(),
|
self._console.clone().into(),
|
||||||
item_kind,
|
item_kind,
|
||||||
Some(Box::new(move |cx| {
|
Some(Box::new(move |cx| {
|
||||||
|
@ -784,6 +792,9 @@ impl RunningState {
|
||||||
debug_assert!(_did_find_pane);
|
debug_assert!(_did_find_pane);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
Event::Focus => {
|
||||||
|
this.active_pane = Some(source_pane.clone());
|
||||||
|
}
|
||||||
Event::ZoomIn => {
|
Event::ZoomIn => {
|
||||||
source_pane.update(cx, |pane, cx| {
|
source_pane.update(cx, |pane, cx| {
|
||||||
pane.set_zoomed(true, cx);
|
pane.set_zoomed(true, cx);
|
||||||
|
@ -800,6 +811,27 @@ impl RunningState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn activate_pane_in_direction(
|
||||||
|
&mut self,
|
||||||
|
direction: SplitDirection,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
if let Some(pane) = self
|
||||||
|
.active_pane
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|pane| self.panes.find_pane_in_direction(pane, direction, cx))
|
||||||
|
{
|
||||||
|
window.focus(&pane.focus_handle(cx));
|
||||||
|
} else {
|
||||||
|
self.workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.activate_pane_in_direction(direction, window, cx)
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn go_to_selected_stack_frame(&self, window: &Window, cx: &mut Context<Self>) {
|
pub(crate) fn go_to_selected_stack_frame(&self, window: &Window, cx: &mut Context<Self>) {
|
||||||
if self.thread_id.is_some() {
|
if self.thread_id.is_some() {
|
||||||
self.stack_frame_list
|
self.stack_frame_list
|
||||||
|
@ -838,8 +870,7 @@ impl RunningState {
|
||||||
&self.module_list
|
&self.module_list
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
pub(crate) fn activate_item(&self, item: DebuggerPaneItem, window: &mut Window, cx: &mut App) {
|
||||||
pub(crate) fn activate_modules_list(&self, window: &mut Window, cx: &mut App) {
|
|
||||||
let (variable_list_position, pane) = self
|
let (variable_list_position, pane) = self
|
||||||
.panes
|
.panes
|
||||||
.panes()
|
.panes()
|
||||||
|
@ -847,7 +878,7 @@ impl RunningState {
|
||||||
.find_map(|pane| {
|
.find_map(|pane| {
|
||||||
pane.read(cx)
|
pane.read(cx)
|
||||||
.items_of_type::<SubView>()
|
.items_of_type::<SubView>()
|
||||||
.position(|view| view.read(cx).view_kind().to_shared_string() == *"Modules")
|
.position(|view| view.read(cx).view_kind() == item)
|
||||||
.map(|view| (view, pane))
|
.map(|view| (view, pane))
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -855,6 +886,7 @@ impl RunningState {
|
||||||
this.activate_item(variable_list_position, true, true, window, cx);
|
this.activate_item(variable_list_position, true, true, window, cx);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn variable_list(&self) -> &Entity<VariableList> {
|
pub(crate) fn variable_list(&self) -> &Entity<VariableList> {
|
||||||
&self.variable_list
|
&self.variable_list
|
||||||
|
|
|
@ -45,6 +45,7 @@ impl Focusable for BreakpointList {
|
||||||
self.focus_handle.clone()
|
self.focus_handle.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BreakpointList {
|
impl BreakpointList {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
session: Entity<Session>,
|
session: Entity<Session>,
|
||||||
|
@ -213,6 +214,7 @@ impl Render for BreakpointList {
|
||||||
}
|
}
|
||||||
v_flex()
|
v_flex()
|
||||||
.id("breakpoint-list")
|
.id("breakpoint-list")
|
||||||
|
.track_focus(&self.focus_handle)
|
||||||
.on_hover(cx.listener(|this, hovered, window, cx| {
|
.on_hover(cx.listener(|this, hovered, window, cx| {
|
||||||
if *hovered {
|
if *hovered {
|
||||||
this.show_scrollbar = true;
|
this.show_scrollbar = true;
|
||||||
|
|
|
@ -7,7 +7,9 @@ use collections::HashMap;
|
||||||
use dap::OutputEvent;
|
use dap::OutputEvent;
|
||||||
use editor::{CompletionProvider, Editor, EditorElement, EditorStyle, ExcerptId};
|
use editor::{CompletionProvider, Editor, EditorElement, EditorStyle, ExcerptId};
|
||||||
use fuzzy::StringMatchCandidate;
|
use fuzzy::StringMatchCandidate;
|
||||||
use gpui::{Context, Entity, Render, Subscription, Task, TextStyle, WeakEntity};
|
use gpui::{
|
||||||
|
Context, Entity, FocusHandle, Focusable, Render, Subscription, Task, TextStyle, WeakEntity,
|
||||||
|
};
|
||||||
use language::{Buffer, CodeLabel, ToOffset};
|
use language::{Buffer, CodeLabel, ToOffset};
|
||||||
use menu::Confirm;
|
use menu::Confirm;
|
||||||
use project::{
|
use project::{
|
||||||
|
@ -28,6 +30,7 @@ pub struct Console {
|
||||||
stack_frame_list: Entity<StackFrameList>,
|
stack_frame_list: Entity<StackFrameList>,
|
||||||
last_token: OutputToken,
|
last_token: OutputToken,
|
||||||
update_output_task: Task<()>,
|
update_output_task: Task<()>,
|
||||||
|
focus_handle: FocusHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Console {
|
impl Console {
|
||||||
|
@ -56,6 +59,7 @@ impl Console {
|
||||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
|
let focus_handle = cx.focus_handle();
|
||||||
|
|
||||||
let this = cx.weak_entity();
|
let this = cx.weak_entity();
|
||||||
let query_bar = cx.new(|cx| {
|
let query_bar = cx.new(|cx| {
|
||||||
|
@ -82,6 +86,7 @@ impl Console {
|
||||||
stack_frame_list,
|
stack_frame_list,
|
||||||
update_output_task: Task::ready(()),
|
update_output_task: Task::ready(()),
|
||||||
last_token: OutputToken(0),
|
last_token: OutputToken(0),
|
||||||
|
focus_handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +235,7 @@ impl Render for Console {
|
||||||
});
|
});
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.track_focus(&self.focus_handle)
|
||||||
.key_context("DebugConsole")
|
.key_context("DebugConsole")
|
||||||
.on_action(cx.listener(Self::evaluate))
|
.on_action(cx.listener(Self::evaluate))
|
||||||
.size_full()
|
.size_full()
|
||||||
|
@ -242,6 +248,12 @@ impl Render for Console {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Focusable for Console {
|
||||||
|
fn focus_handle(&self, _cx: &App) -> gpui::FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ConsoleQueryBarCompletionProvider(WeakEntity<Console>);
|
struct ConsoleQueryBarCompletionProvider(WeakEntity<Console>);
|
||||||
|
|
||||||
impl CompletionProvider for ConsoleQueryBarCompletionProvider {
|
impl CompletionProvider for ConsoleQueryBarCompletionProvider {
|
||||||
|
|
|
@ -132,13 +132,6 @@ impl StackFrameList {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _get_main_stack_frame_id(&self, cx: &mut Context<Self>) -> u64 {
|
|
||||||
self.stack_frames(cx)
|
|
||||||
.first()
|
|
||||||
.map(|stack_frame| stack_frame.dap.id)
|
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn selected_stack_frame_id(&self) -> Option<StackFrameId> {
|
pub fn selected_stack_frame_id(&self) -> Option<StackFrameId> {
|
||||||
self.selected_stack_frame_id
|
self.selected_stack_frame_id
|
||||||
}
|
}
|
||||||
|
@ -557,6 +550,7 @@ impl StackFrameList {
|
||||||
impl Render for StackFrameList {
|
impl Render for StackFrameList {
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
div()
|
div()
|
||||||
|
.track_focus(&self.focus_handle)
|
||||||
.size_full()
|
.size_full()
|
||||||
.p_1()
|
.p_1()
|
||||||
.child(list(self.list.clone()).size_full())
|
.child(list(self.list.clone()).size_full())
|
||||||
|
|
|
@ -929,12 +929,12 @@ impl Render for VariableList {
|
||||||
self.build_entries(cx);
|
self.build_entries(cx);
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.track_focus(&self.focus_handle)
|
||||||
.key_context("VariableList")
|
.key_context("VariableList")
|
||||||
.id("variable-list")
|
.id("variable-list")
|
||||||
.group("variable-list")
|
.group("variable-list")
|
||||||
.overflow_y_scroll()
|
.overflow_y_scroll()
|
||||||
.size_full()
|
.size_full()
|
||||||
.track_focus(&self.focus_handle(cx))
|
|
||||||
.on_action(cx.listener(Self::select_first))
|
.on_action(cx.listener(Self::select_first))
|
||||||
.on_action(cx.listener(Self::select_last))
|
.on_action(cx.listener(Self::select_last))
|
||||||
.on_action(cx.listener(Self::select_prev))
|
.on_action(cx.listener(Self::select_prev))
|
||||||
|
|
|
@ -112,7 +112,7 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext)
|
||||||
});
|
});
|
||||||
|
|
||||||
running_state.update_in(cx, |this, window, cx| {
|
running_state.update_in(cx, |this, window, cx| {
|
||||||
this.activate_modules_list(window, cx);
|
this.activate_item(crate::persistence::DebuggerPaneItem::Modules, window, cx);
|
||||||
cx.refresh_windows();
|
cx.refresh_windows();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ use task::{DebugTaskDefinition, DebugTaskTemplate};
|
||||||
use util::ResultExt as _;
|
use util::ResultExt as _;
|
||||||
use worktree::Worktree;
|
use worktree::Worktree;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum DapStoreEvent {
|
pub enum DapStoreEvent {
|
||||||
DebugClientStarted(SessionId),
|
DebugClientStarted(SessionId),
|
||||||
DebugSessionInitialized(SessionId),
|
DebugSessionInitialized(SessionId),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue