From 2ca340b9f1fba9792fe1fcd953def36bfcbb1d0b Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 12 Jul 2022 18:06:34 -0700 Subject: [PATCH 1/6] Beginning research --- crates/terminal/src/keyboard_to_esc.rs | 5 +++++ crates/terminal/src/terminal.rs | 3 ++- crates/terminal/src/terminal_element.rs | 24 ++++++++++++++++-------- 3 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 crates/terminal/src/keyboard_to_esc.rs diff --git a/crates/terminal/src/keyboard_to_esc.rs b/crates/terminal/src/keyboard_to_esc.rs new file mode 100644 index 0000000000000000000000000000000000000000..6f12bfa14e38d8ebcf6c28cce9b4956acbdbbafe --- /dev/null +++ b/crates/terminal/src/keyboard_to_esc.rs @@ -0,0 +1,5 @@ +use gpui::KeyDownEvent; + +fn to_esc_str(event: &KeyDownEvent) -> &str { + "Test" +} diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index ee39fb1f6a24a3d734ac4aeb4ea7060d2e830b33..da47263a91921804a2b0ada238b4621a5d58cd1d 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -1,5 +1,6 @@ -pub mod color_translation; +mod color_translation; pub mod connection; +mod keyboard_to_esc; mod modal; pub mod terminal_element; diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 8decd0c4045b95476c08c3347f51c9fb053da997..1b622dc25d10e37f5882e05886a4175a64e5156f 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -360,14 +360,22 @@ impl Element for TerminalEl { cx.dispatch_action(ScrollTerminal(vertical_scroll.round() as i32)); }) .is_some(), - Event::KeyDown(KeyDownEvent { - input: Some(input), .. - }) => cx - .is_parent_view_focused() - .then(|| { - cx.dispatch_action(Input(input.to_string())); - }) - .is_some(), + Event::KeyDown( + e @ KeyDownEvent { + input: Some(input), .. + }, + ) => { + dbg!(e); + cx.is_parent_view_focused() + .then(|| { + cx.dispatch_action(Input(input.to_string())); + }) + .is_some() + } + Event::KeyDown(e) => { + dbg!(e); + false + } _ => false, } } From f630ab48213a209a9335d43b038cea94c0e93e9e Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 12 Jul 2022 18:44:36 -0700 Subject: [PATCH 2/6] checkpoint --- crates/terminal/src/keyboard_to_esc.rs | 20 ++++++++++++++++++-- crates/terminal/src/terminal_element.rs | 7 +++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/crates/terminal/src/keyboard_to_esc.rs b/crates/terminal/src/keyboard_to_esc.rs index 6f12bfa14e38d8ebcf6c28cce9b4956acbdbbafe..4c47c67f2dc9f924008a10e4f5643a364b6955ec 100644 --- a/crates/terminal/src/keyboard_to_esc.rs +++ b/crates/terminal/src/keyboard_to_esc.rs @@ -1,5 +1,21 @@ use gpui::KeyDownEvent; -fn to_esc_str(event: &KeyDownEvent) -> &str { - "Test" +pub fn to_esc_str(event: &KeyDownEvent) -> String { + let key = event.keystroke.key.clone(); + let modifiers = ( + event.keystroke.alt, + event.keystroke.cmd, + event.keystroke.ctrl, + event.keystroke.shift, + ); + match (key.as_str(), modifiers) { + //ctrl-l + //shift-tab + //alt-back + //shift-back + //shift + Home, end, page up, page down + NOT alt screen => We handle those + //shift + Home, end, page up, page down + alt screen => Send escape sequence + ("l", (false, false, true, false)) => "\x0c".to_string(), + _ => event.input.clone().unwrap().clone(), + } } diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 1b622dc25d10e37f5882e05886a4175a64e5156f..32d240741401df1c324ff46ff6d0da2a314b9911 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -31,7 +31,10 @@ use theme::TerminalStyle; use std::{cmp::min, ops::Range, rc::Rc, sync::Arc}; use std::{fmt::Debug, ops::Sub}; -use crate::{color_translation::convert_color, ScrollTerminal, Terminal, ZedListener}; +use crate::{ + color_translation::convert_color, keyboard_to_esc::to_esc_str, ScrollTerminal, Terminal, + ZedListener, +}; ///Scrolling is unbearably sluggish by default. Alacritty supports a configurable ///Scroll multiplier that is set to 3 by default. This will be removed when I @@ -368,7 +371,7 @@ impl Element for TerminalEl { dbg!(e); cx.is_parent_view_focused() .then(|| { - cx.dispatch_action(Input(input.to_string())); + cx.dispatch_action(Input(to_esc_str(e))); }) .is_some() } From 494c168c6fcaa0d431338580139915137ccaad53 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 13 Jul 2022 12:15:55 -0700 Subject: [PATCH 3/6] Beginning rewrite of affected systems --- crates/terminal/src/connection.rs | 10 +- crates/terminal/src/connection/events.rs | 112 +++++++++++++++++++++++ crates/terminal/src/keyboard_to_esc.rs | 21 ----- crates/terminal/src/terminal.rs | 18 ++-- crates/terminal/src/terminal_element.rs | 76 +++++++++------ 5 files changed, 177 insertions(+), 60 deletions(-) create mode 100644 crates/terminal/src/connection/events.rs delete mode 100644 crates/terminal/src/keyboard_to_esc.rs diff --git a/crates/terminal/src/connection.rs b/crates/terminal/src/connection.rs index 4c615f6c89d510c8ae079415445408d5fa72a2f2..a7b7cec7a0a034ef9f2e433fd5e37216a684a731 100644 --- a/crates/terminal/src/connection.rs +++ b/crates/terminal/src/connection.rs @@ -1,3 +1,5 @@ +mod events; + use alacritty_terminal::{ config::{Config, PtyConfig}, event::{Event as AlacTermEvent, Notify}, @@ -123,7 +125,7 @@ impl TerminalConnection { AlacTermEvent::PtyWrite(out) => self.write_to_pty(out, cx), AlacTermEvent::MouseCursorDirty => { //Calculate new cursor style. - //TODO + //TODO: alacritty/src/input.rs:L922-L939 //Check on correctly handling mouse events for terminals cx.platform().set_cursor_style(CursorStyle::Arrow); //??? } @@ -173,6 +175,12 @@ impl TerminalConnection { self.term.lock().scroll_display(Scroll::Bottom); self.pty_tx.notify(input); } + + ///Resize the terminal and the PTY. This locks the terminal. + pub fn set_size(&mut self, new_size: SizeInfo) { + self.pty_tx.0.send(Msg::Resize(new_size)).ok(); + self.term.lock().resize(new_size); + } } impl Drop for TerminalConnection { diff --git a/crates/terminal/src/connection/events.rs b/crates/terminal/src/connection/events.rs new file mode 100644 index 0000000000000000000000000000000000000000..f5737b02cd49864b7403ac5a8f49f21cf0d1a556 --- /dev/null +++ b/crates/terminal/src/connection/events.rs @@ -0,0 +1,112 @@ +use alacritty_terminal::term::TermMode; +use gpui::KeyDownEvent; + +pub fn _to_esc_str(event: &KeyDownEvent, _mode: TermMode) -> String { + let key = event.keystroke.key.clone(); + let modifiers = ( + event.keystroke.alt, + event.keystroke.cmd, + event.keystroke.ctrl, + event.keystroke.shift, + ); + match (key.as_str(), modifiers) { + //NOTE TO SELF: Terminals can rewrite the color index with OSC, use alacritty colors properly. + + //ctrl-l + //shift-tab + //alt-back + //shift-back + //shift + Home, end, page up, page down + NOT alt screen => We handle those + //shift + Home, end, page up, page down + alt screen => Send escape sequence + ("l", (false, false, true, false)) => "\x0c".to_string(), + _ => event.input.clone().unwrap().clone(), + } +} + +/* +So, to match alacritty keyboard handling, we need to check APP_CURSOR, and ALT_SCREEN + +And we need to convert the strings that GPUI returns to keys + +And we need a way of easily declaring and matching a modifier pattern on those keys + +And we need to block writing the input to the pty if any of these match + +And I need to figure out how to express this in a cross platform way + +And a way of optionally interfacing this with actions for rebinding in defaults.json + +Design notes: +I would like terminal mode checking to be concealed behind the TerminalConnection in as many ways as possible. +Alacritty has a lot of stuff intermixed for it's input handling. TerminalConnection should be in charge +of anything that needs to conform to a standard that isn't handled by Term, e.g.: +- Reporting mouse events correctly. +- Reporting scrolls -> Depends on MOUSE_MODE, ALT_SCREEN, and ALTERNATE_SCROLL, etc. +- Correctly bracketing a paste +- Storing changed colors +- Focus change sequence + +Scrolling might be handled internally or externally, need a way to ask. Everything else should probably happen internally. + +Standards/OS compliance is in connection.rs. +This takes GPUI events and translates them to the correct terminal stuff +This means that standards compliance outside of connection should be kept to a minimum. Yes, this feels good. +Connection needs to be split up then, into a bunch of event handlers + +NOTE, THE FOLLOWING HAS 2 BINDINGS: +K, ModifiersState::LOGO, Action::Esc("\x0c".into()); +K, ModifiersState::LOGO, Action::ClearHistory; => ctx.terminal_mut().clear_screen(ClearMode::Saved), + + +Handled in therminal: +L, ModifiersState::CTRL, Action::Esc("\x0c".into()); +Tab, ModifiersState::SHIFT, Action::Esc("\x1b[Z".into()); +Backspace, ModifiersState::ALT, Action::Esc("\x1b\x7f".into()); +Backspace, ModifiersState::SHIFT, Action::Esc("\x7f".into()); +Home, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[1;2H".into()); +End, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[1;2F".into()); +PageUp, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[5;2~".into()); +PageDown, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[6;2~".into()); +Home, +BindingMode::APP_CURSOR, Action::Esc("\x1bOH".into()); +Home, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[H".into()); +End, +BindingMode::APP_CURSOR, Action::Esc("\x1bOF".into()); +End, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[F".into()); +Up, +BindingMode::APP_CURSOR, Action::Esc("\x1bOA".into()); +Up, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[A".into()); +Down, +BindingMode::APP_CURSOR, Action::Esc("\x1bOB".into()); +Down, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[B".into()); +Right, +BindingMode::APP_CURSOR, Action::Esc("\x1bOC".into()); +Right, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[C".into()); +Left, +BindingMode::APP_CURSOR, Action::Esc("\x1bOD".into()); +Left, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[D".into()); +Back, Action::Esc("\x7f".into()); +Insert, Action::Esc("\x1b[2~".into()); +Delete, Action::Esc("\x1b[3~".into()); +PageUp, Action::Esc("\x1b[5~".into()); +PageDown, Action::Esc("\x1b[6~".into()); +F1, Action::Esc("\x1bOP".into()); +F2, Action::Esc("\x1bOQ".into()); +F3, Action::Esc("\x1bOR".into()); +F4, Action::Esc("\x1bOS".into()); +F5, Action::Esc("\x1b[15~".into()); +F6, Action::Esc("\x1b[17~".into()); +F7, Action::Esc("\x1b[18~".into()); +F8, Action::Esc("\x1b[19~".into()); +F9, Action::Esc("\x1b[20~".into()); +F10, Action::Esc("\x1b[21~".into()); +F11, Action::Esc("\x1b[23~".into()); +F12, Action::Esc("\x1b[24~".into()); +F13, Action::Esc("\x1b[25~".into()); +F14, Action::Esc("\x1b[26~".into()); +F15, Action::Esc("\x1b[28~".into()); +F16, Action::Esc("\x1b[29~".into()); +F17, Action::Esc("\x1b[31~".into()); +F18, Action::Esc("\x1b[32~".into()); +F19, Action::Esc("\x1b[33~".into()); +F20, Action::Esc("\x1b[34~".into()); +NumpadEnter, Action::Esc("\n".into()); + +MAC: +Insert, ModifiersState::SHIFT, Action::Esc("\x1b[2;2~".into()); + +*/ diff --git a/crates/terminal/src/keyboard_to_esc.rs b/crates/terminal/src/keyboard_to_esc.rs deleted file mode 100644 index 4c47c67f2dc9f924008a10e4f5643a364b6955ec..0000000000000000000000000000000000000000 --- a/crates/terminal/src/keyboard_to_esc.rs +++ /dev/null @@ -1,21 +0,0 @@ -use gpui::KeyDownEvent; - -pub fn to_esc_str(event: &KeyDownEvent) -> String { - let key = event.keystroke.key.clone(); - let modifiers = ( - event.keystroke.alt, - event.keystroke.cmd, - event.keystroke.ctrl, - event.keystroke.shift, - ); - match (key.as_str(), modifiers) { - //ctrl-l - //shift-tab - //alt-back - //shift-back - //shift + Home, end, page up, page down + NOT alt screen => We handle those - //shift + Home, end, page up, page down + alt screen => Send escape sequence - ("l", (false, false, true, false)) => "\x0c".to_string(), - _ => event.input.clone().unwrap().clone(), - } -} diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index da47263a91921804a2b0ada238b4621a5d58cd1d..9a811d2a3bb70ed95bda8577e471aad4a9cea552 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -1,12 +1,10 @@ mod color_translation; pub mod connection; -mod keyboard_to_esc; mod modal; pub mod terminal_element; use alacritty_terminal::{ event::{Event as AlacTermEvent, EventListener}, - event_loop::Msg, grid::Scroll, term::SizeInfo, }; @@ -169,14 +167,6 @@ impl Terminal { } } - ///Resize the terminal and the PTY. This locks the terminal. - fn set_size(&self, new_size: SizeInfo, cx: &mut MutableAppContext) { - self.connection.update(cx, |connection, _| { - connection.pty_tx.0.send(Msg::Resize(new_size)).ok(); - connection.term.lock().resize(new_size); - }) - } - ///Scroll the terminal. This locks the terminal fn scroll_terminal(&mut self, scroll: &ScrollTerminal, cx: &mut ViewContext) { self.connection @@ -188,6 +178,7 @@ impl Terminal { fn input(&mut self, Input(text): &Input, cx: &mut ViewContext) { self.connection.update(cx, |connection, cx| { + //TODO: This is probably not encoding UTF8 correctly (see alacritty/src/input.rs:L825-837) connection.write_to_pty(text.clone(), cx); }); @@ -297,7 +288,12 @@ impl View for Terminal { } fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { - let element = TerminalEl::new(cx.handle()).contained(); + let element = { + let connection_handle = self.connection.clone().downgrade(); + let view_id = cx.view_id(); + TerminalEl::new(view_id, connection_handle, self.modal).contained() + }; + if self.modal { let settings = cx.global::(); let container_style = settings.theme.terminal.modal_container; diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 32d240741401df1c324ff46ff6d0da2a314b9911..1d95bc88f1579509aa1d8a706323cdd1a4ae8b9a 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -21,7 +21,7 @@ use gpui::{ json::json, text_layout::{Line, RunStyle}, Event, FontCache, KeyDownEvent, MouseRegion, PaintContext, Quad, ScrollWheelEvent, - SizeConstraint, TextLayoutCache, WeakViewHandle, + SizeConstraint, TextLayoutCache, WeakModelHandle, }; use itertools::Itertools; use ordered_float::OrderedFloat; @@ -32,8 +32,7 @@ use std::{cmp::min, ops::Range, rc::Rc, sync::Arc}; use std::{fmt::Debug, ops::Sub}; use crate::{ - color_translation::convert_color, keyboard_to_esc::to_esc_str, ScrollTerminal, Terminal, - ZedListener, + color_translation::convert_color, connection::TerminalConnection, ScrollTerminal, ZedListener, }; ///Scrolling is unbearably sluggish by default. Alacritty supports a configurable @@ -47,8 +46,11 @@ const ALACRITTY_SCROLL_MULTIPLIER: f32 = 3.; const DEBUG_GRID: bool = false; ///The GPUI element that paints the terminal. +///We need to keep a reference to the view for mouse events, do we need it for any other terminal stuff, or can we move that to connection? pub struct TerminalEl { - view: WeakViewHandle, + connection: WeakModelHandle, + view_id: usize, + modal: bool, } ///New type pattern so I don't mix these two up @@ -98,8 +100,16 @@ pub struct LayoutState { } impl TerminalEl { - pub fn new(view: WeakViewHandle) -> TerminalEl { - TerminalEl { view } + pub fn new( + view_id: usize, + connection: WeakModelHandle, + modal: bool, + ) -> TerminalEl { + TerminalEl { + view_id, + connection, + modal, + } } } @@ -121,22 +131,19 @@ impl Element for TerminalEl { cx.font_cache() .em_advance(text_style.font_id, text_style.font_size), ); - let view_handle = self.view.upgrade(cx).unwrap(); + let connection_handle = self.connection.upgrade(cx).unwrap(); //Tell the view our new size. Requires a mutable borrow of cx and the view let cur_size = make_new_size(constraint, &cell_width, &line_height); //Note that set_size locks and mutates the terminal. - view_handle.update(cx.app, |view, cx| view.set_size(cur_size, cx)); - - //Now that we're done with the mutable portion, grab the immutable settings and view again - let view = view_handle.read(cx); + connection_handle.update(cx.app, |connection, _| connection.set_size(cur_size)); let (selection_color, terminal_theme) = { let theme = &(cx.global::()).theme; (theme.editor.selection.selection, &theme.terminal) }; - let terminal_mutex = view_handle.read(cx).connection.read(cx).term.clone(); + let terminal_mutex = connection_handle.read(cx).term.clone(); let term = terminal_mutex.lock(); let grid = term.grid(); let cursor_point = grid.cursor.point; @@ -149,7 +156,7 @@ impl Element for TerminalEl { &text_style, terminal_theme, cx.text_layout_cache, - view.modal, + self.modal, content.selection, ); @@ -193,7 +200,7 @@ impl Element for TerminalEl { }); drop(term); - let background_color = if view.modal { + let background_color = if self.modal { terminal_theme.colors.modal_background } else { terminal_theme.colors.background @@ -232,7 +239,7 @@ impl Element for TerminalEl { attach_mouse_handlers( origin, cur_size, - self.view.id(), + self.view_id, &layout.terminal, visible_bounds, cx, @@ -352,6 +359,25 @@ impl Element for TerminalEl { _paint: &mut Self::PaintState, cx: &mut gpui::EventContext, ) -> bool { + //The problem: + //Depending on the terminal mode, we either send an escape sequence + //OR update our own data structures. + //e.g. scrolling. If we do smooth scrolling, then we need to check if + //we own scrolling and then if so, do our scrolling thing. + //Ok, so the terminal connection should have APIs for querying it semantically + //something like `should_handle_scroll()`. This means we need a handle to the connection. + //Actually, this is the only time that this app needs to talk to the outer world. + //TODO for scrolling rework: need a way of intercepting Home/End/PageUp etc. + //Sometimes going to scroll our own internal buffer, sometimes going to send ESC + // + //Same goes for key events + //Actually, we don't use the terminal at all in dispatch_event code, the view + //Handles it all. Check how the editor implements scrolling, is it view-level + //or element level? + + //Question: Can we continue dispatching to the view, so it can talk to the connection + //Or should we instead add a connection into here? + match event { Event::ScrollWheel(ScrollWheelEvent { delta, position, .. @@ -363,18 +389,14 @@ impl Element for TerminalEl { cx.dispatch_action(ScrollTerminal(vertical_scroll.round() as i32)); }) .is_some(), - Event::KeyDown( - e @ KeyDownEvent { - input: Some(input), .. - }, - ) => { - dbg!(e); - cx.is_parent_view_focused() - .then(|| { - cx.dispatch_action(Input(to_esc_str(e))); - }) - .is_some() - } + Event::KeyDown(KeyDownEvent { + input: Some(input), .. + }) => cx + .is_parent_view_focused() + .then(|| { + cx.dispatch_action(Input(input.to_string())); + }) + .is_some(), Event::KeyDown(e) => { dbg!(e); false From 344e0374068c4938576eec484e42640ee3ce0b77 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 13 Jul 2022 12:17:51 -0700 Subject: [PATCH 4/6] remove temporary work --- crates/terminal/src/connection.rs | 2 - crates/terminal/src/connection/events.rs | 112 ----------------------- crates/terminal/src/terminal_element.rs | 4 - 3 files changed, 118 deletions(-) delete mode 100644 crates/terminal/src/connection/events.rs diff --git a/crates/terminal/src/connection.rs b/crates/terminal/src/connection.rs index a7b7cec7a0a034ef9f2e433fd5e37216a684a731..47c631e9e2993898ba63689ab7eeb5ef12a6497f 100644 --- a/crates/terminal/src/connection.rs +++ b/crates/terminal/src/connection.rs @@ -1,5 +1,3 @@ -mod events; - use alacritty_terminal::{ config::{Config, PtyConfig}, event::{Event as AlacTermEvent, Notify}, diff --git a/crates/terminal/src/connection/events.rs b/crates/terminal/src/connection/events.rs deleted file mode 100644 index f5737b02cd49864b7403ac5a8f49f21cf0d1a556..0000000000000000000000000000000000000000 --- a/crates/terminal/src/connection/events.rs +++ /dev/null @@ -1,112 +0,0 @@ -use alacritty_terminal::term::TermMode; -use gpui::KeyDownEvent; - -pub fn _to_esc_str(event: &KeyDownEvent, _mode: TermMode) -> String { - let key = event.keystroke.key.clone(); - let modifiers = ( - event.keystroke.alt, - event.keystroke.cmd, - event.keystroke.ctrl, - event.keystroke.shift, - ); - match (key.as_str(), modifiers) { - //NOTE TO SELF: Terminals can rewrite the color index with OSC, use alacritty colors properly. - - //ctrl-l - //shift-tab - //alt-back - //shift-back - //shift + Home, end, page up, page down + NOT alt screen => We handle those - //shift + Home, end, page up, page down + alt screen => Send escape sequence - ("l", (false, false, true, false)) => "\x0c".to_string(), - _ => event.input.clone().unwrap().clone(), - } -} - -/* -So, to match alacritty keyboard handling, we need to check APP_CURSOR, and ALT_SCREEN - -And we need to convert the strings that GPUI returns to keys - -And we need a way of easily declaring and matching a modifier pattern on those keys - -And we need to block writing the input to the pty if any of these match - -And I need to figure out how to express this in a cross platform way - -And a way of optionally interfacing this with actions for rebinding in defaults.json - -Design notes: -I would like terminal mode checking to be concealed behind the TerminalConnection in as many ways as possible. -Alacritty has a lot of stuff intermixed for it's input handling. TerminalConnection should be in charge -of anything that needs to conform to a standard that isn't handled by Term, e.g.: -- Reporting mouse events correctly. -- Reporting scrolls -> Depends on MOUSE_MODE, ALT_SCREEN, and ALTERNATE_SCROLL, etc. -- Correctly bracketing a paste -- Storing changed colors -- Focus change sequence - -Scrolling might be handled internally or externally, need a way to ask. Everything else should probably happen internally. - -Standards/OS compliance is in connection.rs. -This takes GPUI events and translates them to the correct terminal stuff -This means that standards compliance outside of connection should be kept to a minimum. Yes, this feels good. -Connection needs to be split up then, into a bunch of event handlers - -NOTE, THE FOLLOWING HAS 2 BINDINGS: -K, ModifiersState::LOGO, Action::Esc("\x0c".into()); -K, ModifiersState::LOGO, Action::ClearHistory; => ctx.terminal_mut().clear_screen(ClearMode::Saved), - - -Handled in therminal: -L, ModifiersState::CTRL, Action::Esc("\x0c".into()); -Tab, ModifiersState::SHIFT, Action::Esc("\x1b[Z".into()); -Backspace, ModifiersState::ALT, Action::Esc("\x1b\x7f".into()); -Backspace, ModifiersState::SHIFT, Action::Esc("\x7f".into()); -Home, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[1;2H".into()); -End, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[1;2F".into()); -PageUp, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[5;2~".into()); -PageDown, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Action::Esc("\x1b[6;2~".into()); -Home, +BindingMode::APP_CURSOR, Action::Esc("\x1bOH".into()); -Home, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[H".into()); -End, +BindingMode::APP_CURSOR, Action::Esc("\x1bOF".into()); -End, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[F".into()); -Up, +BindingMode::APP_CURSOR, Action::Esc("\x1bOA".into()); -Up, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[A".into()); -Down, +BindingMode::APP_CURSOR, Action::Esc("\x1bOB".into()); -Down, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[B".into()); -Right, +BindingMode::APP_CURSOR, Action::Esc("\x1bOC".into()); -Right, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[C".into()); -Left, +BindingMode::APP_CURSOR, Action::Esc("\x1bOD".into()); -Left, ~BindingMode::APP_CURSOR, Action::Esc("\x1b[D".into()); -Back, Action::Esc("\x7f".into()); -Insert, Action::Esc("\x1b[2~".into()); -Delete, Action::Esc("\x1b[3~".into()); -PageUp, Action::Esc("\x1b[5~".into()); -PageDown, Action::Esc("\x1b[6~".into()); -F1, Action::Esc("\x1bOP".into()); -F2, Action::Esc("\x1bOQ".into()); -F3, Action::Esc("\x1bOR".into()); -F4, Action::Esc("\x1bOS".into()); -F5, Action::Esc("\x1b[15~".into()); -F6, Action::Esc("\x1b[17~".into()); -F7, Action::Esc("\x1b[18~".into()); -F8, Action::Esc("\x1b[19~".into()); -F9, Action::Esc("\x1b[20~".into()); -F10, Action::Esc("\x1b[21~".into()); -F11, Action::Esc("\x1b[23~".into()); -F12, Action::Esc("\x1b[24~".into()); -F13, Action::Esc("\x1b[25~".into()); -F14, Action::Esc("\x1b[26~".into()); -F15, Action::Esc("\x1b[28~".into()); -F16, Action::Esc("\x1b[29~".into()); -F17, Action::Esc("\x1b[31~".into()); -F18, Action::Esc("\x1b[32~".into()); -F19, Action::Esc("\x1b[33~".into()); -F20, Action::Esc("\x1b[34~".into()); -NumpadEnter, Action::Esc("\n".into()); - -MAC: -Insert, ModifiersState::SHIFT, Action::Esc("\x1b[2;2~".into()); - -*/ diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 1d95bc88f1579509aa1d8a706323cdd1a4ae8b9a..09dce20f97d10af3d9e8d3a082485435eb1aa156 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -397,10 +397,6 @@ impl Element for TerminalEl { cx.dispatch_action(Input(input.to_string())); }) .is_some(), - Event::KeyDown(e) => { - dbg!(e); - false - } _ => false, } } From 4f9d88f3e0abaa498f5cefb84de6a71a73702caf Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 13 Jul 2022 13:06:23 -0700 Subject: [PATCH 5/6] Made a quick fix for modal issues, better solution pending rewrite --- assets/keymaps/default.json | 1 + crates/terminal/src/modal.rs | 7 +++++++ styles/package-lock.json | 1 - 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 6cd3660bf5120d4b16f1f6988588a537b7b92a31..e40a5426ddb29160b69046b36ad33872a9ddf040 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -409,6 +409,7 @@ "bindings": { "ctrl-c": "terminal::Sigint", "escape": "terminal::Escape", + "shift-escape": "terminal::DeployModal", "ctrl-d": "terminal::Quit", "backspace": "terminal::Del", "enter": "terminal::Return", diff --git a/crates/terminal/src/modal.rs b/crates/terminal/src/modal.rs index 43452e5221003f916a0e2fa8f4fc4d5e223681e5..1130050690061e22703fd8594d4bf799630f76b7 100644 --- a/crates/terminal/src/modal.rs +++ b/crates/terminal/src/modal.rs @@ -3,6 +3,7 @@ use workspace::Workspace; use crate::{get_wd_for_workspace, DeployModal, Event, Terminal, TerminalConnection}; +#[derive(Debug)] struct StoredConnection(ModelHandle); pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewContext) { @@ -24,12 +25,18 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon let this = cx.add_view(|cx| Terminal::new(wd, true, cx)); let connection_handle = this.read(cx).connection.clone(); cx.subscribe(&connection_handle, on_event).detach(); + //Set the global immediately, in case the user opens the command palette + cx.set_global::>(Some(StoredConnection( + connection_handle.clone(), + ))); this }) { let connection = closed_terminal_handle.read(cx).connection.clone(); cx.set_global(Some(StoredConnection(connection))); } } + + //The problem is that the terminal modal is never re-stored. } pub fn on_event( diff --git a/styles/package-lock.json b/styles/package-lock.json index 49304dc2fa98dfec942bf6687be56cefc13cdf80..2eb6d3a1bfaeaa206f0cc8a0a03efa0387d144c2 100644 --- a/styles/package-lock.json +++ b/styles/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "styles", "version": "1.0.0", "license": "ISC", "dependencies": { From 7885234fbcdd592c2aaf0c97c0da0a89debff8bd Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 13 Jul 2022 13:19:21 -0700 Subject: [PATCH 6/6] Added clear screan command --- assets/keymaps/default.json | 3 +- crates/terminal/src/connection.rs | 29 +++++++++------- crates/terminal/src/terminal.rs | 58 +++++++++++++++++-------------- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index e40a5426ddb29160b69046b36ad33872a9ddf040..0e13bae79487d7d972de09fe007567c33b6a358c 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -419,7 +419,8 @@ "down": "terminal::Down", "tab": "terminal::Tab", "cmd-v": "terminal::Paste", - "cmd-c": "terminal::Copy" + "cmd-c": "terminal::Copy", + "ctrl-l": "terminal::Clear" } } ] \ No newline at end of file diff --git a/crates/terminal/src/connection.rs b/crates/terminal/src/connection.rs index 47c631e9e2993898ba63689ab7eeb5ef12a6497f..800791370cdf63efee8be8ae7b5095b87da7a7aa 100644 --- a/crates/terminal/src/connection.rs +++ b/crates/terminal/src/connection.rs @@ -1,4 +1,5 @@ use alacritty_terminal::{ + ansi::{ClearMode, Handler}, config::{Config, PtyConfig}, event::{Event as AlacTermEvent, Notify}, event_loop::{EventLoop, Msg, Notifier}, @@ -120,7 +121,7 @@ impl TerminalConnection { AlacTermEvent::Wakeup => { cx.emit(Event::Wakeup); } - AlacTermEvent::PtyWrite(out) => self.write_to_pty(out, cx), + AlacTermEvent::PtyWrite(out) => self.write_to_pty(out), AlacTermEvent::MouseCursorDirty => { //Calculate new cursor style. //TODO: alacritty/src/input.rs:L922-L939 @@ -138,20 +139,17 @@ impl TerminalConnection { AlacTermEvent::ClipboardStore(_, data) => { cx.write_to_clipboard(ClipboardItem::new(data)) } - AlacTermEvent::ClipboardLoad(_, format) => self.write_to_pty( - format( - &cx.read_from_clipboard() - .map(|ci| ci.text().to_string()) - .unwrap_or("".to_string()), - ), - cx, - ), + AlacTermEvent::ClipboardLoad(_, format) => self.write_to_pty(format( + &cx.read_from_clipboard() + .map(|ci| ci.text().to_string()) + .unwrap_or("".to_string()), + )), AlacTermEvent::ColorRequest(index, format) => { let color = self.term.lock().colors()[index].unwrap_or_else(|| { let term_style = &cx.global::().theme.terminal; to_alac_rgb(get_color_at_index(&index, &term_style.colors)) }); - self.write_to_pty(format(color), cx) + self.write_to_pty(format(color)) } AlacTermEvent::CursorBlinkingChange => { //TODO: Set a timer to blink the cursor on and off @@ -164,12 +162,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, cx: &mut ModelContext) { - self.write_bytes_to_pty(input.into_bytes(), cx); + pub fn write_to_pty(&mut 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, _: &mut ModelContext) { + fn write_bytes_to_pty(&mut self, input: Vec) { self.term.lock().scroll_display(Scroll::Bottom); self.pty_tx.notify(input); } @@ -179,6 +177,11 @@ impl TerminalConnection { self.pty_tx.0.send(Msg::Resize(new_size)).ok(); self.term.lock().resize(new_size); } + + pub fn clear(&mut self) { + self.write_to_pty("\x0c".into()); + self.term.lock().clear_screen(ClearMode::Saved); + } } impl Drop for TerminalConnection { diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 9a811d2a3bb70ed95bda8577e471aad4a9cea552..12c092d6e6ffd78fb326aa1eb5e79f534fb41f38 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -88,6 +88,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(Terminal::paste); cx.add_action(Terminal::scroll_terminal); cx.add_action(Terminal::input); + cx.add_action(Terminal::clear); cx.add_action(deploy_modal); } @@ -177,9 +178,9 @@ impl Terminal { } fn input(&mut self, Input(text): &Input, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { + self.connection.update(cx, |connection, _| { //TODO: This is probably not encoding UTF8 correctly (see alacritty/src/input.rs:L825-837) - connection.write_to_pty(text.clone(), cx); + connection.write_to_pty(text.clone()); }); if self.has_bell { @@ -188,6 +189,11 @@ impl Terminal { } } + fn clear(&mut self, _: &Clear, cx: &mut ViewContext) { + self.connection + .update(cx, |connection, _| connection.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); @@ -212,72 +218,72 @@ impl Terminal { ///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, cx| { - connection.write_to_pty(item.text().to_owned(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(item.text().to_owned()); }) } } ///Send the `up` key fn up(&mut self, _: &Up, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(UP_SEQ.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(UP_SEQ.to_string()); }); } ///Send the `down` key fn down(&mut self, _: &Down, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(DOWN_SEQ.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(DOWN_SEQ.to_string()); }); } ///Send the `tab` key fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(TAB_CHAR.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(TAB_CHAR.to_string()); }); } ///Send `SIGINT` (`ctrl-c`) fn send_sigint(&mut self, _: &Sigint, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(ETX_CHAR.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(ETX_CHAR.to_string()); }); } ///Send the `escape` key fn escape(&mut self, _: &Escape, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(ESC_CHAR.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(ESC_CHAR.to_string()); }); } ///Send the `delete` key. TODO: Difference between this and backspace? fn del(&mut self, _: &Del, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(DEL_CHAR.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(DEL_CHAR.to_string()); }); } ///Send a carriage return. TODO: May need to check the terminal mode. fn carriage_return(&mut self, _: &Return, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(CARRIAGE_RETURN_CHAR.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(CARRIAGE_RETURN_CHAR.to_string()); }); } //Send the `left` key fn left(&mut self, _: &Left, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(LEFT_SEQ.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(LEFT_SEQ.to_string()); }); } //Send the `right` key fn right(&mut self, _: &Right, cx: &mut ViewContext) { - self.connection.update(cx, |connection, cx| { - connection.write_to_pty(RIGHT_SEQ.to_string(), cx); + self.connection.update(cx, |connection, _| { + connection.write_to_pty(RIGHT_SEQ.to_string()); }); } } @@ -467,8 +473,8 @@ mod tests { let terminal = cx.add_view(Default::default(), |cx| Terminal::new(None, false, cx)); terminal.update(cx, |terminal, cx| { - terminal.connection.update(cx, |connection, cx| { - connection.write_to_pty("expr 3 + 4".to_string(), cx); + terminal.connection.update(cx, |connection, _| { + connection.write_to_pty("expr 3 + 4".to_string()); }); terminal.carriage_return(&Return, cx); }); @@ -492,8 +498,8 @@ mod tests { cx.set_condition_duration(Some(Duration::from_secs(2))); terminal.update(cx, |terminal, cx| { - terminal.connection.update(cx, |connection, cx| { - connection.write_to_pty("expr 3 + 4".to_string(), cx); + terminal.connection.update(cx, |connection, _| { + connection.write_to_pty("expr 3 + 4".to_string()); }); terminal.carriage_return(&Return, cx); });