Refactored a bunch of stuff, working on tidying element code
This commit is contained in:
parent
dce27870ce
commit
119207a9e5
10 changed files with 549 additions and 584 deletions
140
crates/terminal/src/mappings/colors.rs
Normal file
140
crates/terminal/src/mappings/colors.rs
Normal file
|
@ -0,0 +1,140 @@
|
|||
use alacritty_terminal::{ansi::Color as AnsiColor, term::color::Rgb as AlacRgb};
|
||||
use gpui::color::Color;
|
||||
use theme::TerminalColors;
|
||||
|
||||
///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent
|
||||
pub fn convert_color(alac_color: &AnsiColor, colors: &TerminalColors, modal: bool) -> Color {
|
||||
let background = if modal {
|
||||
colors.modal_background
|
||||
} else {
|
||||
colors.background
|
||||
};
|
||||
|
||||
match alac_color {
|
||||
//Named and theme defined colors
|
||||
alacritty_terminal::ansi::Color::Named(n) => match n {
|
||||
alacritty_terminal::ansi::NamedColor::Black => colors.black,
|
||||
alacritty_terminal::ansi::NamedColor::Red => colors.red,
|
||||
alacritty_terminal::ansi::NamedColor::Green => colors.green,
|
||||
alacritty_terminal::ansi::NamedColor::Yellow => colors.yellow,
|
||||
alacritty_terminal::ansi::NamedColor::Blue => colors.blue,
|
||||
alacritty_terminal::ansi::NamedColor::Magenta => colors.magenta,
|
||||
alacritty_terminal::ansi::NamedColor::Cyan => colors.cyan,
|
||||
alacritty_terminal::ansi::NamedColor::White => colors.white,
|
||||
alacritty_terminal::ansi::NamedColor::BrightBlack => colors.bright_black,
|
||||
alacritty_terminal::ansi::NamedColor::BrightRed => colors.bright_red,
|
||||
alacritty_terminal::ansi::NamedColor::BrightGreen => colors.bright_green,
|
||||
alacritty_terminal::ansi::NamedColor::BrightYellow => colors.bright_yellow,
|
||||
alacritty_terminal::ansi::NamedColor::BrightBlue => colors.bright_blue,
|
||||
alacritty_terminal::ansi::NamedColor::BrightMagenta => colors.bright_magenta,
|
||||
alacritty_terminal::ansi::NamedColor::BrightCyan => colors.bright_cyan,
|
||||
alacritty_terminal::ansi::NamedColor::BrightWhite => colors.bright_white,
|
||||
alacritty_terminal::ansi::NamedColor::Foreground => colors.foreground,
|
||||
alacritty_terminal::ansi::NamedColor::Background => background,
|
||||
alacritty_terminal::ansi::NamedColor::Cursor => colors.cursor,
|
||||
alacritty_terminal::ansi::NamedColor::DimBlack => colors.dim_black,
|
||||
alacritty_terminal::ansi::NamedColor::DimRed => colors.dim_red,
|
||||
alacritty_terminal::ansi::NamedColor::DimGreen => colors.dim_green,
|
||||
alacritty_terminal::ansi::NamedColor::DimYellow => colors.dim_yellow,
|
||||
alacritty_terminal::ansi::NamedColor::DimBlue => colors.dim_blue,
|
||||
alacritty_terminal::ansi::NamedColor::DimMagenta => colors.dim_magenta,
|
||||
alacritty_terminal::ansi::NamedColor::DimCyan => colors.dim_cyan,
|
||||
alacritty_terminal::ansi::NamedColor::DimWhite => colors.dim_white,
|
||||
alacritty_terminal::ansi::NamedColor::BrightForeground => colors.bright_foreground,
|
||||
alacritty_terminal::ansi::NamedColor::DimForeground => colors.dim_foreground,
|
||||
},
|
||||
//'True' colors
|
||||
alacritty_terminal::ansi::Color::Spec(rgb) => Color::new(rgb.r, rgb.g, rgb.b, u8::MAX),
|
||||
//8 bit, indexed colors
|
||||
alacritty_terminal::ansi::Color::Indexed(i) => get_color_at_index(&(*i as usize), colors),
|
||||
}
|
||||
}
|
||||
|
||||
///Converts an 8 bit ANSI color to it's GPUI equivalent.
|
||||
///Accepts usize for compatability with the alacritty::Colors interface,
|
||||
///Other than that use case, should only be called with values in the [0,255] range
|
||||
pub fn get_color_at_index(index: &usize, colors: &TerminalColors) -> Color {
|
||||
match index {
|
||||
//0-15 are the same as the named colors above
|
||||
0 => colors.black,
|
||||
1 => colors.red,
|
||||
2 => colors.green,
|
||||
3 => colors.yellow,
|
||||
4 => colors.blue,
|
||||
5 => colors.magenta,
|
||||
6 => colors.cyan,
|
||||
7 => colors.white,
|
||||
8 => colors.bright_black,
|
||||
9 => colors.bright_red,
|
||||
10 => colors.bright_green,
|
||||
11 => colors.bright_yellow,
|
||||
12 => colors.bright_blue,
|
||||
13 => colors.bright_magenta,
|
||||
14 => colors.bright_cyan,
|
||||
15 => colors.bright_white,
|
||||
//16-231 are mapped to their RGB colors on a 0-5 range per channel
|
||||
16..=231 => {
|
||||
let (r, g, b) = rgb_for_index(&(*index as u8)); //Split the index into it's ANSI-RGB components
|
||||
let step = (u8::MAX as f32 / 5.).floor() as u8; //Split the RGB range into 5 chunks, with floor so no overflow
|
||||
Color::new(r * step, g * step, b * step, u8::MAX) //Map the ANSI-RGB components to an RGB color
|
||||
}
|
||||
//232-255 are a 24 step grayscale from black to white
|
||||
232..=255 => {
|
||||
let i = *index as u8 - 232; //Align index to 0..24
|
||||
let step = (u8::MAX as f32 / 24.).floor() as u8; //Split the RGB grayscale values into 24 chunks
|
||||
Color::new(i * step, i * step, i * step, u8::MAX) //Map the ANSI-grayscale components to the RGB-grayscale
|
||||
}
|
||||
//For compatability with the alacritty::Colors interface
|
||||
256 => colors.foreground,
|
||||
257 => colors.background,
|
||||
258 => colors.cursor,
|
||||
259 => colors.dim_black,
|
||||
260 => colors.dim_red,
|
||||
261 => colors.dim_green,
|
||||
262 => colors.dim_yellow,
|
||||
263 => colors.dim_blue,
|
||||
264 => colors.dim_magenta,
|
||||
265 => colors.dim_cyan,
|
||||
266 => colors.dim_white,
|
||||
267 => colors.bright_foreground,
|
||||
268 => colors.black, //'Dim Background', non-standard color
|
||||
_ => Color::new(0, 0, 0, 255),
|
||||
}
|
||||
}
|
||||
///Generates the rgb channels in [0, 5] for a given index into the 6x6x6 ANSI color cube
|
||||
///See: [8 bit ansi color](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit).
|
||||
///
|
||||
///Wikipedia gives a formula for calculating the index for a given color:
|
||||
///
|
||||
///index = 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
||||
///
|
||||
///This function does the reverse, calculating the r, g, and b components from a given index.
|
||||
fn rgb_for_index(i: &u8) -> (u8, u8, u8) {
|
||||
debug_assert!(i >= &16 && i <= &231);
|
||||
let i = i - 16;
|
||||
let r = (i - (i % 36)) / 36;
|
||||
let g = ((i % 36) - (i % 6)) / 6;
|
||||
let b = (i % 36) % 6;
|
||||
(r, g, b)
|
||||
}
|
||||
|
||||
//Convenience method to convert from a GPUI color to an alacritty Rgb
|
||||
pub fn to_alac_rgb(color: Color) -> AlacRgb {
|
||||
AlacRgb {
|
||||
r: color.r,
|
||||
g: color.g,
|
||||
b: color.g,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_rgb_for_index() {
|
||||
//Test every possible value in the color cube
|
||||
for i in 16..=231 {
|
||||
let (r, g, b) = crate::mappings::colors::rgb_for_index(&(i as u8));
|
||||
assert_eq!(i, 16 + 36 * r + 6 * g + b);
|
||||
}
|
||||
}
|
||||
}
|
435
crates/terminal/src/mappings/keys.rs
Normal file
435
crates/terminal/src/mappings/keys.rs
Normal file
|
@ -0,0 +1,435 @@
|
|||
use alacritty_terminal::term::TermMode;
|
||||
use gpui::keymap::Keystroke;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Modifiers {
|
||||
None,
|
||||
Alt,
|
||||
Ctrl,
|
||||
Shift,
|
||||
CtrlShift,
|
||||
Other,
|
||||
}
|
||||
|
||||
impl Modifiers {
|
||||
fn new(ks: &Keystroke) -> Self {
|
||||
match (ks.alt, ks.ctrl, ks.shift, ks.cmd) {
|
||||
(false, false, false, false) => Modifiers::None,
|
||||
(true, false, false, false) => Modifiers::Alt,
|
||||
(false, true, false, false) => Modifiers::Ctrl,
|
||||
(false, false, true, false) => Modifiers::Shift,
|
||||
(false, true, true, false) => Modifiers::CtrlShift,
|
||||
_ => Modifiers::Other,
|
||||
}
|
||||
}
|
||||
|
||||
fn any(&self) -> bool {
|
||||
match &self {
|
||||
Modifiers::None => false,
|
||||
Modifiers::Alt => true,
|
||||
Modifiers::Ctrl => true,
|
||||
Modifiers::Shift => true,
|
||||
Modifiers::CtrlShift => true,
|
||||
Modifiers::Other => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode) -> Option<String> {
|
||||
let modifiers = Modifiers::new(&keystroke);
|
||||
|
||||
// Manual Bindings including modifiers
|
||||
let manual_esc_str = match (keystroke.key.as_ref(), &modifiers) {
|
||||
//Basic special keys
|
||||
("space", Modifiers::None) => Some(" ".to_string()),
|
||||
("tab", Modifiers::None) => Some("\x09".to_string()),
|
||||
("escape", Modifiers::None) => Some("\x1b".to_string()),
|
||||
("enter", Modifiers::None) => Some("\x0d".to_string()),
|
||||
("backspace", Modifiers::None) => Some("\x7f".to_string()),
|
||||
//Interesting escape codes
|
||||
("tab", Modifiers::Shift) => Some("\x1b[Z".to_string()),
|
||||
("backspace", Modifiers::Alt) => Some("\x1b\x7f".to_string()),
|
||||
("backspace", Modifiers::Shift) => Some("\x7f".to_string()),
|
||||
("home", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
|
||||
Some("\x1b[1;2H".to_string())
|
||||
}
|
||||
("end", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
|
||||
Some("\x1b[1;2F".to_string())
|
||||
}
|
||||
("pageup", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
|
||||
Some("\x1b[5;2~".to_string())
|
||||
}
|
||||
("pagedown", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => {
|
||||
Some("\x1b[6;2~".to_string())
|
||||
}
|
||||
("home", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1bOH".to_string())
|
||||
}
|
||||
("home", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1b[H".to_string())
|
||||
}
|
||||
("end", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1bOF".to_string())
|
||||
}
|
||||
("end", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1b[F".to_string())
|
||||
}
|
||||
("up", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1bOA".to_string())
|
||||
}
|
||||
("up", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1b[A".to_string())
|
||||
}
|
||||
("down", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1bOB".to_string())
|
||||
}
|
||||
("down", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1b[B".to_string())
|
||||
}
|
||||
("right", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1bOC".to_string())
|
||||
}
|
||||
("right", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1b[C".to_string())
|
||||
}
|
||||
("left", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1bOD".to_string())
|
||||
}
|
||||
("left", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => {
|
||||
Some("\x1b[D".to_string())
|
||||
}
|
||||
("back", Modifiers::None) => Some("\x7f".to_string()),
|
||||
("insert", Modifiers::None) => Some("\x1b[2~".to_string()),
|
||||
("delete", Modifiers::None) => Some("\x1b[3~".to_string()),
|
||||
("pageup", Modifiers::None) => Some("\x1b[5~".to_string()),
|
||||
("pagedown", Modifiers::None) => Some("\x1b[6~".to_string()),
|
||||
("f1", Modifiers::None) => Some("\x1bOP".to_string()),
|
||||
("f2", Modifiers::None) => Some("\x1bOQ".to_string()),
|
||||
("f3", Modifiers::None) => Some("\x1bOR".to_string()),
|
||||
("f4", Modifiers::None) => Some("\x1bOS".to_string()),
|
||||
("f5", Modifiers::None) => Some("\x1b[15~".to_string()),
|
||||
("f6", Modifiers::None) => Some("\x1b[17~".to_string()),
|
||||
("f7", Modifiers::None) => Some("\x1b[18~".to_string()),
|
||||
("f8", Modifiers::None) => Some("\x1b[19~".to_string()),
|
||||
("f9", Modifiers::None) => Some("\x1b[20~".to_string()),
|
||||
("f10", Modifiers::None) => Some("\x1b[21~".to_string()),
|
||||
("f11", Modifiers::None) => Some("\x1b[23~".to_string()),
|
||||
("f12", Modifiers::None) => Some("\x1b[24~".to_string()),
|
||||
("f13", Modifiers::None) => Some("\x1b[25~".to_string()),
|
||||
("f14", Modifiers::None) => Some("\x1b[26~".to_string()),
|
||||
("f15", Modifiers::None) => Some("\x1b[28~".to_string()),
|
||||
("f16", Modifiers::None) => Some("\x1b[29~".to_string()),
|
||||
("f17", Modifiers::None) => Some("\x1b[31~".to_string()),
|
||||
("f18", Modifiers::None) => Some("\x1b[32~".to_string()),
|
||||
("f19", Modifiers::None) => Some("\x1b[33~".to_string()),
|
||||
("f20", Modifiers::None) => Some("\x1b[34~".to_string()),
|
||||
// NumpadEnter, Action::Esc("\n".into());
|
||||
//Mappings for caret notation keys
|
||||
("a", Modifiers::Ctrl) => Some("\x01".to_string()), //1
|
||||
("A", Modifiers::CtrlShift) => Some("\x01".to_string()), //1
|
||||
("b", Modifiers::Ctrl) => Some("\x02".to_string()), //2
|
||||
("B", Modifiers::CtrlShift) => Some("\x02".to_string()), //2
|
||||
("c", Modifiers::Ctrl) => Some("\x03".to_string()), //3
|
||||
("C", Modifiers::CtrlShift) => Some("\x03".to_string()), //3
|
||||
("d", Modifiers::Ctrl) => Some("\x04".to_string()), //4
|
||||
("D", Modifiers::CtrlShift) => Some("\x04".to_string()), //4
|
||||
("e", Modifiers::Ctrl) => Some("\x05".to_string()), //5
|
||||
("E", Modifiers::CtrlShift) => Some("\x05".to_string()), //5
|
||||
("f", Modifiers::Ctrl) => Some("\x06".to_string()), //6
|
||||
("F", Modifiers::CtrlShift) => Some("\x06".to_string()), //6
|
||||
("g", Modifiers::Ctrl) => Some("\x07".to_string()), //7
|
||||
("G", Modifiers::CtrlShift) => Some("\x07".to_string()), //7
|
||||
("h", Modifiers::Ctrl) => Some("\x08".to_string()), //8
|
||||
("H", Modifiers::CtrlShift) => Some("\x08".to_string()), //8
|
||||
("i", Modifiers::Ctrl) => Some("\x09".to_string()), //9
|
||||
("I", Modifiers::CtrlShift) => Some("\x09".to_string()), //9
|
||||
("j", Modifiers::Ctrl) => Some("\x0a".to_string()), //10
|
||||
("J", Modifiers::CtrlShift) => Some("\x0a".to_string()), //10
|
||||
("k", Modifiers::Ctrl) => Some("\x0b".to_string()), //11
|
||||
("K", Modifiers::CtrlShift) => Some("\x0b".to_string()), //11
|
||||
("l", Modifiers::Ctrl) => Some("\x0c".to_string()), //12
|
||||
("L", Modifiers::CtrlShift) => Some("\x0c".to_string()), //12
|
||||
("m", Modifiers::Ctrl) => Some("\x0d".to_string()), //13
|
||||
("M", Modifiers::CtrlShift) => Some("\x0d".to_string()), //13
|
||||
("n", Modifiers::Ctrl) => Some("\x0e".to_string()), //14
|
||||
("N", Modifiers::CtrlShift) => Some("\x0e".to_string()), //14
|
||||
("o", Modifiers::Ctrl) => Some("\x0f".to_string()), //15
|
||||
("O", Modifiers::CtrlShift) => Some("\x0f".to_string()), //15
|
||||
("p", Modifiers::Ctrl) => Some("\x10".to_string()), //16
|
||||
("P", Modifiers::CtrlShift) => Some("\x10".to_string()), //16
|
||||
("q", Modifiers::Ctrl) => Some("\x11".to_string()), //17
|
||||
("Q", Modifiers::CtrlShift) => Some("\x11".to_string()), //17
|
||||
("r", Modifiers::Ctrl) => Some("\x12".to_string()), //18
|
||||
("R", Modifiers::CtrlShift) => Some("\x12".to_string()), //18
|
||||
("s", Modifiers::Ctrl) => Some("\x13".to_string()), //19
|
||||
("S", Modifiers::CtrlShift) => Some("\x13".to_string()), //19
|
||||
("t", Modifiers::Ctrl) => Some("\x14".to_string()), //20
|
||||
("T", Modifiers::CtrlShift) => Some("\x14".to_string()), //20
|
||||
("u", Modifiers::Ctrl) => Some("\x15".to_string()), //21
|
||||
("U", Modifiers::CtrlShift) => Some("\x15".to_string()), //21
|
||||
("v", Modifiers::Ctrl) => Some("\x16".to_string()), //22
|
||||
("V", Modifiers::CtrlShift) => Some("\x16".to_string()), //22
|
||||
("w", Modifiers::Ctrl) => Some("\x17".to_string()), //23
|
||||
("W", Modifiers::CtrlShift) => Some("\x17".to_string()), //23
|
||||
("x", Modifiers::Ctrl) => Some("\x18".to_string()), //24
|
||||
("X", Modifiers::CtrlShift) => Some("\x18".to_string()), //24
|
||||
("y", Modifiers::Ctrl) => Some("\x19".to_string()), //25
|
||||
("Y", Modifiers::CtrlShift) => Some("\x19".to_string()), //25
|
||||
("z", Modifiers::Ctrl) => Some("\x1a".to_string()), //26
|
||||
("Z", Modifiers::CtrlShift) => Some("\x1a".to_string()), //26
|
||||
("@", Modifiers::Ctrl) => Some("\x00".to_string()), //0
|
||||
("[", Modifiers::Ctrl) => Some("\x1b".to_string()), //27
|
||||
("\\", Modifiers::Ctrl) => Some("\x1c".to_string()), //28
|
||||
("]", Modifiers::Ctrl) => Some("\x1d".to_string()), //29
|
||||
("^", Modifiers::Ctrl) => Some("\x1e".to_string()), //30
|
||||
("_", Modifiers::Ctrl) => Some("\x1f".to_string()), //31
|
||||
("?", Modifiers::Ctrl) => Some("\x7f".to_string()), //127
|
||||
_ => None,
|
||||
};
|
||||
if manual_esc_str.is_some() {
|
||||
return manual_esc_str;
|
||||
}
|
||||
|
||||
// Automated bindings applying modifiers
|
||||
if modifiers.any() {
|
||||
let modifier_code = modifier_code(&keystroke);
|
||||
let modified_esc_str = match keystroke.key.as_ref() {
|
||||
"up" => Some(format!("\x1b[1;{}A", modifier_code)),
|
||||
"down" => Some(format!("\x1b[1;{}B", modifier_code)),
|
||||
"right" => Some(format!("\x1b[1;{}C", modifier_code)),
|
||||
"left" => Some(format!("\x1b[1;{}D", modifier_code)),
|
||||
"f1" => Some(format!("\x1b[1;{}P", modifier_code)),
|
||||
"f2" => Some(format!("\x1b[1;{}Q", modifier_code)),
|
||||
"f3" => Some(format!("\x1b[1;{}R", modifier_code)),
|
||||
"f4" => Some(format!("\x1b[1;{}S", modifier_code)),
|
||||
"F5" => Some(format!("\x1b[15;{}~", modifier_code)),
|
||||
"f6" => Some(format!("\x1b[17;{}~", modifier_code)),
|
||||
"f7" => Some(format!("\x1b[18;{}~", modifier_code)),
|
||||
"f8" => Some(format!("\x1b[19;{}~", modifier_code)),
|
||||
"f9" => Some(format!("\x1b[20;{}~", modifier_code)),
|
||||
"f10" => Some(format!("\x1b[21;{}~", modifier_code)),
|
||||
"f11" => Some(format!("\x1b[23;{}~", modifier_code)),
|
||||
"f12" => Some(format!("\x1b[24;{}~", modifier_code)),
|
||||
"f13" => Some(format!("\x1b[25;{}~", modifier_code)),
|
||||
"f14" => Some(format!("\x1b[26;{}~", modifier_code)),
|
||||
"f15" => Some(format!("\x1b[28;{}~", modifier_code)),
|
||||
"f16" => Some(format!("\x1b[29;{}~", modifier_code)),
|
||||
"f17" => Some(format!("\x1b[31;{}~", modifier_code)),
|
||||
"f18" => Some(format!("\x1b[32;{}~", modifier_code)),
|
||||
"f19" => Some(format!("\x1b[33;{}~", modifier_code)),
|
||||
"f20" => Some(format!("\x1b[34;{}~", modifier_code)),
|
||||
_ if modifier_code == 2 => None,
|
||||
"insert" => Some(format!("\x1b[2;{}~", modifier_code)),
|
||||
"pageup" => Some(format!("\x1b[5;{}~", modifier_code)),
|
||||
"pagedown" => Some(format!("\x1b[6;{}~", modifier_code)),
|
||||
"end" => Some(format!("\x1b[1;{}F", modifier_code)),
|
||||
"home" => Some(format!("\x1b[1;{}H", modifier_code)),
|
||||
_ => None,
|
||||
};
|
||||
if modified_esc_str.is_some() {
|
||||
return modified_esc_str;
|
||||
}
|
||||
}
|
||||
|
||||
//Fallback to sending the keystroke input directly
|
||||
//Skin colors in utf8 are implemented as a seperate, invisible character
|
||||
//that modifies the associated emoji. Some languages may have similarly
|
||||
//implemented modifiers, e.g. certain diacritics that can be typed as a single character.
|
||||
//This means that we need to assume some user input can result in multi-byte,
|
||||
//multi-char strings. This is somewhat difficult, as GPUI normalizes all
|
||||
//keys into a string representation. Hence, the check here to filter out GPUI
|
||||
//keys that weren't captured above.
|
||||
if !matches_gpui_key_str(&keystroke.key) {
|
||||
return Some(keystroke.key.clone());
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
///Checks if the given string matches a GPUI key string.
|
||||
///Table made from reading the source at gpui/src/platform/mac/event.rs
|
||||
fn matches_gpui_key_str(str: &str) -> bool {
|
||||
match str {
|
||||
"backspace" => true,
|
||||
"up" => true,
|
||||
"down" => true,
|
||||
"left" => true,
|
||||
"right" => true,
|
||||
"pageup" => true,
|
||||
"pagedown" => true,
|
||||
"home" => true,
|
||||
"end" => true,
|
||||
"delete" => true,
|
||||
"enter" => true,
|
||||
"escape" => true,
|
||||
"tab" => true,
|
||||
"f1" => true,
|
||||
"f2" => true,
|
||||
"f3" => true,
|
||||
"f4" => true,
|
||||
"f5" => true,
|
||||
"f6" => true,
|
||||
"f7" => true,
|
||||
"f8" => true,
|
||||
"f9" => true,
|
||||
"f10" => true,
|
||||
"f11" => true,
|
||||
"f12" => true,
|
||||
"space" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Code Modifiers
|
||||
/// ---------+---------------------------
|
||||
/// 2 | Shift
|
||||
/// 3 | Alt
|
||||
/// 4 | Shift + Alt
|
||||
/// 5 | Control
|
||||
/// 6 | Shift + Control
|
||||
/// 7 | Alt + Control
|
||||
/// 8 | Shift + Alt + Control
|
||||
/// ---------+---------------------------
|
||||
/// from: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
|
||||
fn modifier_code(keystroke: &Keystroke) -> u32 {
|
||||
let mut modifier_code = 0;
|
||||
if keystroke.shift {
|
||||
modifier_code |= 1;
|
||||
}
|
||||
if keystroke.alt {
|
||||
modifier_code |= 1 << 1;
|
||||
}
|
||||
if keystroke.ctrl {
|
||||
modifier_code |= 1 << 2;
|
||||
}
|
||||
modifier_code + 1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_scroll_keys() {
|
||||
//These keys should be handled by the scrolling element directly
|
||||
//Need to signify this by returning 'None'
|
||||
let shift_pageup = Keystroke::parse("shift-pageup").unwrap();
|
||||
let shift_pagedown = Keystroke::parse("shift-pagedown").unwrap();
|
||||
let shift_home = Keystroke::parse("shift-home").unwrap();
|
||||
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);
|
||||
|
||||
let alt_screen = TermMode::ALT_SCREEN;
|
||||
assert_eq!(
|
||||
to_esc_str(&shift_pageup, &alt_screen),
|
||||
Some("\x1b[5;2~".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
to_esc_str(&shift_pagedown, &alt_screen),
|
||||
Some("\x1b[6;2~".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
to_esc_str(&shift_home, &alt_screen),
|
||||
Some("\x1b[1;2H".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
to_esc_str(&shift_end, &alt_screen),
|
||||
Some("\x1b[1;2F".to_string())
|
||||
);
|
||||
|
||||
let pageup = Keystroke::parse("pageup").unwrap();
|
||||
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()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_char_fallthrough() {
|
||||
let ks = Keystroke {
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
shift: false,
|
||||
cmd: false,
|
||||
|
||||
key: "🖖🏻".to_string(), //2 char string
|
||||
};
|
||||
|
||||
assert_eq!(to_esc_str(&ks, &TermMode::NONE), Some("🖖🏻".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_application_mode() {
|
||||
let app_cursor = TermMode::APP_CURSOR;
|
||||
let none = TermMode::NONE;
|
||||
|
||||
let up = Keystroke::parse("up").unwrap();
|
||||
let down = Keystroke::parse("down").unwrap();
|
||||
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, &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()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ctrl_codes() {
|
||||
let letters_lower = 'a'..='z';
|
||||
let letters_upper = 'A'..='Z';
|
||||
let mode = TermMode::ANY;
|
||||
|
||||
for (lower, upper) in letters_lower.zip(letters_upper) {
|
||||
assert_eq!(
|
||||
to_esc_str(
|
||||
&Keystroke::parse(&format!("ctrl-{}", lower)).unwrap(),
|
||||
&mode
|
||||
),
|
||||
to_esc_str(
|
||||
&Keystroke::parse(&format!("ctrl-shift-{}", upper)).unwrap(),
|
||||
&mode
|
||||
),
|
||||
"On letter: {}/{}",
|
||||
lower,
|
||||
upper
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modifier_code_calc() {
|
||||
// Code Modifiers
|
||||
// ---------+---------------------------
|
||||
// 2 | Shift
|
||||
// 3 | Alt
|
||||
// 4 | Shift + Alt
|
||||
// 5 | Control
|
||||
// 6 | Shift + Control
|
||||
// 7 | Alt + Control
|
||||
// 8 | Shift + Alt + Control
|
||||
// ---------+---------------------------
|
||||
// from: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
|
||||
assert_eq!(2, modifier_code(&Keystroke::parse("shift-A").unwrap()));
|
||||
assert_eq!(3, modifier_code(&Keystroke::parse("alt-A").unwrap()));
|
||||
assert_eq!(4, modifier_code(&Keystroke::parse("shift-alt-A").unwrap()));
|
||||
assert_eq!(5, modifier_code(&Keystroke::parse("ctrl-A").unwrap()));
|
||||
assert_eq!(6, modifier_code(&Keystroke::parse("shift-ctrl-A").unwrap()));
|
||||
assert_eq!(7, modifier_code(&Keystroke::parse("alt-ctrl-A").unwrap()));
|
||||
assert_eq!(
|
||||
8,
|
||||
modifier_code(&Keystroke::parse("shift-ctrl-alt-A").unwrap())
|
||||
);
|
||||
}
|
||||
}
|
2
crates/terminal/src/mappings/mod.rs
Normal file
2
crates/terminal/src/mappings/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod colors;
|
||||
pub mod keys;
|
Loading…
Add table
Add a link
Reference in a new issue