Checkpoint, this commit does not compile

This commit is contained in:
Mikayla Maki 2022-07-20 12:41:04 -07:00
parent b493bafb48
commit 9b6df1fb61
6 changed files with 116 additions and 50 deletions

1
Cargo.lock generated
View file

@ -5368,6 +5368,7 @@ dependencies = [
"shellexpand",
"smallvec",
"theme",
"thiserror",
"util",
"workspace",
]

View file

@ -25,6 +25,7 @@ dirs = "4.0.0"
shellexpand = "2.1.0"
libc = "0.2"
anyhow = "1"
thiserror = "1.0"
[dev-dependencies]

View file

@ -13,12 +13,14 @@ use alacritty_terminal::{
tty::{self, setup_env},
Term,
};
use anyhow::{bail, Result};
use futures::{
channel::mpsc::{unbounded, UnboundedSender},
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
StreamExt,
};
use settings::{Settings, Shell};
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc};
use thiserror::Error;
use gpui::{keymap::Keystroke, ClipboardItem, CursorStyle, Entity, ModelContext};
@ -52,23 +54,84 @@ impl EventListener for ZedListener {
}
}
pub enum TerminalConnection {
Connected(Terminal),
Disconnected {
directory: Option<PathBuf>,
shell: Option<Shell>,
error: Option<std::io::Error>,
},
#[derive(Error, Debug)]
pub struct TerminalError {
directory: Option<PathBuf>,
shell: Option<Shell>,
source: std::io::Error,
}
impl TerminalConnection {
impl Display for TerminalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let dir_string: String = self
.directory
.map(|path| {
match path
.into_os_string()
.into_string()
.map_err(|os_str| format!("<non-utf8 path> {}", os_str.to_string_lossy()))
{
Ok(s) => s,
Err(s) => s,
}
})
.unwrap_or_else(|| {
let default_dir =
dirs::home_dir().map(|buf| buf.into_os_string().to_string_lossy());
match default_dir {
Some(dir) => format!("<none specified, using home> {}", dir),
None => "<none specified, could not find home>".to_string(),
}
});
let shell = self
.shell
.map(|shell| match shell {
Shell::System => {
let mut buf = [0; 1024];
let pw = alacritty_unix::get_pw_entry(&mut buf).ok();
match pw {
Some(pw) => format!("<system defined shell> {}", pw.shell),
None => "<could not access system defined shell>".to_string(),
}
}
Shell::Program(s) => s,
Shell::WithArguments { program, args } => format!("{} {}", program, args.join(" ")),
})
.unwrap_or_else(|| {
let mut buf = [0; 1024];
let pw = alacritty_unix::get_pw_entry(&mut buf).ok();
match pw {
Some(pw) => {
format!("<none specified, using system defined shell> {}", pw.shell)
}
None => {
"<none specified, could not access system defined shell> {}".to_string()
}
}
});
write!(
f,
"Working directory: {} Shell command: `{}`, IOError: {}",
dir_string, shell, self.source
)
}
}
pub struct DisconnectedPTY {
terminal: Terminal,
events_rx: UnboundedReceiver<AlacTermEvent>,
}
impl DisconnectedPTY {
pub fn new(
working_directory: Option<PathBuf>,
shell: Option<Shell>,
env: Option<HashMap<String, String>>,
initial_size: TerminalDimensions,
cx: &mut ModelContext<Self>,
) -> TerminalConnection {
) -> Result<DisconnectedPTY> {
let pty_config = {
let alac_shell = shell.clone().and_then(|shell| match shell {
Shell::System => None,
@ -107,11 +170,11 @@ impl TerminalConnection {
let pty = match tty::new(&pty_config, initial_size.into(), None) {
Ok(pty) => pty,
Err(error) => {
return TerminalConnection::Disconnected {
bail!(TerminalError {
directory: working_directory,
shell,
error: Some(error),
};
source: error,
});
}
};
@ -149,20 +212,20 @@ impl TerminalConnection {
associated_directory: working_directory,
};
Ok(DisconnectedPTY {
terminal,
events_rx,
})
}
pub fn connect(self, cx: &mut ModelContext<Terminal>) -> Terminal {
cx.spawn_weak(|this, mut cx| async move {
//Listen for terminal events
while let Some(event) = events_rx.next().await {
while let Some(event) = self.events_rx.next().await {
match this.upgrade(&cx) {
Some(this) => {
this.update(&mut cx, |this, cx| {
match this {
TerminalConnection::Connected(conn) => {
conn.process_terminal_event(event, cx)
}
//There should never be a state where the terminal is disconnected
//And receiving events from the pty
TerminalConnection::Disconnected { .. } => unreachable!(),
}
this.process_terminal_event(event, cx);
cx.notify();
});
@ -173,14 +236,7 @@ impl TerminalConnection {
})
.detach();
TerminalConnection::Connected(terminal)
}
pub fn get_terminal(&self) -> Option<&Terminal> {
match self {
TerminalConnection::Connected(conn) => Some(&conn),
TerminalConnection::Disconnected { .. } => None,
}
self.terminal
}
}
@ -196,7 +252,7 @@ impl Terminal {
fn process_terminal_event(
&mut self,
event: alacritty_terminal::event::Event,
cx: &mut ModelContext<TerminalConnection>,
cx: &mut ModelContext<Terminal>,
) {
match event {
// TODO: Handle is_self_focused in subscription on terminal view
@ -361,21 +417,23 @@ impl Terminal {
}
}
impl Drop for TerminalConnection {
impl Drop for DisconnectedPTY {
fn drop(&mut self) {
match self {
TerminalConnection::Connected(conn) => {
conn.pty_tx.0.send(Msg::Shutdown).ok();
}
_ => {}
};
self.terminal.pty_tx.0.send(Msg::Shutdown).ok();
}
}
impl Entity for TerminalConnection {
impl Drop for Terminal {
fn drop(&mut self) {
self.pty_tx.0.send(Msg::Shutdown).ok();
}
}
impl Entity for Terminal {
type Event = Event;
}
//TODO Move this around
mod alacritty_unix {
use alacritty_terminal::config::Program;
use gpui::anyhow::{bail, Result};

View file

@ -1,10 +1,10 @@
use gpui::{ModelHandle, ViewContext};
use workspace::Workspace;
use crate::{get_wd_for_workspace, DeployModal, Event, TerminalConnection, TerminalView};
use crate::{connection::Terminal, get_wd_for_workspace, DeployModal, Event, TerminalView};
#[derive(Debug)]
struct StoredConnection(ModelHandle<TerminalConnection>);
struct StoredConnection(ModelHandle<Terminal>);
pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewContext<Workspace>) {
// Pull the terminal connection out of the global if it has been stored
@ -46,7 +46,7 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon
pub fn on_event(
workspace: &mut Workspace,
_: ModelHandle<TerminalConnection>,
_: ModelHandle<Terminal>,
event: &Event,
cx: &mut ViewContext<Workspace>,
) {

View file

@ -3,7 +3,7 @@ pub mod connection;
mod modal;
pub mod terminal_element;
use connection::{Event, TerminalConnection};
use connection::{DisconnectedPTY, Event, Terminal, TerminalError};
use dirs::home_dir;
use gpui::{
actions, elements::*, geometry::vector::vec2f, keymap::Keystroke, AppContext, ClipboardItem,
@ -64,7 +64,7 @@ pub fn init(cx: &mut MutableAppContext) {
///A terminal view, maintains the PTY's file handles and communicates with the terminal
pub struct TerminalView {
connection: ModelHandle<TerminalConnection>,
connection: Result<ModelHandle<Terminal>, TerminalError>,
has_new_content: bool,
//Currently using iTerm bell, show bell emoji in tab until input is received
has_bell: bool,
@ -94,14 +94,20 @@ impl TerminalView {
(shell, envs)
};
let connection = cx
.add_model(|cx| TerminalConnection::new(working_directory, shell, envs, size_info, cx));
let connection = DisconnectedPTY::new(working_directory, shell, envs, size_info)
.map(|pty| cx.add_model(|cx| pty.connect(cx)))
.map_err(|err| {
match err.downcast::<TerminalError>() {
Ok(err) => err,
Err(_) => unreachable!(), //This should never happen
}
});
TerminalView::from_connection(connection, modal, cx)
}
fn from_connection(
connection: ModelHandle<TerminalConnection>,
connection: Result<ModelHandle<Terminal>, TerminalError>,
modal: bool,
cx: &mut ViewContext<Self>,
) -> TerminalView {

View file

@ -24,7 +24,7 @@ impl<'a> TerminalTestContext<'a> {
);
let connection =
cx.add_model(|cx| TerminalConnection::new(None, None, None, size_info, cx));
cx.add_model(|cx| TerminalConnection::new_tty(None, None, None, size_info, cx));
TerminalTestContext { cx, connection }
}