mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-29 10:31:14 -03:00
Extract KeyEvent type
The be used in the grandchild commit.
This commit is contained in:
@@ -142,11 +142,53 @@ pub enum ReadlineCmd {
|
||||
ReverseRepeatJump,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct KeyEvent {
|
||||
pub key: Key,
|
||||
}
|
||||
|
||||
impl KeyEvent {
|
||||
pub(crate) fn new(modifiers: Modifiers, codepoint: char) -> Self {
|
||||
Self::from(Key::new(modifiers, codepoint))
|
||||
}
|
||||
pub(crate) fn from_raw(codepoint: char) -> Self {
|
||||
Self::from(Key::from_raw(codepoint))
|
||||
}
|
||||
pub fn from_single_byte(c: u8) -> Self {
|
||||
Self::from(Key::from_single_byte(c))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Key> for KeyEvent {
|
||||
fn from(key: Key) -> Self {
|
||||
Self { key }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for KeyEvent {
|
||||
type Target = Key;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.key
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for KeyEvent {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.key
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Key> for KeyEvent {
|
||||
fn eq(&self, key: &Key) -> bool {
|
||||
&self.key == key
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an event on the character input stream.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CharEventType {
|
||||
/// A character was entered.
|
||||
Char(Key),
|
||||
Char(KeyInputEvent),
|
||||
|
||||
/// A readline event.
|
||||
Readline(ReadlineCmd),
|
||||
@@ -172,9 +214,9 @@ pub struct ReadlineCmdEvent {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyEvent {
|
||||
pub struct KeyInputEvent {
|
||||
// The key.
|
||||
pub key: Key,
|
||||
pub key: KeyEvent,
|
||||
// The style to use when inserting characters into the command line.
|
||||
pub input_style: CharInputStyle,
|
||||
/// The sequence of characters in the input mapping which generated this event.
|
||||
@@ -207,7 +249,7 @@ pub enum ImplicitEvent {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CharEvent {
|
||||
/// A character was entered.
|
||||
Key(KeyEvent),
|
||||
Key(KeyInputEvent),
|
||||
|
||||
/// A readline event.
|
||||
Readline(ReadlineCmdEvent),
|
||||
@@ -240,7 +282,7 @@ pub fn get_char(&self) -> char {
|
||||
kevt.key.codepoint
|
||||
}
|
||||
|
||||
pub fn get_key(&self) -> Option<&KeyEvent> {
|
||||
pub fn get_key(&self) -> Option<&KeyInputEvent> {
|
||||
match self {
|
||||
CharEvent::Key(kevt) => Some(kevt),
|
||||
_ => None,
|
||||
@@ -262,15 +304,15 @@ pub fn get_command(&self) -> Option<&wstr> {
|
||||
}
|
||||
|
||||
pub fn from_char(c: char) -> CharEvent {
|
||||
Self::from_key(Key::from_raw(c))
|
||||
Self::from_key(KeyEvent::from_raw(c))
|
||||
}
|
||||
|
||||
pub fn from_key(key: Key) -> CharEvent {
|
||||
pub fn from_key(key: KeyEvent) -> CharEvent {
|
||||
Self::from_key_seq(key, WString::new())
|
||||
}
|
||||
|
||||
pub fn from_key_seq(key: Key, seq: WString) -> CharEvent {
|
||||
CharEvent::Key(KeyEvent {
|
||||
pub fn from_key_seq(key: KeyEvent, seq: WString) -> CharEvent {
|
||||
CharEvent::Key(KeyInputEvent {
|
||||
key,
|
||||
input_style: CharInputStyle::Normal,
|
||||
seq,
|
||||
@@ -726,7 +768,7 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
|
||||
let key_with_escape = if read_byte == 0x1b {
|
||||
self.parse_escape_sequence(&mut buffer, &mut have_escape_prefix)
|
||||
} else {
|
||||
canonicalize_control_char(read_byte)
|
||||
canonicalize_control_char(read_byte).map(KeyEvent::from)
|
||||
};
|
||||
if self.paste_is_buffering() {
|
||||
if read_byte != 0x1b {
|
||||
@@ -736,7 +778,7 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
|
||||
}
|
||||
let mut seq = WString::new();
|
||||
let mut key = key_with_escape;
|
||||
if key == Some(Key::from_raw(key::Invalid)) {
|
||||
if key.is_some_and(|key| key == Key::from_raw(key::Invalid)) {
|
||||
continue;
|
||||
}
|
||||
assert!(key.map_or(true, |key| key.codepoint != key::Invalid));
|
||||
@@ -780,7 +822,7 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
|
||||
continue;
|
||||
};
|
||||
(
|
||||
CharEvent::from_key_seq(Key::from_raw(c), seq.clone()),
|
||||
CharEvent::from_key_seq(KeyEvent::from_raw(c), seq.clone()),
|
||||
Some(seq.chars().skip(1).map(CharEvent::from_char)),
|
||||
)
|
||||
};
|
||||
@@ -797,7 +839,8 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
|
||||
}
|
||||
});
|
||||
let vintr = shell_modes().c_cc[libc::VINTR];
|
||||
if vintr != 0 && key == Some(Key::from_single_byte(vintr)) {
|
||||
if vintr != 0 && key.is_some_and(|key| key == Key::from_single_byte(vintr))
|
||||
{
|
||||
FLOG!(
|
||||
reader,
|
||||
"Received interrupt key, giving up waiting for response from terminal"
|
||||
@@ -827,22 +870,22 @@ fn parse_escape_sequence(
|
||||
&mut self,
|
||||
buffer: &mut Vec<u8>,
|
||||
have_escape_prefix: &mut bool,
|
||||
) -> Option<Key> {
|
||||
) -> Option<KeyEvent> {
|
||||
assert!(buffer.len() <= 2);
|
||||
let recursive_invocation = buffer.len() == 2;
|
||||
let Some(next) = self.try_readb(buffer) else {
|
||||
if !self.paste_is_buffering() {
|
||||
return Some(Key::from_raw(key::Escape));
|
||||
return Some(KeyEvent::from_raw(key::Escape));
|
||||
}
|
||||
return None;
|
||||
};
|
||||
let invalid = Key::from_raw(key::Invalid);
|
||||
let invalid = KeyEvent::from_raw(key::Invalid);
|
||||
if recursive_invocation && next == b'\x1b' {
|
||||
return Some(
|
||||
match self.parse_escape_sequence(buffer, have_escape_prefix) {
|
||||
Some(mut nested_sequence) => {
|
||||
if nested_sequence == invalid {
|
||||
return Some(Key::from_raw(key::Escape));
|
||||
if nested_sequence == invalid.key {
|
||||
return Some(KeyEvent::from_raw(key::Escape));
|
||||
}
|
||||
nested_sequence.modifiers.alt = true;
|
||||
nested_sequence
|
||||
@@ -866,7 +909,7 @@ fn parse_escape_sequence(
|
||||
match canonicalize_control_char(next) {
|
||||
Some(mut key) => {
|
||||
key.modifiers.alt = true;
|
||||
Some(key)
|
||||
Some(KeyEvent::from(key))
|
||||
}
|
||||
None => {
|
||||
*have_escape_prefix = true;
|
||||
@@ -878,7 +921,7 @@ fn parse_escape_sequence(
|
||||
fn parse_codepoint(
|
||||
&mut self,
|
||||
state: &mut mbstate_t,
|
||||
out_key: &mut Option<Key>,
|
||||
out_key: &mut Option<KeyEvent>,
|
||||
out_seq: &mut WString,
|
||||
buffer: &[u8],
|
||||
i: usize,
|
||||
@@ -928,7 +971,7 @@ fn parse_codepoint(
|
||||
if !fish_reserved_codepoint(res) {
|
||||
if *have_escape_prefix && i != 0 {
|
||||
*have_escape_prefix = false;
|
||||
*out_key = Some(alt(res));
|
||||
*out_key = Some(KeyEvent::from(alt(res)));
|
||||
}
|
||||
*consumed += 1;
|
||||
out_seq.push(res);
|
||||
@@ -942,11 +985,11 @@ fn parse_codepoint(
|
||||
ControlFlow::Continue(true)
|
||||
}
|
||||
|
||||
fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
|
||||
// The maximum number of CSI parameters is defined by NPAR, nominally 16.
|
||||
let mut params = [[0_u32; 4]; 16];
|
||||
let Some(mut c) = self.try_readb(buffer) else {
|
||||
return Some(ctrl('['));
|
||||
return Some(KeyEvent::from(ctrl('[')));
|
||||
};
|
||||
let mut next_char = |zelf: &mut Self| zelf.try_readb(buffer).unwrap_or(0xff);
|
||||
let private_mode;
|
||||
@@ -993,10 +1036,7 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
codepoint = shifted_codepoint;
|
||||
}
|
||||
}
|
||||
Key {
|
||||
modifiers,
|
||||
codepoint,
|
||||
}
|
||||
KeyEvent::new(modifiers, codepoint)
|
||||
};
|
||||
|
||||
let key = match c {
|
||||
@@ -1013,9 +1053,9 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
return None;
|
||||
}
|
||||
match params[0][0] {
|
||||
23 | 24 => shift(
|
||||
23 | 24 => KeyEvent::from(shift(
|
||||
char::from_u32(u32::from(function_key(11)) + params[0][0] - 23).unwrap(), // rxvt style
|
||||
),
|
||||
)),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
@@ -1154,23 +1194,23 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
char::from_u32(u32::from(function_key(11)) + params[0][0] - 23).unwrap(),
|
||||
None,
|
||||
),
|
||||
25 | 26 => {
|
||||
shift(char::from_u32(u32::from(function_key(3)) + params[0][0] - 25).unwrap())
|
||||
} // rxvt style
|
||||
25 | 26 => KeyEvent::from(shift(
|
||||
char::from_u32(u32::from(function_key(3)) + params[0][0] - 25).unwrap(),
|
||||
)), // rxvt style
|
||||
27 => {
|
||||
let key =
|
||||
canonicalize_keyed_control_char(char::from_u32(params[2][0]).unwrap());
|
||||
masked_key(key, None)
|
||||
}
|
||||
28 | 29 => {
|
||||
shift(char::from_u32(u32::from(function_key(5)) + params[0][0] - 28).unwrap())
|
||||
} // rxvt style
|
||||
31 | 32 => {
|
||||
shift(char::from_u32(u32::from(function_key(7)) + params[0][0] - 31).unwrap())
|
||||
} // rxvt style
|
||||
33 | 34 => {
|
||||
shift(char::from_u32(u32::from(function_key(9)) + params[0][0] - 33).unwrap())
|
||||
} // rxvt style
|
||||
28 | 29 => KeyEvent::from(shift(
|
||||
char::from_u32(u32::from(function_key(5)) + params[0][0] - 28).unwrap(),
|
||||
)), // rxvt style
|
||||
31 | 32 => KeyEvent::from(shift(
|
||||
char::from_u32(u32::from(function_key(7)) + params[0][0] - 31).unwrap(),
|
||||
)), // rxvt style
|
||||
33 | 34 => KeyEvent::from(shift(
|
||||
char::from_u32(u32::from(function_key(9)) + params[0][0] - 33).unwrap(),
|
||||
)), // rxvt style
|
||||
200 => {
|
||||
self.paste_start_buffering();
|
||||
return None;
|
||||
@@ -1235,7 +1275,7 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
)),
|
||||
)
|
||||
}
|
||||
b'Z' => shift(key::Tab),
|
||||
b'Z' => KeyEvent::from(shift(key::Tab)),
|
||||
b'I' => {
|
||||
self.push_front(CharEvent::Implicit(ImplicitEvent::FocusIn));
|
||||
return None;
|
||||
@@ -1263,10 +1303,10 @@ fn disable_mouse_tracking(&mut self) {
|
||||
self.push_front(CharEvent::Implicit(ImplicitEvent::DisableMouseTracking));
|
||||
}
|
||||
|
||||
fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
|
||||
let mut raw_mask = 0;
|
||||
let Some(mut code) = self.try_readb(buffer) else {
|
||||
return Some(alt('O'));
|
||||
return Some(KeyEvent::from(alt('O')));
|
||||
};
|
||||
while (b'0'..=b'9').contains(&code) {
|
||||
raw_mask = raw_mask * 10 + u32::from(code - b'0');
|
||||
@@ -1275,36 +1315,36 @@ fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
let modifiers = parse_mask(raw_mask.saturating_sub(1));
|
||||
#[rustfmt::skip]
|
||||
let key = match code {
|
||||
b' ' => Key::new(modifiers, key::Space),
|
||||
b'A' => Key::new(modifiers, key::Up),
|
||||
b'B' => Key::new(modifiers, key::Down),
|
||||
b'C' => Key::new(modifiers, key::Right),
|
||||
b'D' => Key::new(modifiers, key::Left),
|
||||
b'F' => Key::new(modifiers, key::End),
|
||||
b'H' => Key::new(modifiers, key::Home),
|
||||
b'I' => Key::new(modifiers, key::Tab),
|
||||
b'M' => Key::new(modifiers, key::Enter),
|
||||
b'P' => Key::new(modifiers, function_key(1)),
|
||||
b'Q' => Key::new(modifiers, function_key(2)),
|
||||
b'R' => Key::new(modifiers, function_key(3)),
|
||||
b'S' => Key::new(modifiers, function_key(4)),
|
||||
b'X' => Key::new(modifiers, '='),
|
||||
b'j' => Key::new(modifiers, '*'),
|
||||
b'k' => Key::new(modifiers, '+'),
|
||||
b'l' => Key::new(modifiers, ','),
|
||||
b'm' => Key::new(modifiers, '-'),
|
||||
b'n' => Key::new(modifiers, '.'),
|
||||
b'o' => Key::new(modifiers, '/'),
|
||||
b'p' => Key::new(modifiers, '0'),
|
||||
b'q' => Key::new(modifiers, '1'),
|
||||
b'r' => Key::new(modifiers, '2'),
|
||||
b's' => Key::new(modifiers, '3'),
|
||||
b't' => Key::new(modifiers, '4'),
|
||||
b'u' => Key::new(modifiers, '5'),
|
||||
b'v' => Key::new(modifiers, '6'),
|
||||
b'w' => Key::new(modifiers, '7'),
|
||||
b'x' => Key::new(modifiers, '8'),
|
||||
b'y' => Key::new(modifiers, '9'),
|
||||
b' ' => KeyEvent::new(modifiers, key::Space),
|
||||
b'A' => KeyEvent::new(modifiers, key::Up),
|
||||
b'B' => KeyEvent::new(modifiers, key::Down),
|
||||
b'C' => KeyEvent::new(modifiers, key::Right),
|
||||
b'D' => KeyEvent::new(modifiers, key::Left),
|
||||
b'F' => KeyEvent::new(modifiers, key::End),
|
||||
b'H' => KeyEvent::new(modifiers, key::Home),
|
||||
b'I' => KeyEvent::new(modifiers, key::Tab),
|
||||
b'M' => KeyEvent::new(modifiers, key::Enter),
|
||||
b'P' => KeyEvent::new(modifiers, function_key(1)),
|
||||
b'Q' => KeyEvent::new(modifiers, function_key(2)),
|
||||
b'R' => KeyEvent::new(modifiers, function_key(3)),
|
||||
b'S' => KeyEvent::new(modifiers, function_key(4)),
|
||||
b'X' => KeyEvent::new(modifiers, '='),
|
||||
b'j' => KeyEvent::new(modifiers, '*'),
|
||||
b'k' => KeyEvent::new(modifiers, '+'),
|
||||
b'l' => KeyEvent::new(modifiers, ','),
|
||||
b'm' => KeyEvent::new(modifiers, '-'),
|
||||
b'n' => KeyEvent::new(modifiers, '.'),
|
||||
b'o' => KeyEvent::new(modifiers, '/'),
|
||||
b'p' => KeyEvent::new(modifiers, '0'),
|
||||
b'q' => KeyEvent::new(modifiers, '1'),
|
||||
b'r' => KeyEvent::new(modifiers, '2'),
|
||||
b's' => KeyEvent::new(modifiers, '3'),
|
||||
b't' => KeyEvent::new(modifiers, '4'),
|
||||
b'u' => KeyEvent::new(modifiers, '5'),
|
||||
b'v' => KeyEvent::new(modifiers, '6'),
|
||||
b'w' => KeyEvent::new(modifiers, '7'),
|
||||
b'x' => KeyEvent::new(modifiers, '8'),
|
||||
b'y' => KeyEvent::new(modifiers, '9'),
|
||||
_ => return None,
|
||||
};
|
||||
Some(key)
|
||||
@@ -1334,10 +1374,10 @@ fn parse_xtversion(&mut self, buffer: &mut Vec<u8>) {
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_dcs(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
|
||||
fn parse_dcs(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
|
||||
assert!(buffer.len() == 2);
|
||||
let Some(success) = self.try_readb(buffer) else {
|
||||
return Some(alt('P'));
|
||||
return Some(KeyEvent::from(alt('P')));
|
||||
};
|
||||
let success = match success {
|
||||
b'0' => false,
|
||||
@@ -1589,7 +1629,7 @@ fn select_interrupted(&mut self) {}
|
||||
fn enqueue_interrupt_key(&mut self) {
|
||||
let vintr = shell_modes().c_cc[libc::VINTR];
|
||||
if vintr != 0 {
|
||||
let interrupt_evt = CharEvent::from_key(Key::from_single_byte(vintr));
|
||||
let interrupt_evt = CharEvent::from_key(KeyEvent::from_single_byte(vintr));
|
||||
if unblock_input(self.blocking_wait()) {
|
||||
FLOG!(
|
||||
reader,
|
||||
@@ -1629,7 +1669,7 @@ pub(crate) fn unblock_input(mut wait_guard: MutexGuard<Option<BlockingWait>>) ->
|
||||
true
|
||||
}
|
||||
|
||||
fn invalid_sequence(buffer: &[u8]) -> Option<Key> {
|
||||
fn invalid_sequence(buffer: &[u8]) -> Option<KeyEvent> {
|
||||
FLOG!(
|
||||
reader,
|
||||
"Error: invalid escape sequence: ",
|
||||
|
||||
Reference in New Issue
Block a user