1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 13:16:39 +03:00

fix(input): support alt-left-bracket

This commit is contained in:
Aram Drevekenin 2023-02-12 09:57:44 +01:00 committed by Wez Furlong
parent b021551080
commit f2e342a25f
2 changed files with 105 additions and 35 deletions

View File

@ -1453,6 +1453,13 @@ impl InputParser {
modifiers: Modifiers::NONE,
}),
);
map.insert(
b"\x1b[",
InputEvent::Key(KeyEvent {
key: KeyCode::Char('['),
modifiers: Modifiers::ALT,
}),
);
map
}
@ -1606,7 +1613,10 @@ impl InputParser {
}
}
match (self.key_map.lookup(self.buf.as_slice()), maybe_more) {
match (
self.key_map.lookup(self.buf.as_slice(), maybe_more),
maybe_more,
) {
// If we got an unambiguous ESC and we have more data to
// follow, then this is likely the Meta version of the
// following keypress. Buffer up the escape key and
@ -1674,9 +1684,9 @@ impl InputParser {
self.process_bytes(callback, maybe_more);
}
pub fn parse_as_vec(&mut self, bytes: &[u8]) -> Vec<InputEvent> {
pub fn parse_as_vec(&mut self, bytes: &[u8], maybe_more: bool) -> Vec<InputEvent> {
let mut result = Vec::new();
self.parse(bytes, |event| result.push(event), false);
self.parse(bytes, |event| result.push(event), maybe_more);
result
}
@ -1692,10 +1702,13 @@ impl InputParser {
mod test {
use super::*;
const NO_MORE: bool = false;
const MAYBE_MORE: bool = true;
#[test]
fn simple() {
let mut p = InputParser::new();
let inputs = p.parse_as_vec(b"hello");
let inputs = p.parse_as_vec(b"hello", NO_MORE);
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
@ -1726,7 +1739,7 @@ mod test {
#[test]
fn control_characters() {
let mut p = InputParser::new();
let inputs = p.parse_as_vec(b"\x03\x1bJ\x7f");
let inputs = p.parse_as_vec(b"\x03\x1bJ\x7f", NO_MORE);
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
@ -1749,7 +1762,7 @@ mod test {
#[test]
fn arrow_keys() {
let mut p = InputParser::new();
let inputs = p.parse_as_vec(b"\x1bOA\x1bOB\x1bOC\x1bOD");
let inputs = p.parse_as_vec(b"\x1bOA\x1bOB\x1bOC\x1bOD", NO_MORE);
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
@ -1799,22 +1812,19 @@ mod test {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
})],
p.parse_as_vec(b"\x1b")
p.parse_as_vec(b"\x1b", false)
);
let mut inputs = Vec::new();
// Fragment this F-key sequence across two different pushes
p.parse(b"\x1b[11", |evt| inputs.push(evt), true);
p.parse(b"", |evt| inputs.push(evt), false);
// make sure we recognize it as just the F-key
// An incomplete F-key sequence fragmented across two different pushes
p.parse(b"\x1b[11", |evt| inputs.push(evt), MAYBE_MORE);
p.parse(b"", |evt| inputs.push(evt), NO_MORE);
// since we finish with maybe_more false (NO_MORE), the results should be the longest matching
// parts of said f-key sequence
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
modifiers: Modifiers::ALT,
key: KeyCode::Char('['),
}),
InputEvent::Key(KeyEvent {
@ -1830,11 +1840,31 @@ mod test {
);
}
#[test]
fn alt_left_bracket() {
// tests that `Alt` + `[` is recognized as a single
// event rather than two events (one `Esc` the second `Char('[')`)
let mut p = InputParser::new();
let mut inputs = Vec::new();
p.parse(b"\x1b[", |evt| inputs.push(evt), false);
assert_eq!(
vec![InputEvent::Key(KeyEvent {
modifiers: Modifiers::ALT,
key: KeyCode::Char('['),
}),],
inputs
);
}
#[test]
fn modify_other_keys_parse() {
let mut p = InputParser::new();
let inputs =
p.parse_as_vec(b"\x1b[27;5;13~\x1b[27;5;9~\x1b[27;6;8~\x1b[27;2;127~\x1b[27;6;27~");
let inputs = p.parse_as_vec(
b"\x1b[27;5;13~\x1b[27;5;9~\x1b[27;6;8~\x1b[27;2;127~\x1b[27;6;27~",
NO_MORE,
);
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
@ -2037,7 +2067,7 @@ mod test {
let mut p = InputParser::new();
let input = b"\x1b[<66;42;12M\x1b[<67;42;12M";
let res = p.parse_as_vec(input);
let res = p.parse_as_vec(input, MAYBE_MORE);
assert_eq!(
vec![

View File

@ -37,7 +37,7 @@ impl<Value: Debug> Node<Value> {
}
}
fn lookup(&self, key: &[u8], depth: usize) -> NodeFind<&Value> {
fn lookup(&self, key: &[u8], depth: usize, maybe_more: bool) -> NodeFind<&Value> {
if key.is_empty() {
// We've matched the maximum extent of the input key.
if self.children.is_empty() {
@ -50,7 +50,13 @@ impl<Value: Debug> Node<Value> {
}
}
return match self.value.as_ref() {
Some(value) => NodeFind::AmbiguousMatch(depth, value),
Some(value) => {
if maybe_more {
NodeFind::AmbiguousMatch(depth, value)
} else {
NodeFind::Exact(depth, value)
}
}
None => NodeFind::AmbiguousBackTrack,
};
}
@ -60,12 +66,23 @@ impl<Value: Debug> Node<Value> {
.binary_search_by(|node| node.label.cmp(&key[0]))
{
Ok(idx) => {
match self.children[idx].lookup(&key[1..], depth + 1) {
match self.children[idx].lookup(&key[1..], depth + 1, maybe_more) {
NodeFind::AmbiguousBackTrack => {
// The child didn't have an exact match, so check
// whether we do
match self.value.as_ref() {
Some(value) => NodeFind::AmbiguousMatch(depth, value),
Some(value) => {
// We do! If we're expecting more, let's return an AmbiguousMatch,
// otherwise, let's treat this as an Exact match
//
// see the "lookup_with_multiple_ambiguous_matches_"
// test cases in this file for an example
if maybe_more {
NodeFind::AmbiguousMatch(depth, value)
} else {
NodeFind::Exact(depth, value)
}
}
None => NodeFind::AmbiguousBackTrack,
}
}
@ -173,8 +190,8 @@ impl<Value: Debug + Clone> KeyMap<Value> {
/// case; if the caller knows that no more data is available this can be
/// treated as `Found::None`, but otherwise it would be best to read more
/// data from the stream and retry with a longer input.
pub fn lookup<S: AsRef<[u8]>>(&self, key: S) -> Found<Value> {
match self.root.lookup(key.as_ref(), 0) {
pub fn lookup<S: AsRef<[u8]>>(&self, key: S, maybe_more: bool) -> Found<Value> {
match self.root.lookup(key.as_ref(), 0, maybe_more) {
NodeFind::None => Found::None,
NodeFind::AmbiguousBackTrack => Found::NeedData,
NodeFind::Exact(depth, value) => Found::Exact(depth, value.clone()),
@ -187,10 +204,13 @@ impl<Value: Debug + Clone> KeyMap<Value> {
mod test {
use super::*;
const NO_MORE: bool = false;
const MAYBE_MORE: bool = true;
#[test]
fn lookup_empty() {
let km: KeyMap<bool> = KeyMap::new();
assert_eq!(km.lookup("boo"), Found::None);
assert_eq!(km.lookup("boo", true), Found::None);
}
#[test]
@ -199,12 +219,32 @@ mod test {
km.insert("boa", true);
km.insert("boo", true);
km.insert("boom", false);
assert_eq!(km.lookup("b"), Found::NeedData);
assert_eq!(km.lookup("bo"), Found::NeedData);
assert_eq!(km.lookup("boa"), Found::Exact(3, true),);
assert_eq!(km.lookup("boo"), Found::Ambiguous(3, true),);
assert_eq!(km.lookup("boom"), Found::Exact(4, false),);
assert_eq!(km.lookup("boom!"), Found::Exact(4, false),);
assert_eq!(km.lookup("b", MAYBE_MORE), Found::NeedData);
assert_eq!(km.lookup("bo", MAYBE_MORE), Found::NeedData);
assert_eq!(km.lookup("boa", MAYBE_MORE), Found::Exact(3, true),);
assert_eq!(km.lookup("boo", MAYBE_MORE), Found::Ambiguous(3, true),);
assert_eq!(km.lookup("boom", MAYBE_MORE), Found::Exact(4, false),);
assert_eq!(km.lookup("boom!", MAYBE_MORE), Found::Exact(4, false),);
}
#[test]
fn lookup_with_multiple_ambiguous_matches_without_additional_input() {
let mut km = KeyMap::new();
km.insert("boa", false);
km.insert("boo", false);
km.insert("boom", true);
km.insert("boom!!", false);
assert_eq!(km.lookup("boom!", NO_MORE), Found::Exact(4, true));
}
#[test]
fn lookup_with_multiple_ambiguous_matches_with_potential_additional_input() {
let mut km = KeyMap::new();
km.insert("boa", false);
km.insert("boo", false);
km.insert("boom", true);
km.insert("boom!!", false);
assert_eq!(km.lookup("boom!", MAYBE_MORE), Found::Ambiguous(4, true));
}
#[test]
@ -213,8 +253,8 @@ mod test {
km.insert("\x03", true);
km.insert("\x27", true);
km.insert("\x03XYZ", true);
assert_eq!(km.lookup("\x03"), Found::Ambiguous(1, true),);
assert_eq!(km.lookup("\x03foo"), Found::Exact(1, true),);
assert_eq!(km.lookup("\x03X"), Found::Ambiguous(1, true),);
assert_eq!(km.lookup("\x03", MAYBE_MORE), Found::Ambiguous(1, true),);
assert_eq!(km.lookup("\x03foo", MAYBE_MORE), Found::Exact(1, true),);
assert_eq!(km.lookup("\x03X", MAYBE_MORE), Found::Ambiguous(1, true),);
}
}