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:
parent
b021551080
commit
f2e342a25f
@ -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![
|
||||
|
@ -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),);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user