From 150d2ff53fb021be7ed82316a5e96fe948565910 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 18 Jul 2022 14:53:56 -0700 Subject: [PATCH] Attempting to continue rebase --- crates/gpui/src/app.rs | 26 +--- crates/terminal/src/connection.rs | 109 ++++++++++--- crates/terminal/src/modal.rs | 12 +- crates/terminal/src/terminal.rs | 147 +++++++++--------- crates/terminal/src/terminal_element.rs | 107 +++++++------ .../src/tests/terminal_test_context.rs | 14 +- 6 files changed, 229 insertions(+), 186 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 547e55699c8b4f89a093cf262b27274996d67ec3..2cd6687bcb052206e4b21918a3822d9cf959d9f0 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1781,21 +1781,6 @@ impl MutableAppContext { }) } - pub fn try_add_model(&mut self, build_model: F) -> Result> - where - T: Entity, - F: FnOnce(&mut ModelContext) -> Result, - { - self.update(|this| { - let model_id = post_inc(&mut this.next_entity_id); - let handle = ModelHandle::new(model_id, &this.cx.ref_counts); - let mut cx = ModelContext::new(this, model_id); - let model = build_model(&mut cx)?; - this.cx.models.insert(model_id, Box::new(model)); - Ok(handle) - }) - } - pub fn add_window( &mut self, window_options: WindowOptions, @@ -1970,13 +1955,10 @@ impl MutableAppContext { for model_id in dropped_models { self.subscriptions.lock().remove(&model_id); self.observations.lock().remove(&model_id); - //Model handles and IDs may have been created to instantiate a model without - //finishing successfully (`try_add_model()`) - if let Some(mut model) = self.cx.models.remove(&model_id) { - model.release(self); - self.pending_effects - .push_back(Effect::ModelRelease { model_id, model }); - } + let mut model = self.cx.models.remove(&model_id).unwrap(); + model.release(self); + self.pending_effects + .push_back(Effect::ModelRelease { model_id, model }); } for (window_id, view_id) in dropped_views { diff --git a/crates/terminal/src/connection.rs b/crates/terminal/src/connection.rs index 6515806949407b1c3a4bd1c1024aa18c1a08f61e..5809f11eaa83c179d2306feedfbf9d1352cd3110 100644 --- a/crates/terminal/src/connection.rs +++ b/crates/terminal/src/connection.rs @@ -6,10 +6,11 @@ use alacritty_terminal::{ event::{Event as AlacTermEvent, EventListener, Notify}, event_loop::{EventLoop, Msg, Notifier}, grid::Scroll, + selection::Selection, sync::FairMutex, - term::{SizeInfo, TermMode}, + term::{cell::Cell, RenderableContent, SizeInfo, TermMode}, tty::{self, setup_env}, - Term, + Grid, Term, }; use anyhow::Result; use futures::channel::mpsc::{ @@ -48,12 +49,13 @@ impl EventListener for ZedListener { } } -pub struct TerminalConnection { - pub pty_tx: Notifier, - pub term: Arc>>, - pub title: String, - pub associated_directory: Option, - pub cur_size: SizeInfo, +pub enum TerminalConnection { + Connected(Terminal), + Disconnected { + directory: Option, + shell: Option, + error: std::io::Error, + }, } impl TerminalConnection { @@ -63,7 +65,7 @@ impl TerminalConnection { env: Option>, initial_size: SizeInfo, cx: &mut ModelContext, - ) -> Result { + ) -> TerminalConnection { let pty_config = { let shell = shell.and_then(|shell| match shell { Shell::System => None, @@ -99,7 +101,16 @@ impl TerminalConnection { let term = Arc::new(FairMutex::new(term)); //Setup the pty... - let pty = tty::new(&pty_config, &initial_size, None)?; + let pty = match tty::new(&pty_config, &initial_size, None) { + Ok(pty) => pty, + Err(error) => { + return TerminalConnection::Disconnected { + directory: working_directory, + shell, + error, + }; + } + }; let shell = { let mut buf = [0; 1024]; @@ -121,13 +132,20 @@ impl TerminalConnection { let pty_tx = event_loop.channel(); let _io_thread = event_loop.spawn(); + let terminal = Terminal { + pty_tx: Notifier(pty_tx), + term, + title: DEFAULT_TITLE.to_string(), + associated_directory: working_directory, + }; + cx.spawn_weak(|this, mut cx| async move { //Listen for terminal events while let Some(event) = events_rx.next().await { match this.upgrade(&cx) { Some(this) => { this.update(&mut cx, |this, cx| { - this.process_terminal_event(event, cx); + terminal.process_terminal_event(event, cx); cx.notify(); }); } @@ -137,20 +155,30 @@ impl TerminalConnection { }) .detach(); - Ok(TerminalConnection { - pty_tx: Notifier(pty_tx), - term, - title: shell.to_string(), - cur_size: initial_size, - associated_directory: working_directory, - }) + TerminalConnection::Connected(terminal) } + pub fn get_terminal(&self) -> Option<&Terminal> { + match self { + TerminalConnection::Connected(conn) => Some(&conn), + TerminalConnection::Disconnected { .. } => None, + } + } +} + +pub struct Terminal { + pty_tx: Notifier, + term: Arc>>, + pub title: String, + pub associated_directory: Option, +} + +impl Terminal { ///Takes events from Alacritty and translates them to behavior on this view fn process_terminal_event( &mut self, event: alacritty_terminal::event::Event, - cx: &mut ModelContext, + cx: &mut ModelContext, ) { match event { // TODO: Handle is_self_focused in subscription on terminal view @@ -198,12 +226,12 @@ impl TerminalConnection { } ///Write the Input payload to the tty. This locks the terminal so we can scroll it. - pub fn write_to_pty(&mut self, input: String) { + 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(&mut self, input: Vec) { + fn write_bytes_to_pty(&self, input: Vec) { self.term.lock().scroll_display(Scroll::Bottom); self.pty_tx.notify(input); } @@ -214,12 +242,12 @@ impl TerminalConnection { self.term.lock().resize(new_size); } - pub fn clear(&mut self) { + pub fn clear(&self) { self.write_to_pty("\x0c".into()); self.term.lock().clear_screen(ClearMode::Saved); } - pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool { + pub fn try_keystroke(&self, keystroke: &Keystroke) -> bool { let guard = self.term.lock(); let mode = guard.mode(); let esc = to_esc_str(keystroke, mode); @@ -233,7 +261,7 @@ impl TerminalConnection { } ///Paste text into the terminal - pub fn paste(&mut self, text: &str) { + pub fn paste(&self, text: &str) { if self.term.lock().mode().contains(TermMode::BRACKETED_PASTE) { self.write_to_pty("\x1b[200~".to_string()); self.write_to_pty(text.replace('\x1b', "").to_string()); @@ -243,6 +271,32 @@ impl TerminalConnection { } } + pub fn copy(&self) -> Option { + let term = self.term.lock(); + term.selection_to_string() + } + + ///Takes the selection out of the terminal + pub fn take_selection(&self) -> Option { + self.term.lock().selection.take() + } + + ///Sets the selection object on the terminal + pub fn set_selection(&self, sel: Option) { + self.term.lock().selection = sel; + } + + ///Get the relevant rendering values from the terminal + pub fn renderable_content(&self) -> (RenderableContent, &Grid) { + let term = self.term.lock(); + (term.renderable_content(), term.grid()) + } + + ///Scroll the terminal + pub fn scroll(&self, scroll: Scroll) { + self.term.lock().scroll_display(scroll) + } + // pub fn click(&mut self, pos: Vector2F, clicks: usize) {} // pub fn drag(prev_pos: Vector2F, pos: Vector2F) {} @@ -252,7 +306,12 @@ impl TerminalConnection { impl Drop for TerminalConnection { fn drop(&mut self) { - self.pty_tx.0.send(Msg::Shutdown).ok(); + match self { + TerminalConnection::Connected(conn) => { + conn.pty_tx.0.send(Msg::Shutdown).ok(); + } + _ => {} + }; } } diff --git a/crates/terminal/src/modal.rs b/crates/terminal/src/modal.rs index 7349ae233efcb285a27d09d05a258647a69c6d16..91d2d9ff738b634513e862cd5d7ac9ad7d706f59 100644 --- a/crates/terminal/src/modal.rs +++ b/crates/terminal/src/modal.rs @@ -1,8 +1,7 @@ use gpui::{ModelHandle, ViewContext}; -use util::ResultExt; use workspace::Workspace; -use crate::{get_wd_for_workspace, DeployModal, Event, Terminal, TerminalConnection}; +use crate::{get_wd_for_workspace, DeployModal, Event, TerminalConnection, TerminalView}; #[derive(Debug)] struct StoredConnection(ModelHandle); @@ -17,7 +16,7 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon if let Some(StoredConnection(stored_connection)) = possible_connection { // Create a view from the stored connection workspace.toggle_modal(cx, |_, cx| { - cx.add_view(|cx| Terminal::from_connection(stored_connection.clone(), true, cx)) + cx.add_view(|cx| TerminalView::from_connection(stored_connection.clone(), true, cx)) }); cx.set_global::>(Some(StoredConnection( stored_connection.clone(), @@ -27,10 +26,7 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon if let Some(closed_terminal_handle) = workspace.toggle_modal(cx, |workspace, cx| { let wd = get_wd_for_workspace(workspace, cx); - //TODO: Create a 'failed to launch' view which prints the error and config details. - let this = cx - .add_option_view(|cx| Terminal::new(wd, true, cx).log_err()) - .unwrap(); + let this = cx.add_view(|cx| TerminalView::new(wd, true, cx)); let connection_handle = this.read(cx).connection.clone(); cx.subscribe(&connection_handle, on_event).detach(); @@ -60,7 +56,7 @@ pub fn on_event( if workspace .modal() .cloned() - .and_then(|modal| modal.downcast::()) + .and_then(|modal| modal.downcast::()) .is_some() { workspace.dismiss_modal(cx) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 605d9533f2237cb14154eb652fa5e0ecd7416a88..bc1c471bfa3b88a8512153b15b89b0a56611e506 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -4,7 +4,6 @@ mod modal; pub mod terminal_element; use alacritty_terminal::term::SizeInfo; -use anyhow::Result; use connection::{Event, TerminalConnection}; use dirs::home_dir; use gpui::{ @@ -17,7 +16,6 @@ use project::{LocalWorktree, Project, ProjectPath}; use settings::{Settings, WorkingDirectory}; use smallvec::SmallVec; use std::path::{Path, PathBuf}; -use util::ResultExt; use workspace::{Item, Workspace}; use crate::terminal_element::TerminalEl; @@ -50,21 +48,21 @@ actions!( ///Initialize and register all of our action handlers pub fn init(cx: &mut MutableAppContext) { //Global binding overrrides - cx.add_action(Terminal::ctrl_c); - cx.add_action(Terminal::up); - cx.add_action(Terminal::down); - cx.add_action(Terminal::escape); - cx.add_action(Terminal::enter); + cx.add_action(TerminalView::ctrl_c); + cx.add_action(TerminalView::up); + cx.add_action(TerminalView::down); + cx.add_action(TerminalView::escape); + cx.add_action(TerminalView::enter); //Useful terminal actions - cx.add_action(Terminal::deploy); + cx.add_action(TerminalView::deploy); cx.add_action(deploy_modal); - cx.add_action(Terminal::copy); - cx.add_action(Terminal::paste); - cx.add_action(Terminal::clear); + cx.add_action(TerminalView::copy); + cx.add_action(TerminalView::paste); + cx.add_action(TerminalView::clear); } ///A terminal view, maintains the PTY's file handles and communicates with the terminal -pub struct Terminal { +pub struct TerminalView { connection: ModelHandle, has_new_content: bool, //Currently using iTerm bell, show bell emoji in tab until input is received @@ -73,18 +71,14 @@ pub struct Terminal { modal: bool, } -impl Entity for Terminal { +impl Entity for TerminalView { type Event = Event; } -impl Terminal { +impl TerminalView { ///Create a new Terminal view. This spawns a task, a thread, and opens the TTY devices ///To get the right working directory from a workspace, use: `get_wd_for_workspace()` - fn new( - working_directory: Option, - modal: bool, - cx: &mut ViewContext, - ) -> Result { + fn new(working_directory: Option, modal: bool, cx: &mut ViewContext) -> Self { //The details here don't matter, the terminal will be resized on the first layout let size_info = SizeInfo::new( DEBUG_TERMINAL_WIDTH, @@ -103,18 +97,17 @@ impl Terminal { (shell, envs) }; - let connection = cx.try_add_model(|cx| { - TerminalConnection::new(working_directory, shell, envs, size_info, cx) - })?; + let connection = cx + .add_model(|cx| TerminalConnection::new(working_directory, shell, envs, size_info, cx)); - Ok(Terminal::from_connection(connection, modal, cx)) + TerminalView::from_connection(connection, modal, cx) } fn from_connection( connection: ModelHandle, modal: bool, cx: &mut ViewContext, - ) -> Terminal { + ) -> TerminalView { cx.observe(&connection, |_, _, cx| cx.notify()).detach(); cx.subscribe(&connection, |this, _, event, cx| match event { Event::Wakeup => { @@ -137,7 +130,7 @@ impl Terminal { }) .detach(); - Terminal { + TerminalView { connection, has_new_content: true, has_bell: false, @@ -152,73 +145,79 @@ impl Terminal { fn clear(&mut self, _: &Clear, cx: &mut ViewContext) { self.connection - .update(cx, |connection, _| connection.clear()); + .read(cx) + .get_terminal() + .map(|term| term.clear()); } ///Create a new Terminal in the current working directory or the user's home directory fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { let wd = get_wd_for_workspace(workspace, cx); - if let Some(view) = cx.add_option_view(|cx| Terminal::new(wd, false, cx).log_err()) { - workspace.add_item(Box::new(view), cx); - } + let view = cx.add_view(|cx| TerminalView::new(wd, false, cx)); + workspace.add_item(Box::new(view), cx); } ///Attempt to paste the clipboard into the terminal fn copy(&mut self, _: &Copy, cx: &mut ViewContext) { - let term = self.connection.read(cx).term.lock(); - let copy_text = term.selection_to_string(); - match copy_text { - Some(s) => cx.write_to_clipboard(ClipboardItem::new(s)), - None => (), - } + self.connection + .read(cx) + .get_terminal() + .and_then(|term| term.copy()) + .map(|text| cx.write_to_clipboard(ClipboardItem::new(text))); } ///Attempt to paste the clipboard into the terminal fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { - if let Some(item) = cx.read_from_clipboard() { - self.connection.update(cx, |connection, _| { - connection.paste(item.text()); - }) - } + cx.read_from_clipboard().map(|item| { + self.connection + .read(cx) + .get_terminal() + .map(|term| term.paste(item.text())); + }); } ///Synthesize the keyboard event corresponding to 'up' fn up(&mut self, _: &Up, cx: &mut ViewContext) { - self.connection.update(cx, |connection, _| { - connection.try_keystroke(&Keystroke::parse("up").unwrap()); - }); + self.connection + .read(cx) + .get_terminal() + .map(|term| term.try_keystroke(&Keystroke::parse("up").unwrap())); } ///Synthesize the keyboard event corresponding to 'down' fn down(&mut self, _: &Down, cx: &mut ViewContext) { - self.connection.update(cx, |connection, _| { - connection.try_keystroke(&Keystroke::parse("down").unwrap()); - }); + self.connection + .read(cx) + .get_terminal() + .map(|term| term.try_keystroke(&Keystroke::parse("down").unwrap())); } ///Synthesize the keyboard event corresponding to 'ctrl-c' fn ctrl_c(&mut self, _: &CtrlC, cx: &mut ViewContext) { - self.connection.update(cx, |connection, _| { - connection.try_keystroke(&Keystroke::parse("ctrl-c").unwrap()); - }); + self.connection + .read(cx) + .get_terminal() + .map(|term| term.try_keystroke(&Keystroke::parse("ctrl-c").unwrap())); } ///Synthesize the keyboard event corresponding to 'escape' fn escape(&mut self, _: &Escape, cx: &mut ViewContext) { - self.connection.update(cx, |connection, _| { - connection.try_keystroke(&Keystroke::parse("escape").unwrap()); - }); + self.connection + .read(cx) + .get_terminal() + .map(|term| term.try_keystroke(&Keystroke::parse("escape").unwrap())); } ///Synthesize the keyboard event corresponding to 'enter' fn enter(&mut self, _: &Enter, cx: &mut ViewContext) { - self.connection.update(cx, |connection, _| { - connection.try_keystroke(&Keystroke::parse("enter").unwrap()); - }); + self.connection + .read(cx) + .get_terminal() + .map(|term| term.try_keystroke(&Keystroke::parse("enter").unwrap())); } } -impl View for Terminal { +impl View for TerminalView { fn ui_name() -> &'static str { "Terminal" } @@ -252,36 +251,42 @@ impl View for Terminal { } } -impl Item for Terminal { +impl Item for TerminalView { fn tab_content( &self, _detail: Option, tab_theme: &theme::Tab, cx: &gpui::AppContext, ) -> ElementBox { - Flex::row() - .with_child( - Label::new( - self.connection.read(cx).title.clone(), - tab_theme.label.clone(), - ) + let mut flex = Flex::row(); + + let title = match self.connection.read(cx) { + TerminalConnection::Connected(conn) => conn.title, + TerminalConnection::Disconnected { .. } => "Terminal".to_string(), //TODO ask nate about htis + }; + + flex.with_child( + Label::new(title, tab_theme.label.clone()) .aligned() .contained() .boxed(), - ) - .boxed() + ) + .boxed() } fn clone_on_split(&self, cx: &mut ViewContext) -> Option { //From what I can tell, there's no way to tell the current working //Directory of the terminal from outside the shell. There might be //solutions to this, but they are non-trivial and require more IPC - Terminal::new( - self.connection.read(cx).associated_directory.clone(), - false, - cx, - ) - .ok() + + let wd = self + .connection + .read(cx) + .get_terminal() + .and_then(|term| term.associated_directory) + .clone(); + + Some(TerminalView::new(wd, false, cx)) } fn project_path(&self, _cx: &gpui::AppContext) -> Option { diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 514d5ee1d47ebe85735b9d701fdc6a07b8fb4c4f..0d34914b767b996a8dabc73838dff51b30c750ea 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -105,17 +105,20 @@ impl TerminalEl { MouseButton::Left, move |MouseButtonEvent { position, .. }, cx| { if let Some(conn_handle) = mouse_down_connection.upgrade(cx.app) { - conn_handle.update(cx.app, |conn, _cx| { - let mut term = conn.term.lock(); - let (point, side) = mouse_to_cell_data( - position, - origin, - conn.cur_size, - term.renderable_content().display_offset, - ); - term.selection = - Some(Selection::new(SelectionType::Simple, point, side)) - }); + conn_handle.update(cx.app, |connection, cx| { + connection.get_terminal().map(|terminal| { + let (point, side) = mouse_to_cell_data( + position, + origin, + cur_size, + terminal.get_display_offset(), + ); + + terminal.mouse_down(point, side); + + cx.notify(); + }); + }) } }, ) @@ -130,13 +133,11 @@ impl TerminalEl { cx.focus_parent_view(); if let Some(conn_handle) = click_connection.upgrade(cx.app) { conn_handle.update(cx.app, |conn, cx| { - let mut term = conn.term.lock(); - let (point, side) = mouse_to_cell_data( position, origin, - conn.cur_size, - term.renderable_content().display_offset, + // conn.cur_size, + // term.renderable_content().display_offset, ); let selection_type = match click_count { @@ -150,9 +151,7 @@ impl TerminalEl { let selection = selection_type.map(|selection_type| { Selection::new(selection_type, point, side) }); - - term.selection = selection; - + conn.set_selection(selection); cx.notify(); }); } @@ -162,22 +161,19 @@ impl TerminalEl { MouseButton::Left, move |_, MouseMovedEvent { position, .. }, cx| { if let Some(conn_handle) = drag_connection.upgrade(cx.app) { - conn_handle.update(cx.app, |conn, cx| { - let mut term = conn.term.lock(); - - let (point, side) = mouse_to_cell_data( - position, - origin, - conn.cur_size, - term.renderable_content().display_offset, - ); - - if let Some(mut selection) = term.selection.take() { - selection.update(point, side); - term.selection = Some(selection); - } - - cx.notify() + conn_handle.update(cx.app, |connection, cx| { + connection.get_terminal().map(|terminal| { + let (point, side) = mouse_to_cell_data( + position, + origin, + cur_size, + terminal.get_display_offset(), + ); + + terminal.drag(point, side); + + cx.notify() + }); }); } }, @@ -197,14 +193,17 @@ impl Element for TerminalEl { ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { let tcx = TerminalLayoutContext::new(cx.global::(), &cx.font_cache()); - let term = { - let connection = self.connection.upgrade(cx).unwrap().read(cx); - //This locks the terminal, so resize it first. - connection.set_size(make_new_size(constraint, &tcx.cell_width, &tcx.line_height)); - connection.term.lock() - }; + let terminal = self + .connection + .upgrade(cx) + .unwrap() + .read(cx) + .get_terminal() //TODO! + .unwrap(); + //This locks the terminal, so resize it first. + terminal.set_size(make_new_size(constraint, &tcx.cell_width, &tcx.line_height)); - let content = term.renderable_content(); + let (content, grid) = terminal.renderable_content(); //Layout grid cells @@ -219,7 +218,7 @@ impl Element for TerminalEl { //Layout cursor let cursor = layout_cursor( - term.grid(), + grid, cx.text_layout_cache, &tcx, content.cursor.point, @@ -390,14 +389,12 @@ impl Element for TerminalEl { let vertical_scroll = (delta.y() / layout.line_height.0) * ALACRITTY_SCROLL_MULTIPLIER; - if let Some(connection) = self.connection.upgrade(cx.app) { - connection.update(cx.app, |connection, _| { - connection - .term - .lock() - .scroll_display(Scroll::Delta(vertical_scroll.round() as i32)); - }) - } + self.connection + .upgrade(cx.app) + .and_then(|handle| handle.read(cx.app).get_terminal()) + .map(|terminal| { + terminal.scroll(Scroll::Delta(vertical_scroll.round() as i32)); + }); }) .is_some(), Event::KeyDown(KeyDownEvent { keystroke, .. }) => { @@ -412,16 +409,18 @@ impl Element for TerminalEl { self.connection .upgrade(cx.app) - .map(|connection| { - connection - .update(cx.app, |connection, _| connection.try_keystroke(keystroke)) - }) + .and_then(|model_handle| model_handle.read(cx.app).get_terminal()) + .map(|term| term.try_keystroke(keystroke)) .unwrap_or(false) } _ => false, } } + fn metadata(&self) -> Option<&dyn std::any::Any> { + None + } + fn debug( &self, _bounds: gpui::geometry::rect::RectF, diff --git a/crates/terminal/src/tests/terminal_test_context.rs b/crates/terminal/src/tests/terminal_test_context.rs index 64d602ffb5cdbcae67ca70fe2c34d1b0d73aafe8..b20fe9d6855ab628090e5ff3d4f85ab13c70c521 100644 --- a/crates/terminal/src/tests/terminal_test_context.rs +++ b/crates/terminal/src/tests/terminal_test_context.rs @@ -29,7 +29,7 @@ impl<'a> TerminalTestContext<'a> { ); let connection = - cx.add_model(|cx| TerminalConnection::new(None, None, None, size_info, cx).unwrap()); + cx.add_model(|cx| TerminalConnection::new(None, None, None, size_info, cx)); TerminalTestContext { cx, connection } } @@ -40,8 +40,11 @@ impl<'a> TerminalTestContext<'a> { { let command = command.to_string(); self.connection.update(self.cx, |connection, _| { - connection.write_to_pty(command); - connection.write_to_pty("\r".to_string()); + connection.get_terminal().unwrap().write_to_pty(command); + connection + .get_terminal() + .unwrap() + .write_to_pty("\r".to_string()); }); self.connection @@ -58,9 +61,8 @@ impl<'a> TerminalTestContext<'a> { } fn grid_as_str(connection: &TerminalConnection) -> String { - let term = connection.term.lock(); - let grid_iterator = term.renderable_content().display_iter; - let lines = grid_iterator.group_by(|i| i.point.line.0); + let (grid_iterator, _) = connection.get_terminal().unwrap().renderable_content(); + let lines = grid_iterator.display_iter.group_by(|i| i.point.line.0); lines .into_iter() .map(|(_, line)| line.map(|i| i.c).collect::())