// See LICENSE file for copyright and license details. //! Parse the socket info. //! //! For now this module will have 2 methods. One for inmediate execution and //! other for add a bindind. use x11::xlib; use x11::keysym; use command::*; use ::socket::ParsedCmd; use ::socket::FnType; macro_rules! simple_try { ($expr:expr) => (match $expr { Ok(val) => val, Err(err) => { return Err(err) } }) } fn modifier_from<'a>(s: &'a str) -> Result { match s { "Mod1" => Ok(xlib::Mod1Mask), "Mod2" => Ok(xlib::Mod2Mask), "Mod3" => Ok(xlib::Mod3Mask), "Mod4" => Ok(xlib::Mod4Mask), "Control" => Ok(xlib::ControlMask), "Shift" => Ok(xlib::ShiftMask), _ => Err("unknown modifier"), } } fn modifiers<'a>(s: &'a str) -> Result, &'static str> { let mut result = vec![]; for smod in s.split("-") { let modifier = simple_try!(modifier_from(smod)); result.push(modifier); } Ok(result) } fn key<'a>(s: &'a str) -> Result { match s { "a" => Ok(keysym::XK_a), "b" => Ok(keysym::XK_b), "c" => Ok(keysym::XK_c), "d" => Ok(keysym::XK_d), "e" => Ok(keysym::XK_e), "f" => Ok(keysym::XK_f), "g" => Ok(keysym::XK_g), "h" => Ok(keysym::XK_h), "i" => Ok(keysym::XK_i), "j" => Ok(keysym::XK_j), "k" => Ok(keysym::XK_k), "l" => Ok(keysym::XK_l), "m" => Ok(keysym::XK_m), "n" => Ok(keysym::XK_n), "o" => Ok(keysym::XK_o), "p" => Ok(keysym::XK_p), "q" => Ok(keysym::XK_q), "r" => Ok(keysym::XK_r), "s" => Ok(keysym::XK_s), "t" => Ok(keysym::XK_t), "u" => Ok(keysym::XK_u), "v" => Ok(keysym::XK_v), "w" => Ok(keysym::XK_w), "x" => Ok(keysym::XK_x), "y" => Ok(keysym::XK_y), "z" => Ok(keysym::XK_z), "A" => Ok(keysym::XK_A), "B" => Ok(keysym::XK_B), "C" => Ok(keysym::XK_C), "D" => Ok(keysym::XK_D), "E" => Ok(keysym::XK_E), "F" => Ok(keysym::XK_F), "G" => Ok(keysym::XK_G), "H" => Ok(keysym::XK_H), "I" => Ok(keysym::XK_I), "J" => Ok(keysym::XK_J), "K" => Ok(keysym::XK_K), "L" => Ok(keysym::XK_L), "M" => Ok(keysym::XK_M), "N" => Ok(keysym::XK_N), "O" => Ok(keysym::XK_O), "P" => Ok(keysym::XK_P), "Q" => Ok(keysym::XK_Q), "R" => Ok(keysym::XK_R), "S" => Ok(keysym::XK_S), "T" => Ok(keysym::XK_T), "U" => Ok(keysym::XK_U), "V" => Ok(keysym::XK_V), "W" => Ok(keysym::XK_W), "X" => Ok(keysym::XK_X), "Y" => Ok(keysym::XK_Y), "Z" => Ok(keysym::XK_Z), "1" => Ok(keysym::XK_1), "2" => Ok(keysym::XK_2), "Tab" => Ok(keysym::XK_Tab), "Return" => Ok(keysym::XK_Return), _ => Err("unknown key"), } } fn func<'a>(s: &'a str) -> Result { match s { "exec" => Ok(exec), "move-win" => Ok(move_win), "move-win-to" => Ok(move_win_to), "move-win-sticky" => Ok(move_win_sticky), "resize-win" => Ok(resize_win), "resize-win-sticky" => Ok(resize_win_sticky), "focus-next" => Ok(focus_next), "close-win" => Ok(close_win), "fullscreen" => Ok(fullscreen), "change-desktop" => Ok(change_desktop), "quit" => Ok(quit_dotwm), _ => Err("unknown function"), } } pub fn parse<'a>(input: &'a str) -> Result, &'static str> { let args: Vec<&'a str> = input.split_whitespace().collect(); match args.first() { Some(cmd) => { match cmd { &"bind" => { if args.len() > 2 { let modifiers = simple_try!(modifiers(args[1])); let key = simple_try!(key(args[2])); let func = simple_try!(func(args[3])); let arguments: &[&'a str]= &args[4..]; Ok(ParsedCmd { f: FnType::Bind, modifiers: modifiers, key: key, args: arguments.to_vec(), func: func, }) } else { Err("missing arguments") } }, &"exec" => { Ok(ParsedCmd { f: FnType::Exec, modifiers: vec![], key: 0, args: vec![], func: exec }) }, _ => { Err("unknown command") }, } }, None => Err("no input"), } } #[test] fn parse_unknown() { let res = parse("unknown"); if let Err(e) = res { assert_eq!(e, "unknown command"); } else { assert!(false); } } #[test] fn parse_bind_modifier() { let res = parse("bind modifier1 k exec "); if let Err(e) = res { assert_eq!(e, "unknown modifier"); } else { assert!(false); } let res2 = parse("bind Mod4 k exec "); if let Ok(modifier) = res2 { assert_eq!(modifier.modifiers[0], xlib::Mod4Mask); } else { assert!(false); } } #[test] fn parse_bind_key() { let res = parse("bind Mod4 ' exec "); if let Err(e) = res { assert_eq!(e, "unknown key"); } else { assert!(false); } let res2 = parse("bind Mod4 k exec "); if let Ok(modifier) = res2 { assert_eq!(modifier.key, keysym::XK_k); } else { assert!(false); } } #[test] fn parse_exec() { let res = parse("exec Mod4 ' exec "); if let Ok(pcmd) = res { assert_eq!(pcmd.f, FnType::Exec); } else { assert!(false); } }