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
|
// 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() {
|
4 => {
|
||||||
5 => {
|
// Escape code of the form `^[[NM~`
|
||||||
// Escape code of the form `^[[NM~`
|
if input[3].eq(&OtherKey('~')) {
|
||||||
if input[4].eq(&OtherKey('~')) {
|
let action = match (input[1].unwrap(), input[2].unwrap()) {
|
||||||
let action = match (input[2].unwrap(), input[3].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'),
|
('1', '9') => Function('8'),
|
||||||
('1', '9') => Function('8'),
|
('2', '0') => Function('9'),
|
||||||
('2', '0') => Function('9'),
|
('2', '1') => Function('X'), // F10
|
||||||
('2', '1') => Function('X'), // F10
|
('2', '4') => Function('T'), // F12
|
||||||
('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,
|
_ => Escape,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some(action);
|
return Some(action);
|
||||||
}
|
}
|
||||||
}
|
// Escape code of the form `^[OX`
|
||||||
4 => {
|
OtherKey('O') => {
|
||||||
// Escape code of the form `^[[N~`
|
let action = match input[1].unwrap() {
|
||||||
if input[3].eq(&OtherKey('~')) {
|
'H' => HomeKey,
|
||||||
let action = match input[2].unwrap() {
|
'F' => EndKey,
|
||||||
'1' => HomeKey,
|
'P' => Function('1'),
|
||||||
'3' => DeleteKey,
|
'Q' => Function('2'),
|
||||||
'4' => EndKey,
|
'R' => Function('3'),
|
||||||
'5' => PageUp,
|
'S' => Function('4'),
|
||||||
'6' => PageDown,
|
_ => Escape,
|
||||||
'7' => HomeKey,
|
|
||||||
'8' => EndKey,
|
|
||||||
_ => input[2], // Escape,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some(action);
|
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
|
// 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();
|
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user