WIP
This commit is contained in:
parent
2733f91d8c
commit
c42da5c9b9
6 changed files with 77 additions and 80 deletions
|
@ -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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"))]
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue