From be4873b92bffd2fcdd571e51a1cbf8c0e79e291d Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 25 Jul 2022 15:54:49 -0700 Subject: [PATCH] Checkpoint, build failing --- crates/terminal/README.md | 8 +++ crates/terminal/src/modal.rs | 2 +- crates/terminal/src/terminal.rs | 55 +++++++++++-------- .../src/{terminal_tab.rs => terminal_view.rs} | 0 4 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 crates/terminal/README.md rename crates/terminal/src/{terminal_tab.rs => terminal_view.rs} (100%) diff --git a/crates/terminal/README.md b/crates/terminal/README.md new file mode 100644 index 0000000000..c1e64726b2 --- /dev/null +++ b/crates/terminal/README.md @@ -0,0 +1,8 @@ +Design notes: + +This crate is split into two conceptual halves: +- The terminal.rs file and the ./src/mappings/ folder, these contain the code for interacting with Alacritty and maintaining the pty event loop. Some behavior in this file is constrained by terminal protocols and standards. The Zed init function is also placed here. +- Everything else. These other files integrate the `Terminal` struct created in terminal.rs into the rest of GPUI. The main entry point for GPUI is the terminal_view.rs file and the modal.rs file. + +Terminals are created externally, and so can fail in unexpected ways However, GPUI currently does not have an API for models than can fail to instantiate. `TerminalBuilder` solves this by using Rust's type system to split `Terminal` instantiation into a 2 step process: first attempt to create the file handles with `TerminalBuilder::new()`, check the result, then call `TerminalBuilder::subscribe(cx)` from within a model context. +The TerminalView struct abstracts over failed and successful terminals, and provides other constructs a standardized way of instantiating an always-successful terminal view. \ No newline at end of file diff --git a/crates/terminal/src/modal.rs b/crates/terminal/src/modal.rs index a238f4cbc1..2fbf713495 100644 --- a/crates/terminal/src/modal.rs +++ b/crates/terminal/src/modal.rs @@ -2,7 +2,7 @@ use gpui::{ModelHandle, ViewContext}; use workspace::Workspace; use crate::{ - terminal_tab::{get_working_directory, DeployModal, TerminalContent, TerminalView}, + terminal_view::{get_working_directory, DeployModal, TerminalContent, TerminalView}, Event, Terminal, }; diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 207ed6a69f..4d6c7db646 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -2,7 +2,7 @@ pub mod connected_el; pub mod connected_view; pub mod mappings; pub mod modal; -pub mod terminal_tab; +pub mod terminal_view; use alacritty_terminal::{ ansi::{ClearMode, Handler}, @@ -22,7 +22,7 @@ use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use modal::deploy_modal; use settings::{Settings, Shell}; use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc, time::Duration}; -use terminal_tab::TerminalView; +use terminal_view::TerminalView; use thiserror::Error; use gpui::{ @@ -319,6 +319,7 @@ impl TerminalBuilder { pty_tx: Notifier(pty_tx), term, title: shell_txt.to_string(), + event_stack: vec![], }; Ok(TerminalBuilder { @@ -330,8 +331,8 @@ impl TerminalBuilder { pub fn subscribe(mut self, cx: &mut ModelContext) -> Terminal { cx.spawn_weak(|this, mut cx| async move { 'outer: loop { - //Even as low as 45 locks zed up - let delay = cx.background().timer(Duration::from_secs_f32(1.0 / 30.)); + //TODO: Pending GPUI updates, sync this to some higher, smarter system. + let delay = cx.background().timer(Duration::from_secs_f32(1.0 / 60.)); let mut events = vec![]; @@ -349,9 +350,8 @@ impl TerminalBuilder { match this.upgrade(&cx) { Some(this) => { this.update(&mut cx, |this, cx| { - for event in events { - this.process_terminal_event(event, cx); - } + this.push_events(events); + cx.notify(); }); } None => break 'outer, @@ -370,13 +370,19 @@ pub struct Terminal { pty_tx: Notifier, term: Arc>>, pub title: String, + event_stack: Vec, } impl Terminal { + fn push_events(&mut self, events: Vec) { + self.event_stack.extend(events) + } + ///Takes events from Alacritty and translates them to behavior on this view fn process_terminal_event( &mut self, event: alacritty_terminal::event::Event, + term: &mut Term, cx: &mut ModelContext, ) { match event { @@ -384,7 +390,10 @@ impl Terminal { AlacTermEvent::Wakeup => { cx.emit(Event::Wakeup); } - AlacTermEvent::PtyWrite(out) => self.write_to_pty(out), + AlacTermEvent::PtyWrite(out) => { + term.scroll_display(Scroll::Bottom); + self.pty_tx.notify(out.into_bytes()) + } AlacTermEvent::MouseCursorDirty => { //Calculate new cursor style. //TODO: alacritty/src/input.rs:L922-L939 @@ -408,7 +417,7 @@ impl Terminal { .unwrap_or("".to_string()), )), AlacTermEvent::ColorRequest(index, format) => { - let color = self.term.lock().colors()[index].unwrap_or_else(|| { + let color = term.colors()[index].unwrap_or_else(|| { let term_style = &cx.global::().theme.terminal; to_alac_rgb(get_color_at_index(&index, &term_style.colors)) }); @@ -427,13 +436,7 @@ impl Terminal { ///Write the Input payload to the tty. This locks the terminal so we can scroll it. pub fn write_to_pty(&self, input: String) { - self.write_bytes_to_pty(input.into_bytes()); - } - - ///Write the Input payload to the tty. This locks the terminal so we can scroll it. - fn write_bytes_to_pty(&self, input: Vec) { - self.term.lock().scroll_display(Scroll::Bottom); - self.pty_tx.notify(input); + self.event_stack.push(AlacTermEvent::PtyWrite(input)) } ///Resize the terminal and the PTY. This locks the terminal. @@ -487,19 +490,23 @@ impl Terminal { self.term.lock().selection = sel; } - pub fn render_lock(&self, new_size: Option, f: F) -> T + pub fn render_lock(&self, cx: &mut ModelContext, f: F) -> T where F: FnOnce(RenderableContent, char) -> T, { - if let Some(new_size) = new_size { - self.pty_tx.0.send(Msg::Resize(new_size.into())).ok(); //Give the PTY a chance to react to the new size - //TODO: Is this bad for performance? - } - let mut term = self.term.lock(); //Lock - if let Some(new_size) = new_size { - term.resize(new_size); //Reflow + //TODO, handle resizes + // if let Some(new_size) = new_size { + // self.pty_tx.0.send(Msg::Resize(new_size.into())).ok(); + // } + + // if let Some(new_size) = new_size { + // term.resize(new_size); //Reflow + // } + + for event in self.event_stack.drain(..) { + self.process_terminal_event(event, &mut term, cx) } let content = term.renderable_content(); diff --git a/crates/terminal/src/terminal_tab.rs b/crates/terminal/src/terminal_view.rs similarity index 100% rename from crates/terminal/src/terminal_tab.rs rename to crates/terminal/src/terminal_view.rs