Terminal in debugger (#29328)
- **debug-terminal** - **Use terminal inside debugger to spawn commands** Closes #ISSUE Release Notes: - N/A
This commit is contained in:
parent
d3911e34de
commit
c147daae4a
9 changed files with 255 additions and 170 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::persistence::DebuggerPaneItem;
|
||||||
use crate::{
|
use crate::{
|
||||||
ClearAllBreakpoints, Continue, CreateDebuggingSession, Disconnect, Pause, Restart, StepBack,
|
ClearAllBreakpoints, Continue, CreateDebuggingSession, Disconnect, Pause, Restart, StepBack,
|
||||||
StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
|
StepInto, StepOut, StepOver, Stop, ToggleIgnoreBreakpoints, persistence,
|
||||||
|
@ -32,8 +33,10 @@ use settings::Settings;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task::{DebugTaskDefinition, DebugTaskTemplate};
|
use task::{
|
||||||
use terminal_view::terminal_panel::TerminalPanel;
|
DebugTaskDefinition, DebugTaskTemplate, HideStrategy, RevealStrategy, RevealTarget, TaskId,
|
||||||
|
};
|
||||||
|
use terminal_view::TerminalView;
|
||||||
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
use ui::{ContextMenu, Divider, DropdownMenu, Tooltip, prelude::*};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
Workspace,
|
Workspace,
|
||||||
|
@ -293,23 +296,21 @@ impl DebugPanel {
|
||||||
|
|
||||||
(session.clone(), dap_store.boot_session(session, cx))
|
(session.clone(), dap_store.boot_session(session, cx))
|
||||||
})?;
|
})?;
|
||||||
|
Self::register_session(this.clone(), session.clone(), cx).await?;
|
||||||
|
|
||||||
match task.await {
|
if let Err(e) = task.await {
|
||||||
Err(e) => {
|
this.update(cx, |this, cx| {
|
||||||
this.update(cx, |this, cx| {
|
this.workspace
|
||||||
this.workspace
|
.update(cx, |workspace, cx| {
|
||||||
.update(cx, |workspace, cx| {
|
workspace.show_error(&e, cx);
|
||||||
workspace.show_error(&e, cx);
|
})
|
||||||
})
|
.ok();
|
||||||
.ok();
|
})
|
||||||
})
|
.ok();
|
||||||
.ok();
|
|
||||||
|
|
||||||
session
|
session
|
||||||
.update(cx, |session, cx| session.shutdown(cx))?
|
.update(cx, |session, cx| session.shutdown(cx))?
|
||||||
.await;
|
.await;
|
||||||
}
|
|
||||||
Ok(_) => Self::register_session(this, session, cx).await?,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
|
@ -467,6 +468,7 @@ impl DebugPanel {
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
dap_store::DapStoreEvent::RunInTerminal {
|
dap_store::DapStoreEvent::RunInTerminal {
|
||||||
|
session_id,
|
||||||
title,
|
title,
|
||||||
cwd,
|
cwd,
|
||||||
command,
|
command,
|
||||||
|
@ -476,6 +478,7 @@ impl DebugPanel {
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.handle_run_in_terminal_request(
|
self.handle_run_in_terminal_request(
|
||||||
|
*session_id,
|
||||||
title.clone(),
|
title.clone(),
|
||||||
cwd.clone(),
|
cwd.clone(),
|
||||||
command.clone(),
|
command.clone(),
|
||||||
|
@ -499,6 +502,7 @@ impl DebugPanel {
|
||||||
|
|
||||||
fn handle_run_in_terminal_request(
|
fn handle_run_in_terminal_request(
|
||||||
&self,
|
&self,
|
||||||
|
session_id: SessionId,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
cwd: Option<Arc<Path>>,
|
cwd: Option<Arc<Path>>,
|
||||||
command: Option<String>,
|
command: Option<String>,
|
||||||
|
@ -506,56 +510,83 @@ impl DebugPanel {
|
||||||
envs: HashMap<String, String>,
|
envs: HashMap<String, String>,
|
||||||
mut sender: mpsc::Sender<Result<u32>>,
|
mut sender: mpsc::Sender<Result<u32>>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
let terminal_task = self.workspace.update(cx, |workspace, cx| {
|
let Some(session) = self
|
||||||
let terminal_panel = workspace.panel::<TerminalPanel>(cx).ok_or_else(|| {
|
.sessions
|
||||||
anyhow!("RunInTerminal DAP request failed because TerminalPanel wasn't found")
|
.iter()
|
||||||
});
|
.find(|s| s.read(cx).session_id(cx) == session_id)
|
||||||
|
else {
|
||||||
let terminal_panel = match terminal_panel {
|
return Task::ready(Err(anyhow!("no session {:?} found", session_id)));
|
||||||
Ok(panel) => panel,
|
};
|
||||||
Err(err) => return Task::ready(Err(err)),
|
let running = session.read(cx).running_state();
|
||||||
};
|
let cwd = cwd.map(|p| p.to_path_buf());
|
||||||
|
let shell = self
|
||||||
terminal_panel.update(cx, |terminal_panel, cx| {
|
.project
|
||||||
let terminal_task = terminal_panel.add_terminal(
|
.read(cx)
|
||||||
TerminalKind::Debug {
|
.terminal_settings(&cwd, cx)
|
||||||
command,
|
.shell
|
||||||
args,
|
.clone();
|
||||||
envs,
|
let kind = if let Some(command) = command {
|
||||||
cwd,
|
let title = title.clone().unwrap_or(command.clone());
|
||||||
title,
|
TerminalKind::Task(task::SpawnInTerminal {
|
||||||
},
|
id: TaskId("debug".to_string()),
|
||||||
task::RevealStrategy::Never,
|
full_label: title.clone(),
|
||||||
window,
|
label: title.clone(),
|
||||||
cx,
|
command: command.clone(),
|
||||||
);
|
args,
|
||||||
|
command_label: title.clone(),
|
||||||
cx.spawn(async move |_, cx| {
|
cwd,
|
||||||
let pid_task = async move {
|
env: envs,
|
||||||
let terminal = terminal_task.await?;
|
use_new_terminal: true,
|
||||||
|
allow_concurrent_runs: true,
|
||||||
terminal.read_with(cx, |terminal, _| terminal.pty_info.pid())
|
reveal: RevealStrategy::NoFocus,
|
||||||
};
|
reveal_target: RevealTarget::Dock,
|
||||||
|
hide: HideStrategy::Never,
|
||||||
pid_task.await
|
shell,
|
||||||
})
|
show_summary: false,
|
||||||
|
show_command: false,
|
||||||
|
show_rerun: false,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
TerminalKind::Shell(cwd.map(|c| c.to_path_buf()))
|
||||||
|
};
|
||||||
|
|
||||||
|
let workspace = self.workspace.clone();
|
||||||
|
let project = self.project.downgrade();
|
||||||
|
|
||||||
|
let terminal_task = self.project.update(cx, |project, cx| {
|
||||||
|
project.create_terminal(kind, window.window_handle(), cx)
|
||||||
|
});
|
||||||
|
let terminal_task = cx.spawn_in(window, async move |_, cx| {
|
||||||
|
let terminal = terminal_task.await?;
|
||||||
|
|
||||||
|
let terminal_view = cx.new_window_entity(|window, cx| {
|
||||||
|
TerminalView::new(terminal.clone(), workspace, None, project, window, cx)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
running.update_in(cx, |running, window, cx| {
|
||||||
|
running.ensure_pane_item(DebuggerPaneItem::Terminal, window, cx);
|
||||||
|
running.debug_terminal.update(cx, |debug_terminal, cx| {
|
||||||
|
debug_terminal.terminal = Some(terminal_view);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
})?;
|
||||||
|
|
||||||
|
anyhow::Ok(terminal.read_with(cx, |terminal, _| terminal.pty_info.pid())?)
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
match terminal_task {
|
match terminal_task.await {
|
||||||
Ok(pid_task) => match pid_task.await {
|
Ok(pid_task) => match pid_task {
|
||||||
Ok(Some(pid)) => sender.send(Ok(pid.as_u32())).await?,
|
Some(pid) => sender.send(Ok(pid.as_u32())).await?,
|
||||||
Ok(None) => {
|
None => {
|
||||||
sender
|
sender
|
||||||
.send(Err(anyhow!(
|
.send(Err(anyhow!(
|
||||||
"Terminal was spawned but PID was not available"
|
"Terminal was spawned but PID was not available"
|
||||||
)))
|
)))
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
Err(error) => sender.send(Err(anyhow!(error))).await?,
|
|
||||||
},
|
},
|
||||||
Err(error) => sender.send(Err(anyhow!(error))).await?,
|
Err(error) => sender.send(Err(anyhow!(error))).await?,
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ use util::ResultExt;
|
||||||
use workspace::{Member, Pane, PaneAxis, Workspace};
|
use workspace::{Member, Pane, PaneAxis, Workspace};
|
||||||
|
|
||||||
use crate::session::running::{
|
use crate::session::running::{
|
||||||
self, RunningState, SubView, breakpoint_list::BreakpointList, console::Console,
|
self, DebugTerminal, RunningState, SubView, breakpoint_list::BreakpointList, console::Console,
|
||||||
loaded_source_list::LoadedSourceList, module_list::ModuleList,
|
loaded_source_list::LoadedSourceList, module_list::ModuleList,
|
||||||
stack_frame_list::StackFrameList, variable_list::VariableList,
|
stack_frame_list::StackFrameList, variable_list::VariableList,
|
||||||
};
|
};
|
||||||
|
@ -22,6 +22,7 @@ pub(crate) enum DebuggerPaneItem {
|
||||||
Frames,
|
Frames,
|
||||||
Modules,
|
Modules,
|
||||||
LoadedSources,
|
LoadedSources,
|
||||||
|
Terminal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebuggerPaneItem {
|
impl DebuggerPaneItem {
|
||||||
|
@ -33,6 +34,7 @@ impl DebuggerPaneItem {
|
||||||
DebuggerPaneItem::Frames,
|
DebuggerPaneItem::Frames,
|
||||||
DebuggerPaneItem::Modules,
|
DebuggerPaneItem::Modules,
|
||||||
DebuggerPaneItem::LoadedSources,
|
DebuggerPaneItem::LoadedSources,
|
||||||
|
DebuggerPaneItem::Terminal,
|
||||||
];
|
];
|
||||||
VARIANTS
|
VARIANTS
|
||||||
}
|
}
|
||||||
|
@ -55,6 +57,7 @@ impl DebuggerPaneItem {
|
||||||
DebuggerPaneItem::Frames => SharedString::new_static("Frames"),
|
DebuggerPaneItem::Frames => SharedString::new_static("Frames"),
|
||||||
DebuggerPaneItem::Modules => SharedString::new_static("Modules"),
|
DebuggerPaneItem::Modules => SharedString::new_static("Modules"),
|
||||||
DebuggerPaneItem::LoadedSources => SharedString::new_static("Sources"),
|
DebuggerPaneItem::LoadedSources => SharedString::new_static("Sources"),
|
||||||
|
DebuggerPaneItem::Terminal => SharedString::new_static("Terminal"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +172,7 @@ pub(crate) fn deserialize_pane_layout(
|
||||||
console: &Entity<Console>,
|
console: &Entity<Console>,
|
||||||
breakpoint_list: &Entity<BreakpointList>,
|
breakpoint_list: &Entity<BreakpointList>,
|
||||||
loaded_sources: &Entity<LoadedSourceList>,
|
loaded_sources: &Entity<LoadedSourceList>,
|
||||||
|
terminal: &Entity<DebugTerminal>,
|
||||||
subscriptions: &mut HashMap<EntityId, Subscription>,
|
subscriptions: &mut HashMap<EntityId, Subscription>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<RunningState>,
|
cx: &mut Context<RunningState>,
|
||||||
|
@ -191,6 +195,7 @@ pub(crate) fn deserialize_pane_layout(
|
||||||
console,
|
console,
|
||||||
breakpoint_list,
|
breakpoint_list,
|
||||||
loaded_sources,
|
loaded_sources,
|
||||||
|
terminal,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
|
@ -273,6 +278,13 @@ pub(crate) fn deserialize_pane_layout(
|
||||||
})),
|
})),
|
||||||
cx,
|
cx,
|
||||||
)),
|
)),
|
||||||
|
DebuggerPaneItem::Terminal => Box::new(SubView::new(
|
||||||
|
pane.focus_handle(cx),
|
||||||
|
terminal.clone().into(),
|
||||||
|
DebuggerPaneItem::Terminal,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,12 @@ impl DebugSession {
|
||||||
&self.mode
|
&self.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn running_state(&self) -> Entity<RunningState> {
|
||||||
|
match &self.mode {
|
||||||
|
DebugSessionState::Running(running_state) => running_state.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn label(&self, cx: &App) -> String {
|
pub(crate) fn label(&self, cx: &App) -> String {
|
||||||
if let Some(label) = self.label.get() {
|
if let Some(label) = self.label.get() {
|
||||||
return label.to_owned();
|
return label.to_owned();
|
||||||
|
|
|
@ -27,6 +27,7 @@ use project::{
|
||||||
use rpc::proto::ViewId;
|
use rpc::proto::ViewId;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use stack_frame_list::StackFrameList;
|
use stack_frame_list::StackFrameList;
|
||||||
|
use terminal_view::TerminalView;
|
||||||
use ui::{
|
use ui::{
|
||||||
ActiveTheme, AnyElement, App, Context, ContextMenu, DropdownMenu, FluentBuilder,
|
ActiveTheme, AnyElement, App, Context, ContextMenu, DropdownMenu, FluentBuilder,
|
||||||
InteractiveElement, IntoElement, Label, LabelCommon as _, ParentElement, Render, SharedString,
|
InteractiveElement, IntoElement, Label, LabelCommon as _, ParentElement, Render, SharedString,
|
||||||
|
@ -35,7 +36,7 @@ use ui::{
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use variable_list::VariableList;
|
use variable_list::VariableList;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
ActivePaneDecorator, DraggedTab, Item, Member, Pane, PaneGroup, Workspace,
|
ActivePaneDecorator, DraggedTab, Item, ItemHandle, Member, Pane, PaneGroup, Workspace,
|
||||||
item::TabContentParams, move_item, pane::Event,
|
item::TabContentParams, move_item, pane::Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ pub struct RunningState {
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
stack_frame_list: Entity<stack_frame_list::StackFrameList>,
|
stack_frame_list: Entity<stack_frame_list::StackFrameList>,
|
||||||
loaded_sources_list: Entity<LoadedSourceList>,
|
loaded_sources_list: Entity<LoadedSourceList>,
|
||||||
|
pub debug_terminal: Entity<DebugTerminal>,
|
||||||
module_list: Entity<module_list::ModuleList>,
|
module_list: Entity<module_list::ModuleList>,
|
||||||
_console: Entity<Console>,
|
_console: Entity<Console>,
|
||||||
breakpoint_list: Entity<BreakpointList>,
|
breakpoint_list: Entity<BreakpointList>,
|
||||||
|
@ -364,6 +366,40 @@ pub(crate) fn new_debugger_pane(
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DebugTerminal {
|
||||||
|
pub terminal: Option<Entity<TerminalView>>,
|
||||||
|
focus_handle: FocusHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugTerminal {
|
||||||
|
fn empty(cx: &mut Context<Self>) -> Self {
|
||||||
|
Self {
|
||||||
|
terminal: None,
|
||||||
|
focus_handle: cx.focus_handle(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl gpui::Render for DebugTerminal {
|
||||||
|
fn render(&mut self, _window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
if let Some(terminal) = self.terminal.clone() {
|
||||||
|
terminal.into_any_element()
|
||||||
|
} else {
|
||||||
|
div().track_focus(&self.focus_handle).into_any_element()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Focusable for DebugTerminal {
|
||||||
|
fn focus_handle(&self, cx: &App) -> FocusHandle {
|
||||||
|
if let Some(terminal) = self.terminal.as_ref() {
|
||||||
|
return terminal.focus_handle(cx);
|
||||||
|
} else {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RunningState {
|
impl RunningState {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
session: Entity<Session>,
|
session: Entity<Session>,
|
||||||
|
@ -380,6 +416,8 @@ impl RunningState {
|
||||||
StackFrameList::new(workspace.clone(), session.clone(), weak_state, window, cx)
|
StackFrameList::new(workspace.clone(), session.clone(), weak_state, window, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let debug_terminal = cx.new(DebugTerminal::empty);
|
||||||
|
|
||||||
let variable_list =
|
let variable_list =
|
||||||
cx.new(|cx| VariableList::new(session.clone(), stack_frame_list.clone(), window, cx));
|
cx.new(|cx| VariableList::new(session.clone(), stack_frame_list.clone(), window, cx));
|
||||||
|
|
||||||
|
@ -452,6 +490,7 @@ impl RunningState {
|
||||||
&console,
|
&console,
|
||||||
&breakpoint_list,
|
&breakpoint_list,
|
||||||
&loaded_source_list,
|
&loaded_source_list,
|
||||||
|
&debug_terminal,
|
||||||
&mut pane_close_subscriptions,
|
&mut pane_close_subscriptions,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
|
@ -494,6 +533,7 @@ impl RunningState {
|
||||||
breakpoint_list,
|
breakpoint_list,
|
||||||
loaded_sources_list: loaded_source_list,
|
loaded_sources_list: loaded_source_list,
|
||||||
pane_close_subscriptions,
|
pane_close_subscriptions,
|
||||||
|
debug_terminal,
|
||||||
_schedule_serialize: None,
|
_schedule_serialize: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -525,6 +565,90 @@ impl RunningState {
|
||||||
self.panes.pane_at_pixel_position(position).is_some()
|
self.panes.pane_at_pixel_position(position).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_sub_view(
|
||||||
|
&self,
|
||||||
|
item_kind: DebuggerPaneItem,
|
||||||
|
pane: &Entity<Pane>,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Box<dyn ItemHandle> {
|
||||||
|
match item_kind {
|
||||||
|
DebuggerPaneItem::Console => {
|
||||||
|
let weak_console = self._console.clone().downgrade();
|
||||||
|
|
||||||
|
Box::new(SubView::new(
|
||||||
|
pane.focus_handle(cx),
|
||||||
|
self._console.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
Some(Box::new(move |cx| {
|
||||||
|
weak_console
|
||||||
|
.read_with(cx, |console, cx| console.show_indicator(cx))
|
||||||
|
.unwrap_or_default()
|
||||||
|
})),
|
||||||
|
cx,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
DebuggerPaneItem::Variables => Box::new(SubView::new(
|
||||||
|
self.variable_list.focus_handle(cx),
|
||||||
|
self.variable_list.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
DebuggerPaneItem::BreakpointList => Box::new(SubView::new(
|
||||||
|
self.breakpoint_list.focus_handle(cx),
|
||||||
|
self.breakpoint_list.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
DebuggerPaneItem::Frames => Box::new(SubView::new(
|
||||||
|
self.stack_frame_list.focus_handle(cx),
|
||||||
|
self.stack_frame_list.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
DebuggerPaneItem::Modules => Box::new(SubView::new(
|
||||||
|
self.module_list.focus_handle(cx),
|
||||||
|
self.module_list.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
DebuggerPaneItem::LoadedSources => Box::new(SubView::new(
|
||||||
|
self.loaded_sources_list.focus_handle(cx),
|
||||||
|
self.loaded_sources_list.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
DebuggerPaneItem::Terminal => Box::new(SubView::new(
|
||||||
|
self.debug_terminal.focus_handle(cx),
|
||||||
|
self.debug_terminal.clone().into(),
|
||||||
|
item_kind,
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ensure_pane_item(
|
||||||
|
&mut self,
|
||||||
|
item_kind: DebuggerPaneItem,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
if self.pane_items_status(cx).get(&item_kind) == Some(&true) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let pane = self.panes.last_pane();
|
||||||
|
let sub_view = self.create_sub_view(item_kind, &pane, cx);
|
||||||
|
|
||||||
|
pane.update(cx, |pane, cx| {
|
||||||
|
pane.add_item_inner(sub_view, false, false, false, None, window, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add_pane_item(
|
pub(crate) fn add_pane_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
item_kind: DebuggerPaneItem,
|
item_kind: DebuggerPaneItem,
|
||||||
|
@ -538,58 +662,7 @@ impl RunningState {
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(pane) = self.panes.pane_at_pixel_position(position) {
|
if let Some(pane) = self.panes.pane_at_pixel_position(position) {
|
||||||
let sub_view = match item_kind {
|
let sub_view = self.create_sub_view(item_kind, pane, cx);
|
||||||
DebuggerPaneItem::Console => {
|
|
||||||
let weak_console = self._console.clone().downgrade();
|
|
||||||
|
|
||||||
Box::new(SubView::new(
|
|
||||||
pane.focus_handle(cx),
|
|
||||||
self._console.clone().into(),
|
|
||||||
item_kind,
|
|
||||||
Some(Box::new(move |cx| {
|
|
||||||
weak_console
|
|
||||||
.read_with(cx, |console, cx| console.show_indicator(cx))
|
|
||||||
.unwrap_or_default()
|
|
||||||
})),
|
|
||||||
cx,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
DebuggerPaneItem::Variables => Box::new(SubView::new(
|
|
||||||
self.variable_list.focus_handle(cx),
|
|
||||||
self.variable_list.clone().into(),
|
|
||||||
item_kind,
|
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
)),
|
|
||||||
DebuggerPaneItem::BreakpointList => Box::new(SubView::new(
|
|
||||||
self.breakpoint_list.focus_handle(cx),
|
|
||||||
self.breakpoint_list.clone().into(),
|
|
||||||
item_kind,
|
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
)),
|
|
||||||
DebuggerPaneItem::Frames => Box::new(SubView::new(
|
|
||||||
self.stack_frame_list.focus_handle(cx),
|
|
||||||
self.stack_frame_list.clone().into(),
|
|
||||||
item_kind,
|
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
)),
|
|
||||||
DebuggerPaneItem::Modules => Box::new(SubView::new(
|
|
||||||
self.module_list.focus_handle(cx),
|
|
||||||
self.module_list.clone().into(),
|
|
||||||
item_kind,
|
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
)),
|
|
||||||
DebuggerPaneItem::LoadedSources => Box::new(SubView::new(
|
|
||||||
self.loaded_sources_list.focus_handle(cx),
|
|
||||||
self.loaded_sources_list.clone().into(),
|
|
||||||
item_kind,
|
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
|
|
||||||
pane.update(cx, |pane, cx| {
|
pane.update(cx, |pane, cx| {
|
||||||
pane.add_item(sub_view, false, false, None, window, cx);
|
pane.add_item(sub_view, false, false, None, window, cx);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{tests::start_debug_session, *};
|
use crate::{persistence::DebuggerPaneItem, tests::start_debug_session, *};
|
||||||
use dap::{
|
use dap::{
|
||||||
ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint,
|
ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint,
|
||||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
||||||
|
@ -25,7 +25,7 @@ use std::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
|
use terminal_view::terminal_panel::TerminalPanel;
|
||||||
use tests::{active_debug_session_panel, init_test, init_test_workspace};
|
use tests::{active_debug_session_panel, init_test, init_test_workspace};
|
||||||
use util::path;
|
use util::path;
|
||||||
use workspace::{Item, dock::Panel};
|
use workspace::{Item, dock::Panel};
|
||||||
|
@ -385,22 +385,17 @@ async fn test_handle_successful_run_in_terminal_reverse_request(
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, _window, cx| {
|
.update(cx, |workspace, _window, cx| {
|
||||||
let terminal_panel = workspace.panel::<TerminalPanel>(cx).unwrap();
|
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
|
||||||
|
let session = debug_panel.read(cx).active_session().unwrap();
|
||||||
let panel = terminal_panel.read(cx).pane().unwrap().read(cx);
|
let running = session.read(cx).running_state();
|
||||||
|
assert_eq!(
|
||||||
assert_eq!(1, panel.items_len());
|
running
|
||||||
assert!(
|
|
||||||
panel
|
|
||||||
.active_item()
|
|
||||||
.unwrap()
|
|
||||||
.downcast::<TerminalView>()
|
|
||||||
.unwrap()
|
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.terminal()
|
.pane_items_status(cx)
|
||||||
.read(cx)
|
.get(&DebuggerPaneItem::Terminal),
|
||||||
.debug_terminal()
|
Some(&true)
|
||||||
);
|
);
|
||||||
|
assert!(running.read(cx).debug_terminal.read(cx).terminal.is_some());
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,6 @@ pub enum TerminalKind {
|
||||||
Shell(Option<PathBuf>),
|
Shell(Option<PathBuf>),
|
||||||
/// Run a task.
|
/// Run a task.
|
||||||
Task(SpawnInTerminal),
|
Task(SpawnInTerminal),
|
||||||
/// Run a debug terminal.
|
|
||||||
Debug {
|
|
||||||
command: Option<String>,
|
|
||||||
args: Vec<String>,
|
|
||||||
envs: HashMap<String, String>,
|
|
||||||
cwd: Option<Arc<Path>>,
|
|
||||||
title: Option<String>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SshCommand describes how to connect to a remote server
|
/// SshCommand describes how to connect to a remote server
|
||||||
|
@ -105,7 +97,6 @@ impl Project {
|
||||||
self.active_project_directory(cx)
|
self.active_project_directory(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminalKind::Debug { cwd, .. } => cwd.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut settings_location = None;
|
let mut settings_location = None;
|
||||||
|
@ -209,7 +200,6 @@ impl Project {
|
||||||
this.active_project_directory(cx)
|
this.active_project_directory(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminalKind::Debug { cwd, .. } => cwd.clone(),
|
|
||||||
};
|
};
|
||||||
let ssh_details = this.ssh_details(cx);
|
let ssh_details = this.ssh_details(cx);
|
||||||
|
|
||||||
|
@ -243,7 +233,6 @@ impl Project {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut python_venv_activate_command = None;
|
let mut python_venv_activate_command = None;
|
||||||
let debug_terminal = matches!(kind, TerminalKind::Debug { .. });
|
|
||||||
|
|
||||||
let (spawn_task, shell) = match kind {
|
let (spawn_task, shell) = match kind {
|
||||||
TerminalKind::Shell(_) => {
|
TerminalKind::Shell(_) => {
|
||||||
|
@ -339,27 +328,6 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminalKind::Debug {
|
|
||||||
command,
|
|
||||||
args,
|
|
||||||
envs,
|
|
||||||
title,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
env.extend(envs);
|
|
||||||
|
|
||||||
let shell = if let Some(program) = command {
|
|
||||||
Shell::WithArguments {
|
|
||||||
program,
|
|
||||||
args,
|
|
||||||
title_override: Some(title.unwrap_or("Debug Terminal".into()).into()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
settings.shell.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
(None, shell)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
TerminalBuilder::new(
|
TerminalBuilder::new(
|
||||||
local_path.map(|path| path.to_path_buf()),
|
local_path.map(|path| path.to_path_buf()),
|
||||||
|
@ -373,7 +341,6 @@ impl Project {
|
||||||
ssh_details.is_some(),
|
ssh_details.is_some(),
|
||||||
window,
|
window,
|
||||||
completion_tx,
|
completion_tx,
|
||||||
debug_terminal,
|
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.map(|builder| {
|
.map(|builder| {
|
||||||
|
|
|
@ -352,7 +352,6 @@ impl TerminalBuilder {
|
||||||
is_ssh_terminal: bool,
|
is_ssh_terminal: bool,
|
||||||
window: AnyWindowHandle,
|
window: AnyWindowHandle,
|
||||||
completion_tx: Sender<Option<ExitStatus>>,
|
completion_tx: Sender<Option<ExitStatus>>,
|
||||||
debug_terminal: bool,
|
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> Result<TerminalBuilder> {
|
) -> Result<TerminalBuilder> {
|
||||||
// If the parent environment doesn't have a locale set
|
// If the parent environment doesn't have a locale set
|
||||||
|
@ -502,7 +501,6 @@ impl TerminalBuilder {
|
||||||
word_regex: RegexSearch::new(WORD_REGEX).unwrap(),
|
word_regex: RegexSearch::new(WORD_REGEX).unwrap(),
|
||||||
python_file_line_regex: RegexSearch::new(PYTHON_FILE_LINE_REGEX).unwrap(),
|
python_file_line_regex: RegexSearch::new(PYTHON_FILE_LINE_REGEX).unwrap(),
|
||||||
vi_mode_enabled: false,
|
vi_mode_enabled: false,
|
||||||
debug_terminal,
|
|
||||||
is_ssh_terminal,
|
is_ssh_terminal,
|
||||||
python_venv_directory,
|
python_venv_directory,
|
||||||
};
|
};
|
||||||
|
@ -660,7 +658,6 @@ pub struct Terminal {
|
||||||
python_file_line_regex: RegexSearch,
|
python_file_line_regex: RegexSearch,
|
||||||
task: Option<TaskState>,
|
task: Option<TaskState>,
|
||||||
vi_mode_enabled: bool,
|
vi_mode_enabled: bool,
|
||||||
debug_terminal: bool,
|
|
||||||
is_ssh_terminal: bool,
|
is_ssh_terminal: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1855,10 +1852,6 @@ impl Terminal {
|
||||||
self.task.as_ref()
|
self.task.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_terminal(&self) -> bool {
|
|
||||||
self.debug_terminal
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait_for_completed_task(&self, cx: &App) -> Task<Option<ExitStatus>> {
|
pub fn wait_for_completed_task(&self, cx: &App) -> Task<Option<ExitStatus>> {
|
||||||
if let Some(task) = self.task() {
|
if let Some(task) = self.task() {
|
||||||
if task.status == TaskStatus::Running {
|
if task.status == TaskStatus::Running {
|
||||||
|
|
|
@ -1420,9 +1420,6 @@ impl Item for TerminalView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None if self.terminal.read(cx).debug_terminal() => {
|
|
||||||
(IconName::Debug, Color::Muted, None)
|
|
||||||
}
|
|
||||||
None => (IconName::Terminal, Color::Muted, None),
|
None => (IconName::Terminal, Color::Muted, None),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1583,7 +1580,7 @@ impl SerializableItem for TerminalView {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<Task<gpui::Result<()>>> {
|
) -> Option<Task<gpui::Result<()>>> {
|
||||||
let terminal = self.terminal().read(cx);
|
let terminal = self.terminal().read(cx);
|
||||||
if terminal.task().is_some() || terminal.debug_terminal() {
|
if terminal.task().is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,10 @@ impl PaneGroup {
|
||||||
self.root.first_pane()
|
self.root.first_pane()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last_pane(&self) -> Entity<Pane> {
|
||||||
|
self.root.last_pane()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_pane_in_direction(
|
pub fn find_pane_in_direction(
|
||||||
&mut self,
|
&mut self,
|
||||||
active_pane: &Entity<Pane>,
|
active_pane: &Entity<Pane>,
|
||||||
|
@ -360,6 +364,13 @@ impl Member {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn last_pane(&self) -> Entity<Pane> {
|
||||||
|
match self {
|
||||||
|
Member::Axis(axis) => axis.members.last().unwrap().last_pane(),
|
||||||
|
Member::Pane(pane) => pane.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(
|
||||||
&self,
|
&self,
|
||||||
basis: usize,
|
basis: usize,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue