From 48258645bb0c095b36921bd9d1a07ac01dbec739 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 19 Jan 2024 11:25:50 -0700 Subject: [PATCH] Move default keybinds out of config --- src/config.rs | 129 ------------------------------------------------ src/key_bind.rs | 77 +++++++++++++++++++++++++++++ src/main.rs | 66 +++++++++++++++++++++++-- src/menu.rs | 14 ++++-- 4 files changed, 148 insertions(+), 138 deletions(-) create mode 100644 src/key_bind.rs diff --git a/src/config.rs b/src/config.rs index 422b72d..cbb124e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,68 +2,13 @@ use cosmic::{ cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry}, - iced::keyboard::{KeyCode, Modifiers}, theme, }; use cosmic_text::Metrics; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, fmt}; - -use crate::{ContextPage, Message}; pub const CONFIG_VERSION: u64 = 1; -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] -pub enum Action { - CloseFile, - CloseProject, - Copy, - Cut, - Find, - FindAndReplace, - NewFile, - NewWindow, - OpenFileDialog, - OpenProjectDialog, - Paste, - Quit, - Redo, - Save, - SelectAll, - ToggleGitManagement, - ToggleProjectSearch, - ToggleSettingsPage, - ToggleWordWrap, - Undo, -} - -impl Action { - pub fn message(&self) -> Message { - match self { - Self::CloseFile => Message::CloseFile, - Self::CloseProject => Message::CloseProject, - Self::Copy => Message::Copy, - Self::Cut => Message::Cut, - Self::Find => Message::Find(Some(false)), - Self::FindAndReplace => Message::Find(Some(true)), - Self::NewFile => Message::NewFile, - Self::NewWindow => Message::NewWindow, - Self::OpenFileDialog => Message::OpenFileDialog, - Self::OpenProjectDialog => Message::OpenProjectDialog, - Self::Paste => Message::Paste, - Self::Quit => Message::Quit, - Self::Redo => Message::Redo, - Self::Save => Message::Save, - Self::SelectAll => Message::SelectAll, - Self::ToggleGitManagement => Message::ToggleContextPage(ContextPage::GitManagement), - Self::ToggleProjectSearch => Message::ToggleContextPage(ContextPage::ProjectSearch), - Self::ToggleSettingsPage => Message::ToggleContextPage(ContextPage::Settings), - Self::ToggleWordWrap => Message::ToggleWordWrap, - Self::Undo => Message::Undo, - } - } -} - #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum AppTheme { Dark, @@ -81,78 +26,6 @@ impl AppTheme { } } -#[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: Vec, - pub key_code: KeyCode, -} - -impl KeyBind { - //TODO: load from config - pub fn load() -> HashMap { - let mut keybinds = HashMap::new(); - - macro_rules! bind { - ([$($modifier:ident),+ $(,)?], $key_code:ident, $action:ident) => {{ - keybinds.insert( - KeyBind { - modifiers: vec![$(Modifier::$modifier),+], - key_code: KeyCode::$key_code, - }, - Action::$action, - ); - }}; - } - - bind!([Ctrl], W, CloseFile); - bind!([Ctrl], X, Cut); - bind!([Ctrl], C, Copy); - bind!([Ctrl], F, Find); - bind!([Ctrl], H, FindAndReplace); - bind!([Ctrl], V, Paste); - bind!([Ctrl], T, NewFile); - bind!([Ctrl], N, NewWindow); - bind!([Ctrl], O, OpenFileDialog); - bind!([Ctrl, Shift], O, OpenProjectDialog); - bind!([Ctrl], Q, Quit); - bind!([Ctrl, Shift], Z, Redo); - bind!([Ctrl], S, Save); - bind!([Ctrl], A, SelectAll); - bind!([Ctrl, Shift], G, ToggleGitManagement); - bind!([Ctrl, Shift], F, ToggleProjectSearch); - bind!([Ctrl], Comma, ToggleSettingsPage); - bind!([Alt], Z, ToggleWordWrap); - bind!([Ctrl], Z, Undo); - - 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 { - for modifier in self.modifiers.iter() { - write!(f, "{:?} + ", modifier)?; - } - write!(f, "{:?}", self.key_code) - } -} - #[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Config { pub app_theme: AppTheme, @@ -165,7 +38,6 @@ pub struct Config { pub tab_width: u16, pub vim_bindings: bool, pub word_wrap: bool, - pub keybinds: HashMap, } impl Default for Config { @@ -181,7 +53,6 @@ impl Default for Config { tab_width: 4, vim_bindings: false, word_wrap: false, - keybinds: KeyBind::load(), } } } diff --git a/src/key_bind.rs b/src/key_bind.rs new file mode 100644 index 0000000..a36f2e4 --- /dev/null +++ b/src/key_bind.rs @@ -0,0 +1,77 @@ +use cosmic::iced::keyboard::{KeyCode, Modifiers}; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, fmt}; + +use crate::Action; + +#[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: Vec, + pub key_code: KeyCode, +} + +impl KeyBind { + 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 { + for modifier in self.modifiers.iter() { + write!(f, "{:?} + ", modifier)?; + } + write!(f, "{:?}", self.key_code) + } +} + +//TODO: load from config +pub fn key_binds() -> HashMap { + let mut key_binds = HashMap::new(); + + macro_rules! bind { + ([$($modifier:ident),+ $(,)?], $key_code:ident, $action:ident) => {{ + key_binds.insert( + KeyBind { + modifiers: vec![$(Modifier::$modifier),+], + key_code: KeyCode::$key_code, + }, + Action::$action, + ); + }}; + } + + bind!([Ctrl], W, CloseFile); + bind!([Ctrl], X, Cut); + bind!([Ctrl], C, Copy); + bind!([Ctrl], F, Find); + bind!([Ctrl], H, FindAndReplace); + bind!([Ctrl], V, Paste); + bind!([Ctrl], T, NewFile); + bind!([Ctrl], N, NewWindow); + bind!([Ctrl], O, OpenFileDialog); + bind!([Ctrl, Shift], O, OpenProjectDialog); + bind!([Ctrl], Q, Quit); + bind!([Ctrl, Shift], Z, Redo); + bind!([Ctrl], S, Save); + bind!([Ctrl], A, SelectAll); + bind!([Ctrl, Shift], G, ToggleGitManagement); + bind!([Ctrl, Shift], F, ToggleProjectSearch); + bind!([Ctrl], Comma, ToggleSettingsPage); + bind!([Alt], Z, ToggleWordWrap); + bind!([Ctrl], Z, Undo); + + key_binds +} diff --git a/src/main.rs b/src/main.rs index 1cb1680..4960a97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,8 +18,10 @@ use cosmic::{ Application, ApplicationExt, Apply, Element, }; use cosmic_text::{Cursor, Edit, Family, FontSystem, Selection, SwashCache, SyntaxSystem, ViMode}; +use serde::{Deserialize, Serialize}; use std::{ any::TypeId, + collections::HashMap, env, fs, io, path::{Path, PathBuf}, process, @@ -27,7 +29,7 @@ use std::{ }; use tokio::time; -use config::{Action, AppTheme, Config, CONFIG_VERSION}; +use config::{AppTheme, Config, CONFIG_VERSION}; mod config; use git::{GitDiff, GitDiffLine, GitRepository, GitStatus, GitStatusKind}; @@ -36,6 +38,9 @@ mod git; use icon_cache::IconCache; mod icon_cache; +use key_bind::{key_binds, KeyBind}; +mod key_bind; + use line_number::LineNumberCache; mod line_number; @@ -149,6 +154,57 @@ fn main() -> Result<(), Box> { Ok(()) } +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub enum Action { + CloseFile, + CloseProject, + Copy, + Cut, + Find, + FindAndReplace, + NewFile, + NewWindow, + OpenFileDialog, + OpenProjectDialog, + Paste, + Quit, + Redo, + Save, + SelectAll, + ToggleGitManagement, + ToggleProjectSearch, + ToggleSettingsPage, + ToggleWordWrap, + Undo, +} + +impl Action { + pub fn message(&self) -> Message { + match self { + Self::CloseFile => Message::CloseFile, + Self::CloseProject => Message::CloseProject, + Self::Copy => Message::Copy, + Self::Cut => Message::Cut, + Self::Find => Message::Find(Some(false)), + Self::FindAndReplace => Message::Find(Some(true)), + Self::NewFile => Message::NewFile, + Self::NewWindow => Message::NewWindow, + Self::OpenFileDialog => Message::OpenFileDialog, + Self::OpenProjectDialog => Message::OpenProjectDialog, + Self::Paste => Message::Paste, + Self::Quit => Message::Quit, + Self::Redo => Message::Redo, + Self::Save => Message::Save, + Self::SelectAll => Message::SelectAll, + Self::ToggleGitManagement => Message::ToggleContextPage(ContextPage::GitManagement), + Self::ToggleProjectSearch => Message::ToggleContextPage(ContextPage::ProjectSearch), + Self::ToggleSettingsPage => Message::ToggleContextPage(ContextPage::Settings), + Self::ToggleWordWrap => Message::ToggleWordWrap, + Self::Undo => Message::Undo, + } + } +} + #[derive(Clone, Debug)] pub struct Flags { config_handler: Option, @@ -264,6 +320,7 @@ pub struct App { tab_model: segmented_button::SingleSelectModel, config_handler: Option, config: Config, + key_binds: HashMap, app_themes: Vec, font_names: Vec, font_size_names: Vec, @@ -970,6 +1027,7 @@ impl Application for App { tab_model: segmented_button::Model::builder().build(), config_handler: flags.config_handler, config: flags.config, + key_binds: key_binds(), app_themes, font_names, font_size_names, @@ -1281,7 +1339,7 @@ impl Application for App { self.git_project_status = Some(project_status); } Message::Key(modifiers, key_code) => { - for (key_bind, action) in self.config.keybinds.iter() { + for (key_bind, action) in self.key_binds.iter() { if key_bind.matches(modifiers, key_code) { return self.update(action.message()); } @@ -1765,7 +1823,7 @@ impl Application for App { } fn header_start(&self) -> Vec> { - vec![menu_bar(&self.config)] + vec![menu_bar(&self.config, &self.key_binds)] } fn view(&self) -> Element { @@ -1838,7 +1896,7 @@ impl Application for App { text_box = text_box.line_numbers(); } let mut popover = - widget::popover(text_box, menu::context_menu(&self.config, tab_id)); + widget::popover(text_box, menu::context_menu(&self.key_binds, tab_id)); popover = match tab.context_menu { Some(position) => popover.position(position), None => popover.show_popup(false), diff --git a/src/menu.rs b/src/menu.rs index 54fea29..9855529 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -14,8 +14,9 @@ use cosmic::{ }, Element, }; +use std::collections::HashMap; -use crate::{fl, icon_cache_get, Action, Config, ContextPage, Message}; +use crate::{fl, icon_cache_get, Action, Config, ContextPage, KeyBind, Message}; macro_rules! menu_button { ($($x:expr),+ $(,)?) => ( @@ -32,10 +33,13 @@ macro_rules! menu_button { ); } -pub fn context_menu<'a>(config: &Config, entity: segmented_button::Entity) -> Element<'a, Message> { +pub fn context_menu<'a>( + key_binds: &HashMap, + entity: segmented_button::Entity, +) -> Element<'a, Message> { let menu_item = |menu_label, menu_action| { let mut key = String::new(); - for (key_bind, key_action) in config.keybinds.iter() { + for (key_bind, key_action) in key_binds.iter() { if key_action == &menu_action { key = key_bind.to_string(); break; @@ -76,7 +80,7 @@ pub fn context_menu<'a>(config: &Config, entity: segmented_button::Entity) -> El .into() } -pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> { +pub fn menu_bar<'a>(config: &Config, key_binds: &HashMap) -> Element<'a, Message> { //TODO: port to libcosmic let menu_root = |label| { widget::button(widget::text(label)) @@ -89,7 +93,7 @@ pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> { let find_key = |message: &Message| -> String { let mut key = String::new(); - for (key_bind, action) in config.keybinds.iter() { + for (key_bind, action) in key_binds.iter() { if &action.message() == message { key = key_bind.to_string(); break;