diff options
author | Jeff Zhao <jeff.no.zhao@gmail.com> | 2021-04-30 11:15:19 -0400 |
---|---|---|
committer | Jeff Zhao <jeff.no.zhao@gmail.com> | 2021-04-30 11:17:48 -0400 |
commit | e17bf9d8cf283aaa02e2cee92331b593aba4b704 (patch) | |
tree | fefa11adb08f065b8029434db4ecb36755c09b51 /src/config/keymap | |
parent | 49758f09f45b39845ede9626fe0ca4f3eedf6698 (diff) |
move more config into their own folders
Diffstat (limited to 'src/config/keymap')
-rw-r--r-- | src/config/keymap/keymapping.rs | 293 | ||||
-rw-r--r-- | src/config/keymap/keyparse.rs | 82 | ||||
-rw-r--r-- | src/config/keymap/mod.rs | 5 |
3 files changed, 380 insertions, 0 deletions
diff --git a/src/config/keymap/keymapping.rs b/src/config/keymap/keymapping.rs new file mode 100644 index 0000000..c3f6ee1 --- /dev/null +++ b/src/config/keymap/keymapping.rs @@ -0,0 +1,293 @@ +use serde_derive::Deserialize; + +use std::collections::{hash_map::Entry, HashMap}; + +#[cfg(feature = "mouse")] +use termion::event::MouseEvent; +use termion::event::{Event, Key}; + +use super::keyparse::str_to_event; +use crate::commands::{CommandKeybind, KeyCommand}; +use crate::config::{parse_to_config_file, ConfigStructure, Flattenable}; +use crate::io::IoWorkerOptions; + +#[derive(Debug, Deserialize)] +struct CommandKeymap { + pub command: String, + pub keys: Vec<String>, +} + +#[derive(Debug, Deserialize)] +struct RawAppKeyMapping { + #[serde(default)] + mapcommand: Vec<CommandKeymap>, +} + +impl Flattenable<AppKeyMapping> for RawAppKeyMapping { + fn flatten(self) -> AppKeyMapping { + let mut keymaps = AppKeyMapping::new(); + for m in self.mapcommand { + match KeyCommand::parse_command(m.command.as_str()) { + Ok(command) => { + let events: Vec<Event> = m + .keys + .iter() + .filter_map(|s| str_to_event(s.as_str())) + .collect(); + + if events.len() != m.keys.len() { + eprintln!("Failed to parse events: {:?}", m.keys); + continue; + } + + let result = insert_keycommand(&mut keymaps, command, &events); + match result { + Ok(_) => {} + Err(e) => eprintln!("{}", e), + } + } + Err(e) => eprintln!("{}", e.cause()), + } + } + keymaps + } +} + +#[derive(Debug)] +pub struct AppKeyMapping { + map: HashMap<Event, CommandKeybind>, +} + +impl std::convert::AsRef<HashMap<Event, CommandKeybind>> for AppKeyMapping { + fn as_ref(&self) -> &HashMap<Event, CommandKeybind> { + &self.map + } +} + +impl std::convert::AsMut<HashMap<Event, CommandKeybind>> for AppKeyMapping { + fn as_mut(&mut self) -> &mut HashMap<Event, CommandKeybind> { + &mut self.map + } +} + +impl AppKeyMapping { + pub fn new() -> Self { + Self { + map: HashMap::new(), + } + } + + pub fn default_res(&mut self) -> Result<(), String> { + let mut m = self; + + let cmd = KeyCommand::CursorMoveUp(1); + let keys = [Event::Key(Key::Up)]; + insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::CursorMoveDown(1); + let keys = [Event::Key(Key::Down)]; + insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::ParentDirectory; + let keys = [Event::Key(Key::Left)]; + insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::OpenFile; + let keys = [Event::Key(Key::Right)]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::OpenFile; + let keys = [Event::Key(Key::Char('\n'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CursorMoveHome; + let keys = [Event::Key(Key::Home)]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CursorMoveEnd; + let keys = [Event::Key(Key::End)]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CursorMovePageUp; + let keys = [Event::Key(Key::PageUp)]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CursorMovePageDown; + let keys = [Event::Key(Key::PageDown)]; + insert_keycommand(&mut m, cmd, &keys)?; + + // vim keys + let cmd = KeyCommand::CursorMoveUp(1); + let keys = [Event::Key(Key::Char('k'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CursorMoveDown(1); + let keys = [Event::Key(Key::Char('j'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::ParentDirectory; + let keys = [Event::Key(Key::Char('h'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::OpenFile; + let keys = [Event::Key(Key::Char('l'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::NewTab; + let keys = [Event::Key(Key::Char('T'))]; + insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::NewTab; + let keys = [Event::Key(Key::Ctrl('t'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CloseTab; + let keys = [Event::Key(Key::Char('W'))]; + insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::CloseTab; + let keys = [Event::Key(Key::Ctrl('w'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CloseTab; + let keys = [Event::Key(Key::Char('q'))]; + insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::ForceQuit; + let keys = [Event::Key(Key::Char('Q'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::ReloadDirList; + let keys = [Event::Key(Key::Char('R'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::ToggleHiddenFiles; + let keys = [Event::Key(Key::Char('z')), Event::Key(Key::Char('h'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::TabSwitch(1); + let keys = [Event::Key(Key::Char('\t'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::TabSwitch(-1); + let keys = [Event::Key(Key::BackTab)]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::OpenFileWith; + let keys = [Event::Key(Key::Char('r'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CutFiles; + let keys = [Event::Key(Key::Char('d')), Event::Key(Key::Char('d'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CopyFiles; + let keys = [Event::Key(Key::Char('y')), Event::Key(Key::Char('y'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::PasteFiles(IoWorkerOptions::default()); + let keys = [Event::Key(Key::Char('p')), Event::Key(Key::Char('p'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::DeleteFiles; + let keys = [Event::Key(Key::Delete)]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::DeleteFiles; + let keys = [Event::Key(Key::Char('D')), Event::Key(Key::Char('d'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::RenameFileAppend; + let keys = [Event::Key(Key::Char('a'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::RenameFilePrepend; + let keys = [Event::Key(Key::Char('A'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CommandLine("search ".to_string(), "".to_string()); + let keys = [Event::Key(Key::Char('/'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::SearchNext; + let keys = [Event::Key(Key::Char('n'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::SearchPrev; + let keys = [Event::Key(Key::Char('N'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::BulkRename; + let keys = [Event::Key(Key::Char('b')), Event::Key(Key::Char('b'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::SetMode; + let keys = [Event::Key(Key::Char('='))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CommandLine("".to_string(), "".to_string()); + let keys = [Event::Key(Key::Char(';'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CommandLine("mkdir ".to_string(), "".to_string()); + let keys = [Event::Key(Key::Char('m')), Event::Key(Key::Char('k'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + let cmd = KeyCommand::CommandLine("rename ".to_string(), "".to_string()); + let keys = [Event::Key(Key::Char('c')), Event::Key(Key::Char('w'))]; + insert_keycommand(&mut m, cmd, &keys)?; + + Ok(()) + } +} + +impl std::default::Default for AppKeyMapping { + fn default() -> Self { + let mut m = Self { + map: HashMap::new(), + }; + let _ = m.default_res(); + m + } +} + +impl ConfigStructure for AppKeyMapping { + fn get_config(file_name: &str) -> Self { + parse_to_config_file::<RawAppKeyMapping, AppKeyMapping>(file_name) + .unwrap_or_else(Self::default) + } +} + +fn insert_keycommand( + keymap: &mut AppKeyMapping, + keycommand: KeyCommand, + events: &[Event], +) -> Result<(), String> { + let num_events = events.len(); + if num_events == 0 { + return Ok(()); + } + + let event = events[0].clone(); + if num_events == 1 { + match keymap.as_mut().entry(event) { + Entry::Occupied(_) => { + return Err(format!("Error: Keybindings ambiguous for {}", keycommand)) + } + Entry::Vacant(entry) => entry.insert(CommandKeybind::SimpleKeybind(keycommand)), + }; + return Ok(()); + } + + match keymap.as_mut().entry(event) { + Entry::Occupied(mut entry) => match entry.get_mut() { + CommandKeybind::CompositeKeybind(ref mut m) => { + insert_keycommand(m, keycommand, &events[1..]) + } + _ => Err(format!("Error: Keybindings ambiguous for {}", keycommand)), + }, + Entry::Vacant(entry) => { + let mut new_map = AppKeyMapping::new(); + let result = insert_keycommand(&mut new_map, keycommand, &events[1..]); + if result.is_ok() { + let composite_command = CommandKeybind::CompositeKeybind(new_map); + entry.insert(composite_command); + } + result + } + } +} diff --git a/src/config/keymap/keyparse.rs b/src/config/keymap/keyparse.rs new file mode 100644 index 0000000..de1e0dd --- /dev/null +++ b/src/config/keymap/keyparse.rs @@ -0,0 +1,82 @@ +use termion::event::{Event, Key, MouseButton, MouseEvent}; + +pub fn str_to_event(s: &str) -> Option<Event> { + if let Some(k) = str_to_key(s) { + Some(Event::Key(k)) + } else if let Some(m) = str_to_mouse(s) { + Some(Event::Mouse(m)) + } else { + None + } +} + +pub fn str_to_key(s: &str) -> Option<Key> { + if s.is_empty() { + return None; + } + + let key = match s { + "backspace" => Some(Key::Backspace), + "backtab" => Some(Key::BackTab), + "left" => Some(Key::Left), + "right" => Some(Key::Right), + "up" => Some(Key::Up), + "down" => Some(Key::Down), + "home" => Some(Key::Home), + "end" => Some(Key::End), + "page_up" => Some(Key::PageUp), + "page_down" => Some(Key::PageDown), + "delete" => Some(Key::Delete), + "insert" => Some(Key::Insert), + "escape" => Some(Key::Esc), + "f1" => Some(Key::F(1)), + "f2" => Some(Key::F(2)), + "f3" => Some(Key::F(3)), + "f4" => Some(Key::F(4)), + "f5" => Some(Key::F(5)), + "f6" => Some(Key::F(6)), + "f7" => Some(Key::F(7)), + "f8" => Some(Key::F(8)), + "f9" => Some(Key::F(9)), + "f10" => Some(Key::F(10)), + "f11" => Some(Key::F(11)), + "f12" => Some(Key::F(12)), + _ => None, + }; + + if key.is_some() { + return key; + } + + if s.starts_with("ctrl+") { + let ch = s.chars().nth("ctrl+".len()); + let key = match ch { + Some(ch) => Some(Key::Ctrl(ch)), + None => None, + }; + return key; + } else if s.starts_with("alt+") { + let ch = s.chars().nth("alt+".len()); + let key = match ch { + Some(ch) => Some(Key::Alt(ch)), + None => None, + }; + return key; + } else if s.len() == 1 { + let ch = s.chars().next(); + let key = match ch { + Some(ch) => Some(Key::Char(ch)), + None => None, + }; + return key; + } + None +} + +pub fn str_to_mouse(s: &str) -> Option<MouseEvent> { + match s { + "scroll_up" => Some(MouseEvent::Press(MouseButton::WheelUp, 0, 0)), + "scroll_down" => Some(MouseEvent::Press(MouseButton::WheelDown, 0, 0)), + _ => None, + } +} diff --git a/src/config/keymap/mod.rs b/src/config/keymap/mod.rs new file mode 100644 index 0000000..a224626 --- /dev/null +++ b/src/config/keymap/mod.rs @@ -0,0 +1,5 @@ +pub mod keyparse; + +mod keymapping; + +pub use self::keymapping::AppKeyMapping; |