Rework input logic to remove throttling

This commit is contained in:
Timothy Warren 2019-09-03 11:48:40 -04:00
parent dd9166d465
commit ae74513e88

View File

@ -122,40 +122,78 @@ impl Editor {
// Terminal // Terminal
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// Convert stdin to specific keypresses
fn read_key(&mut self) -> Option<EditorKey<char>> { fn read_key(&mut self) -> Option<EditorKey<char>> {
/* // --------------------------------------------------------------------
TODO: Read 1 byte by default, and read additional bytes // Match single character
if the first byte is an escape character, to resolve the // --------------------------------------------------------------------
unintentional input throttling
*/
let stdin = io::stdin(); let stdin = io::stdin();
let stdin = stdin.lock(); let stdin = stdin.lock();
let mut in_str = String::new(); let mut br = BufReader::with_capacity(5, stdin);
let mut buffer = BufReader::with_capacity(4, stdin);
buffer.read_to_string(&mut in_str).unwrap(); 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![]; 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 { input.push(match char {
'\x08' => Backspace,
'\x7f' => Backspace,
'\x1b' => Escape, '\x1b' => Escape,
'\r' => Enter,
_ => OtherKey(char), _ => OtherKey(char),
}); });
} }
// Since we matched Escape earlier, if the input is empty,
// this must be the escape key
if input.is_empty() { if input.is_empty() {
return None; return Some(Escape);
} }
if input[0].eq(&Escape) {
match input.len() { match input.len() {
5 => { 4 => {
// Escape code of the form `^[[NM~` // Escape code of the form `^[[NM~`
if input[4].eq(&OtherKey('~')) { if input[3].eq(&OtherKey('~')) {
let action = match (input[2].unwrap(), input[3].unwrap()) { let action = match (input[1].unwrap(), input[2].unwrap()) {
('1', '5') => Function('5'), ('1', '5') => Function('5'),
('1', '7') => Function('6'), ('1', '7') => Function('6'),
('1', '8') => Function('7'), ('1', '8') => Function('7'),
@ -169,10 +207,10 @@ impl Editor {
return Some(action); return Some(action);
} }
} }
4 => { 3 => {
// Escape code of the form `^[[N~` // Escape code of the form `^[[N~`
if input[3].eq(&OtherKey('~')) { if input[2].eq(&OtherKey('~')) {
let action = match input[2].unwrap() { let action = match input[1].unwrap() {
'1' => HomeKey, '1' => HomeKey,
'3' => DeleteKey, '3' => DeleteKey,
'4' => EndKey, '4' => EndKey,
@ -180,17 +218,17 @@ impl Editor {
'6' => PageDown, '6' => PageDown,
'7' => HomeKey, '7' => HomeKey,
'8' => EndKey, '8' => EndKey,
_ => input[2], // Escape, _ => input[1], // Escape,
}; };
return Some(action); return Some(action);
} }
} }
3 => { 2 => {
match input[1] { match input[0] {
// Escape code of the form `^[[X` // Escape code of the form `^[[X`
OtherKey('[') => { OtherKey('[') => {
let action = match input[2].unwrap() { let action = match input[1].unwrap() {
'A' => ArrowUp, 'A' => ArrowUp,
'B' => ArrowDown, 'B' => ArrowDown,
'C' => ArrowRight, 'C' => ArrowRight,
@ -199,31 +237,30 @@ impl Editor {
'F' => EndKey, 'F' => EndKey,
// Eh, just return escape otherwise // Eh, just return escape otherwise
_ => input[2], //Escape, _ => Escape,
}; };
return Some(action); return Some(action);
} }
// Escape code of the form `^[OX` // Escape code of the form `^[OX`
OtherKey('O') => { OtherKey('O') => {
let action = match input[2].unwrap() { let action = match input[1].unwrap() {
'H' => HomeKey, 'H' => HomeKey,
'F' => EndKey, 'F' => EndKey,
'P' => Function('1'), 'P' => Function('1'),
'Q' => Function('2'), 'Q' => Function('2'),
'R' => Function('3'), 'R' => Function('3'),
'S' => Function('4'), 'S' => Function('4'),
_ => input[2], //Escape, _ => Escape,
}; };
return Some(action); return Some(action);
} }
_ => return Some(input[1]), _ => return Some(Escape),
} }
} }
_ => return Some(input[0]), _ => return Some(input[0]),
} }
}
// If the character doesn't match any escape sequences, just // If the character doesn't match any escape sequences, just
// pass that character on // pass that character on
@ -344,6 +381,7 @@ impl Editor {
self.cursor_x = self.rows[self.cursor_y].chars.len(); self.cursor_x = self.rows[self.cursor_y].chars.len();
} }
} }
Function(_) => (),
OtherKey(c) => { OtherKey(c) => {
if c.is_ascii_control() { if c.is_ascii_control() {
if c == ctrl_key('q') { if c == ctrl_key('q') {
@ -373,7 +411,6 @@ impl Editor {
self.insert_char(c); self.insert_char(c);
} }
} }
_ => (),
}; };
self.quit_times = KILO_QUIT_TIMES; self.quit_times = KILO_QUIT_TIMES;