From c53e3c262e132765262c550974a4daf70dae5089 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 27 Apr 2023 18:13:43 +0200 Subject: [PATCH] Include key bindings in config --- cove-config/src/doc.rs | 10 ++ cove-config/src/keys.rs | 311 +++++++++++++++++++++++++++++++++++++--- cove-config/src/lib.rs | 3 + 3 files changed, 305 insertions(+), 19 deletions(-) diff --git a/cove-config/src/doc.rs b/cove-config/src/doc.rs index 4a344a0..9253364 100644 --- a/cove-config/src/doc.rs +++ b/cove-config/src/doc.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::path::PathBuf; +use cove_input::KeyBinding; pub use cove_macro::Document; #[derive(Clone, Default)] @@ -192,3 +193,12 @@ impl Document for HashMap { doc } } + +impl Document for KeyBinding { + fn doc() -> Doc { + let mut doc = Doc::default(); + doc.value_info.required = Some(true); + doc.value_info.r#type = Some("key binding".to_string()); + doc + } +} diff --git a/cove-config/src/keys.rs b/cove-config/src/keys.rs index 1823335..5e2e45e 100644 --- a/cove-config/src/keys.rs +++ b/cove-config/src/keys.rs @@ -1,93 +1,366 @@ use cove_input::{Group, KeyBinding}; +use serde::Deserialize; -#[derive(Debug, Group)] +use crate::doc::Document; + +macro_rules! default_bindings { + ( $( + pub mod $mod:ident { $( + pub fn $name:ident => [ $($key:expr),* ]; + )* } + )*) => { + mod default { $( + pub mod $mod { $( + pub fn $name() -> ::cove_input::KeyBinding { + ::cove_input::KeyBinding::new().with_keys([ $($key),* ]).unwrap() + } + )* } + )* } + }; +} + +default_bindings! { + pub mod general { + pub fn exit => ["ctrl+c"]; + pub fn abort => ["esc"]; + pub fn confirm => ["enter"]; + pub fn help => ["f1", "?"]; + pub fn log => ["f12"]; + } + + pub mod scroll { + pub fn up_line => ["ctrl+y"]; + pub fn down_line => ["ctrl+e"]; + pub fn up_half => ["ctrl+u"]; + pub fn down_half => ["ctrl+d"]; + pub fn up_full => ["ctrl+b"]; + pub fn down_full => ["ctrl+f"]; + } + + pub mod cursor { + pub fn up => ["k", "up"]; + pub fn down => ["j", "down"]; + pub fn to_top => ["g", "home"]; + pub fn to_bottom => ["G", "end"]; + pub fn center => ["z"]; + } + + pub mod tree_cursor { + pub fn to_above_sibling => ["K", "ctrl+up"]; + pub fn to_below_sibling => ["J", "ctrl+down"]; + pub fn to_parent => ["p"]; + pub fn to_root => ["P"]; + pub fn to_prev_message => ["h", "left"]; + pub fn to_next_message => ["l", "right"]; + pub fn to_prev_unseen_message => ["H", "ctrl+left"]; + pub fn to_next_unseen_message => ["L", "ctrl+right"]; + } + + pub mod tree_op { + pub fn reply => ["r"]; + pub fn reply_alternate => ["R"]; + pub fn new_thread => ["t"]; + pub fn fold_tree => [" "]; + pub fn toggle_seen => ["s"]; + pub fn mark_visible_seen => ["S"]; + pub fn mark_older_seen => ["ctrl+s"]; + } + + pub mod editor_cursor { + pub fn left => []; + pub fn right => []; + pub fn left_word => []; + pub fn right_word => []; + pub fn start => []; + pub fn end => []; + pub fn up => []; + pub fn down => []; + } + + pub mod editor_op { + pub fn newline => []; + pub fn backspace => []; + pub fn delete => []; + pub fn clear => []; + } + +} + +#[derive(Debug, Deserialize, Document, Group)] pub struct General { /// Quit cove. + #[serde(default = "default::general::exit")] pub exit: KeyBinding, /// Abort/close. + #[serde(default = "default::general::abort")] pub abort: KeyBinding, /// Confirm. + #[serde(default = "default::general::confirm")] pub confirm: KeyBinding, /// Show this help. + #[serde(default = "default::general::help")] pub help: KeyBinding, /// Show log. + #[serde(default = "default::general::log")] pub log: KeyBinding, } -#[derive(Debug, Group)] +impl Default for General { + fn default() -> Self { + Self { + exit: default::general::exit(), + abort: default::general::abort(), + confirm: default::general::confirm(), + help: default::general::help(), + log: default::general::log(), + } + } +} + +#[derive(Debug, Deserialize, Document, Group)] pub struct Scroll { /// Scroll up one line. + #[serde(default = "default::scroll::up_line")] pub up_line: KeyBinding, /// Scroll down one line. + #[serde(default = "default::scroll::down_line")] pub down_line: KeyBinding, /// Scroll up half a screen. + #[serde(default = "default::scroll::up_half")] pub up_half: KeyBinding, /// Scroll down half a screen. + #[serde(default = "default::scroll::down_half")] pub down_half: KeyBinding, /// Scroll up a full screen. + #[serde(default = "default::scroll::up_full")] pub up_full: KeyBinding, /// Scroll down a full screen. + #[serde(default = "default::scroll::down_full")] pub down_full: KeyBinding, } -#[derive(Debug, Group)] +impl Default for Scroll { + fn default() -> Self { + Self { + up_line: default::scroll::up_line(), + down_line: default::scroll::down_line(), + up_half: default::scroll::up_half(), + down_half: default::scroll::down_half(), + up_full: default::scroll::up_full(), + down_full: default::scroll::down_full(), + } + } +} + +#[derive(Debug, Deserialize, Document, Group)] pub struct Cursor { /// Move cursor up. + #[serde(default = "default::cursor::up")] pub up: KeyBinding, /// Move cursor down. + #[serde(default = "default::cursor::down")] pub down: KeyBinding, /// Move cursor to top. + #[serde(default = "default::cursor::to_top")] pub to_top: KeyBinding, /// Move cursor to bottom. + #[serde(default = "default::cursor::to_bottom")] pub to_bottom: KeyBinding, /// Center cursor. + #[serde(default = "default::cursor::center")] pub center: KeyBinding, } -#[derive(Debug, Group)] -pub struct TreeCursor { - /// Move cursor to above sibling. - pub to_above_sibling: KeyBinding, - /// Move cursor to below sibling. - pub to_below_sibling: KeyBinding, - /// Move cursor to parent. - pub to_parent: KeyBinding, - /// Move cursor to root. - pub to_root: KeyBinding, - /// Move cursor to previous message. - pub to_prev_message: KeyBinding, - /// Move cursor to next message. - pub to_next_message: KeyBinding, +impl Default for Cursor { + fn default() -> Self { + Self { + up: default::cursor::up(), + down: default::cursor::down(), + to_top: default::cursor::to_top(), + to_bottom: default::cursor::to_bottom(), + center: default::cursor::center(), + } + } } -#[derive(Debug, Group)] +#[derive(Debug, Deserialize, Document, Group)] pub struct EditorCursor { /// Move cursor left. + #[serde(default = "default::editor_cursor::left")] pub left: KeyBinding, /// Move cursor right. + #[serde(default = "default::editor_cursor::right")] pub right: KeyBinding, /// Move cursor left a word. + #[serde(default = "default::editor_cursor::left_word")] pub left_word: KeyBinding, /// Move cursor right a word. + #[serde(default = "default::editor_cursor::right_word")] pub right_word: KeyBinding, /// Move cursor to start of line. + #[serde(default = "default::editor_cursor::start")] pub start: KeyBinding, /// Move cursor to end of line. + #[serde(default = "default::editor_cursor::end")] pub end: KeyBinding, /// Move cursor up. + #[serde(default = "default::editor_cursor::up")] pub up: KeyBinding, /// Move cursor down. + #[serde(default = "default::editor_cursor::down")] pub down: KeyBinding, } -#[derive(Debug, Group)] +impl Default for EditorCursor { + fn default() -> Self { + Self { + left: default::editor_cursor::left(), + right: default::editor_cursor::right(), + left_word: default::editor_cursor::left_word(), + right_word: default::editor_cursor::right_word(), + start: default::editor_cursor::start(), + end: default::editor_cursor::end(), + up: default::editor_cursor::up(), + down: default::editor_cursor::down(), + } + } +} + +#[derive(Debug, Deserialize, Document, Group)] pub struct EditorOp { /// Insert newline. + #[serde(default = "default::editor_op::newline")] pub newline: KeyBinding, /// Delete before cursor. + #[serde(default = "default::editor_op::backspace")] pub backspace: KeyBinding, /// Delete after cursor. + #[serde(default = "default::editor_op::delete")] pub delete: KeyBinding, /// Clear editor contents. + #[serde(default = "default::editor_op::clear")] pub clear: KeyBinding, } + +impl Default for EditorOp { + fn default() -> Self { + Self { + newline: default::editor_op::newline(), + backspace: default::editor_op::backspace(), + delete: default::editor_op::delete(), + clear: default::editor_op::clear(), + } + } +} + +#[derive(Debug, Default, Deserialize, Document)] +pub struct Editor { + #[serde(default)] + pub cursor: EditorCursor, + #[serde(default)] + pub action: EditorOp, +} + +#[derive(Debug, Deserialize, Document, Group)] +pub struct TreeCursor { + /// Move cursor to above sibling. + #[serde(default = "default::tree_cursor::to_above_sibling")] + pub to_above_sibling: KeyBinding, + /// Move cursor to below sibling. + #[serde(default = "default::tree_cursor::to_below_sibling")] + pub to_below_sibling: KeyBinding, + /// Move cursor to parent. + #[serde(default = "default::tree_cursor::to_parent")] + pub to_parent: KeyBinding, + /// Move cursor to root. + #[serde(default = "default::tree_cursor::to_root")] + pub to_root: KeyBinding, + /// Move cursor to previous message. + #[serde(default = "default::tree_cursor::to_prev_message")] + pub to_prev_message: KeyBinding, + /// Move cursor to next message. + #[serde(default = "default::tree_cursor::to_next_message")] + pub to_next_message: KeyBinding, + /// Move cursor to previous unseen message. + #[serde(default = "default::tree_cursor::to_prev_unseen_message")] + pub to_prev_unseen_message: KeyBinding, + /// Move cursor to next unseen message. + #[serde(default = "default::tree_cursor::to_next_unseen_message")] + pub to_next_unseen_message: KeyBinding, +} + +impl Default for TreeCursor { + fn default() -> Self { + Self { + to_above_sibling: default::tree_cursor::to_above_sibling(), + to_below_sibling: default::tree_cursor::to_below_sibling(), + to_parent: default::tree_cursor::to_parent(), + to_root: default::tree_cursor::to_root(), + to_prev_message: default::tree_cursor::to_prev_message(), + to_next_message: default::tree_cursor::to_next_message(), + to_prev_unseen_message: default::tree_cursor::to_prev_unseen_message(), + to_next_unseen_message: default::tree_cursor::to_next_unseen_message(), + } + } +} + +#[derive(Debug, Deserialize, Document, Group)] +pub struct TreeOp { + /// Reply to message (inline if possible). + #[serde(default = "default::tree_op::reply")] + pub reply: KeyBinding, + /// Reply to message, opposite of normal reply. + #[serde(default = "default::tree_op::reply_alternate")] + pub reply_alternate: KeyBinding, + /// Start a new thread. + #[serde(default = "default::tree_op::new_thread")] + pub new_thread: KeyBinding, + /// Fold current message's subtree. + #[serde(default = "default::tree_op::fold_tree")] + pub fold_tree: KeyBinding, + /// Toggle current message's seen status. + #[serde(default = "default::tree_op::toggle_seen")] + pub toggle_seen: KeyBinding, + /// Mark all visible messages as seen. + #[serde(default = "default::tree_op::mark_visible_seen")] + pub mark_visible_seen: KeyBinding, + /// Mark all older messages as seen. + #[serde(default = "default::tree_op::mark_older_seen")] + pub mark_older_seen: KeyBinding, +} + +impl Default for TreeOp { + fn default() -> Self { + Self { + reply: default::tree_op::reply(), + reply_alternate: default::tree_op::reply_alternate(), + new_thread: default::tree_op::new_thread(), + fold_tree: default::tree_op::fold_tree(), + toggle_seen: default::tree_op::toggle_seen(), + mark_visible_seen: default::tree_op::mark_visible_seen(), + mark_older_seen: default::tree_op::mark_older_seen(), + } + } +} + +#[derive(Debug, Default, Deserialize, Document)] +pub struct Tree { + #[serde(default)] + pub cursor: TreeCursor, + #[serde(default)] + pub action: TreeOp, +} + +#[derive(Debug, Default, Deserialize, Document)] +pub struct Keys { + #[serde(default)] + pub general: General, + #[serde(default)] + pub scroll: Scroll, + #[serde(default)] + pub cursor: Cursor, + #[serde(default)] + pub editor: Editor, + #[serde(default)] + pub tree: Tree, +} diff --git a/cove-config/src/lib.rs b/cove-config/src/lib.rs index e90f05a..ef9c731 100644 --- a/cove-config/src/lib.rs +++ b/cove-config/src/lib.rs @@ -82,6 +82,9 @@ pub struct Config { // TODO Invoke external notification command? pub euph: Euph, + + #[serde(default)] + pub keys: Keys, } impl Config {