From a611b0906c4164d3a09b4f046ec7074405a5355b Mon Sep 17 00:00:00 2001 From: Tyler Ryan Date: Sat, 3 Dec 2022 03:48:45 -0600 Subject: [PATCH] About to change a match statement. About to change a match statement to an if statement. You can't compare anything to a dynamic variable in a match statement (at least on easily). So I'm going to change it to a good ole if statement. Once done, the user should be able to customize their keys bindings. --- src/app/impl_view.rs | 5 + src/keybinds.rs | 300 ++++++++++++++++++++++--------------------- src/main.rs | 1 + src/theme.rs | 2 +- src/utils.rs | 52 ++++++-- 5 files changed, 201 insertions(+), 159 deletions(-) diff --git a/src/app/impl_view.rs b/src/app/impl_view.rs index c0f1eb4..c0c502e 100644 --- a/src/app/impl_view.rs +++ b/src/app/impl_view.rs @@ -13,6 +13,7 @@ use notify::DebouncedEvent; use crate::app::{App, MessageKind}; use crate::habit::{HabitWrapper, ViewMode}; use crate::utils::{self, GRID_WIDTH, VIEW_HEIGHT, VIEW_WIDTH}; +use crate::CONFIGURATION; impl View for App { fn draw(&self, printer: &Printer) { @@ -58,6 +59,7 @@ impl View for App { } fn on_event(&mut self, e: Event) -> EventResult { + let up = CONFIGURATION.keybindings.up; match self.file_event_recv.try_recv() { Ok(DebouncedEvent::Write(_)) => { let read_from_file = |file: PathBuf| -> Vec> { @@ -78,6 +80,9 @@ impl View for App { if self.habits.is_empty() { return EventResult::Ignored; } + + // TODO: Using a match statment, it won't be able to match on a dynamic variable + // This will have to be changed to an if statement match e { Event::Key(Key::Right) | Event::Key(Key::Tab) | Event::Char('l') => { self.set_focus(Absolute::Right); diff --git a/src/keybinds.rs b/src/keybinds.rs index 65a61a5..f6c5f1c 100644 --- a/src/keybinds.rs +++ b/src/keybinds.rs @@ -1,149 +1,151 @@ -use std::convert::From; - -use cursive::event::Event as CursiveEvent; -use serde::ser; -use serde::{self, Deserialize, Serialize, Serializer}; - -#[derive(Debug, PartialEq)] -struct Event(CursiveEvent); - -macro_rules! event { - ($thing:expr) => { - Event { 0: $thing }; - }; -} - -impl From for Event -where - T: AsRef, -{ - fn from(key: T) -> Self { - let key = key.as_ref(); - if key.len() == 1 { - // single key - return event!(CursiveEvent::Char(key.chars().nth(0).unwrap())); - } else if (key.starts_with("c-") || key.starts_with("C-")) && key.len() == 3 { - // ctrl-key - return event!(CursiveEvent::CtrlChar(key.chars().nth(2).unwrap())); - } else { - panic!( - r"Invalid keybind in configuration! - (I intend to handle this error gracefully in the near future)" - ); - } - } -} - -enum Bind { - Char(char), - CtrlChar(char), - AltChar(char), -} - -impl Serialize for Bind { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Bind::Char(c) => serializer.serialize_newtype_variant("bind", 0, "regular", &c), - Bind::CtrlChar(c) => serializer.serialize_newtype_variant("bind", 0, "ctrl", &c), - Bind::AltChar(c) => serializer.serialize_newtype_variant("bind", 0, "alt", &c), - } - } -} - -impl Deserialize for Bind { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - eprintln!("hell = {:#?}", hell); - } -} - -impl From for CursiveEvent { - fn from(key: Bind) -> Self { - match key { - Bind::Char(c) => CursiveEvent::Char(c), - Bind::CtrlChar(c) => CursiveEvent::Char(c), - Bind::AltChar(c) => CursiveEvent::AltChar(c), - } - } -} - - -#[derive(Serialize, Deserialize)] -pub struct Movement { - up: Bind, - down: Bind, - left: Bind, - right: Bind, -} - -impl Movement { - pub fn new(left: char, down: char, up: char, right: char) -> Self { - return Movement { - up: Bind::Char(up), - down: Bind::Char(down), - left: Bind::Char(left), - right: Bind::Char(right), - }; - } -} - -#[derive(Serialize, Deserialize)] -pub struct KeyBinds { - grid: Movement, - cursor: Movement, - week_mode: Bind, - global_week_mode: Bind, - rename_habit: Bind, -} - -impl std::default::Default for KeyBinds { - fn default() -> Self { - let grid = Movement::new('h', 'j', 'k', 'l'); - let cursor = Movement::new('H', 'J', 'K', 'L'); - return KeyBinds { - grid, - cursor, - week_mode: Bind::Char('v'), - global_week_mode: Bind::Char('V'), - rename_habit: Bind::Char('R'), - }; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn normal_keybind() { - let bind = "X"; - let expected = CursiveEvent::Char('X'); - assert_eq!(Event::from(bind), event!(expected)); - } - - #[test] - fn control_keybind() { - let bind = "C-x"; - let expected = CursiveEvent::CtrlChar('x'); - assert_eq!(Event::from(bind), event!(expected)); - } - - #[test] - fn lower_case_control_keybind() { - let bind = "c-x"; - let expected = CursiveEvent::CtrlChar('x'); - assert_eq!(Event::from(bind), event!(expected)); - } - - #[test] - #[should_panic] - fn very_long_and_wrong_keybind() { - let bind = "alksdjfalkjdf"; - Event::from(bind); - } -} +// use std::convert::From; + +// use cursive::event::Event as CursiveEvent; +// use serde::ser; +// use serde::{self, Deserialize, Serialize, Serializer}; +// use crate::CONFIGURATION; + +// #[derive(Debug, PartialEq)] +// struct Event(CursiveEvent); + +// macro_rules! event { +// ($thing:expr) => { +// Event { 0: $thing }; +// }; +// } + +// impl From for Event +// where +// T: AsRef, +// { +// fn from(key: T) -> Self { +// let key = key.as_ref(); +// if key.len() == 1 { +// // single key +// return event!(CursiveEvent::Char(key.chars().nth(0).unwrap())); +// } else if (key.starts_with("c-") || key.starts_with("C-")) && key.len() == 3 { +// // ctrl-key +// return event!(CursiveEvent::CtrlChar(key.chars().nth(2).unwrap())); +// } else { +// panic!( +// r"Invalid keybind in configuration! +// (I intend to handle this error gracefully in the near future)" +// ); +// } +// } +// } + +// enum Bind { +// Char(char), +// CtrlChar(char), +// AltChar(char), +// } + +// impl Serialize for Bind { +// fn serialize(&self, serializer: S) -> Result +// where +// S: Serializer, +// { +// match self { +// Bind::Char(c) => serializer.serialize_newtype_variant("bind", 0, "regular", &c), +// Bind::CtrlChar(c) => serializer.serialize_newtype_variant("bind", 0, "ctrl", &c), +// Bind::AltChar(c) => serializer.serialize_newtype_variant("bind", 0, "alt", &c), +// } +// } +// } + +// impl Deserialize for Bind { +// fn deserialize(deserializer: D) -> Result +// where +// D: Deserializer<'de>, +// { +// eprintln!("hell = {:#?}", hell); +// } +// } + +// impl From for CursiveEvent { +// fn from(key: Bind) -> Self { +// match key { +// Bind::Char(c) => CursiveEvent::Char(c), +// Bind::CtrlChar(c) => CursiveEvent::Char(c), +// Bind::AltChar(c) => CursiveEvent::AltChar(c), +// } +// } +// } + + +// #[derive(Serialize, Deserialize)] +// pub struct Movement { +// up: Bind, +// down: Bind, +// left: Bind, +// right: Bind, +// } + +// impl Movement { +// pub fn new(left: char, down: char, up: char, right: char) -> Self { +// return Movement { +// up: Bind::Char(up), +// down: Bind::Char(down), +// left: Bind::Char(left), +// right: Bind::Char(right), +// }; +// } +// } + +// #[derive(Serialize, Deserialize)] +// pub struct KeyBinds { +// grid: Movement, +// cursor: Movement, +// week_mode: Bind, +// global_week_mode: Bind, +// rename_habit: Bind, +// } + +// impl std::default::Default for KeyBinds { +// fn default() -> Self { +// let up: String = CONFIGURATION.keybindings.up(); +// let grid = Movement::new(&up, 'j', 'k', 'l'); +// let cursor = Movement::new('H', 'J', 'K', 'L'); +// return KeyBinds { +// grid, +// cursor, +// week_mode: Bind::Char('v'), +// global_week_mode: Bind::Char('V'), +// rename_habit: Bind::Char('R'), +// }; +// } +// } + +// #[cfg(test)] +// mod tests { +// use super::*; + +// #[test] +// fn normal_keybind() { +// let bind = "X"; +// let expected = CursiveEvent::Char('X'); +// assert_eq!(Event::from(bind), event!(expected)); +// } + +// #[test] +// fn control_keybind() { +// let bind = "C-x"; +// let expected = CursiveEvent::CtrlChar('x'); +// assert_eq!(Event::from(bind), event!(expected)); +// } + +// #[test] +// fn lower_case_control_keybind() { +// let bind = "c-x"; +// let expected = CursiveEvent::CtrlChar('x'); +// assert_eq!(Event::from(bind), event!(expected)); +// } + +// #[test] +// #[should_panic] +// fn very_long_and_wrong_keybind() { +// let bind = "alksdjfalkjdf"; +// Event::from(bind); +// } +// } diff --git a/src/main.rs b/src/main.rs index 92e29f9..6667ae2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod habit; mod theme; mod utils; mod views; +mod keybinds; use crate::app::App; use crate::command::{open_command_window, Command}; diff --git a/src/theme.rs b/src/theme.rs index 264bef4..9e18cfe 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -20,7 +20,7 @@ pub fn pallete_gen() -> Palette { pub fn theme_gen() -> Theme { let mut t = Theme::default(); t.shadow = false; - t.borders = BorderStyle::None; + t.borders = BorderStyle::Simple; t.palette = pallete_gen(); return t; } diff --git a/src/utils.rs b/src/utils.rs index d9543fc..8e5d4fa 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -76,32 +76,63 @@ fn dark_red() -> String { "dark white".into() } impl Default for Colors { fn default() -> Self { Colors { - reached: cyan(), - todo: magenta(), - inactive: light_black(), - future: magenta(), - cursor: light_black(), - today: dark_red(), + reached: cyan(), + todo: magenta(), + inactive: light_black(), + future: magenta(), + cursor: light_black(), + today: dark_red(), stats_bar_bg: light_black(), stats_bar_fg: light_black(), } } } +#[derive(Serialize, Deserialize)] +pub struct KeyBindings { + #[serde(default = "up")] + pub up: char , + #[serde(default = "down")] + pub down: char , + #[serde(default = "left")] + pub left: char , + #[serde(default = "right")] + pub right: char , +} + +fn up() -> char { 'k' } +fn down() -> char { 'j' } +fn left() -> char { 'h' } +fn right() -> char { 'l' } + +impl Default for KeyBindings { + fn default() -> Self { + KeyBindings { + up: up() , + down: down() , + left: left() , + right: right(), + } + } +} + #[derive(Serialize, Deserialize)] pub struct AppConfig { #[serde(default)] pub look: Characters, - #[serde(default)] pub colors: Colors, + #[serde(default)] + pub keybindings: KeyBindings, + } impl Default for AppConfig { fn default() -> Self { AppConfig { - look: Default::default(), - colors: Default::default(), + look: Default::default(), + colors: Default::default(), + keybindings: Default::default(), } } } @@ -132,6 +163,9 @@ impl AppConfig { pub fn stats_bar_fg_color(&self) -> Color { return Color::parse(&self.colors.stats_bar_fg).unwrap_or(Color::Dark(BaseColor::White)); } + pub fn move_up(self) -> char { + return self.keybindings.up; + } } pub fn load_configuration_file() -> AppConfig {