Rework input logic to remove throttling
This commit is contained in:
parent
dd9166d465
commit
ae74513e88
189
src/editor.rs
189
src/editor.rs
@ -122,107 +122,144 @@ impl Editor {
|
||||
// Terminal
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// Convert stdin to specific keypresses
|
||||
fn read_key(&mut self) -> Option<EditorKey<char>> {
|
||||
/*
|
||||
TODO: Read 1 byte by default, and read additional bytes
|
||||
if the first byte is an escape character, to resolve the
|
||||
unintentional input throttling
|
||||
*/
|
||||
// --------------------------------------------------------------------
|
||||
// Match single character
|
||||
// --------------------------------------------------------------------
|
||||
let stdin = io::stdin();
|
||||
let stdin = stdin.lock();
|
||||
let mut in_str = String::new();
|
||||
let mut buffer = BufReader::with_capacity(4, stdin);
|
||||
buffer.read_to_string(&mut in_str).unwrap();
|
||||
let mut br = BufReader::with_capacity(5, stdin);
|
||||
|
||||
let mut first_read = [0; 1];
|
||||
br.read_exact(&mut first_read);
|
||||
let first_str = String::from_utf8(first_read.to_vec());
|
||||
if first_str.is_err() {
|
||||
return None;
|
||||
}
|
||||
let first_str = first_str.unwrap();
|
||||
|
||||
// Read the first character, if it isn't escape, just return it
|
||||
let mut chars = first_str.chars();
|
||||
let char = chars.next();
|
||||
if char.is_none() {
|
||||
return None;
|
||||
}
|
||||
let char = char.unwrap();
|
||||
match char {
|
||||
'\0' => return None,
|
||||
'\x1b' => (),
|
||||
'\x08' => return Some(Backspace),
|
||||
'\x7f' => return Some(Backspace),
|
||||
'\r' => return Some(Enter),
|
||||
c => return Some(OtherKey(c)),
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Match escape sequence
|
||||
// --------------------------------------------------------------------
|
||||
let mut seq = [0;4];
|
||||
br.read_exact(&mut seq);
|
||||
let seq_str = String::from_utf8(seq.to_vec());
|
||||
|
||||
// On error, just continue the input loop
|
||||
if seq_str.is_err() {
|
||||
return None;
|
||||
}
|
||||
let seq_str = seq_str.unwrap();
|
||||
|
||||
let mut input: Vec<EditorKey<char>> = vec![];
|
||||
|
||||
for char in in_str.chars() {
|
||||
for char in seq_str.chars() {
|
||||
// Since the fixed array is always filled, there
|
||||
// will be null characters. Ignore these.
|
||||
if char == '\0' {
|
||||
continue;
|
||||
}
|
||||
|
||||
input.push(match char {
|
||||
'\x08' => Backspace,
|
||||
'\x7f' => Backspace,
|
||||
'\x1b' => Escape,
|
||||
'\r' => Enter,
|
||||
_ => OtherKey(char),
|
||||
});
|
||||
}
|
||||
|
||||
// Since we matched Escape earlier, if the input is empty,
|
||||
// this must be the escape key
|
||||
if input.is_empty() {
|
||||
return None;
|
||||
return Some(Escape);
|
||||
}
|
||||
|
||||
if input[0].eq(&Escape) {
|
||||
match input.len() {
|
||||
5 => {
|
||||
// Escape code of the form `^[[NM~`
|
||||
if input[4].eq(&OtherKey('~')) {
|
||||
let action = match (input[2].unwrap(), input[3].unwrap()) {
|
||||
('1', '5') => Function('5'),
|
||||
('1', '7') => Function('6'),
|
||||
('1', '8') => Function('7'),
|
||||
('1', '9') => Function('8'),
|
||||
('2', '0') => Function('9'),
|
||||
('2', '1') => Function('X'), // F10
|
||||
('2', '4') => Function('T'), // F12
|
||||
match input.len() {
|
||||
4 => {
|
||||
// Escape code of the form `^[[NM~`
|
||||
if input[3].eq(&OtherKey('~')) {
|
||||
let action = match (input[1].unwrap(), input[2].unwrap()) {
|
||||
('1', '5') => Function('5'),
|
||||
('1', '7') => Function('6'),
|
||||
('1', '8') => Function('7'),
|
||||
('1', '9') => Function('8'),
|
||||
('2', '0') => Function('9'),
|
||||
('2', '1') => Function('X'), // F10
|
||||
('2', '4') => Function('T'), // F12
|
||||
_ => Escape,
|
||||
};
|
||||
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
// Escape code of the form `^[[N~`
|
||||
if input[2].eq(&OtherKey('~')) {
|
||||
let action = match input[1].unwrap() {
|
||||
'1' => HomeKey,
|
||||
'3' => DeleteKey,
|
||||
'4' => EndKey,
|
||||
'5' => PageUp,
|
||||
'6' => PageDown,
|
||||
'7' => HomeKey,
|
||||
'8' => EndKey,
|
||||
_ => input[1], // Escape,
|
||||
};
|
||||
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
match input[0] {
|
||||
// Escape code of the form `^[[X`
|
||||
OtherKey('[') => {
|
||||
let action = match input[1].unwrap() {
|
||||
'A' => ArrowUp,
|
||||
'B' => ArrowDown,
|
||||
'C' => ArrowRight,
|
||||
'D' => ArrowLeft,
|
||||
'H' => HomeKey,
|
||||
'F' => EndKey,
|
||||
|
||||
// Eh, just return escape otherwise
|
||||
_ => Escape,
|
||||
};
|
||||
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
// Escape code of the form `^[[N~`
|
||||
if input[3].eq(&OtherKey('~')) {
|
||||
let action = match input[2].unwrap() {
|
||||
'1' => HomeKey,
|
||||
'3' => DeleteKey,
|
||||
'4' => EndKey,
|
||||
'5' => PageUp,
|
||||
'6' => PageDown,
|
||||
'7' => HomeKey,
|
||||
'8' => EndKey,
|
||||
_ => input[2], // Escape,
|
||||
// Escape code of the form `^[OX`
|
||||
OtherKey('O') => {
|
||||
let action = match input[1].unwrap() {
|
||||
'H' => HomeKey,
|
||||
'F' => EndKey,
|
||||
'P' => Function('1'),
|
||||
'Q' => Function('2'),
|
||||
'R' => Function('3'),
|
||||
'S' => Function('4'),
|
||||
_ => Escape,
|
||||
};
|
||||
|
||||
return Some(action);
|
||||
}
|
||||
_ => return Some(Escape),
|
||||
}
|
||||
3 => {
|
||||
match input[1] {
|
||||
// Escape code of the form `^[[X`
|
||||
OtherKey('[') => {
|
||||
let action = match input[2].unwrap() {
|
||||
'A' => ArrowUp,
|
||||
'B' => ArrowDown,
|
||||
'C' => ArrowRight,
|
||||
'D' => ArrowLeft,
|
||||
'H' => HomeKey,
|
||||
'F' => EndKey,
|
||||
|
||||
// Eh, just return escape otherwise
|
||||
_ => input[2], //Escape,
|
||||
};
|
||||
|
||||
return Some(action);
|
||||
}
|
||||
// Escape code of the form `^[OX`
|
||||
OtherKey('O') => {
|
||||
let action = match input[2].unwrap() {
|
||||
'H' => HomeKey,
|
||||
'F' => EndKey,
|
||||
'P' => Function('1'),
|
||||
'Q' => Function('2'),
|
||||
'R' => Function('3'),
|
||||
'S' => Function('4'),
|
||||
_ => input[2], //Escape,
|
||||
};
|
||||
|
||||
return Some(action);
|
||||
}
|
||||
_ => return Some(input[1]),
|
||||
}
|
||||
}
|
||||
_ => return Some(input[0]),
|
||||
}
|
||||
_ => return Some(input[0]),
|
||||
}
|
||||
|
||||
// If the character doesn't match any escape sequences, just
|
||||
@ -344,6 +381,7 @@ impl Editor {
|
||||
self.cursor_x = self.rows[self.cursor_y].chars.len();
|
||||
}
|
||||
}
|
||||
Function(_) => (),
|
||||
OtherKey(c) => {
|
||||
if c.is_ascii_control() {
|
||||
if c == ctrl_key('q') {
|
||||
@ -373,7 +411,6 @@ impl Editor {
|
||||
self.insert_char(c);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
||||
self.quit_times = KILO_QUIT_TIMES;
|
||||
|
Loading…
Reference in New Issue
Block a user