This commit is contained in:
Mikayla Maki 2022-12-08 16:10:22 -08:00
parent 2733f91d8c
commit c42da5c9b9
6 changed files with 77 additions and 80 deletions

View file

@ -62,7 +62,7 @@ use std::{
}, },
time::Instant, time::Instant,
}; };
use terminal::Terminal; use terminal::{Terminal, TerminalBuilder};
use thiserror::Error; use thiserror::Error;
use util::{defer, post_inc, ResultExt, TryFutureExt as _}; use util::{defer, post_inc, ResultExt, TryFutureExt as _};
@ -1196,14 +1196,29 @@ impl Project {
pub fn create_terminal_connection( pub fn create_terminal_connection(
&mut self, &mut self,
_cx: &mut ModelContext<Self>, working_directory: Option<PathBuf>,
window_id: usize,
cx: &mut ModelContext<Self>,
) -> Result<ModelHandle<Terminal>> { ) -> Result<ModelHandle<Terminal>> {
if self.is_remote() { if self.is_remote() {
return Err(anyhow!( return Err(anyhow!(
"creating terminals as a guest is not supported yet" "creating terminals as a guest is not supported yet"
)); ));
} else { } else {
unimplemented!() let settings = cx.global::<Settings>();
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)))
} }
} }

View file

@ -221,6 +221,12 @@ pub enum WorkingDirectory {
Always { directory: String }, Always { directory: String },
} }
impl Default for WorkingDirectory {
fn default() -> Self {
Self::CurrentProjectDirectory
}
}
#[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema)] #[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum DockAnchor { pub enum DockAnchor {
@ -473,30 +479,30 @@ impl Settings {
}) })
} }
pub fn terminal_scroll(&self) -> AlternateScroll { fn terminal_setting<F, R: Default + Clone>(&self, f: F) -> R
*self.terminal_overrides.alternate_scroll.as_ref().unwrap_or( where
self.terminal_defaults F: Fn(&TerminalSettings) -> Option<&R>,
.alternate_scroll {
.as_ref() f(&self.terminal_overrides)
.unwrap_or_else(|| &AlternateScroll::On), .or_else(|| f(&self.terminal_defaults))
) .cloned()
.unwrap_or_else(|| R::default())
} }
pub fn terminal_shell(&self) -> Option<Shell> { pub fn terminal_scroll(&self) -> AlternateScroll {
self.terminal_overrides self.terminal_setting(|terminal_setting| terminal_setting.alternate_scroll.as_ref())
.shell }
.as_ref()
.or(self.terminal_defaults.shell.as_ref()) pub fn terminal_shell(&self) -> Shell {
.cloned() self.terminal_setting(|terminal_setting| terminal_setting.shell.as_ref())
} }
pub fn terminal_env(&self) -> HashMap<String, String> { pub fn terminal_env(&self) -> HashMap<String, String> {
self.terminal_overrides.env.clone().unwrap_or_else(|| { self.terminal_setting(|terminal_setting| terminal_setting.env.as_ref())
self.terminal_defaults }
.env
.clone() pub fn terminal_strategy(&self) -> WorkingDirectory {
.unwrap_or_else(|| HashMap::default()) self.terminal_setting(|terminal_setting| terminal_setting.working_directory.as_ref())
})
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]

View file

@ -198,7 +198,7 @@ impl Dimensions for TerminalSize {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub struct TerminalError { pub struct TerminalError {
pub directory: Option<PathBuf>, pub directory: Option<PathBuf>,
pub shell: Option<Shell>, pub shell: Shell,
pub source: std::io::Error, pub source: std::io::Error,
} }
@ -226,24 +226,20 @@ impl TerminalError {
}) })
} }
pub fn shell_to_string(&self) -> Option<String> { pub fn shell_to_string(&self) -> String {
self.shell.as_ref().map(|shell| match shell { match &self.shell {
Shell::System => "<system shell>".to_string(), Shell::System => "<system shell>".to_string(),
Shell::Program(p) => p.to_string(), Shell::Program(p) => p.to_string(),
Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")), Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")),
}) }
} }
pub fn fmt_shell(&self) -> String { pub fn fmt_shell(&self) -> String {
self.shell match &self.shell {
.clone() Shell::System => "<system defined shell>".to_string(),
.map(|shell| match shell { Shell::Program(s) => s.to_string(),
Shell::System => "<system defined shell>".to_string(), Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")),
}
Shell::Program(s) => s,
Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")),
})
.unwrap_or_else(|| "<none specified, using system defined shell>".to_string())
} }
} }
@ -268,18 +264,18 @@ pub struct TerminalBuilder {
impl TerminalBuilder { impl TerminalBuilder {
pub fn new( pub fn new(
working_directory: Option<PathBuf>, working_directory: Option<PathBuf>,
shell: Option<Shell>, shell: Shell,
mut env: HashMap<String, String>, mut env: HashMap<String, String>,
blink_settings: Option<TerminalBlink>, blink_settings: Option<TerminalBlink>,
alternate_scroll: AlternateScroll, alternate_scroll: AlternateScroll,
window_id: usize, window_id: usize,
) -> Result<TerminalBuilder> { ) -> Result<TerminalBuilder> {
let pty_config = { let pty_config = {
let alac_shell = shell.clone().and_then(|shell| match shell { let alac_shell = match shell.clone() {
Shell::System => None, Shell::System => None,
Shell::Program(program) => Some(Program::Just(program)), Shell::Program(program) => Some(Program::Just(program)),
Shell::WithArguments { program, args } => Some(Program::WithArgs { program, args }), Shell::WithArguments { program, args } => Some(Program::WithArgs { program, args }),
}); };
PtyConfig { PtyConfig {
shell: alac_shell, shell: alac_shell,

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[lib] [lib]
path = "src/terminal_container_view.rs" path = "src/terminal_view.rs"
doctest = false doctest = false
[dependencies] [dependencies]

View file

@ -1,18 +1,14 @@
mod persistence;
pub mod terminal_element;
pub mod terminal_view;
use crate::persistence::TERMINAL_DB; use crate::persistence::TERMINAL_DB;
use crate::terminal_view::TerminalView; use crate::TerminalView;
use terminal::alacritty_terminal::index::Point; 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 dirs::home_dir;
use gpui::{ use gpui::{
actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, Task, actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, Task,
View, ViewContext, ViewHandle, WeakViewHandle, View, ViewContext, ViewHandle, WeakViewHandle,
}; };
use terminal_view::regex_search_for_query;
use util::{truncate_and_trailoff, ResultExt}; use util::{truncate_and_trailoff, ResultExt};
use workspace::searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle}; use workspace::searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle};
use workspace::{ use workspace::{
@ -36,7 +32,7 @@ pub fn init(cx: &mut MutableAppContext) {
register_deserializable_item::<TerminalContainer>(cx); register_deserializable_item::<TerminalContainer>(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 //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, _: &workspace::NewTerminal,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) { ) {
let strategy = cx let strategy = cx.global::<Settings>().terminal_strategy();
.global::<Settings>()
.terminal_overrides
.working_directory
.clone()
.unwrap_or(WorkingDirectory::CurrentProjectDirectory);
let working_directory = get_working_directory(workspace, cx, 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); workspace.add_item(Box::new(view), cx);
} }
///Create a new Terminal view. This spawns a task, a thread, and opens the TTY devices ///Create a new Terminal view. This spawns a task, a thread, and opens the TTY devices
pub fn new( pub fn new(
working_directory: Option<PathBuf>, model: anyhow::Result<ModelHandle<Terminal>>,
modal: bool,
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let settings = cx.global::<Settings>(); let content = match model {
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(),
) {
Ok(terminal) => { Ok(terminal) => {
let terminal = cx.add_model(|cx| terminal.subscribe(cx));
let item_id = cx.view_id(); let item_id = cx.view_id();
let view = cx.add_view(|cx| { 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)) cx.subscribe(&view, |_this, _content, event, cx| cx.emit(*event))
.detach(); .detach();
TerminalContainerContent::Connected(view) TerminalContainerContent::Connected(view)
@ -136,7 +116,7 @@ impl TerminalContainer {
TerminalContainer { TerminalContainer {
content, 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 //We want to be able to select the text
//Want to be able to scroll if the error message is massive somehow (resiliency) //Want to be able to scroll if the error message is massive somehow (resiliency)
let program_text = { let program_text = format!("Shell Program: `{}`", self.error.shell_to_string());
match self.error.shell_to_string() {
Some(shell_txt) => format!("Shell Program: `{}`", shell_txt),
None => "No program specified".to_string(),
}
};
let directory_text = { let directory_text = {
match self.error.directory.as_ref() { match self.error.directory.as_ref() {

View file

@ -1,3 +1,7 @@
mod persistence;
pub mod terminal_container_view;
pub mod terminal_element;
use std::{ops::RangeInclusive, time::Duration}; use std::{ops::RangeInclusive, time::Duration};
use context_menu::{ContextMenu, ContextMenuItem}; use context_menu::{ContextMenu, ContextMenuItem};
@ -52,6 +56,7 @@ impl_actions!(terminal, [SendText, SendKeystroke]);
impl_internal_actions!(project_panel, [DeployContextMenu]); impl_internal_actions!(project_panel, [DeployContextMenu]);
pub fn init(cx: &mut MutableAppContext) { pub fn init(cx: &mut MutableAppContext) {
terminal_container_view::init(cx);
//Useful terminal views //Useful terminal views
cx.add_action(TerminalView::send_text); cx.add_action(TerminalView::send_text);
cx.add_action(TerminalView::send_keystroke); cx.add_action(TerminalView::send_keystroke);