From c42da5c9b9185dbefb70de5e144f3c70d9d7528b Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 8 Dec 2022 16:10:22 -0800 Subject: [PATCH] WIP --- crates/project/src/project.rs | 21 ++++++- crates/settings/src/settings.rs | 44 +++++++------- crates/terminal/src/terminal.rs | 28 ++++----- crates/terminal_view/Cargo.toml | 2 +- .../src/terminal_container_view.rs | 57 ++++++------------- crates/terminal_view/src/terminal_view.rs | 5 ++ 6 files changed, 77 insertions(+), 80 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 40f1c93e51..545570da89 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -62,7 +62,7 @@ use std::{ }, time::Instant, }; -use terminal::Terminal; +use terminal::{Terminal, TerminalBuilder}; use thiserror::Error; use util::{defer, post_inc, ResultExt, TryFutureExt as _}; @@ -1196,14 +1196,29 @@ impl Project { pub fn create_terminal_connection( &mut self, - _cx: &mut ModelContext, + 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 { - unimplemented!() + 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))) } } diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index dd23f80abd..f0c64a1bb9 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -221,6 +221,12 @@ pub enum WorkingDirectory { Always { directory: String }, } +impl Default for WorkingDirectory { + fn default() -> Self { + Self::CurrentProjectDirectory + } +} + #[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum DockAnchor { @@ -473,30 +479,30 @@ impl Settings { }) } - pub fn terminal_scroll(&self) -> AlternateScroll { - *self.terminal_overrides.alternate_scroll.as_ref().unwrap_or( - self.terminal_defaults - .alternate_scroll - .as_ref() - .unwrap_or_else(|| &AlternateScroll::On), - ) + fn terminal_setting(&self, f: F) -> R + where + F: Fn(&TerminalSettings) -> Option<&R>, + { + f(&self.terminal_overrides) + .or_else(|| f(&self.terminal_defaults)) + .cloned() + .unwrap_or_else(|| R::default()) } - pub fn terminal_shell(&self) -> Option { - self.terminal_overrides - .shell - .as_ref() - .or(self.terminal_defaults.shell.as_ref()) - .cloned() + pub fn terminal_scroll(&self) -> AlternateScroll { + self.terminal_setting(|terminal_setting| terminal_setting.alternate_scroll.as_ref()) + } + + pub fn terminal_shell(&self) -> Shell { + self.terminal_setting(|terminal_setting| terminal_setting.shell.as_ref()) } pub fn terminal_env(&self) -> HashMap { - self.terminal_overrides.env.clone().unwrap_or_else(|| { - self.terminal_defaults - .env - .clone() - .unwrap_or_else(|| HashMap::default()) - }) + self.terminal_setting(|terminal_setting| terminal_setting.env.as_ref()) + } + + pub fn terminal_strategy(&self) -> WorkingDirectory { + self.terminal_setting(|terminal_setting| terminal_setting.working_directory.as_ref()) } #[cfg(any(test, feature = "test-support"))] diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 4b69de0bf2..7cdac33cda 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -198,7 +198,7 @@ impl Dimensions for TerminalSize { #[derive(Error, Debug)] pub struct TerminalError { pub directory: Option, - pub shell: Option, + pub shell: Shell, pub source: std::io::Error, } @@ -226,24 +226,20 @@ impl TerminalError { }) } - pub fn shell_to_string(&self) -> Option { - self.shell.as_ref().map(|shell| match shell { + pub fn shell_to_string(&self) -> String { + match &self.shell { Shell::System => "".to_string(), Shell::Program(p) => p.to_string(), Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")), - }) + } } pub fn fmt_shell(&self) -> String { - self.shell - .clone() - .map(|shell| match shell { - Shell::System => "".to_string(), - - Shell::Program(s) => s, - Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")), - }) - .unwrap_or_else(|| "".to_string()) + match &self.shell { + Shell::System => "".to_string(), + Shell::Program(s) => s.to_string(), + Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")), + } } } @@ -268,18 +264,18 @@ pub struct TerminalBuilder { impl TerminalBuilder { pub fn new( working_directory: Option, - shell: Option, + shell: Shell, mut env: HashMap, blink_settings: Option, alternate_scroll: AlternateScroll, window_id: usize, ) -> Result { let pty_config = { - let alac_shell = shell.clone().and_then(|shell| match shell { + let alac_shell = match shell.clone() { Shell::System => None, Shell::Program(program) => Some(Program::Just(program)), Shell::WithArguments { program, args } => Some(Program::WithArgs { program, args }), - }); + }; PtyConfig { shell: alac_shell, diff --git a/crates/terminal_view/Cargo.toml b/crates/terminal_view/Cargo.toml index fae60a943d..05fda2c75f 100644 --- a/crates/terminal_view/Cargo.toml +++ b/crates/terminal_view/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [lib] -path = "src/terminal_container_view.rs" +path = "src/terminal_view.rs" doctest = false [dependencies] diff --git a/crates/terminal_view/src/terminal_container_view.rs b/crates/terminal_view/src/terminal_container_view.rs index 9d8b79cd39..322bf5ab52 100644 --- a/crates/terminal_view/src/terminal_container_view.rs +++ b/crates/terminal_view/src/terminal_container_view.rs @@ -1,18 +1,14 @@ -mod persistence; -pub mod terminal_element; -pub mod terminal_view; - use crate::persistence::TERMINAL_DB; -use crate::terminal_view::TerminalView; +use crate::TerminalView; use terminal::alacritty_terminal::index::Point; -use terminal::{Event, TerminalBuilder, TerminalError}; +use terminal::{Event, Terminal, TerminalError}; +use crate::regex_search_for_query; use dirs::home_dir; use gpui::{ actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; -use terminal_view::regex_search_for_query; use util::{truncate_and_trailoff, ResultExt}; use workspace::searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle}; use workspace::{ @@ -36,7 +32,7 @@ pub fn init(cx: &mut MutableAppContext) { register_deserializable_item::(cx); - terminal_view::init(cx); + // terminal_view::init(cx); } //Make terminal view an enum, that can give you views for the error and non-error states @@ -81,47 +77,31 @@ impl TerminalContainer { _: &workspace::NewTerminal, cx: &mut ViewContext, ) { - let strategy = cx - .global::() - .terminal_overrides - .working_directory - .clone() - .unwrap_or(WorkingDirectory::CurrentProjectDirectory); + let strategy = cx.global::().terminal_strategy(); let working_directory = get_working_directory(workspace, cx, strategy); - let view = cx.add_view(|cx| { - TerminalContainer::new(working_directory, false, workspace.database_id(), cx) + + let window_id = cx.window_id(); + let terminal = workspace.project().update(cx, |project, cx| { + project.create_terminal_connection(working_directory, window_id, cx) }); + + let view = cx.add_view(|cx| TerminalContainer::new(terminal, workspace.database_id(), cx)); workspace.add_item(Box::new(view), cx); } ///Create a new Terminal view. This spawns a task, a thread, and opens the TTY devices pub fn new( - working_directory: Option, - modal: bool, + model: anyhow::Result>, workspace_id: WorkspaceId, cx: &mut ViewContext, ) -> Self { - let settings = cx.global::(); - let shell = settings.terminal_shell(); - let envs = settings.terminal_env(); - let scroll = settings.terminal_scroll(); - - let content = match TerminalBuilder::new( - working_directory.clone(), - shell, - envs, - settings.terminal_overrides.blinking.clone(), - scroll, - cx.window_id(), - ) { + let content = match model { Ok(terminal) => { - let terminal = cx.add_model(|cx| terminal.subscribe(cx)); let item_id = cx.view_id(); let view = cx.add_view(|cx| { - TerminalView::from_terminal(terminal, modal, workspace_id, item_id, cx) + TerminalView::from_terminal(terminal, false, workspace_id, item_id, cx) }); - cx.subscribe(&view, |_this, _content, event, cx| cx.emit(*event)) .detach(); TerminalContainerContent::Connected(view) @@ -136,7 +116,7 @@ impl TerminalContainer { TerminalContainer { content, - associated_directory: working_directory, + associated_directory: None, //working_directory, } } @@ -183,12 +163,7 @@ impl View for ErrorView { //We want to be able to select the text //Want to be able to scroll if the error message is massive somehow (resiliency) - let program_text = { - match self.error.shell_to_string() { - Some(shell_txt) => format!("Shell Program: `{}`", shell_txt), - None => "No program specified".to_string(), - } - }; + let program_text = format!("Shell Program: `{}`", self.error.shell_to_string()); let directory_text = { match self.error.directory.as_ref() { diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index c2f5c5c114..dbe861b781 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -1,3 +1,7 @@ +mod persistence; +pub mod terminal_container_view; +pub mod terminal_element; + use std::{ops::RangeInclusive, time::Duration}; use context_menu::{ContextMenu, ContextMenuItem}; @@ -52,6 +56,7 @@ impl_actions!(terminal, [SendText, SendKeystroke]); impl_internal_actions!(project_panel, [DeployContextMenu]); pub fn init(cx: &mut MutableAppContext) { + terminal_container_view::init(cx); //Useful terminal views cx.add_action(TerminalView::send_text); cx.add_action(TerminalView::send_keystroke);