From c8b786d7dc8f1f854418e94e29c6675a675895df Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 3 Nov 2023 16:16:24 -0600 Subject: [PATCH] Make config serializable --- Cargo.lock | 1 + Cargo.toml | 1 + src/config.rs | 116 ++++++++++++++++++++++++++++++++------------------ src/main.rs | 48 ++++++++++----------- src/menu.rs | 6 +-- src/tab.rs | 5 +-- 6 files changed, 104 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b2ede5..97c2b71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -826,6 +826,7 @@ dependencies = [ "log", "rfd", "rust-embed", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6d5961e..5f26e31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ fontdb = "0.15.0" lazy_static = "1.4.0" log = "0.4.20" rfd = "0.12.0" +serde = { version = "1", features = ["serde_derive"] } # Internationalization i18n-embed = { version = "0.13.4", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6.4" diff --git a/src/config.rs b/src/config.rs index b89d7be..21b3dff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,87 +1,119 @@ -use cosmic::iced::keyboard::{KeyCode, Modifiers}; +use cosmic::{ + cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry}, + iced::keyboard::{KeyCode, Modifiers}, +}; use cosmic_text::Metrics; +use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fmt}; use crate::{ContextPage, Message}; -// Makes key binding definitions simpler -const CTRL: Modifiers = Modifiers::CTRL; -const ALT: Modifiers = Modifiers::ALT; -const SHIFT: Modifiers = Modifiers::SHIFT; +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub enum Action { + Cut, + Copy, + Paste, + NewFile, + NewWindow, + OpenFileDialog, + Save, + Quit, + ToggleSettingsPage, + ToggleWordWrap, +} -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +impl Action { + pub fn message(&self) -> Message { + match self { + Self::Cut => Message::Cut, + Self::Copy => Message::Copy, + Self::Paste => Message::Paste, + Self::NewFile => Message::NewFile, + Self::NewWindow => Message::NewWindow, + Self::OpenFileDialog => Message::OpenFileDialog, + Self::Save => Message::Save, + Self::Quit => Message::Quit, + Self::ToggleSettingsPage => Message::ToggleContextPage(ContextPage::Settings), + Self::ToggleWordWrap => Message::ToggleWordWrap, + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub enum Modifier { + Super, + Ctrl, + Alt, + Shift, +} + +#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct KeyBind { - pub modifiers: Modifiers, + pub modifiers: Vec, pub key_code: KeyCode, } impl KeyBind { //TODO: load from config - pub fn load() -> HashMap { + pub fn load() -> HashMap { let mut keybinds = HashMap::new(); macro_rules! bind { - ($modifiers:expr, $key_code:ident, $message:expr) => {{ + ([$($modifier:ident),+ $(,)?], $key_code:ident, $action:ident) => {{ keybinds.insert( KeyBind { - modifiers: $modifiers, + modifiers: vec![$(Modifier::$modifier),+], key_code: KeyCode::$key_code, }, - $message, + Action::$action, ); }}; } - bind!(CTRL, X, Message::Cut); - bind!(CTRL, C, Message::Copy); - bind!(CTRL, V, Message::Paste); - bind!(CTRL, N, Message::NewFile); - bind!(CTRL | SHIFT, N, Message::NewWindow); - bind!(CTRL, O, Message::OpenFileDialog); - bind!(CTRL, S, Message::Save); - bind!(CTRL, Q, Message::Quit); - bind!( - CTRL, - Comma, - Message::ToggleContextPage(ContextPage::Settings) - ); - bind!(ALT, Z, Message::ToggleWordWrap); + bind!([Ctrl], X, Cut); + bind!([Ctrl], C, Copy); + bind!([Ctrl], V, Paste); + bind!([Ctrl], N, NewFile); + bind!([Ctrl, Shift], N, NewWindow); + bind!([Ctrl], O, OpenFileDialog); + bind!([Ctrl], S, Save); + bind!([Ctrl], Q, Quit); + bind!([Ctrl], Comma, ToggleSettingsPage); + bind!([Alt], Z, ToggleWordWrap); keybinds } + + pub fn matches(&self, modifiers: Modifiers, key_code: KeyCode) -> bool { + self.key_code == key_code + && modifiers.logo() == self.modifiers.contains(&Modifier::Super) + && modifiers.control() == self.modifiers.contains(&Modifier::Ctrl) + && modifiers.alt() == self.modifiers.contains(&Modifier::Alt) + && modifiers.shift() == self.modifiers.contains(&Modifier::Shift) + } } impl fmt::Display for KeyBind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.modifiers.logo() { - write!(f, "Super + ")?; - } - if self.modifiers.control() { - write!(f, "Ctrl + ")?; - } - if self.modifiers.alt() { - write!(f, "Alt + ")?; - } - if self.modifiers.shift() { - write!(f, "Shift + ")?; + for modifier in self.modifiers.iter() { + write!(f, "{:?} + ", modifier)?; } write!(f, "{:?}", self.key_code) } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Config { pub font_size: u16, pub syntax_theme_dark: String, pub syntax_theme_light: String, pub vim_bindings: bool, pub word_wrap: bool, - pub keybinds: HashMap, + pub keybinds: HashMap, } -impl Config { - //TODO: load from cosmic-config - pub fn load() -> Self { +impl Default for Config { + fn default() -> Self { Self { font_size: 14, syntax_theme_dark: "base16-eighties.dark".to_string(), @@ -91,7 +123,9 @@ impl Config { keybinds: KeyBind::load(), } } +} +impl Config { // Calculate metrics from font size pub fn metrics(&self) -> Metrics { let font_size = self.font_size as f32; diff --git a/src/main.rs b/src/main.rs index b08c82a..3dbb3bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ use std::{ sync::Mutex, }; -use config::{Config, KeyBind}; +use config::Config; mod config; mod localize; @@ -67,7 +67,7 @@ pub enum Message { Copy, DefaultFont(usize), DefaultFontSize(usize), - KeyBind(KeyBind), + Key(keyboard::Modifiers, keyboard::KeyCode), NewFile, NewWindow, OpenFileDialog, @@ -370,7 +370,7 @@ impl cosmic::Application for App { core, nav_model: nav_bar::Model::builder().build(), tab_model: segmented_button::Model::builder().build(), - config: Config::load(), + config: Config::default(), font_names, font_size_names, font_sizes, @@ -511,21 +511,19 @@ impl cosmic::Application for App { } } } - Message::DefaultFontSize(index) => { - match self.font_sizes.get(index) { - Some(font_size) => { - self.config.font_size = *font_size; - self.save_config(); - } - None => { - log::warn!("failed to find font with index {}", index); - } + Message::DefaultFontSize(index) => match self.font_sizes.get(index) { + Some(font_size) => { + self.config.font_size = *font_size; + self.save_config(); } - } - Message::KeyBind(key_bind) => { - for (config_key_bind, config_message) in self.config.keybinds.iter() { - if config_key_bind == &key_bind { - return self.update(config_message.clone()); + None => { + log::warn!("failed to find font with index {}", index); + } + }, + Message::Key(modifiers, key_code) => { + for (key_bind, action) in self.config.keybinds.iter() { + if key_bind.matches(modifiers, key_code) { + return self.update(action.message()); } } } @@ -769,9 +767,11 @@ impl cosmic::Application for App { ) .add( widget::settings::item::builder(fl!("default-font-size")).control( - widget::dropdown(&self.font_size_names, font_size_selected, |index| { - Message::DefaultFontSize(index) - }), + widget::dropdown( + &self.font_size_names, + font_size_selected, + |index| Message::DefaultFontSize(index), + ), ), ) .into(), @@ -810,7 +810,8 @@ impl cosmic::Application for App { match self.active_tab() { Some(tab) => { - tab_column = tab_column.push(text_box(&tab.editor, self.config.metrics()).padding(8)); + tab_column = + tab_column.push(text_box(&tab.editor, self.config.metrics()).padding(8)); let status = match tab.editor.lock().unwrap().mode() { ViMode::Passthrough => { //TODO: status line @@ -853,10 +854,7 @@ impl cosmic::Application for App { event::Event::Keyboard(keyboard::Event::KeyPressed { modifiers, key_code, - }) => Some(Message::KeyBind(KeyBind { - modifiers, - key_code, - })), + }) => Some(Message::Key(modifiers, key_code)), _ => None, }) } diff --git a/src/menu.rs b/src/menu.rs index 7e8064e..97d0279 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -41,9 +41,9 @@ pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> { let find_key = |message: &Message| -> String { let mut key = String::new(); - for (config_key_bind, config_message) in config.keybinds.iter() { - if config_message == message { - key = config_key_bind.to_string(); + for (key_bind, action) in config.keybinds.iter() { + if &action.message() == message { + key = key_bind.to_string(); break; } } diff --git a/src/tab.rs b/src/tab.rs index 77a8f12..bc0d3a6 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -17,10 +17,7 @@ impl Tab { let attrs = cosmic_text::Attrs::new().family(cosmic_text::Family::Monospace); let editor = SyntaxEditor::new( - Buffer::new( - &mut FONT_SYSTEM.lock().unwrap(), - config.metrics(), - ), + Buffer::new(&mut FONT_SYSTEM.lock().unwrap(), config.metrics()), &SYNTAX_SYSTEM, config.syntax_theme(cosmic::theme::is_dark()), )