diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 0325d07ce6..bec6de0475 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1,6 +1,7 @@ mod ignore; mod lsp_command; pub mod search; +pub mod terminals; pub mod worktree; #[cfg(test)] @@ -61,7 +62,8 @@ use std::{ }, time::{Duration, Instant, SystemTime}, }; -use terminal::{Terminal, TerminalBuilder}; +use terminals::Terminals; + use util::{debug_panic, defer, post_inc, ResultExt, TryFutureExt as _}; pub use fs::*; @@ -123,6 +125,7 @@ pub struct Project { buffers_being_formatted: HashSet, nonce: u128, _maintain_buffer_languages: Task<()>, + terminals: Terminals, } enum OpenBuffer { @@ -439,6 +442,9 @@ impl Project { buffers_being_formatted: Default::default(), next_language_server_id: 0, nonce: StdRng::from_entropy().gen(), + terminals: Terminals { + local_handles: Vec::new(), + }, }) } @@ -516,6 +522,9 @@ impl Project { buffers_being_formatted: Default::default(), buffer_snapshots: Default::default(), nonce: StdRng::from_entropy().gen(), + terminals: Terminals { + local_handles: Vec::new(), + }, }; for worktree in worktrees { let _ = this.add_worktree(&worktree, cx); @@ -1184,34 +1193,6 @@ impl Project { !self.is_local() } - pub fn create_terminal( - &mut self, - working_directory: Option, - window_id: usize, - cx: &mut ModelContext, - ) -> Result> { - if self.is_remote() { - return Err(anyhow!( - "creating terminals as a guest is not supported yet" - )); - } else { - let settings = cx.global::(); - let shell = settings.terminal_shell(); - let envs = settings.terminal_env(); - let scroll = settings.terminal_scroll(); - - TerminalBuilder::new( - working_directory.clone(), - shell, - envs, - settings.terminal_overrides.blinking.clone(), - scroll, - window_id, - ) - .map(|builder| cx.add_model(|cx| builder.subscribe(cx))) - } - } - pub fn create_buffer( &mut self, text: &str, diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs new file mode 100644 index 0000000000..b01546ff5c --- /dev/null +++ b/crates/project/src/terminals.rs @@ -0,0 +1,63 @@ +use std::path::PathBuf; + +use gpui::{ModelContext, ModelHandle, WeakModelHandle}; +use settings::Settings; +use terminal::{Terminal, TerminalBuilder}; + +use crate::Project; + +pub struct Terminals { + pub(crate) local_handles: Vec>, +} + +impl Project { + pub fn create_terminal( + &mut self, + working_directory: Option, + window_id: usize, + cx: &mut ModelContext, + ) -> anyhow::Result> { + if self.is_remote() { + return Err(anyhow::anyhow!( + "creating terminals as a guest is not supported yet" + )); + } else { + let settings = cx.global::(); + let shell = settings.terminal_shell(); + let envs = settings.terminal_env(); + let scroll = settings.terminal_scroll(); + + let terminal = TerminalBuilder::new( + working_directory.clone(), + shell, + envs, + settings.terminal_overrides.blinking.clone(), + scroll, + window_id, + ) + .map(|builder| { + let terminal_handle = cx.add_model(|cx| builder.subscribe(cx)); + + self.terminals + .local_handles + .push(terminal_handle.downgrade()); + + let id = terminal_handle.id(); + cx.observe_release(&terminal_handle, move |project, _terminal, _cx| { + let handles = &mut project.terminals.local_handles; + + if let Some(index) = handles.iter().position(|terminal| terminal.id() == id) { + handles.remove(index); + } + }) + .detach(); + + terminal_handle + }); + + terminal + } + } +} + +// TODO: Add a few tests for adding and removing terminal tabs diff --git a/crates/workspace/src/terminal_button.rs b/crates/workspace/src/terminal_button.rs index 91bbef79d5..118df7cab1 100644 --- a/crates/workspace/src/terminal_button.rs +++ b/crates/workspace/src/terminal_button.rs @@ -11,9 +11,10 @@ pub struct TerminalButton { workspace: WeakViewHandle, } +// TODO: Rename this to `DeployTerminalButton` impl TerminalButton { pub fn new(workspace: ViewHandle, cx: &mut ViewContext) -> Self { - // When dock moves, redraw so that the icon and toggle status matches. + // When terminal moves, redraw so that the icon and toggle status matches. cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach(); Self { @@ -63,6 +64,7 @@ impl View for TerminalButton { }) .with_cursor_style(CursorStyle::PointingHand) .on_up(MouseButton::Left, move |_, _| { + // TODO: Do we need this stuff? // let dock_pane = workspace.read(cx.app).dock_pane(); // let drop_index = dock_pane.read(cx.app).items_len() + 1; // handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx);