From db7a09c87bcbb3b27450c7f6a370b51951b11eb3 Mon Sep 17 00:00:00 2001 From: Rasmus Larsen Date: Tue, 21 May 2019 18:11:54 +0200 Subject: [PATCH] Command parser --- src/command.rs | 151 +++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 9 +-- src/ui/queue.rs | 3 +- 3 files changed, 156 insertions(+), 7 deletions(-) diff --git a/src/command.rs b/src/command.rs index 2ce5f0c..9a8c3bd 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,4 +1,6 @@ use queue::RepeatSetting; +use std::collections::HashMap; +use std::iter::FromIterator; #[derive(Clone, Serialize, Deserialize, Debug)] pub enum PlaylistCommands { @@ -66,7 +68,152 @@ pub enum Command { Back, Open, Goto(GotoMode), - Move(MoveMode, Option), - Shift(ShiftMode, Option), + Move(MoveMode, Option), + Shift(ShiftMode, Option), Search(String), } + +fn register_aliases(map: &mut HashMap<&str, &str>, cmd: &'static str, names: Vec<&'static str>) { + for a in names { + map.insert(a, cmd); + } +} + +lazy_static! { + static ref ALIASES: HashMap<&'static str, &'static str> = { + let mut m = HashMap::new(); + + register_aliases(&mut m, "quit", vec!["q", "x"]); + register_aliases( + &mut m, + "playpause", + vec!["pause", "toggleplay", "toggleplayback"], + ); + register_aliases(&mut m, "repeat", vec!["loop"]); + + m.insert("1", "foo"); + m.insert("2", "bar"); + m.insert("3", "baz"); + m + }; +} + +fn handle_aliases(input: &str) -> &str { + if let Some(cmd) = ALIASES.get(input) { + handle_aliases(cmd) + } else { + input + } +} + +pub fn parse(input: &str) -> Option { + let components: Vec<_> = input.trim().split(' ').collect(); + + let command = handle_aliases(&components[0]); + let args = components[1..].to_vec(); + + match command { + "quit" => Some(Command::Quit), + "playpause" => Some(Command::TogglePlay), + "stop" => Some(Command::Stop), + "previous" => Some(Command::Previous), + "next" => Some(Command::Next), + "clear" => Some(Command::Clear), + "queue" => Some(Command::Queue), + "play" => Some(Command::Play), + "delete" => Some(Command::Delete), + "back" => Some(Command::Back), + "open" => Some(Command::Open), + "search" => args.get(0).map(|query| Command::Search(query.to_string())), + "shift" => { + let amount = args.get(1).and_then(|amount| amount.parse().ok()); + + args.get(0) + .and_then(|direction| match *direction { + "up" => Some(ShiftMode::Up), + "down" => Some(ShiftMode::Down), + _ => None, + }) + .map(|mode| Command::Shift(mode, amount)) + } + "move" => { + let amount = args.get(1).and_then(|amount| amount.parse().ok()); + + args.get(0) + .and_then(|direction| match *direction { + "up" => Some(MoveMode::Up), + "down" => Some(MoveMode::Down), + "left" => Some(MoveMode::Left), + "right" => Some(MoveMode::Right), + _ => None, + }) + .map(|mode| Command::Move(mode, amount)) + } + "goto" => args + .get(0) + .and_then(|mode| match *mode { + "album" => Some(GotoMode::Album), + "artist" => Some(GotoMode::Artist), + _ => None, + }) + .map(Command::Goto), + "share" => args + .get(0) + .and_then(|target| match *target { + "selected" => Some(TargetMode::Selected), + "current" => Some(TargetMode::Current), + _ => None, + }) + .map(Command::Share), + "shuffle" => { + let shuffle = args.get(0).and_then(|mode| match *mode { + "on" => Some(true), + "off" => Some(false), + _ => None, + }); + + Some(Command::Shuffle(shuffle)) + } + "repeat" => { + let mode = args.get(0).and_then(|mode| match *mode { + "list" | "playlist" | "queue" => Some(RepeatSetting::RepeatPlaylist), + "track" | "once" => Some(RepeatSetting::RepeatTrack), + "none" | "off" => Some(RepeatSetting::None), + _ => None, + }); + + Some(Command::Repeat(mode)) + } + "seek" => args.get(0).and_then(|arg| match arg.chars().nth(0) { + Some(x) if x == '-' || x == '+' => String::from_iter(arg.chars().skip(1)) + .parse::() + .ok() + .map(|amount| { + Command::Seek(SeekDirection::Relative( + amount + * match x { + '-' => -1, + _ => 1, + }, + )) + }), + _ => String::from_iter(arg.chars()) + .parse() + .ok() + .map(|amount| Command::Seek(SeekDirection::Absolute(amount))), + }), + "focus" => args.get(0).map(|target| Command::Focus(target.to_string())), + "playlists" => args + .get(0) + .and_then(|action| match *action { + "update" => Some(PlaylistCommands::Update), + _ => None, + }) + .map(Command::Playlists), + "save" => args.get(0).map(|target| match *target { + "queue" => Command::SaveQueue, + _ => Command::Save, + }), + _ => None, + } +} diff --git a/src/main.rs b/src/main.rs index 77bef0e..620ca83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -233,8 +233,6 @@ fn main() { }); }); - /* - TODO: Write parser for commands { let ev = event_manager.clone(); let cmd_manager = cmd_manager.clone(); @@ -243,11 +241,14 @@ fn main() { let mut main = s.find_id::("main").unwrap(); main.clear_cmdline(); } - cmd_manager.handle(s, cmd.to_string()[1..].to_string()); + let c = &cmd[1..]; + let parsed = command::parse(c); + if let Some(parsed) = parsed { + cmd_manager.handle(s, parsed); + } ev.trigger(); }); } - */ cursive.add_fullscreen_layer(layout.with_id("main")); diff --git a/src/ui/queue.rs b/src/ui/queue.rs index 17e872a..cad090d 100644 --- a/src/ui/queue.rs +++ b/src/ui/queue.rs @@ -113,7 +113,8 @@ impl ViewExt for QueueView { match mode { ShiftMode::Up if selected > 0 => { - self.queue.shift(selected, selected.saturating_sub(amount)); + self.queue + .shift(selected, (selected as i32).saturating_sub(amount) as usize); self.list.move_focus(-(amount as i32)); return Ok(CommandResult::Consumed(None)); }