diff --git a/Cargo.toml b/Cargo.toml index e1e498d7..ef9ee7c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ authors = ["Mark Wallace "] [dependencies] libc = "*" ncurses = "*" +getopts = "0.2" diff --git a/src/event.rs b/src/event.rs index 010832da..a4040f18 100644 --- a/src/event.rs +++ b/src/event.rs @@ -54,3 +54,44 @@ pub enum Event { EvActUp, EvActYank, } + +pub fn parse_action(action: &str) -> Option { + match action { + "abort" => Some(Event::EvActAbort), + "accept" => Some(Event::EvActAccept), + "backward-char" => Some(Event::EvActBackwardChar), + "backward-delete-char" => Some(Event::EvActBackwardDeleteChar), + "backward-kill-word" => Some(Event::EvActBackwardKillWord), + "backward-word" => Some(Event::EvActBackwardWord), + "beginning-of-line" => Some(Event::EvActBeginningOfLine), + "cancel" => Some(Event::EvActCancel), + "clear-screen" => Some(Event::EvActClearScreen), + "delete-char" => Some(Event::EvActDeleteChar), + "delete-charEOF" => Some(Event::EvActDeleteCharEOF), + "deselect-all" => Some(Event::EvActDeselectAll), + "down" => Some(Event::EvActDown), + "end-of-line" => Some(Event::EvActEndOfLine), + "forward-char" => Some(Event::EvActForwardChar), + "forward-word" => Some(Event::EvActForwardWord), + "ignore" => Some(Event::EvActIgnore), + "kill-line" => Some(Event::EvActKillLine), + "kill-word" => Some(Event::EvActKillWord), + "next-history" => Some(Event::EvActNextHistory), + "page-down" => Some(Event::EvActPageDown), + "page-up" => Some(Event::EvActPageUp), + "previous-history" => Some(Event::EvActPreviousHistory), + "select-all" => Some(Event::EvActSelectAll), + "toggle" => Some(Event::EvActToggle), + "toggle-all" => Some(Event::EvActToggleAll), + "toggle-down" => Some(Event::EvActToggleDown), + "toggle-in" => Some(Event::EvActToggleIn), + "toggle-out" => Some(Event::EvActToggleOut), + "toggle-sort" => Some(Event::EvActToggleSort), + "toggle-up" => Some(Event::EvActToggleUp), + "unix-line-discard" => Some(Event::EvActUnixLineDiscard), + "unix-word-rubout" => Some(Event::EvActUnixWordRubout), + "up" => Some(Event::EvActUp), + "yank" => Some(Event::EvActYank), + _ => None + } +} diff --git a/src/input.rs b/src/input.rs index d742127e..b25a5f9d 100644 --- a/src/input.rs +++ b/src/input.rs @@ -11,7 +11,7 @@ use std::collections::VecDeque; use std::time::Duration; use util::eventbox::EventBox; -use event::Event; +use event::{Event, parse_action}; use ncurses::*; @@ -52,6 +52,33 @@ impl Input { } } } + + pub fn bind(&mut self, key: &str, action: &str) { + let key = parse_key(key); + let action = parse_action(action); + if key == None || action == None {return;} + + let key = key.unwrap(); + let act = action.unwrap(); + + // remove the key for existing keymap; + let _ = self.keymap.remove(&key); + self.keymap.entry(key).or_insert(act); + } + + // keymap is comma separated: 'ctrl-j:accept,ctrl-k:kill-line' + pub fn parse_keymap(&mut self, keymap: Option) { + if let Some(key_action) = keymap { + for pair in key_action.split(',') { + let vec: Vec<&str> = pair.split(':').collect(); + if vec.len() != 2 { + continue; + } else { + self.bind(vec[0], vec[1]); + } + } + } + } } struct KeyBoard { @@ -268,32 +295,8 @@ impl KeyBoard { #[derive(Eq, PartialEq, Hash, Debug)] pub enum Key { - CtrlA, - CtrlB, - CtrlC, - CtrlD, - CtrlE, - CtrlF, - CtrlG, - CtrlH, - Tab, - CtrlJ, - CtrlK, - CtrlL, - Enter, - CtrlN, - CtrlO, - CtrlP, - CtrlQ, - CtrlR, - CtrlS, - CtrlT, - CtrlU, - CtrlV, - CtrlW, - CtrlX, - CtrlY, - CtrlZ, + CtrlA, CtrlB, CtrlC, CtrlD, CtrlE, CtrlF, CtrlG, CtrlH, Tab, CtrlJ, CtrlK, CtrlL, Enter, + CtrlN, CtrlO, CtrlP, CtrlQ, CtrlR, CtrlS, CtrlT, CtrlU, CtrlV, CtrlW, CtrlX, CtrlY, CtrlZ, ESC, Mouse, @@ -314,35 +317,106 @@ pub enum Key { AltSpace, AltSlash, AltBS, - AltA, - AltB, - AltC, - AltD, - AltE, - AltF, - AltG, - AltH, - AltI, - AltJ, - AltK, - AltL, - AltM, - AltN, - AltO, - AltP, - AltQ, - AltR, - AltS, - AltT, - AltU, - AltV, - AltW, - AltX, - AltY, - AltZ, + + AltA, AltB, AltC, AltD, AltE, AltF, AltG, AltH, AltI, AltJ, AltK, AltL, AltM, + AltN, AltO, AltP, AltQ, AltR, AltS, AltT, AltU, AltV, AltW, AltX, AltY, AltZ, Char(char), } +pub fn parse_key(key: &str) -> Option { + match key { + "ctrl-a" => Some(Key::CtrlA), + "ctrl-b" => Some(Key::CtrlB), + "ctrl-c" => Some(Key::CtrlC), + "ctrl-d" => Some(Key::CtrlD), + "ctrl-e" => Some(Key::CtrlE), + "ctrl-f" => Some(Key::CtrlF), + "ctrl-g" => Some(Key::CtrlG), + "ctrl-h" => Some(Key::CtrlH), + "tab" | "ctrl-i" => Some(Key::Tab), + "ctrl-j" => Some(Key::CtrlJ), + "ctrl-k" => Some(Key::CtrlK), + "ctrl-l" => Some(Key::CtrlL), + "enter" | "return" | "ctrl-m" => Some(Key::Enter), + "ctrl-n" => Some(Key::CtrlN), + "ctrl-o" => Some(Key::CtrlO), + "ctrl-p" => Some(Key::CtrlP), + "ctrl-q" => Some(Key::CtrlQ), + "ctrl-r" => Some(Key::CtrlR), + "ctrl-s" => Some(Key::CtrlS), + "ctrl-t" => Some(Key::CtrlT), + "ctrl-u" => Some(Key::CtrlU), + "ctrl-v" => Some(Key::CtrlV), + "ctrl-w" => Some(Key::CtrlW), + "ctrl-x" => Some(Key::CtrlX), + "ctrl-y" => Some(Key::CtrlY), + "ctrl-z" => Some(Key::CtrlZ), + + "esc" => Some(Key::ESC), + "mouse" => Some(Key::Mouse), + "doubleclick" => Some(Key::DoubleClick), + "btab" | "shift-tab" => Some(Key::BTab), + "bspace" | "bs" => Some(Key::BSpace), + "del" => Some(Key::Del), + "pgup" | "page-up" => Some(Key::PgUp), + "pgdn" | "page-down" => Some(Key::PgDn), + "up" => Some(Key::Up), + "down" => Some(Key::Down), + "left" => Some(Key::Left), + "right" => Some(Key::Right), + "home" => Some(Key::Home), + "end" => Some(Key::End), + "shift-left" => Some(Key::SLeft), + "shift-right" => Some(Key::SRight), + + "f1" => Some(Key::F1), + "f2" => Some(Key::F2), + "f3" => Some(Key::F3), + "f4" => Some(Key::F4), + "f5" => Some(Key::F5), + "f6" => Some(Key::F6), + "f7" => Some(Key::F7), + "f8" => Some(Key::F8), + "f9" => Some(Key::F9), + "f10" => Some(Key::F10), + "f11" => Some(Key::F11), + "f12" => Some(Key::F12), + + "altenter" => Some(Key::AltEnter), + "altspace" => Some(Key::AltSpace), + "altslash" => Some(Key::AltSlash), + "alt-bs" | "alt-bspace" => Some(Key::AltBS), + + "alt-a" => Some(Key::AltA), + "alt-b" => Some(Key::AltB), + "alt-c" => Some(Key::AltC), + "alt-d" => Some(Key::AltD), + "alt-e" => Some(Key::AltE), + "alt-f" => Some(Key::AltF), + "alt-g" => Some(Key::AltG), + "alt-h" => Some(Key::AltH), + "alt-i" => Some(Key::AltI), + "alt-j" => Some(Key::AltJ), + "alt-k" => Some(Key::AltK), + "alt-l" => Some(Key::AltL), + "alt-m" => Some(Key::AltM), + "alt-n" => Some(Key::AltN), + "alt-o" => Some(Key::AltO), + "alt-p" => Some(Key::AltP), + "alt-q" => Some(Key::AltQ), + "alt-r" => Some(Key::AltR), + "alt-s" => Some(Key::AltS), + "alt-t" => Some(Key::AltT), + "alt-u" => Some(Key::AltU), + "alt-v" => Some(Key::AltV), + "alt-w" => Some(Key::AltW), + "alt-x" => Some(Key::AltX), + "alt-y" => Some(Key::AltY), + "alt-z" => Some(Key::AltZ), + _ => None, + } +} + fn get_default_key_map() -> HashMap { let mut ret = HashMap::new(); ret.insert(Key::ESC, Event::EvActAbort); @@ -407,3 +481,4 @@ fn get_default_key_map() -> HashMap { ret.insert(Key::CtrlY, Event::EvActYank); ret } + diff --git a/src/main.rs b/src/main.rs index a63c15a8..40192106 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(io)] extern crate libc; extern crate ncurses; +extern crate getopts; mod util; mod item; mod reader; @@ -29,9 +30,30 @@ use matcher::Matcher; use model::Model; use libc::{sigemptyset, sigaddset, sigwait, pthread_sigmask}; use curses::{ColorTheme, Curses}; +use getopts::Options; +use std::env; fn main() { + // option parsing + let args: Vec = env::args().collect(); + let program = args[0].clone(); + + let mut opts = Options::new(); + opts.optopt("b", "bind", "comma seperated keybindings", "ctrl-j:accept,ctrl-k:kill-line"); + opts.optflag("h", "help", "print this help menu"); + + let options = match opts.parse(&args[1..]) { + Ok(m) => { m } + Err(f) => { panic!(f.to_string()) } + }; + + // print help message + if options.opt_present("h") { + print_usage(&program, opts); + return + } + let theme = curses::ColorTheme::new(); let mut curse = Curses::new(); curse.init(Some(&theme), false, false); @@ -54,6 +76,7 @@ fn main() { let eb_clone_input = eb.clone(); let mut input = Input::new(eb_clone_input); + input.parse_keymap(options.opt_str("b")); // register terminal resize event, `pthread_sigmask` should be run before any thread. let mut sigset = unsafe {mem::uninitialized()}; @@ -192,3 +215,8 @@ fn main() { endwin(); model.output(); } + +fn print_usage(program: &str, opts: Options) { + let brief = format!("Usage: {} [options]", program); + print!("{}", opts.usage(&brief)); +}