summaryrefslogtreecommitdiffstats
path: root/src/config/keymap
diff options
context:
space:
mode:
authorJeff Zhao <jeff.no.zhao@gmail.com>2021-04-30 11:15:19 -0400
committerJeff Zhao <jeff.no.zhao@gmail.com>2021-04-30 11:17:48 -0400
commite17bf9d8cf283aaa02e2cee92331b593aba4b704 (patch)
treefefa11adb08f065b8029434db4ecb36755c09b51 /src/config/keymap
parent49758f09f45b39845ede9626fe0ca4f3eedf6698 (diff)
move more config into their own folders
Diffstat (limited to 'src/config/keymap')
-rw-r--r--src/config/keymap/keymapping.rs293
-rw-r--r--src/config/keymap/keyparse.rs82
-rw-r--r--src/config/keymap/mod.rs5
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;