use std::{fs, u8}; use ratatui::crossterm::event::KeyCode; use serde::Deserialize; #[derive(Deserialize)] pub struct KeybindsString { pub GoBack:String, pub Open:String, pub MenuUp:String, pub MenuDown:String, pub MenuLeft:String, pub MenuRight:String, pub AddFavourite:String, } pub struct Keybinds { pub GoBack:KeyCode, pub Open:KeyCode, pub MenuUp:KeyCode, pub MenuDown:KeyCode, pub MenuLeft:KeyCode, pub MenuRight:KeyCode, pub AddFavourite:KeyCode, } impl KeybindsString { pub fn build() -> Result { let f = "keybinds.toml"; if let Ok(exists)= fs::exists(f) { if exists { if let Ok(content)= fs::read_to_string(f) { let parsed:KeybindsString = toml::from_str(&content).unwrap(); return Ok(parsed); } } } return Err(f.to_owned()); } } impl Keybinds { pub fn build() -> Result { let x: Result = match KeybindsString::build() { Ok(ks) => Ok( Self { GoBack: ks.GoBack.to_key_code()?, Open: ks.Open.to_key_code()?, MenuUp: ks.MenuUp.to_key_code()?, MenuDown: ks.MenuDown.to_key_code()?, MenuLeft: ks.MenuLeft.to_key_code()?, MenuRight: ks.MenuRight.to_key_code()?, AddFavourite: ks.AddFavourite.to_key_code()?, } ), Err(f) => Err(f), }; x } pub fn buildOrDefault() -> Result { let x: Result = match KeybindsString::build() { Ok(ks) => Ok( Self { GoBack: ks.GoBack.to_key_code().unwrap_or(KeyCode::Esc), Open: ks.Open.to_key_code().unwrap_or(KeyCode::Enter), MenuUp: ks.MenuUp.to_key_code().unwrap_or(KeyCode::Up), MenuDown: ks.MenuDown.to_key_code().unwrap_or(KeyCode::Down), MenuLeft: ks.MenuLeft.to_key_code().unwrap_or(KeyCode::Left), MenuRight: ks.MenuRight.to_key_code().unwrap_or(KeyCode::Right), AddFavourite: ks.AddFavourite.to_key_code().unwrap_or(KeyCode::Char('p')), } ), Err(f) => Err(f), }; x } } trait StringToKeyCode { fn to_key_code(self) -> Result; } impl StringToKeyCode for String { fn to_key_code(self) -> Result { match self.to_uppercase().as_ref() { "BACKSPACE"=>Ok(KeyCode::Backspace), "ENTER"=>Ok(KeyCode::Enter), "LEFT"=>Ok(KeyCode::Left), "RIGHT"=>Ok(KeyCode::Right), "UP"=>Ok(KeyCode::Up), "DOWN"=>Ok(KeyCode::Down), "HOME"=>Ok(KeyCode::Home), "END"=>Ok(KeyCode::End), "PAGEUP"=>Ok(KeyCode::PageUp), "PAGEDOWN"=>Ok(KeyCode::PageDown), "TAB"=>Ok(KeyCode::Tab), "BACKTAB"=>Ok(KeyCode::BackTab), "DELETE"=>Ok(KeyCode::Delete), "INSERT"=>Ok(KeyCode::Insert), "ESC"=>Ok(KeyCode::Esc), "CAPSLOCK"=>Ok(KeyCode::CapsLock), "SCROLLLOCK"=>Ok(KeyCode::ScrollLock), "NUMLOCK"=>Ok(KeyCode::NumLock), "PRINTSCREEN"=>Ok(KeyCode::PrintScreen), "PAUSE"=>Ok(KeyCode::Pause), "MENU"=>Ok(KeyCode::Menu), "KEYPADBEGIN"=>Ok(KeyCode::KeypadBegin), a => { let chars: Vec = a.chars().collect(); return match chars.as_slice() { [c] => Ok(KeyCode::Char(*c)), ['F', d] if d.is_ascii_digit() =>{ let dg = d.to_digit(10).unwrap() as u8; Ok(KeyCode::F(dg)) }, _ => Err(format!("{} is invalid", self)) }; } } } }