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

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
This commit is contained in:
tidely 2025-06-03 06:12:28 +03:00 committed by GitHub
parent 56d4c0af9f
commit 8ab7d44d51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 162 additions and 196 deletions

View file

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

View file

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

View file

@ -514,7 +514,7 @@ impl Project {
terminal_handle: &Entity<Terminal>, terminal_handle: &Entity<Terminal>,
cx: &mut App, 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>> { pub fn local_terminal_handles(&self) -> &Vec<WeakEntity<terminal::Terminal>> {

View file

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

View file

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

View file

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