chiark / gitweb /
Store an OurKey in FileStatusLine and MenuKeypressLine.
authorSimon Tatham <anakin@pobox.com>
Thu, 28 Dec 2023 08:45:45 +0000 (08:45 +0000)
committerSimon Tatham <anakin@pobox.com>
Thu, 28 Dec 2023 08:45:45 +0000 (08:45 +0000)
Now we have a representation for keystrokes that can trigger actions,
this is the first step towards a DRY representation in which each menu
and status line configures just once the a set of triples (keypress,
help text, action to take).

Not sure what form the 'action' part of that triple will take yet,
though.

src/text.rs

index 1cd40b48b728e4e3db73d15b9dec57c8744c633b..33f834ce15dfdfbdf501f8cc389eeb427e362395 100644 (file)
@@ -6,6 +6,7 @@ use std::collections::{HashMap, BTreeMap, BTreeSet};
 use unicode_width::UnicodeWidthStr;
 
 use super::html;
+use super::tui::OurKey;
 use super::coloured_string::{ColouredString, ColouredStringSlice};
 
 pub trait TextFragment {
@@ -1087,11 +1088,31 @@ fn test_media() {
         });
 }
 
-type Key = String; // FIXME: maybe make this a richer type later so we
-                   // can match it against actual keypresses
+fn key_to_string(key: OurKey) -> String {
+    match key {
+        // Menu and file keypresses are case insensitive, and the UI shows
+        // them in uppercase always
+        OurKey::Pr(c) => c.to_uppercase().to_string(),
+        OurKey::Ctrl(c) => format!("^{}", c),
+        OurKey::FunKey(n) => format!("F{}", n),
+        OurKey::Backspace => "BS".to_string(), // likely won't come up
+        OurKey::Return => "RET".to_string(),
+        OurKey::Escape => "ESC".to_string(),
+        OurKey::Up => "Up".to_string(),
+        OurKey::Down => "Down".to_string(),
+        OurKey::Left => "Left".to_string(),
+        OurKey::Right => "Right".to_string(),
+        OurKey::PgUp => "PgUp".to_string(),
+        OurKey::PgDn => "PgDn".to_string(),
+        OurKey::Home => "Home".to_string(),
+        OurKey::End => "End".to_string(),
+        OurKey::Ins => "Ins".to_string(),
+        OurKey::Del => "Del".to_string(),
+    }
+}
 
 struct Keypress {
-    key: Key,
+    key: OurKey,
     description: ColouredString,
 }
 
@@ -1127,7 +1148,8 @@ impl FileStatusLine {
         self
     }
 
-    pub fn add(mut self, key: Key, description: &str, priority: usize) -> Self {
+    pub fn add(mut self, key: OurKey, description: &str,
+               priority: usize) -> Self {
         self.keypresses.push((Keypress {
                     key: key,
                     description: ColouredString::plain(description)
@@ -1139,8 +1161,8 @@ impl FileStatusLine {
         let mut bypri = BTreeMap::new();
         for (kp, pri) in &self.keypresses {
             // [key]:desc
-            let key: &str = &kp.key;
-            let width = UnicodeWidthStr::width(key) +
+            let key = key_to_string(kp.key);
+            let width = UnicodeWidthStr::width(&key as &str) +
                 kp.description.width() + 3;
 
             if let Some(priwidth) = bypri.get_mut(pri) {
@@ -1184,23 +1206,23 @@ fn test_filestatus_build() {
     assert_eq!(fs.message, Some("hello, world".to_owned()));
 
     let fsf = FileStatusLine::new()
-        .add("A".to_owned(), "Annoy", 10)
+        .add(OurKey::Pr('A'), "Annoy", 10)
         .finalise();
     assert_eq!(fsf.priwidth, vec! {
             (10, 9),
         });
 
     let fsf = FileStatusLine::new()
-        .add("A".to_owned(), "Annoy", 10)
-        .add("B".to_owned(), "Badger", 10)
+        .add(OurKey::Pr('A'), "Annoy", 10)
+        .add(OurKey::Pr('B'), "Badger", 10)
         .finalise();
     assert_eq!(fsf.priwidth, vec! {
             (10, 9 + 10 + FileStatusLine::SPACING),
         });
 
     let fsf = FileStatusLine::new()
-        .add("A".to_owned(), "Annoy", 10)
-        .add("B".to_owned(), "Badger", 5)
+        .add(OurKey::Pr('A'), "Annoy", 10)
+        .add(OurKey::Pr('B'), "Badger", 5)
         .finalise();
     assert_eq!(fsf.priwidth, vec! {
             (10, 9),
@@ -1208,7 +1230,7 @@ fn test_filestatus_build() {
         });
 
     let fsf = FileStatusLine::new()
-        .add("A".to_owned(), "Annoy", 10)
+        .add(OurKey::Pr('A'), "Annoy", 10)
         .finalise();
     assert_eq!(fsf.priwidth, vec! {
             (10, 9),
@@ -1216,7 +1238,7 @@ fn test_filestatus_build() {
 
     let fsf = FileStatusLine::new()
         .set_proportion(2, 3)
-        .add("A".to_owned(), "Annoy", 10)
+        .add(OurKey::Pr('A'), "Annoy", 10)
         .finalise();
     assert_eq!(fsf.priwidth, vec! {
             (10, 9 + FileStatusLine::SPACING),
@@ -1224,7 +1246,7 @@ fn test_filestatus_build() {
 
     let fsf = FileStatusLine::new()
         .message("aha")
-        .add("A".to_owned(), "Annoy", 10)
+        .add(OurKey::Pr('A'), "Annoy", 10)
         .finalise();
     assert_eq!(fsf.priwidth, vec! {
             (10, 9 + FileStatusLine::SPACING),
@@ -1267,7 +1289,8 @@ impl TextFragment for FileStatusLineFinal {
             for (kp, pri) in &self.fs.keypresses {
                 if *pri >= minpri {
                     let mut ckey = ColouredString::plain("[");
-                    let ckp = ColouredString::uniform(&kp.key, 'k');
+                    let ckp = ColouredString::uniform(
+                        &key_to_string(kp.key), 'k');
                     ckey.push_str(&ckp.slice());
                     ckey.push_str(&ColouredString::plain("]:").slice());
                     ckey.push_str(&kp.description.slice());
@@ -1295,10 +1318,10 @@ fn test_filestatus_render() {
     let fs = FileStatusLine::new()
         .message("stoat")
         .set_proportion(34, 55)
-        .add("A".to_owned(), "Annoy", 10)
-        .add("B".to_owned(), "Badger", 10)
-        .add("C".to_owned(), "Critical", 1000)
-        .add("D".to_owned(), "Dull", 1)
+        .add(OurKey::Pr('a'), "Annoy", 10)
+        .add(OurKey::Pr('b'), "Badger", 10)
+        .add(OurKey::Pr('c'), "Critical", 1000)
+        .add(OurKey::Pr('d'), "Dull", 1)
         .into_box();
 
     assert_eq!(fs.render(80), vec! {
@@ -1343,7 +1366,7 @@ fn test_filestatus_render() {
 
     let fs = FileStatusLine::new()
         .set_proportion(1, 11)
-        .add("K".to_owned(), "Keypress", 10)
+        .add(OurKey::Pr('K'), "Keypress", 10)
         .into_box();
 
     assert_eq!(fs.render(19), vec! {
@@ -1360,7 +1383,7 @@ fn test_filestatus_render() {
 
     let fs = FileStatusLine::new()
         .message("weasel")
-        .add("K".to_owned(), "Keypress", 10)
+        .add(OurKey::Pr('K'), "Keypress", 10)
         .into_box();
 
     assert_eq!(fs.render(21), vec! {
@@ -1384,8 +1407,11 @@ pub struct MenuKeypressLine {
 }
 
 impl MenuKeypressLine {
-    pub fn new(key: Key, description: ColouredString) -> Box<dyn TextFragment> {
-        let lwid = UnicodeWidthStr::width(&key as &str) + 2; // [] around it
+    pub fn new(key: OurKey, description: ColouredString)
+               -> Box<dyn TextFragment> {
+        // +2 for [] around the key name
+        let lwid = UnicodeWidthStr::width(&key_to_string(key) as &str) + 2;
+
         let rwid = description.width();
         Box::new(MenuKeypressLine {
                 keypress: Keypress {
@@ -1415,9 +1441,10 @@ impl TextFragment for MenuKeypressLine {
         let llspace = lspace / 2;
         let lrspace = lspace - llspace;
 
+        let keydesc = key_to_string(self.keypress.key);
         let line = ColouredString::plain(" ").repeat(leftpad + llspace) +
                 ColouredString::plain("[") +
-                ColouredString::uniform(&self.keypress.key, 'k') +
+                ColouredString::uniform(&keydesc, 'k') +
                 ColouredString::plain("]") +
                 ColouredString::plain(" ").repeat(lrspace) +
                 ColouredString::plain(" = ") +
@@ -1435,7 +1462,7 @@ impl TextFragment for MenuKeypressLine {
 
 #[test]
 fn test_menu_keypress() {
-    let mut mk = MenuKeypressLine::new("S".to_owned(), ColouredString::general(
+    let mut mk = MenuKeypressLine::new(OurKey::Pr('S'), ColouredString::general(
             "Something or other",
             "K                 "));