diff --git a/crates/terminal/src/mappings/keys.rs b/crates/terminal/src/mappings/keys.rs index 7e0c6e3d17..1a3d7c6454 100644 --- a/crates/terminal/src/mappings/keys.rs +++ b/crates/terminal/src/mappings/keys.rs @@ -2,7 +2,7 @@ use alacritty_terminal::term::TermMode; use gpui::keymap::Keystroke; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub enum Modifiers { None, Alt, @@ -45,10 +45,10 @@ impl Modifiers { ///that depend on terminal modes also have a mapping that doesn't depend on the terminal mode. ///This is fragile, but as these mappings are locked up in legacy compatibility, it's probably good enough pub fn might_convert(keystroke: &Keystroke) -> bool { - to_esc_str(keystroke, &TermMode::NONE).is_some() + to_esc_str(keystroke, &TermMode::NONE, false).is_some() } -pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode) -> Option { +pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) -> Option { let modifiers = Modifiers::new(keystroke); // Manual Bindings including modifiers @@ -244,6 +244,17 @@ pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode) -> Option { } } + let alt_meta_binding = if alt_is_meta && modifiers == Modifiers::Alt && keystroke.key.is_ascii() + { + Some(format!("\x1b{}", keystroke.key)) + } else { + None + }; + + if alt_meta_binding.is_some() { + return alt_meta_binding; + } + None } @@ -286,26 +297,26 @@ mod test { let shift_end = Keystroke::parse("shift-end").unwrap(); let none = TermMode::NONE; - assert_eq!(to_esc_str(&shift_pageup, &none), None); - assert_eq!(to_esc_str(&shift_pagedown, &none), None); - assert_eq!(to_esc_str(&shift_home, &none), None); - assert_eq!(to_esc_str(&shift_end, &none), None); + assert_eq!(to_esc_str(&shift_pageup, &none, false), None); + assert_eq!(to_esc_str(&shift_pagedown, &none, false), None); + assert_eq!(to_esc_str(&shift_home, &none, false), None); + assert_eq!(to_esc_str(&shift_end, &none, false), None); let alt_screen = TermMode::ALT_SCREEN; assert_eq!( - to_esc_str(&shift_pageup, &alt_screen), + to_esc_str(&shift_pageup, &alt_screen, false), Some("\x1b[5;2~".to_string()) ); assert_eq!( - to_esc_str(&shift_pagedown, &alt_screen), + to_esc_str(&shift_pagedown, &alt_screen, false), Some("\x1b[6;2~".to_string()) ); assert_eq!( - to_esc_str(&shift_home, &alt_screen), + to_esc_str(&shift_home, &alt_screen, false), Some("\x1b[1;2H".to_string()) ); assert_eq!( - to_esc_str(&shift_end, &alt_screen), + to_esc_str(&shift_end, &alt_screen, false), Some("\x1b[1;2F".to_string()) ); @@ -313,8 +324,14 @@ mod test { let pagedown = Keystroke::parse("pagedown").unwrap(); let any = TermMode::ANY; - assert_eq!(to_esc_str(&pageup, &any), Some("\x1b[5~".to_string())); - assert_eq!(to_esc_str(&pagedown, &any), Some("\x1b[6~".to_string())); + 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()) + ); } #[test] @@ -327,7 +344,7 @@ mod test { function: false, key: "🖖🏻".to_string(), //2 char string }; - assert_eq!(to_esc_str(&ks, &TermMode::NONE), None); + assert_eq!(to_esc_str(&ks, &TermMode::NONE, false), None); } #[test] @@ -340,15 +357,27 @@ mod test { let left = Keystroke::parse("left").unwrap(); let right = Keystroke::parse("right").unwrap(); - assert_eq!(to_esc_str(&up, &none), Some("\x1b[A".to_string())); - assert_eq!(to_esc_str(&down, &none), Some("\x1b[B".to_string())); - assert_eq!(to_esc_str(&right, &none), Some("\x1b[C".to_string())); - assert_eq!(to_esc_str(&left, &none), Some("\x1b[D".to_string())); + 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, &app_cursor), Some("\x1bOA".to_string())); - assert_eq!(to_esc_str(&down, &app_cursor), Some("\x1bOB".to_string())); - assert_eq!(to_esc_str(&right, &app_cursor), Some("\x1bOC".to_string())); - assert_eq!(to_esc_str(&left, &app_cursor), Some("\x1bOD".to_string())); + 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(&right, &app_cursor, false), + Some("\x1bOC".to_string()) + ); + assert_eq!( + to_esc_str(&left, &app_cursor, false), + Some("\x1bOD".to_string()) + ); } #[test] @@ -361,11 +390,13 @@ mod test { assert_eq!( to_esc_str( &Keystroke::parse(&format!("ctrl-{}", lower)).unwrap(), - &mode + &mode, + false ), to_esc_str( &Keystroke::parse(&format!("ctrl-shift-{}", upper)).unwrap(), - &mode + &mode, + false ), "On letter: {}/{}", lower, diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index d6c22ee6bc..a93dd09670 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -677,8 +677,8 @@ impl Terminal { self.write_to_pty(input); } - pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool { - let esc = to_esc_str(keystroke, &self.last_content.mode); + pub fn try_keystroke(&mut self, keystroke: &Keystroke, alt_is_meta: bool) -> bool { + let esc = to_esc_str(keystroke, &self.last_content.mode, alt_is_meta); if let Some(esc) = esc { self.input(esc); true diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index d88511cbce..51ebf63e5e 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -775,7 +775,15 @@ impl Element for TerminalElement { self.terminal .upgrade(cx.app) .map(|model_handle| { - model_handle.update(cx.app, |term, _| term.try_keystroke(keystroke)) + model_handle.update(cx.app, |term, cx| { + term.try_keystroke( + keystroke, + cx.global::() + .terminal_overrides + .option_as_meta + .unwrap_or(false), + ) + }) }) .unwrap_or(false) } diff --git a/crates/terminal/src/terminal_view.rs b/crates/terminal/src/terminal_view.rs index ec35ba0a5c..9ba90d42dc 100644 --- a/crates/terminal/src/terminal_view.rs +++ b/crates/terminal/src/terminal_view.rs @@ -155,8 +155,14 @@ impl TerminalView { { cx.show_character_palette(); } else { - self.terminal.update(cx, |term, _| { - term.try_keystroke(&Keystroke::parse("ctrl-cmd-space").unwrap()) + self.terminal.update(cx, |term, cx| { + term.try_keystroke( + &Keystroke::parse("ctrl-cmd-space").unwrap(), + cx.global::() + .terminal_overrides + .option_as_meta + .unwrap_or(false), + ) }); } } @@ -280,7 +286,7 @@ impl TerminalView { fn up(&mut self, _: &Up, cx: &mut ViewContext) { self.clear_bel(cx); self.terminal.update(cx, |term, _| { - term.try_keystroke(&Keystroke::parse("up").unwrap()) + term.try_keystroke(&Keystroke::parse("up").unwrap(), false) }); } @@ -288,7 +294,7 @@ impl TerminalView { fn down(&mut self, _: &Down, cx: &mut ViewContext) { self.clear_bel(cx); self.terminal.update(cx, |term, _| { - term.try_keystroke(&Keystroke::parse("down").unwrap()) + term.try_keystroke(&Keystroke::parse("down").unwrap(), false) }); } @@ -296,7 +302,7 @@ impl TerminalView { fn ctrl_c(&mut self, _: &CtrlC, cx: &mut ViewContext) { self.clear_bel(cx); self.terminal.update(cx, |term, _| { - term.try_keystroke(&Keystroke::parse("ctrl-c").unwrap()) + term.try_keystroke(&Keystroke::parse("ctrl-c").unwrap(), false) }); } @@ -304,7 +310,7 @@ impl TerminalView { fn escape(&mut self, _: &Escape, cx: &mut ViewContext) { self.clear_bel(cx); self.terminal.update(cx, |term, _| { - term.try_keystroke(&Keystroke::parse("escape").unwrap()) + term.try_keystroke(&Keystroke::parse("escape").unwrap(), false) }); } @@ -312,7 +318,7 @@ impl TerminalView { fn enter(&mut self, _: &Enter, cx: &mut ViewContext) { self.clear_bel(cx); self.terminal.update(cx, |term, _| { - term.try_keystroke(&Keystroke::parse("enter").unwrap()) + term.try_keystroke(&Keystroke::parse("enter").unwrap(), false) }); } }