use std::fmt;
use std::str::FromStr;
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
#[non_exhaustive]
pub enum Key {
Invalid,
Check,
PasteStart,
PasteEnd,
Pr(char),
Ctrl(char),
Meta(char),
MetaCtrl(char),
Tab,
Return,
BackSp,
Esc,
BackTab,
MetaTab,
MetaReturn,
MetaBackSp,
MetaEsc,
MetaBackTab,
F(u32),
Up,
Down,
Left,
Right,
PgUp,
PgDn,
Home,
Insert,
Delete,
End,
ShiftF(u32),
ShiftUp,
ShiftDown,
ShiftLeft,
ShiftRight,
ShiftPgUp,
ShiftPgDn,
ShiftHome,
ShiftInsert,
ShiftDelete,
ShiftEnd,
MetaF(u32),
MetaUp,
MetaDown,
MetaLeft,
MetaRight,
MetaPgUp,
MetaPgDn,
MetaHome,
MetaInsert,
MetaDelete,
MetaEnd,
MetaShiftF(u32),
MetaShiftUp,
MetaShiftDown,
MetaShiftLeft,
MetaShiftRight,
MetaShiftPgUp,
MetaShiftPgDn,
MetaShiftHome,
MetaShiftInsert,
MetaShiftDelete,
MetaShiftEnd,
CtrlF(u32),
CtrlUp,
CtrlDown,
CtrlLeft,
CtrlRight,
CtrlPgUp,
CtrlPgDn,
CtrlHome,
CtrlInsert,
CtrlDelete,
CtrlEnd,
CtrlShiftF(u32),
CtrlShiftUp,
CtrlShiftDown,
CtrlShiftLeft,
CtrlShiftRight,
CtrlShiftPgUp,
CtrlShiftPgDn,
CtrlShiftHome,
CtrlShiftInsert,
CtrlShiftDelete,
CtrlShiftEnd,
MetaCtrlF(u32),
MetaCtrlUp,
MetaCtrlDown,
MetaCtrlLeft,
MetaCtrlRight,
MetaCtrlPgUp,
MetaCtrlPgDn,
MetaCtrlHome,
MetaCtrlInsert,
MetaCtrlDelete,
MetaCtrlEnd,
MetaCtrlShiftF(u32),
MetaCtrlShiftUp,
MetaCtrlShiftDown,
MetaCtrlShiftLeft,
MetaCtrlShiftRight,
MetaCtrlShiftPgUp,
MetaCtrlShiftPgDn,
MetaCtrlShiftHome,
MetaCtrlShiftInsert,
MetaCtrlShiftDelete,
MetaCtrlShiftEnd,
}
impl fmt::Debug for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (base, modf) = self.base();
match modf.0 & 7 {
0 => (),
1 => write!(f, "S-")?,
2 => write!(f, "M-")?,
3 => write!(f, "M-S-")?,
4 => write!(f, "C-")?,
5 => write!(f, "C-S-")?,
6 => write!(f, "M-C-")?,
_ => write!(f, "M-C-S-")?,
}
match base {
Key::Invalid => write!(f, "Invalid"),
Key::Check => write!(f, "Check"),
Key::PasteStart => write!(f, "PasteStart"),
Key::PasteEnd => write!(f, "PasteEnd"),
Key::Pr(ch) => write!(f, "{ch}"),
Key::Tab => write!(f, "Tab"),
Key::Return => write!(f, "Return"),
Key::BackSp => write!(f, "BackSp"),
Key::Esc => write!(f, "Esc"),
Key::BackTab => write!(f, "BackTab"),
Key::F(num) => write!(f, "F{num}"),
Key::Up => write!(f, "Up"),
Key::Down => write!(f, "Down"),
Key::Left => write!(f, "Left"),
Key::Right => write!(f, "Right"),
Key::PgUp => write!(f, "PgUp"),
Key::PgDn => write!(f, "PgDn"),
Key::Home => write!(f, "Home"),
Key::Insert => write!(f, "Insert"),
Key::Delete => write!(f, "Delete"),
Key::End => write!(f, "End"),
_ => write!(f, "???"),
}
}
}
#[derive(Debug)]
pub struct ParseKeyError;
impl FromStr for Key {
type Err = ParseKeyError;
fn from_str(mut s: &str) -> Result<Key, ParseKeyError> {
let mut modf = Mod::none();
if let Some(rest) = s.strip_prefix("M-") {
s = rest;
modf |= Mod::meta();
}
if let Some(rest) = s.strip_prefix("C-") {
s = rest;
modf |= Mod::ctrl();
}
if let Some(rest) = s.strip_prefix("S-") {
s = rest;
modf |= Mod::shift();
}
let mut it = s.chars();
if let Some(ch) = it.next() {
if it.as_str().is_empty() {
return Ok(Key::Pr(ch).with(modf));
}
#[allow(clippy::manual_range_contains)]
if ch == 'F'
&& let Ok(v) = it.as_str().parse::<u32>()
&& v >= 1
&& v <= 20
{
return Ok(Key::F(v).with(modf));
}
}
let key = match (s, modf.has_shift(), modf.has_ctrl(), modf.has_meta()) {
("Invalid", false, false, false) => Key::Invalid,
("Check", false, false, false) => Key::Check,
("PasteStart", false, false, false) => Key::PasteStart,
("PasteEnd", false, false, false) => Key::PasteEnd,
("Return", false, false, _) => Key::Return,
("BackSp", false, false, _) => Key::BackSp,
("Esc", false, false, _) => Key::Esc,
("Tab", false, false, _) => Key::Tab,
("BackTab", false, false, _) => Key::BackTab,
("Up", _, _, _) => Key::Up,
("Down", _, _, _) => Key::Down,
("Left", _, _, _) => Key::Left,
("Right", _, _, _) => Key::Right,
("PgUp", _, _, _) => Key::PgUp,
("PgDn", _, _, _) => Key::PgDn,
("Home", _, _, _) => Key::Home,
("Insert", _, _, _) => Key::Insert,
("Delete", _, _, _) => Key::Delete,
("End", _, _, _) => Key::End,
_ => return Err(ParseKeyError),
};
Ok(key.with(modf))
}
}
struct Scan<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> Scan<'a> {
fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
fn grab(&mut self, v: u8) -> bool {
if self.data.get(self.pos) == Some(&v) {
self.pos += 1;
true
} else {
false
}
}
fn len(&self) -> usize {
self.data.len() - self.pos
}
fn is_empty(&self) -> bool {
self.data.len() == self.pos
}
fn next(&mut self) -> Option<u8> {
if self.pos < self.data.len() {
self.pos += 1;
Some(self.data[self.pos - 1])
} else {
None
}
}
fn take(&mut self, count: usize) -> Option<&'a [u8]> {
if self.pos + count <= self.data.len() {
self.pos += count;
Some(&self.data[self.pos - count..self.pos])
} else {
None
}
}
fn grab_num(&mut self) -> Option<u32> {
let pos0 = self.pos;
let mut val = 0;
while self.pos < self.data.len()
&& self.data[self.pos] >= b'0'
&& self.data[self.pos] <= b'9'
{
val = val * 10 + u32::from(self.data[self.pos] - b'0');
self.pos += 1;
}
if self.pos > pos0 { Some(val) } else { None }
}
}
impl Key {
pub fn base(self) -> (Self, Mod) {
let same = (self, Mod::none());
match self {
Self::Invalid => same,
Self::Check => same,
Self::PasteStart => same,
Self::PasteEnd => same,
Self::Pr(_) => same,
Self::Ctrl(ch) => (Self::Pr(ch), Mod::ctrl()),
Self::Meta(ch) => (Self::Pr(ch), Mod::meta()),
Self::MetaCtrl(ch) => (Self::Pr(ch), Mod::meta_ctrl()),
Self::Tab => same,
Self::Return => same,
Self::BackSp => same,
Self::Esc => same,
Self::BackTab => same,
Self::MetaTab => (Self::Tab, Mod::meta()),
Self::MetaReturn => (Self::Return, Mod::meta()),
Self::MetaBackSp => (Self::BackSp, Mod::meta()),
Self::MetaEsc => (Self::Esc, Mod::meta()),
Self::MetaBackTab => (Self::BackTab, Mod::meta()),
Self::F(_) => same,
Self::Up => same,
Self::Down => same,
Self::Left => same,
Self::Right => same,
Self::PgUp => same,
Self::PgDn => same,
Self::Home => same,
Self::Insert => same,
Self::Delete => same,
Self::End => same,
Self::ShiftF(n) => (Self::F(n), Mod::shift()),
Self::ShiftUp => (Self::Up, Mod::shift()),
Self::ShiftDown => (Self::Down, Mod::shift()),
Self::ShiftLeft => (Self::Left, Mod::shift()),
Self::ShiftRight => (Self::Right, Mod::shift()),
Self::ShiftPgUp => (Self::PgUp, Mod::shift()),
Self::ShiftPgDn => (Self::PgDn, Mod::shift()),
Self::ShiftHome => (Self::Home, Mod::shift()),
Self::ShiftInsert => (Self::Insert, Mod::shift()),
Self::ShiftDelete => (Self::Delete, Mod::shift()),
Self::ShiftEnd => (Self::End, Mod::shift()),
Self::MetaF(n) => (Self::F(n), Mod::meta()),
Self::MetaUp => (Self::Up, Mod::meta()),
Self::MetaDown => (Self::Down, Mod::meta()),
Self::MetaLeft => (Self::Left, Mod::meta()),
Self::MetaRight => (Self::Right, Mod::meta()),
Self::MetaPgUp => (Self::PgUp, Mod::meta()),
Self::MetaPgDn => (Self::PgDn, Mod::meta()),
Self::MetaHome => (Self::Home, Mod::meta()),
Self::MetaInsert => (Self::Insert, Mod::meta()),
Self::MetaDelete => (Self::Delete, Mod::meta()),
Self::MetaEnd => (Self::End, Mod::meta()),
Self::MetaShiftF(n) => (Self::F(n), Mod::meta_shift()),
Self::MetaShiftUp => (Self::Up, Mod::meta_shift()),
Self::MetaShiftDown => (Self::Down, Mod::meta_shift()),
Self::MetaShiftLeft => (Self::Left, Mod::meta_shift()),
Self::MetaShiftRight => (Self::Right, Mod::meta_shift()),
Self::MetaShiftPgUp => (Self::PgUp, Mod::meta_shift()),
Self::MetaShiftPgDn => (Self::PgDn, Mod::meta_shift()),
Self::MetaShiftHome => (Self::Home, Mod::meta_shift()),
Self::MetaShiftInsert => (Self::Insert, Mod::meta_shift()),
Self::MetaShiftDelete => (Self::Delete, Mod::meta_shift()),
Self::MetaShiftEnd => (Self::End, Mod::meta_shift()),
Self::CtrlF(n) => (Self::F(n), Mod::ctrl()),
Self::CtrlUp => (Self::Up, Mod::ctrl()),
Self::CtrlDown => (Self::Down, Mod::ctrl()),
Self::CtrlLeft => (Self::Left, Mod::ctrl()),
Self::CtrlRight => (Self::Right, Mod::ctrl()),
Self::CtrlPgUp => (Self::PgUp, Mod::ctrl()),
Self::CtrlPgDn => (Self::PgDn, Mod::ctrl()),
Self::CtrlHome => (Self::Home, Mod::ctrl()),
Self::CtrlInsert => (Self::Insert, Mod::ctrl()),
Self::CtrlDelete => (Self::Delete, Mod::ctrl()),
Self::CtrlEnd => (Self::End, Mod::ctrl()),
Self::CtrlShiftF(n) => (Self::F(n), Mod::ctrl_shift()),
Self::CtrlShiftUp => (Self::Up, Mod::ctrl_shift()),
Self::CtrlShiftDown => (Self::Down, Mod::ctrl_shift()),
Self::CtrlShiftLeft => (Self::Left, Mod::ctrl_shift()),
Self::CtrlShiftRight => (Self::Right, Mod::ctrl_shift()),
Self::CtrlShiftPgUp => (Self::PgUp, Mod::ctrl_shift()),
Self::CtrlShiftPgDn => (Self::PgDn, Mod::ctrl_shift()),
Self::CtrlShiftHome => (Self::Home, Mod::ctrl_shift()),
Self::CtrlShiftInsert => (Self::Insert, Mod::ctrl_shift()),
Self::CtrlShiftDelete => (Self::Delete, Mod::ctrl_shift()),
Self::CtrlShiftEnd => (Self::End, Mod::ctrl_shift()),
Self::MetaCtrlF(n) => (Self::F(n), Mod::meta_ctrl()),
Self::MetaCtrlUp => (Self::Up, Mod::meta_ctrl()),
Self::MetaCtrlDown => (Self::Down, Mod::meta_ctrl()),
Self::MetaCtrlLeft => (Self::Left, Mod::meta_ctrl()),
Self::MetaCtrlRight => (Self::Right, Mod::meta_ctrl()),
Self::MetaCtrlPgUp => (Self::PgUp, Mod::meta_ctrl()),
Self::MetaCtrlPgDn => (Self::PgDn, Mod::meta_ctrl()),
Self::MetaCtrlHome => (Self::Home, Mod::meta_ctrl()),
Self::MetaCtrlInsert => (Self::Insert, Mod::meta_ctrl()),
Self::MetaCtrlDelete => (Self::Delete, Mod::meta_ctrl()),
Self::MetaCtrlEnd => (Self::End, Mod::meta_ctrl()),
Self::MetaCtrlShiftF(n) => (Self::F(n), Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftUp => (Self::Up, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftDown => (Self::Down, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftLeft => (Self::Left, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftRight => (Self::Right, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftPgUp => (Self::PgUp, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftPgDn => (Self::PgDn, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftHome => (Self::Home, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftInsert => (Self::Insert, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftDelete => (Self::Delete, Mod::meta_ctrl_shift()),
Self::MetaCtrlShiftEnd => (Self::End, Mod::meta_ctrl_shift()),
}
}
pub fn with(self, modf: Mod) -> Self {
let (base, old) = self.base();
let m = (old | modf).0 & 7;
match (base, m) {
(Self::Invalid, _) => self,
(Self::Check, _) => self,
(Self::PasteStart, _) => self,
(Self::PasteEnd, _) => self,
(Self::Pr(ch), 0 | 1) => Self::Pr(ch),
(Self::Pr(ch), 2 | 3) => Self::Meta(ch),
(Self::Pr(ch), 4 | 5) => Self::Ctrl(ch),
(Self::Pr(ch), 6 | 7) => Self::MetaCtrl(ch),
(Self::Tab, 0 | 1 | 4 | 5) => Self::Tab,
(Self::Tab, 2 | 3 | 6 | 7) => Self::MetaTab,
(Self::Return, 0 | 1 | 4 | 5) => Self::Return,
(Self::Return, 2 | 3 | 6 | 7) => Self::MetaReturn,
(Self::BackSp, 0 | 1 | 4 | 5) => Self::BackSp,
(Self::BackSp, 2 | 3 | 6 | 7) => Self::MetaBackSp,
(Self::Esc, 0 | 1 | 4 | 5) => Self::Esc,
(Self::Esc, 2 | 3 | 6 | 7) => Self::MetaEsc,
(Self::BackTab, 0 | 1 | 4 | 5) => Self::BackTab,
(Self::BackTab, 2 | 3 | 6 | 7) => Self::MetaBackTab,
(Self::F(n), 0) => Self::F(n),
(Self::F(n), 1) => Self::ShiftF(n),
(Self::F(n), 2) => Self::MetaF(n),
(Self::F(n), 3) => Self::MetaShiftF(n),
(Self::F(n), 4) => Self::CtrlF(n),
(Self::F(n), 5) => Self::CtrlShiftF(n),
(Self::F(n), 6) => Self::MetaCtrlF(n),
(Self::F(n), 7) => Self::MetaCtrlShiftF(n),
(Self::Up, 0) => Self::Up,
(Self::Up, 1) => Self::ShiftUp,
(Self::Up, 2) => Self::MetaUp,
(Self::Up, 3) => Self::MetaShiftUp,
(Self::Up, 4) => Self::CtrlUp,
(Self::Up, 5) => Self::CtrlShiftUp,
(Self::Up, 6) => Self::MetaCtrlUp,
(Self::Up, 7) => Self::MetaCtrlShiftUp,
(Self::Down, 0) => Self::Down,
(Self::Down, 1) => Self::ShiftDown,
(Self::Down, 2) => Self::MetaDown,
(Self::Down, 3) => Self::MetaShiftDown,
(Self::Down, 4) => Self::CtrlDown,
(Self::Down, 5) => Self::CtrlShiftDown,
(Self::Down, 6) => Self::MetaCtrlDown,
(Self::Down, 7) => Self::MetaCtrlShiftDown,
(Self::Left, 0) => Self::Left,
(Self::Left, 1) => Self::ShiftLeft,
(Self::Left, 2) => Self::MetaLeft,
(Self::Left, 3) => Self::MetaShiftLeft,
(Self::Left, 4) => Self::CtrlLeft,
(Self::Left, 5) => Self::CtrlShiftLeft,
(Self::Left, 6) => Self::MetaCtrlLeft,
(Self::Left, 7) => Self::MetaCtrlShiftLeft,
(Self::Right, 0) => Self::Right,
(Self::Right, 1) => Self::ShiftRight,
(Self::Right, 2) => Self::MetaRight,
(Self::Right, 3) => Self::MetaShiftRight,
(Self::Right, 4) => Self::CtrlRight,
(Self::Right, 5) => Self::CtrlShiftRight,
(Self::Right, 6) => Self::MetaCtrlRight,
(Self::Right, 7) => Self::MetaCtrlShiftRight,
(Self::PgUp, 0) => Self::PgUp,
(Self::PgUp, 1) => Self::ShiftPgUp,
(Self::PgUp, 2) => Self::MetaPgUp,
(Self::PgUp, 3) => Self::MetaShiftPgUp,
(Self::PgUp, 4) => Self::CtrlPgUp,
(Self::PgUp, 5) => Self::CtrlShiftPgUp,
(Self::PgUp, 6) => Self::MetaCtrlPgUp,
(Self::PgUp, 7) => Self::MetaCtrlShiftPgUp,
(Self::PgDn, 0) => Self::PgDn,
(Self::PgDn, 1) => Self::ShiftPgDn,
(Self::PgDn, 2) => Self::MetaPgDn,
(Self::PgDn, 3) => Self::MetaShiftPgDn,
(Self::PgDn, 4) => Self::CtrlPgDn,
(Self::PgDn, 5) => Self::CtrlShiftPgDn,
(Self::PgDn, 6) => Self::MetaCtrlPgDn,
(Self::PgDn, 7) => Self::MetaCtrlShiftPgDn,
(Self::Home, 0) => Self::Home,
(Self::Home, 1) => Self::ShiftHome,
(Self::Home, 2) => Self::MetaHome,
(Self::Home, 3) => Self::MetaShiftHome,
(Self::Home, 4) => Self::CtrlHome,
(Self::Home, 5) => Self::CtrlShiftHome,
(Self::Home, 6) => Self::MetaCtrlHome,
(Self::Home, 7) => Self::MetaCtrlShiftHome,
(Self::Insert, 0) => Self::Insert,
(Self::Insert, 1) => Self::ShiftInsert,
(Self::Insert, 2) => Self::MetaInsert,
(Self::Insert, 3) => Self::MetaShiftInsert,
(Self::Insert, 4) => Self::CtrlInsert,
(Self::Insert, 5) => Self::CtrlShiftInsert,
(Self::Insert, 6) => Self::MetaCtrlInsert,
(Self::Insert, 7) => Self::MetaCtrlShiftInsert,
(Self::Delete, 0) => Self::Delete,
(Self::Delete, 1) => Self::ShiftDelete,
(Self::Delete, 2) => Self::MetaDelete,
(Self::Delete, 3) => Self::MetaShiftDelete,
(Self::Delete, 4) => Self::CtrlDelete,
(Self::Delete, 5) => Self::CtrlShiftDelete,
(Self::Delete, 6) => Self::MetaCtrlDelete,
(Self::Delete, 7) => Self::MetaCtrlShiftDelete,
(Self::End, 0) => Self::End,
(Self::End, 1) => Self::ShiftEnd,
(Self::End, 2) => Self::MetaEnd,
(Self::End, 3) => Self::MetaShiftEnd,
(Self::End, 4) => Self::CtrlEnd,
(Self::End, 5) => Self::CtrlShiftEnd,
(Self::End, 6) => Self::MetaCtrlEnd,
(Self::End, 7) => Self::MetaCtrlShiftEnd,
_ => self,
}
}
fn try_meta(self) -> Option<Self> {
let key = self.with(Mod::meta());
if key == self { None } else { Some(key) }
}
pub(crate) fn decode(data: &[u8], force: bool) -> Option<(usize, Key)> {
let mut sc = Scan::new(data);
let key = if sc.grab(27) {
if sc.grab(27) {
Self::decode_esc_esc(&mut sc, force)
} else {
Self::decode_esc(&mut sc, force)
}
} else {
Self::decode_bare(&mut sc, force)
};
key.map(|key| (sc.pos, key))
}
fn decode_bare(sc: &mut Scan<'_>, force: bool) -> Option<Key> {
Some(match sc.next() {
Some(c) if c < 32 => match c {
9 => Key::Tab,
13 => Key::Return,
_ => Key::Ctrl((c + 64) as char),
},
Some(c) if c < 0x80 => match c {
127 => Key::BackSp,
_ => Key::Pr(c as char),
},
Some(c) if c < 0xC0 => Key::Invalid,
Some(c) => {
sc.pos -= 1;
let len = match c >> 4 {
15 => 4,
14 => 3,
_ => 2,
};
if let Some(seq) = sc.take(len) {
match std::str::from_utf8(seq).ok().and_then(|s| s.chars().next()) {
Some(c) => Key::Pr(c),
None => Key::Invalid,
}
} else if !force {
return None; } else {
sc.take(sc.len());
Key::Invalid
}
}
None => return None, })
}
fn decode_esc(sc: &mut Scan<'_>, force: bool) -> Option<Key> {
Some(if sc.is_empty() {
if !force {
return None; }
Key::Esc
} else if sc.grab(b'O') {
return Self::decode_esc_o(sc, force);
} else if sc.grab(b'[') {
return Self::decode_esc_bracket(sc, force);
} else {
let mark = sc.pos;
if let Some(key) = Self::decode_bare(sc, force).and_then(|k| k.try_meta()) {
key
} else {
sc.pos = mark;
Key::Esc
}
})
}
fn decode_esc_o(sc: &mut Scan<'_>, force: bool) -> Option<Key> {
let mark = sc.pos;
let modf = Mod::from_parsed_num(sc.grab_num());
Some(
match sc.next() {
Some(b'A') => Key::Up,
Some(b'B') => Key::Down,
Some(b'C') => Key::Right,
Some(b'D') => Key::Left,
Some(b'F') => Key::End,
Some(b'H') => Key::Home,
Some(b'M') => Key::Return, Some(b'P') => Key::F(1),
Some(b'Q') => Key::F(2),
Some(b'R') => Key::F(3),
Some(b'S') => Key::F(4),
None if !force => return None, _ => {
sc.pos = mark;
return Some(Key::Meta('O'));
}
}
.with(modf),
)
}
fn decode_esc_bracket(sc: &mut Scan<'_>, force: bool) -> Option<Key> {
let mark = sc.pos;
let mut num = 0;
let mut modf = Mod::none();
if let Some(v) = sc.grab_num() {
num = v;
}
if sc.grab(b';') {
modf = Mod::from_parsed_num(sc.grab_num());
sc.grab(b';');
}
let key = match sc.next() {
Some(b'A') => Key::Up,
Some(b'B') => Key::Down,
Some(b'C') => Key::Right,
Some(b'D') => Key::Left,
Some(b'F') => Key::End,
Some(b'H') => Key::Home,
Some(b'P') => Key::F(1),
Some(b'Q') => Key::F(2),
Some(b'R') => Key::F(3),
Some(b'S') => Key::F(4),
Some(b'Z') => Key::BackTab,
Some(b'[') => match sc.next() {
Some(b'A') => Key::F(1),
Some(b'B') => Key::F(2),
Some(b'C') => Key::F(3),
Some(b'D') => Key::F(4),
Some(b'E') => Key::F(5),
None if !force => return None, _ => {
sc.pos = mark;
Key::Meta('[')
}
},
Some(b'~') => {
let v = num;
num = 0;
match v {
1 => Key::Home,
2 => Key::Insert,
3 => Key::Delete,
4 => Key::End,
5 => Key::PgUp,
6 => Key::PgDn,
11..=15 => Key::F(v - 10),
17..=21 => Key::F(v - 11),
23..=26 => Key::F(v - 12),
28..=29 => Key::F(v - 13),
31..=34 => Key::F(v - 14),
200 => Key::PasteStart,
201 => Key::PasteEnd,
_ => Key::Invalid,
}
}
_ => {
if sc.is_empty() && !force {
return None; }
sc.pos = mark;
return Some(Key::Meta('['));
}
};
if num != 0 {
modf |= Mod::from_parsed_num(Some(num));
}
Some(key.with(modf))
}
fn decode_esc_esc(sc: &mut Scan<'_>, force: bool) -> Option<Key> {
let mark = sc.pos;
Some(if sc.is_empty() {
if !force {
return None; }
Key::MetaEsc
} else if let Some(key) = Self::decode_esc(sc, force).and_then(|k| k.try_meta()) {
key
} else {
sc.pos = mark;
Key::MetaEsc
})
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Mod(pub u8);
impl Mod {
pub fn none() -> Self {
Self(0)
}
pub fn shift() -> Self {
Self(1)
}
pub fn meta() -> Self {
Self(2)
}
pub fn meta_shift() -> Self {
Self(3)
}
pub fn ctrl() -> Self {
Self(4)
}
pub fn ctrl_shift() -> Self {
Self(5)
}
pub fn meta_ctrl() -> Self {
Self(6)
}
pub fn meta_ctrl_shift() -> Self {
Self(7)
}
pub fn has_shift(self) -> bool {
(self.0 & 1) != 0
}
pub fn has_meta(self) -> bool {
(self.0 & 2) != 0
}
pub fn has_ctrl(self) -> bool {
(self.0 & 4) != 0
}
fn from_parsed_num(n: Option<u32>) -> Self {
Self(n.unwrap_or(1).saturating_sub(1) as u8 & 15)
}
}
impl std::ops::BitOr for Mod {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for Mod {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}