Merge branch 'main' into copy-test-update
This commit is contained in:
commit
1b3fb257b2
6 changed files with 520 additions and 135 deletions
|
@ -407,19 +407,16 @@
|
||||||
{
|
{
|
||||||
"context": "Terminal",
|
"context": "Terminal",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"ctrl-c": "terminal::Sigint",
|
// Overrides for global bindings, remove at your own risk:
|
||||||
"escape": "terminal::Escape",
|
|
||||||
"ctrl-d": "terminal::Quit",
|
|
||||||
"backspace": "terminal::Del",
|
|
||||||
"enter": "terminal::Return",
|
|
||||||
"left": "terminal::Left",
|
|
||||||
"right": "terminal::Right",
|
|
||||||
"up": "terminal::Up",
|
"up": "terminal::Up",
|
||||||
"down": "terminal::Down",
|
"down": "terminal::Down",
|
||||||
"tab": "terminal::Tab",
|
"escape": "terminal::Escape",
|
||||||
"cmd-v": "terminal::Paste",
|
"enter": "terminal::Enter",
|
||||||
|
"ctrl-c": "terminal::CtrlC",
|
||||||
|
// Useful terminal actions:
|
||||||
"cmd-c": "terminal::Copy",
|
"cmd-c": "terminal::Copy",
|
||||||
"ctrl-l": "terminal::Clear"
|
"cmd-v": "terminal::Paste",
|
||||||
|
"cmd-k": "terminal::Clear"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,5 +28,3 @@ gpui = { path = "../gpui", features = ["test-support"] }
|
||||||
client = { path = "../client", features = ["test-support"]}
|
client = { path = "../client", features = ["test-support"]}
|
||||||
project = { path = "../project", features = ["test-support"]}
|
project = { path = "../project", features = ["test-support"]}
|
||||||
workspace = { path = "../workspace", features = ["test-support"] }
|
workspace = { path = "../workspace", features = ["test-support"] }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod keymappings;
|
||||||
|
|
||||||
use alacritty_terminal::{
|
use alacritty_terminal::{
|
||||||
ansi::{ClearMode, Handler},
|
ansi::{ClearMode, Handler},
|
||||||
config::{Config, PtyConfig},
|
config::{Config, PtyConfig},
|
||||||
|
@ -13,13 +15,15 @@ use futures::{channel::mpsc::unbounded, StreamExt};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use gpui::{ClipboardItem, CursorStyle, Entity, ModelContext};
|
use gpui::{keymap::Keystroke, ClipboardItem, CursorStyle, Entity, ModelContext};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color_translation::{get_color_at_index, to_alac_rgb},
|
color_translation::{get_color_at_index, to_alac_rgb},
|
||||||
ZedListener,
|
ZedListener,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::keymappings::to_esc_str;
|
||||||
|
|
||||||
const DEFAULT_TITLE: &str = "Terminal";
|
const DEFAULT_TITLE: &str = "Terminal";
|
||||||
|
|
||||||
///Upward flowing events, for changing the title and such
|
///Upward flowing events, for changing the title and such
|
||||||
|
@ -182,6 +186,19 @@ impl TerminalConnection {
|
||||||
self.write_to_pty("\x0c".into());
|
self.write_to_pty("\x0c".into());
|
||||||
self.term.lock().clear_screen(ClearMode::Saved);
|
self.term.lock().clear_screen(ClearMode::Saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool {
|
||||||
|
let guard = self.term.lock();
|
||||||
|
let mode = guard.mode();
|
||||||
|
let esc = to_esc_str(keystroke, mode);
|
||||||
|
drop(guard);
|
||||||
|
if esc.is_some() {
|
||||||
|
self.write_to_pty(esc.unwrap());
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TerminalConnection {
|
impl Drop for TerminalConnection {
|
||||||
|
|
444
crates/terminal/src/connection/keymappings.rs
Normal file
444
crates/terminal/src/connection/keymappings.rs
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
use alacritty_terminal::term::TermMode;
|
||||||
|
use gpui::keymap::Keystroke;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Connection events still to do:
|
||||||
|
- Reporting mouse events correctly.
|
||||||
|
- Reporting scrolls
|
||||||
|
- Correctly bracketing a paste
|
||||||
|
- Storing changed colors
|
||||||
|
- Focus change sequence
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[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())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ pub mod terminal_element;
|
||||||
|
|
||||||
use alacritty_terminal::{
|
use alacritty_terminal::{
|
||||||
event::{Event as AlacTermEvent, EventListener},
|
event::{Event as AlacTermEvent, EventListener},
|
||||||
grid::Scroll,
|
|
||||||
term::SizeInfo,
|
term::SizeInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,7 +13,7 @@ use dirs::home_dir;
|
||||||
use editor::Input;
|
use editor::Input;
|
||||||
use futures::channel::mpsc::UnboundedSender;
|
use futures::channel::mpsc::UnboundedSender;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, elements::*, impl_internal_actions, AppContext, ClipboardItem, Entity, ModelHandle,
|
actions, elements::*, keymap::Keystroke, AppContext, ClipboardItem, Entity, ModelHandle,
|
||||||
MutableAppContext, View, ViewContext,
|
MutableAppContext, View, ViewContext,
|
||||||
};
|
};
|
||||||
use modal::deploy_modal;
|
use modal::deploy_modal;
|
||||||
|
@ -27,16 +26,6 @@ use workspace::{Item, Workspace};
|
||||||
|
|
||||||
use crate::terminal_element::TerminalEl;
|
use crate::terminal_element::TerminalEl;
|
||||||
|
|
||||||
//ASCII Control characters on a keyboard
|
|
||||||
const ETX_CHAR: char = 3_u8 as char; //'End of text', the control code for 'ctrl-c'
|
|
||||||
const TAB_CHAR: char = 9_u8 as char;
|
|
||||||
const CARRIAGE_RETURN_CHAR: char = 13_u8 as char;
|
|
||||||
const ESC_CHAR: char = 27_u8 as char; // == \x1b
|
|
||||||
const DEL_CHAR: char = 127_u8 as char;
|
|
||||||
const LEFT_SEQ: &str = "\x1b[D";
|
|
||||||
const RIGHT_SEQ: &str = "\x1b[C";
|
|
||||||
const UP_SEQ: &str = "\x1b[A";
|
|
||||||
const DOWN_SEQ: &str = "\x1b[B";
|
|
||||||
const DEBUG_TERMINAL_WIDTH: f32 = 1000.; //This needs to be wide enough that the prompt can fill the whole space.
|
const DEBUG_TERMINAL_WIDTH: f32 = 1000.; //This needs to be wide enough that the prompt can fill the whole space.
|
||||||
const DEBUG_TERMINAL_HEIGHT: f32 = 200.;
|
const DEBUG_TERMINAL_HEIGHT: f32 = 200.;
|
||||||
const DEBUG_CELL_WIDTH: f32 = 5.;
|
const DEBUG_CELL_WIDTH: f32 = 5.;
|
||||||
|
@ -52,44 +41,34 @@ pub struct ScrollTerminal(pub i32);
|
||||||
actions!(
|
actions!(
|
||||||
terminal,
|
terminal,
|
||||||
[
|
[
|
||||||
Sigint,
|
Deploy,
|
||||||
Escape,
|
|
||||||
Del,
|
|
||||||
Return,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
Tab,
|
CtrlC,
|
||||||
|
Escape,
|
||||||
|
Enter,
|
||||||
Clear,
|
Clear,
|
||||||
Copy,
|
Copy,
|
||||||
Paste,
|
Paste,
|
||||||
Deploy,
|
DeployModal
|
||||||
Quit,
|
|
||||||
DeployModal,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
impl_internal_actions!(terminal, [ScrollTerminal]);
|
|
||||||
|
|
||||||
///Initialize and register all of our action handlers
|
///Initialize and register all of our action handlers
|
||||||
pub fn init(cx: &mut MutableAppContext) {
|
pub fn init(cx: &mut MutableAppContext) {
|
||||||
cx.add_action(Terminal::deploy);
|
//Global binding overrrides
|
||||||
cx.add_action(Terminal::send_sigint);
|
cx.add_action(Terminal::ctrl_c);
|
||||||
cx.add_action(Terminal::escape);
|
|
||||||
cx.add_action(Terminal::quit);
|
|
||||||
cx.add_action(Terminal::del);
|
|
||||||
cx.add_action(Terminal::carriage_return);
|
|
||||||
cx.add_action(Terminal::left);
|
|
||||||
cx.add_action(Terminal::right);
|
|
||||||
cx.add_action(Terminal::up);
|
cx.add_action(Terminal::up);
|
||||||
cx.add_action(Terminal::down);
|
cx.add_action(Terminal::down);
|
||||||
cx.add_action(Terminal::tab);
|
cx.add_action(Terminal::escape);
|
||||||
|
cx.add_action(Terminal::enter);
|
||||||
|
//Useful terminal actions
|
||||||
|
cx.add_action(Terminal::deploy);
|
||||||
|
cx.add_action(deploy_modal);
|
||||||
cx.add_action(Terminal::copy);
|
cx.add_action(Terminal::copy);
|
||||||
cx.add_action(Terminal::paste);
|
cx.add_action(Terminal::paste);
|
||||||
cx.add_action(Terminal::scroll_terminal);
|
|
||||||
cx.add_action(Terminal::input);
|
cx.add_action(Terminal::input);
|
||||||
cx.add_action(Terminal::clear);
|
cx.add_action(Terminal::clear);
|
||||||
cx.add_action(deploy_modal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///A translation struct for Alacritty to communicate with us from their event loop
|
///A translation struct for Alacritty to communicate with us from their event loop
|
||||||
|
@ -168,15 +147,6 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Scroll the terminal. This locks the terminal
|
|
||||||
fn scroll_terminal(&mut self, scroll: &ScrollTerminal, cx: &mut ViewContext<Self>) {
|
|
||||||
self.connection
|
|
||||||
.read(cx)
|
|
||||||
.term
|
|
||||||
.lock()
|
|
||||||
.scroll_display(Scroll::Delta(scroll.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input(&mut self, Input(text): &Input, cx: &mut ViewContext<Self>) {
|
fn input(&mut self, Input(text): &Input, cx: &mut ViewContext<Self>) {
|
||||||
self.connection.update(cx, |connection, _| {
|
self.connection.update(cx, |connection, _| {
|
||||||
//TODO: This is probably not encoding UTF8 correctly (see alacritty/src/input.rs:L825-837)
|
//TODO: This is probably not encoding UTF8 correctly (see alacritty/src/input.rs:L825-837)
|
||||||
|
@ -200,11 +170,6 @@ impl Terminal {
|
||||||
workspace.add_item(Box::new(cx.add_view(|cx| Terminal::new(wd, false, cx))), cx);
|
workspace.add_item(Box::new(cx.add_view(|cx| Terminal::new(wd, false, cx))), cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Tell Zed to close us
|
|
||||||
fn quit(&mut self, _: &Quit, cx: &mut ViewContext<Self>) {
|
|
||||||
cx.emit(Event::CloseTerminal);
|
|
||||||
}
|
|
||||||
|
|
||||||
///Attempt to paste the clipboard into the terminal
|
///Attempt to paste the clipboard into the terminal
|
||||||
fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
|
fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
|
||||||
let term = self.connection.read(cx).term.lock();
|
let term = self.connection.read(cx).term.lock();
|
||||||
|
@ -224,66 +189,38 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Send the `up` key
|
///Synthesize the keyboard event corresponding to 'up'
|
||||||
fn up(&mut self, _: &Up, cx: &mut ViewContext<Self>) {
|
fn up(&mut self, _: &Up, cx: &mut ViewContext<Self>) {
|
||||||
self.connection.update(cx, |connection, _| {
|
self.connection.update(cx, |connection, _| {
|
||||||
connection.write_to_pty(UP_SEQ.to_string());
|
connection.try_keystroke(&Keystroke::parse("up").unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
///Send the `down` key
|
///Synthesize the keyboard event corresponding to 'down'
|
||||||
fn down(&mut self, _: &Down, cx: &mut ViewContext<Self>) {
|
fn down(&mut self, _: &Down, cx: &mut ViewContext<Self>) {
|
||||||
self.connection.update(cx, |connection, _| {
|
self.connection.update(cx, |connection, _| {
|
||||||
connection.write_to_pty(DOWN_SEQ.to_string());
|
connection.try_keystroke(&Keystroke::parse("down").unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
///Send the `tab` key
|
///Synthesize the keyboard event corresponding to 'ctrl-c'
|
||||||
fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
|
fn ctrl_c(&mut self, _: &CtrlC, cx: &mut ViewContext<Self>) {
|
||||||
self.connection.update(cx, |connection, _| {
|
self.connection.update(cx, |connection, _| {
|
||||||
connection.write_to_pty(TAB_CHAR.to_string());
|
connection.try_keystroke(&Keystroke::parse("ctrl-c").unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
///Send `SIGINT` (`ctrl-c`)
|
///Synthesize the keyboard event corresponding to 'escape'
|
||||||
fn send_sigint(&mut self, _: &Sigint, cx: &mut ViewContext<Self>) {
|
|
||||||
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>) {
|
fn escape(&mut self, _: &Escape, cx: &mut ViewContext<Self>) {
|
||||||
self.connection.update(cx, |connection, _| {
|
self.connection.update(cx, |connection, _| {
|
||||||
connection.write_to_pty(ESC_CHAR.to_string());
|
connection.try_keystroke(&Keystroke::parse("escape").unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
///Send the `delete` key. TODO: Difference between this and backspace?
|
///Synthesize the keyboard event corresponding to 'enter'
|
||||||
fn del(&mut self, _: &Del, cx: &mut ViewContext<Self>) {
|
fn enter(&mut self, _: &Enter, cx: &mut ViewContext<Self>) {
|
||||||
self.connection.update(cx, |connection, _| {
|
self.connection.update(cx, |connection, _| {
|
||||||
connection.write_to_pty(DEL_CHAR.to_string());
|
connection.try_keystroke(&Keystroke::parse("enter").unwrap());
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
///Send a carriage return. TODO: May need to check the terminal mode.
|
|
||||||
fn carriage_return(&mut self, _: &Return, cx: &mut ViewContext<Self>) {
|
|
||||||
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>) {
|
|
||||||
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>) {
|
|
||||||
self.connection.update(cx, |connection, _| {
|
|
||||||
connection.write_to_pty(RIGHT_SEQ.to_string());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,8 +423,8 @@ mod tests {
|
||||||
///Integration test for selections, clipboard, and terminal execution
|
///Integration test for selections, clipboard, and terminal execution
|
||||||
#[gpui::test(retries = 5)]
|
#[gpui::test(retries = 5)]
|
||||||
async fn test_copy(cx: &mut TestAppContext) {
|
async fn test_copy(cx: &mut TestAppContext) {
|
||||||
let mut cx = TerminalTestContext::new(cx);
|
|
||||||
|
|
||||||
|
let mut cx = TerminalTestContext::new(cx);
|
||||||
let grid_content = cx
|
let grid_content = cx
|
||||||
.execute_and_wait("expr 3 + 4", |content, _cx| content.contains("7"))
|
.execute_and_wait("expr 3 + 4", |content, _cx| content.contains("7"))
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use alacritty_terminal::{
|
use alacritty_terminal::{
|
||||||
grid::{Dimensions, GridIterator, Indexed},
|
grid::{Dimensions, GridIterator, Indexed, Scroll},
|
||||||
index::{Column as GridCol, Line as GridLine, Point, Side},
|
index::{Column as GridCol, Line as GridLine, Point, Side},
|
||||||
selection::{Selection, SelectionRange, SelectionType},
|
selection::{Selection, SelectionRange, SelectionType},
|
||||||
sync::FairMutex,
|
sync::FairMutex,
|
||||||
|
@ -9,7 +9,7 @@ use alacritty_terminal::{
|
||||||
},
|
},
|
||||||
Term,
|
Term,
|
||||||
};
|
};
|
||||||
use editor::{Cursor, CursorShape, HighlightedRange, HighlightedRangeLine, Input};
|
use editor::{Cursor, CursorShape, HighlightedRange, HighlightedRangeLine};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::Color,
|
color::Color,
|
||||||
elements::*,
|
elements::*,
|
||||||
|
@ -31,9 +31,7 @@ use theme::TerminalStyle;
|
||||||
use std::{cmp::min, ops::Range, rc::Rc, sync::Arc};
|
use std::{cmp::min, ops::Range, rc::Rc, sync::Arc};
|
||||||
use std::{fmt::Debug, ops::Sub};
|
use std::{fmt::Debug, ops::Sub};
|
||||||
|
|
||||||
use crate::{
|
use crate::{color_translation::convert_color, connection::TerminalConnection, ZedListener};
|
||||||
color_translation::convert_color, connection::TerminalConnection, ScrollTerminal, ZedListener,
|
|
||||||
};
|
|
||||||
|
|
||||||
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
|
///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
|
///Scroll multiplier that is set to 3 by default. This will be removed when I
|
||||||
|
@ -359,25 +357,6 @@ impl Element for TerminalEl {
|
||||||
_paint: &mut Self::PaintState,
|
_paint: &mut Self::PaintState,
|
||||||
cx: &mut gpui::EventContext,
|
cx: &mut gpui::EventContext,
|
||||||
) -> bool {
|
) -> 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 {
|
match event {
|
||||||
Event::ScrollWheel(ScrollWheelEvent {
|
Event::ScrollWheel(ScrollWheelEvent {
|
||||||
delta, position, ..
|
delta, position, ..
|
||||||
|
@ -386,17 +365,30 @@ impl Element for TerminalEl {
|
||||||
.then(|| {
|
.then(|| {
|
||||||
let vertical_scroll =
|
let vertical_scroll =
|
||||||
(delta.y() / layout.line_height.0) * ALACRITTY_SCROLL_MULTIPLIER;
|
(delta.y() / layout.line_height.0) * ALACRITTY_SCROLL_MULTIPLIER;
|
||||||
cx.dispatch_action(ScrollTerminal(vertical_scroll.round() as i32));
|
|
||||||
})
|
if let Some(connection) = self.connection.upgrade(cx.app) {
|
||||||
.is_some(),
|
connection.update(cx.app, |connection, _| {
|
||||||
Event::KeyDown(KeyDownEvent {
|
connection
|
||||||
input: Some(input), ..
|
.term
|
||||||
}) => cx
|
.lock()
|
||||||
.is_parent_view_focused()
|
.scroll_display(Scroll::Delta(vertical_scroll.round() as i32));
|
||||||
.then(|| {
|
})
|
||||||
cx.dispatch_action(Input(input.to_string()));
|
}
|
||||||
})
|
})
|
||||||
.is_some(),
|
.is_some(),
|
||||||
|
Event::KeyDown(KeyDownEvent { keystroke, .. }) => {
|
||||||
|
if !cx.is_parent_view_focused() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.connection
|
||||||
|
.upgrade(cx.app)
|
||||||
|
.map(|connection| {
|
||||||
|
connection
|
||||||
|
.update(cx.app, |connection, _| connection.try_keystroke(keystroke))
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue