Treat ctrl+letter chords as their own character class

This commit is contained in:
Timothy Warren 2019-09-17 11:19:46 -04:00
parent 6497111427
commit f8700c8e93
2 changed files with 47 additions and 44 deletions

View File

@ -146,6 +146,8 @@ pub enum KeyCode<T = char> {
EndKey,
PageUp,
PageDown,
/// Control key chords
Ctrl(T),
/// Function keys (F1, etc.) T holds the index
Function(T),
/// Any other type of character
@ -188,6 +190,8 @@ impl Row {
impl KeyCode<char> {
pub fn unwrap(self) -> char {
match self {
self::Ctrl(val) => val,
self::Function(val) => val,
self::OtherKey(val) => val,
_ => panic!("called `KeyCode::unwrap()` on a `None` value"),
}
@ -281,7 +285,13 @@ impl Editor {
'\x08' => return Some(Backspace),
'\x7f' => return Some(Backspace),
'\r' => return Some(Enter),
_ => return Some(OtherKey(ch)),
ch => {
if ch.is_ascii_control() {
return Some(Ctrl(ctrl_to_letter(ch)))
}
return Some(OtherKey(ch))
},
},
None => return None,
}
@ -737,7 +747,7 @@ impl Editor {
loop {
self.set_status_message(&format!("{} {}", prompt, buffer));
self.refresh_screen(false);
self.refresh_screen();
let ch = self.read_key();
if ch.is_some() {
@ -851,14 +861,18 @@ impl Editor {
self.cursor_x = self.rows[self.cursor_y].chars.len();
}
}
Function(_) => (),
OtherKey(c) => {
if c.is_ascii_control() {
if c == ctrl_key('f') {
self.find();
Ctrl(c) => {
match c {
'f' => self.find(),
// 'h' => self._del_or_backspace(Backspace),
's' => {
// Save success/error message handled by save method
match self.save() {
Ok(_) => (),
Err(_) => (),
}
}
if c == ctrl_key('q') {
'q' => {
if self.dirty > 0 && self.quit_times > 0 {
self.set_status_message(&format!("WARNING!!! File has unsaved changes. Press Ctrl-Q {} more times to quit.", self.quit_times));
self.quit_times -= 1;
@ -868,23 +882,14 @@ impl Editor {
print!("\x1b[H");
// Break out of the input loop
return None;
}
if c == ctrl_key('s') {
// Save success/error message handled by save method
match self.save() {
Ok(_) => (),
Err(_) => (),
}
}
if c == ctrl_key('h') {
self._del_or_backspace(Backspace);
}
} else {
self.insert_char(c);
},
_ => (),
}
}
Function(_) => (),
OtherKey(c) => {
self.insert_char(c);
}
};
self.quit_times = KILO_QUIT_TIMES;
@ -1094,11 +1099,7 @@ impl Editor {
}
}
pub fn refresh_screen(&mut self, skip_refresh: bool) {
if skip_refresh {
return;
}
pub fn refresh_screen(&mut self) {
self.scroll();
self.output_buffer.clear();
@ -1618,18 +1619,17 @@ fn get_syntax_db() -> Vec<Syntax> {
]
}
/// Convert Ctrl+letter chords to their
/// ASCII table equivalents
pub fn ctrl_key(c: char) -> char {
/// Convert Ctrl+letter chord to their
/// letter equivalent
pub fn ctrl_to_letter(c: char) -> char {
let key = c as u8;
if !c.is_ascii() {
panic!("CTRL_KEY only accepts ASCII characters");
if (!c.is_ascii_control()) || c == '\x7f' {
panic!("Only ascii control characters have associated letters")
}
// Intentionally "overflow" u8 to wrap around to the
// beginning of the ASCII table. Ctrl+a is 1, Ctrl+b is 2, etc.
(key & 0x1f) as char
// Shift forward to the letter equivalent
(key + 0x60) as char
}
/// Determine whether a character is one which separates tokens
@ -1725,4 +1725,10 @@ mod tests {
assert_eq!(is_separator(ch), false);
}
}
#[test]
fn ctrl_key_functions() {
let a = ctrl_to_letter(ctrl_a);
assert_eq!(a, 'a', "ctrl_to_letter gives letter from ctrl chord");
}
}

View File

@ -38,23 +38,20 @@ fn main() -> Result<(), Error> {
editor.set_status_message("HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find");
let mut skip_refresh: bool = false;
// Main input loop. Editor::process_keypress uses an Option Enum as a sentinel.
// `None` is returned on a quit action, in other cases, `Some(())` is returned,
// continuing the loop
loop {
editor.refresh_screen(skip_refresh);
editor.refresh_screen();
match editor.process_keypress() {
Some(key) => {
match key {
editor::KeyCode::OtherKey('\0') => {
skip_refresh = true;
}
editor::KeyCode::OtherKey('\0') => (),
_ => {
skip_refresh = false;
//println!("{:?}\r\n", key)
()
}
}
}