terminal: Match trait bounds with terminal input (#31441)

tidely created

The core change here is the following:

```rust
fn write_to_pty(&self, input: impl Into<Vec<u8>>);

// into
fn write_to_pty(&self, input: impl Into<Cow<'static, [u8]>>);
```

This matches the trait bounds that's used by the Alacritty crate. We are
now allowed to effectively pass `&'static str` instead of always needing
a `String`.

The main benefit comes from making the `to_esc_str` function return a
`Cow<'static, str>` instead of `String`. We save an allocation in the
following instances:

- When the user presses any special key that isn't alphanumerical (in
the terminal)
- When the uses presses any key while a modifier is active (in the
terminal)
- When focusing/un-focusing the terminal
- When completing or undoing a terminal transaction
- When starting a terminal assist

This basically saves us an allocation on **every key** press in the
terminal.

NOTE: This same optimization can be done for **nearly all** keypresses
in the entirety of Zed by changing the signature of the `Keystroke`
struct in gpui. If the Zed team is interested in a PR for it, let me
know.

Release Notes:

- N/A

Change summary

crates/agent/src/terminal_codegen.rs          |   9 
crates/agent/src/terminal_inline_assistant.rs |   2 
crates/project/src/terminals.rs               |   2 
crates/terminal/src/mappings/keys.rs          | 313 +++++++++-----------
crates/terminal/src/terminal.rs               |  28 +
crates/terminal_view/src/terminal_view.rs     |   4 
6 files changed, 162 insertions(+), 196 deletions(-)

Detailed changes

crates/agent/src/terminal_codegen.rs 🔗

@@ -179,18 +179,17 @@ impl TerminalTransaction {
         // Ensure that the assistant cannot accidentally execute commands that are streamed into the terminal
         let input = Self::sanitize_input(hunk);
         self.terminal
-            .update(cx, |terminal, _| terminal.input(input));
+            .update(cx, |terminal, _| terminal.input(input.into_bytes()));
     }
 
     pub fn undo(&self, cx: &mut App) {
         self.terminal
-            .update(cx, |terminal, _| terminal.input(CLEAR_INPUT.to_string()));
+            .update(cx, |terminal, _| terminal.input(CLEAR_INPUT.as_bytes()));
     }
 
     pub fn complete(&self, cx: &mut App) {
-        self.terminal.update(cx, |terminal, _| {
-            terminal.input(CARRIAGE_RETURN.to_string())
-        });
+        self.terminal
+            .update(cx, |terminal, _| terminal.input(CARRIAGE_RETURN.as_bytes()));
     }
 
     fn sanitize_input(mut input: String) -> String {

crates/agent/src/terminal_inline_assistant.rs 🔗

@@ -202,7 +202,7 @@ impl TerminalInlineAssistant {
             .update(cx, |terminal, cx| {
                 terminal
                     .terminal()
-                    .update(cx, |terminal, _| terminal.input(CLEAR_INPUT.to_string()));
+                    .update(cx, |terminal, _| terminal.input(CLEAR_INPUT.as_bytes()));
             })
             .log_err();
 

crates/project/src/terminals.rs 🔗

@@ -514,7 +514,7 @@ impl Project {
         terminal_handle: &Entity<Terminal>,
         cx: &mut App,
     ) {
-        terminal_handle.update(cx, |terminal, _| terminal.input(command));
+        terminal_handle.update(cx, |terminal, _| terminal.input(command.into_bytes()));
     }
 
     pub fn local_terminal_handles(&self) -> &Vec<WeakEntity<terminal::Terminal>> {

crates/terminal/src/mappings/keys.rs 🔗

@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 /// The mappings defined in this file where created from reading the alacritty source
 use alacritty_terminal::term::TermMode;
 use gpui::Keystroke;
@@ -41,162 +43,138 @@ impl AlacModifiers {
     }
 }
 
-pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) -> Option<String> {
+pub fn to_esc_str(
+    keystroke: &Keystroke,
+    mode: &TermMode,
+    alt_is_meta: bool,
+) -> Option<Cow<'static, str>> {
     let modifiers = AlacModifiers::new(keystroke);
 
     // Manual Bindings including modifiers
-    let manual_esc_str = match (keystroke.key.as_ref(), &modifiers) {
+    let manual_esc_str: Option<&'static str> = match (keystroke.key.as_ref(), &modifiers) {
         //Basic special keys
-        ("tab", AlacModifiers::None) => Some("\x09".to_string()),
-        ("escape", AlacModifiers::None) => Some("\x1b".to_string()),
-        ("enter", AlacModifiers::None) => Some("\x0d".to_string()),
-        ("enter", AlacModifiers::Shift) => Some("\x0d".to_string()),
-        ("enter", AlacModifiers::Alt) => Some("\x1b\x0d".to_string()),
-        ("backspace", AlacModifiers::None) => Some("\x7f".to_string()),
+        ("tab", AlacModifiers::None) => Some("\x09"),
+        ("escape", AlacModifiers::None) => Some("\x1b"),
+        ("enter", AlacModifiers::None) => Some("\x0d"),
+        ("enter", AlacModifiers::Shift) => Some("\x0d"),
+        ("enter", AlacModifiers::Alt) => Some("\x1b\x0d"),
+        ("backspace", AlacModifiers::None) => Some("\x7f"),
         //Interesting escape codes
-        ("tab", AlacModifiers::Shift) => Some("\x1b[Z".to_string()),
-        ("backspace", AlacModifiers::Ctrl) => Some("\x08".to_string()),
-        ("backspace", AlacModifiers::Alt) => Some("\x1b\x7f".to_string()),
-        ("backspace", AlacModifiers::Shift) => Some("\x7f".to_string()),
-        ("space", AlacModifiers::Ctrl) => Some("\x00".to_string()),
-        ("home", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
-            Some("\x1b[1;2H".to_string())
-        }
-        ("end", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
-            Some("\x1b[1;2F".to_string())
-        }
+        ("tab", AlacModifiers::Shift) => Some("\x1b[Z"),
+        ("backspace", AlacModifiers::Ctrl) => Some("\x08"),
+        ("backspace", AlacModifiers::Alt) => Some("\x1b\x7f"),
+        ("backspace", AlacModifiers::Shift) => Some("\x7f"),
+        ("space", AlacModifiers::Ctrl) => Some("\x00"),
+        ("home", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => Some("\x1b[1;2H"),
+        ("end", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => Some("\x1b[1;2F"),
         ("pageup", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
-            Some("\x1b[5;2~".to_string())
+            Some("\x1b[5;2~")
         }
         ("pagedown", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
-            Some("\x1b[6;2~".to_string())
-        }
-        ("home", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1bOH".to_string())
-        }
-        ("home", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1b[H".to_string())
-        }
-        ("end", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1bOF".to_string())
-        }
-        ("end", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1b[F".to_string())
-        }
-        ("up", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1bOA".to_string())
-        }
-        ("up", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1b[A".to_string())
-        }
-        ("down", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1bOB".to_string())
-        }
-        ("down", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1b[B".to_string())
-        }
-        ("right", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1bOC".to_string())
-        }
-        ("right", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1b[C".to_string())
+            Some("\x1b[6;2~")
         }
-        ("left", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1bOD".to_string())
-        }
-        ("left", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
-            Some("\x1b[D".to_string())
-        }
-        ("back", AlacModifiers::None) => Some("\x7f".to_string()),
-        ("insert", AlacModifiers::None) => Some("\x1b[2~".to_string()),
-        ("delete", AlacModifiers::None) => Some("\x1b[3~".to_string()),
-        ("pageup", AlacModifiers::None) => Some("\x1b[5~".to_string()),
-        ("pagedown", AlacModifiers::None) => Some("\x1b[6~".to_string()),
-        ("f1", AlacModifiers::None) => Some("\x1bOP".to_string()),
-        ("f2", AlacModifiers::None) => Some("\x1bOQ".to_string()),
-        ("f3", AlacModifiers::None) => Some("\x1bOR".to_string()),
-        ("f4", AlacModifiers::None) => Some("\x1bOS".to_string()),
-        ("f5", AlacModifiers::None) => Some("\x1b[15~".to_string()),
-        ("f6", AlacModifiers::None) => Some("\x1b[17~".to_string()),
-        ("f7", AlacModifiers::None) => Some("\x1b[18~".to_string()),
-        ("f8", AlacModifiers::None) => Some("\x1b[19~".to_string()),
-        ("f9", AlacModifiers::None) => Some("\x1b[20~".to_string()),
-        ("f10", AlacModifiers::None) => Some("\x1b[21~".to_string()),
-        ("f11", AlacModifiers::None) => Some("\x1b[23~".to_string()),
-        ("f12", AlacModifiers::None) => Some("\x1b[24~".to_string()),
-        ("f13", AlacModifiers::None) => Some("\x1b[25~".to_string()),
-        ("f14", AlacModifiers::None) => Some("\x1b[26~".to_string()),
-        ("f15", AlacModifiers::None) => Some("\x1b[28~".to_string()),
-        ("f16", AlacModifiers::None) => Some("\x1b[29~".to_string()),
-        ("f17", AlacModifiers::None) => Some("\x1b[31~".to_string()),
-        ("f18", AlacModifiers::None) => Some("\x1b[32~".to_string()),
-        ("f19", AlacModifiers::None) => Some("\x1b[33~".to_string()),
-        ("f20", AlacModifiers::None) => Some("\x1b[34~".to_string()),
+        ("home", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => Some("\x1bOH"),
+        ("home", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => Some("\x1b[H"),
+        ("end", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => Some("\x1bOF"),
+        ("end", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => Some("\x1b[F"),
+        ("up", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => Some("\x1bOA"),
+        ("up", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => Some("\x1b[A"),
+        ("down", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => Some("\x1bOB"),
+        ("down", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => Some("\x1b[B"),
+        ("right", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => Some("\x1bOC"),
+        ("right", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => Some("\x1b[C"),
+        ("left", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => Some("\x1bOD"),
+        ("left", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => Some("\x1b[D"),
+        ("back", AlacModifiers::None) => Some("\x7f"),
+        ("insert", AlacModifiers::None) => Some("\x1b[2~"),
+        ("delete", AlacModifiers::None) => Some("\x1b[3~"),
+        ("pageup", AlacModifiers::None) => Some("\x1b[5~"),
+        ("pagedown", AlacModifiers::None) => Some("\x1b[6~"),
+        ("f1", AlacModifiers::None) => Some("\x1bOP"),
+        ("f2", AlacModifiers::None) => Some("\x1bOQ"),
+        ("f3", AlacModifiers::None) => Some("\x1bOR"),
+        ("f4", AlacModifiers::None) => Some("\x1bOS"),
+        ("f5", AlacModifiers::None) => Some("\x1b[15~"),
+        ("f6", AlacModifiers::None) => Some("\x1b[17~"),
+        ("f7", AlacModifiers::None) => Some("\x1b[18~"),
+        ("f8", AlacModifiers::None) => Some("\x1b[19~"),
+        ("f9", AlacModifiers::None) => Some("\x1b[20~"),
+        ("f10", AlacModifiers::None) => Some("\x1b[21~"),
+        ("f11", AlacModifiers::None) => Some("\x1b[23~"),
+        ("f12", AlacModifiers::None) => Some("\x1b[24~"),
+        ("f13", AlacModifiers::None) => Some("\x1b[25~"),
+        ("f14", AlacModifiers::None) => Some("\x1b[26~"),
+        ("f15", AlacModifiers::None) => Some("\x1b[28~"),
+        ("f16", AlacModifiers::None) => Some("\x1b[29~"),
+        ("f17", AlacModifiers::None) => Some("\x1b[31~"),
+        ("f18", AlacModifiers::None) => Some("\x1b[32~"),
+        ("f19", AlacModifiers::None) => Some("\x1b[33~"),
+        ("f20", AlacModifiers::None) => Some("\x1b[34~"),
         // NumpadEnter, Action::Esc("\n".into());
         //Mappings for caret notation keys
-        ("a", AlacModifiers::Ctrl) => Some("\x01".to_string()), //1
-        ("A", AlacModifiers::CtrlShift) => Some("\x01".to_string()), //1
-        ("b", AlacModifiers::Ctrl) => Some("\x02".to_string()), //2
-        ("B", AlacModifiers::CtrlShift) => Some("\x02".to_string()), //2
-        ("c", AlacModifiers::Ctrl) => Some("\x03".to_string()), //3
-        ("C", AlacModifiers::CtrlShift) => Some("\x03".to_string()), //3
-        ("d", AlacModifiers::Ctrl) => Some("\x04".to_string()), //4
-        ("D", AlacModifiers::CtrlShift) => Some("\x04".to_string()), //4
-        ("e", AlacModifiers::Ctrl) => Some("\x05".to_string()), //5
-        ("E", AlacModifiers::CtrlShift) => Some("\x05".to_string()), //5
-        ("f", AlacModifiers::Ctrl) => Some("\x06".to_string()), //6
-        ("F", AlacModifiers::CtrlShift) => Some("\x06".to_string()), //6
-        ("g", AlacModifiers::Ctrl) => Some("\x07".to_string()), //7
-        ("G", AlacModifiers::CtrlShift) => Some("\x07".to_string()), //7
-        ("h", AlacModifiers::Ctrl) => Some("\x08".to_string()), //8
-        ("H", AlacModifiers::CtrlShift) => Some("\x08".to_string()), //8
-        ("i", AlacModifiers::Ctrl) => Some("\x09".to_string()), //9
-        ("I", AlacModifiers::CtrlShift) => Some("\x09".to_string()), //9
-        ("j", AlacModifiers::Ctrl) => Some("\x0a".to_string()), //10
-        ("J", AlacModifiers::CtrlShift) => Some("\x0a".to_string()), //10
-        ("k", AlacModifiers::Ctrl) => Some("\x0b".to_string()), //11
-        ("K", AlacModifiers::CtrlShift) => Some("\x0b".to_string()), //11
-        ("l", AlacModifiers::Ctrl) => Some("\x0c".to_string()), //12
-        ("L", AlacModifiers::CtrlShift) => Some("\x0c".to_string()), //12
-        ("m", AlacModifiers::Ctrl) => Some("\x0d".to_string()), //13
-        ("M", AlacModifiers::CtrlShift) => Some("\x0d".to_string()), //13
-        ("n", AlacModifiers::Ctrl) => Some("\x0e".to_string()), //14
-        ("N", AlacModifiers::CtrlShift) => Some("\x0e".to_string()), //14
-        ("o", AlacModifiers::Ctrl) => Some("\x0f".to_string()), //15
-        ("O", AlacModifiers::CtrlShift) => Some("\x0f".to_string()), //15
-        ("p", AlacModifiers::Ctrl) => Some("\x10".to_string()), //16
-        ("P", AlacModifiers::CtrlShift) => Some("\x10".to_string()), //16
-        ("q", AlacModifiers::Ctrl) => Some("\x11".to_string()), //17
-        ("Q", AlacModifiers::CtrlShift) => Some("\x11".to_string()), //17
-        ("r", AlacModifiers::Ctrl) => Some("\x12".to_string()), //18
-        ("R", AlacModifiers::CtrlShift) => Some("\x12".to_string()), //18
-        ("s", AlacModifiers::Ctrl) => Some("\x13".to_string()), //19
-        ("S", AlacModifiers::CtrlShift) => Some("\x13".to_string()), //19
-        ("t", AlacModifiers::Ctrl) => Some("\x14".to_string()), //20
-        ("T", AlacModifiers::CtrlShift) => Some("\x14".to_string()), //20
-        ("u", AlacModifiers::Ctrl) => Some("\x15".to_string()), //21
-        ("U", AlacModifiers::CtrlShift) => Some("\x15".to_string()), //21
-        ("v", AlacModifiers::Ctrl) => Some("\x16".to_string()), //22
-        ("V", AlacModifiers::CtrlShift) => Some("\x16".to_string()), //22
-        ("w", AlacModifiers::Ctrl) => Some("\x17".to_string()), //23
-        ("W", AlacModifiers::CtrlShift) => Some("\x17".to_string()), //23
-        ("x", AlacModifiers::Ctrl) => Some("\x18".to_string()), //24
-        ("X", AlacModifiers::CtrlShift) => Some("\x18".to_string()), //24
-        ("y", AlacModifiers::Ctrl) => Some("\x19".to_string()), //25
-        ("Y", AlacModifiers::CtrlShift) => Some("\x19".to_string()), //25
-        ("z", AlacModifiers::Ctrl) => Some("\x1a".to_string()), //26
-        ("Z", AlacModifiers::CtrlShift) => Some("\x1a".to_string()), //26
-        ("@", AlacModifiers::Ctrl) => Some("\x00".to_string()), //0
-        ("[", AlacModifiers::Ctrl) => Some("\x1b".to_string()), //27
-        ("\\", AlacModifiers::Ctrl) => Some("\x1c".to_string()), //28
-        ("]", AlacModifiers::Ctrl) => Some("\x1d".to_string()), //29
-        ("^", AlacModifiers::Ctrl) => Some("\x1e".to_string()), //30
-        ("_", AlacModifiers::Ctrl) => Some("\x1f".to_string()), //31
-        ("?", AlacModifiers::Ctrl) => Some("\x7f".to_string()), //127
+        ("a", AlacModifiers::Ctrl) => Some("\x01"), //1
+        ("A", AlacModifiers::CtrlShift) => Some("\x01"), //1
+        ("b", AlacModifiers::Ctrl) => Some("\x02"), //2
+        ("B", AlacModifiers::CtrlShift) => Some("\x02"), //2
+        ("c", AlacModifiers::Ctrl) => Some("\x03"), //3
+        ("C", AlacModifiers::CtrlShift) => Some("\x03"), //3
+        ("d", AlacModifiers::Ctrl) => Some("\x04"), //4
+        ("D", AlacModifiers::CtrlShift) => Some("\x04"), //4
+        ("e", AlacModifiers::Ctrl) => Some("\x05"), //5
+        ("E", AlacModifiers::CtrlShift) => Some("\x05"), //5
+        ("f", AlacModifiers::Ctrl) => Some("\x06"), //6
+        ("F", AlacModifiers::CtrlShift) => Some("\x06"), //6
+        ("g", AlacModifiers::Ctrl) => Some("\x07"), //7
+        ("G", AlacModifiers::CtrlShift) => Some("\x07"), //7
+        ("h", AlacModifiers::Ctrl) => Some("\x08"), //8
+        ("H", AlacModifiers::CtrlShift) => Some("\x08"), //8
+        ("i", AlacModifiers::Ctrl) => Some("\x09"), //9
+        ("I", AlacModifiers::CtrlShift) => Some("\x09"), //9
+        ("j", AlacModifiers::Ctrl) => Some("\x0a"), //10
+        ("J", AlacModifiers::CtrlShift) => Some("\x0a"), //10
+        ("k", AlacModifiers::Ctrl) => Some("\x0b"), //11
+        ("K", AlacModifiers::CtrlShift) => Some("\x0b"), //11
+        ("l", AlacModifiers::Ctrl) => Some("\x0c"), //12
+        ("L", AlacModifiers::CtrlShift) => Some("\x0c"), //12
+        ("m", AlacModifiers::Ctrl) => Some("\x0d"), //13
+        ("M", AlacModifiers::CtrlShift) => Some("\x0d"), //13
+        ("n", AlacModifiers::Ctrl) => Some("\x0e"), //14
+        ("N", AlacModifiers::CtrlShift) => Some("\x0e"), //14
+        ("o", AlacModifiers::Ctrl) => Some("\x0f"), //15
+        ("O", AlacModifiers::CtrlShift) => Some("\x0f"), //15
+        ("p", AlacModifiers::Ctrl) => Some("\x10"), //16
+        ("P", AlacModifiers::CtrlShift) => Some("\x10"), //16
+        ("q", AlacModifiers::Ctrl) => Some("\x11"), //17
+        ("Q", AlacModifiers::CtrlShift) => Some("\x11"), //17
+        ("r", AlacModifiers::Ctrl) => Some("\x12"), //18
+        ("R", AlacModifiers::CtrlShift) => Some("\x12"), //18
+        ("s", AlacModifiers::Ctrl) => Some("\x13"), //19
+        ("S", AlacModifiers::CtrlShift) => Some("\x13"), //19
+        ("t", AlacModifiers::Ctrl) => Some("\x14"), //20
+        ("T", AlacModifiers::CtrlShift) => Some("\x14"), //20
+        ("u", AlacModifiers::Ctrl) => Some("\x15"), //21
+        ("U", AlacModifiers::CtrlShift) => Some("\x15"), //21
+        ("v", AlacModifiers::Ctrl) => Some("\x16"), //22
+        ("V", AlacModifiers::CtrlShift) => Some("\x16"), //22
+        ("w", AlacModifiers::Ctrl) => Some("\x17"), //23
+        ("W", AlacModifiers::CtrlShift) => Some("\x17"), //23
+        ("x", AlacModifiers::Ctrl) => Some("\x18"), //24
+        ("X", AlacModifiers::CtrlShift) => Some("\x18"), //24
+        ("y", AlacModifiers::Ctrl) => Some("\x19"), //25
+        ("Y", AlacModifiers::CtrlShift) => Some("\x19"), //25
+        ("z", AlacModifiers::Ctrl) => Some("\x1a"), //26
+        ("Z", AlacModifiers::CtrlShift) => Some("\x1a"), //26
+        ("@", AlacModifiers::Ctrl) => Some("\x00"), //0
+        ("[", AlacModifiers::Ctrl) => Some("\x1b"), //27
+        ("\\", AlacModifiers::Ctrl) => Some("\x1c"), //28
+        ("]", AlacModifiers::Ctrl) => Some("\x1d"), //29
+        ("^", AlacModifiers::Ctrl) => Some("\x1e"), //30
+        ("_", AlacModifiers::Ctrl) => Some("\x1f"), //31
+        ("?", AlacModifiers::Ctrl) => Some("\x7f"), //127
         _ => None,
     };
-    if manual_esc_str.is_some() {
-        return manual_esc_str;
+    if let Some(esc_str) = manual_esc_str {
+        return Some(Cow::Borrowed(esc_str));
     }
 
     // Automated bindings applying modifiers
@@ -235,8 +213,8 @@ pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) ->
             "home" => Some(format!("\x1b[1;{}H", modifier_code)),
             _ => None,
         };
-        if modified_esc_str.is_some() {
-            return modified_esc_str;
+        if let Some(esc_str) = modified_esc_str {
+            return Some(Cow::Owned(esc_str));
         }
     }
 
@@ -250,7 +228,7 @@ pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) ->
             } else {
                 &keystroke.key
             };
-            return Some(format!("\x1b{}", key));
+            return Some(Cow::Owned(format!("\x1b{}", key)));
         }
     }
 
@@ -306,33 +284,27 @@ mod test {
         let alt_screen = TermMode::ALT_SCREEN;
         assert_eq!(
             to_esc_str(&shift_pageup, &alt_screen, false),
-            Some("\x1b[5;2~".to_string())
+            Some("\x1b[5;2~".into())
         );
         assert_eq!(
             to_esc_str(&shift_pagedown, &alt_screen, false),
-            Some("\x1b[6;2~".to_string())
+            Some("\x1b[6;2~".into())
         );
         assert_eq!(
             to_esc_str(&shift_home, &alt_screen, false),
-            Some("\x1b[1;2H".to_string())
+            Some("\x1b[1;2H".into())
         );
         assert_eq!(
             to_esc_str(&shift_end, &alt_screen, false),
-            Some("\x1b[1;2F".to_string())
+            Some("\x1b[1;2F".into())
         );
 
         let pageup = Keystroke::parse("pageup").unwrap();
         let pagedown = Keystroke::parse("pagedown").unwrap();
         let any = TermMode::ANY;
 
-        assert_eq!(
-            to_esc_str(&pageup, &any, false),
-            Some("\x1b[5~".to_string())
-        );
-        assert_eq!(
-            to_esc_str(&pagedown, &any, false),
-            Some("\x1b[6~".to_string())
-        );
+        assert_eq!(to_esc_str(&pageup, &any, false), Some("\x1b[5~".into()));
+        assert_eq!(to_esc_str(&pagedown, &any, false), Some("\x1b[6~".into()));
     }
 
     #[test]
@@ -361,27 +333,18 @@ mod test {
         let left = Keystroke::parse("left").unwrap();
         let right = Keystroke::parse("right").unwrap();
 
-        assert_eq!(to_esc_str(&up, &none, false), Some("\x1b[A".to_string()));
-        assert_eq!(to_esc_str(&down, &none, false), Some("\x1b[B".to_string()));
-        assert_eq!(to_esc_str(&right, &none, false), Some("\x1b[C".to_string()));
-        assert_eq!(to_esc_str(&left, &none, false), Some("\x1b[D".to_string()));
+        assert_eq!(to_esc_str(&up, &none, false), Some("\x1b[A".into()));
+        assert_eq!(to_esc_str(&down, &none, false), Some("\x1b[B".into()));
+        assert_eq!(to_esc_str(&right, &none, false), Some("\x1b[C".into()));
+        assert_eq!(to_esc_str(&left, &none, false), Some("\x1b[D".into()));
 
-        assert_eq!(
-            to_esc_str(&up, &app_cursor, false),
-            Some("\x1bOA".to_string())
-        );
-        assert_eq!(
-            to_esc_str(&down, &app_cursor, false),
-            Some("\x1bOB".to_string())
-        );
+        assert_eq!(to_esc_str(&up, &app_cursor, false), Some("\x1bOA".into()));
+        assert_eq!(to_esc_str(&down, &app_cursor, false), Some("\x1bOB".into()));
         assert_eq!(
             to_esc_str(&right, &app_cursor, false),
-            Some("\x1bOC".to_string())
-        );
-        assert_eq!(
-            to_esc_str(&left, &app_cursor, false),
-            Some("\x1bOD".to_string())
+            Some("\x1bOC".into())
         );
+        assert_eq!(to_esc_str(&left, &app_cursor, false), Some("\x1bOD".into()));
     }
 
     #[test]

crates/terminal/src/terminal.rs 🔗

@@ -724,12 +724,13 @@ impl Terminal {
                         // The terminal only supports pasting strings, not images.
                         Some(text) => format(text),
                         _ => format(""),
-                    },
+                    }
+                    .into_bytes(),
                 )
             }
-            AlacTermEvent::PtyWrite(out) => self.write_to_pty(out),
+            AlacTermEvent::PtyWrite(out) => self.write_to_pty(out.into_bytes()),
             AlacTermEvent::TextAreaSizeRequest(format) => {
-                self.write_to_pty(format(self.last_content.terminal_bounds.into()))
+                self.write_to_pty(format(self.last_content.terminal_bounds.into()).into_bytes())
             }
             AlacTermEvent::CursorBlinkingChange => {
                 let terminal = self.term.lock();
@@ -761,7 +762,7 @@ impl Terminal {
                 // followed by a color request sequence.
                 let color = self.term.lock().colors()[index]
                     .unwrap_or_else(|| to_alac_rgb(get_color_at_index(index, cx.theme().as_ref())));
-                self.write_to_pty(format(color));
+                self.write_to_pty(format(color).into_bytes());
             }
             AlacTermEvent::ChildExit(error_code) => {
                 self.register_task_finished(Some(error_code), cx);
@@ -1227,11 +1228,11 @@ impl Terminal {
     }
 
     ///Write the Input payload to the tty.
-    fn write_to_pty(&self, input: impl Into<Vec<u8>>) {
+    fn write_to_pty(&self, input: impl Into<Cow<'static, [u8]>>) {
         self.pty_tx.notify(input.into());
     }
 
-    pub fn input(&mut self, input: impl Into<Vec<u8>>) {
+    pub fn input(&mut self, input: impl Into<Cow<'static, [u8]>>) {
         self.events
             .push_back(InternalEvent::Scroll(AlacScroll::Bottom));
         self.events.push_back(InternalEvent::SetSelection(None));
@@ -1345,7 +1346,10 @@ impl Terminal {
         // Keep default terminal behavior
         let esc = to_esc_str(keystroke, &self.last_content.mode, alt_is_meta);
         if let Some(esc) = esc {
-            self.input(esc);
+            match esc {
+                Cow::Borrowed(string) => self.input(string.as_bytes()),
+                Cow::Owned(string) => self.input(string.into_bytes()),
+            };
             true
         } else {
             false
@@ -1378,7 +1382,7 @@ impl Terminal {
             text.replace("\r\n", "\r").replace('\n', "\r")
         };
 
-        self.input(paste_text);
+        self.input(paste_text.into_bytes());
     }
 
     pub fn sync(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -1487,13 +1491,13 @@ impl Terminal {
 
     pub fn focus_in(&self) {
         if self.last_content.mode.contains(TermMode::FOCUS_IN_OUT) {
-            self.write_to_pty("\x1b[I".to_string());
+            self.write_to_pty("\x1b[I".as_bytes());
         }
     }
 
     pub fn focus_out(&mut self) {
         if self.last_content.mode.contains(TermMode::FOCUS_IN_OUT) {
-            self.write_to_pty("\x1b[O".to_string());
+            self.write_to_pty("\x1b[O".as_bytes());
         }
     }
 
@@ -1660,7 +1664,7 @@ impl Terminal {
                 MouseButton::Middle => {
                     if let Some(item) = _cx.read_from_primary() {
                         let text = item.text().unwrap_or_default().to_string();
-                        self.input(text);
+                        self.input(text.into_bytes());
                     }
                 }
                 _ => {}
@@ -1832,7 +1836,7 @@ impl Terminal {
                                 .map(|name| name.to_string_lossy().to_string())
                                 .unwrap_or_default();
 
-                            let argv = fpi.argv.clone();
+                            let argv = fpi.argv.as_slice();
                             let process_name = format!(
                                 "{}{}",
                                 fpi.name,

crates/terminal_view/src/terminal_view.rs 🔗

@@ -266,7 +266,7 @@ impl TerminalView {
     pub(crate) fn commit_text(&mut self, text: &str, cx: &mut Context<Self>) {
         if !text.is_empty() {
             self.terminal.update(cx, |term, _| {
-                term.input(text.to_string());
+                term.input(text.to_string().into_bytes());
             });
         }
     }
@@ -643,7 +643,7 @@ impl TerminalView {
     fn send_text(&mut self, text: &SendText, _: &mut Window, cx: &mut Context<Self>) {
         self.clear_bell(cx);
         self.terminal.update(cx, |term, _| {
-            term.input(text.0.to_string());
+            term.input(text.0.to_string().into_bytes());
         });
     }