From f8700c8e9350693296a40e00b28893aa40becd72 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 17 Sep 2019 11:19:46 -0400 Subject: [PATCH] Treat ctrl+letter chords as their own character class --- src/editor.rs | 80 +++++++++++++++++++++++++++------------------------ src/main.rs | 11 +++---- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/editor.rs b/src/editor.rs index 6fa906d..d20da9e 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -146,6 +146,8 @@ pub enum KeyCode { 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 { 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 { ] } -/// 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"); + } } diff --git a/src/main.rs b/src/main.rs index 8015939..5facfaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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) + + () } } }