diff --git a/src/command.rs b/src/command.rs index 2eb8697..85d7f7f 100644 --- a/src/command.rs +++ b/src/command.rs @@ -28,6 +28,19 @@ pub enum MoveMode { Right, } +#[derive(Display, Clone, Serialize, Deserialize, Debug)] +#[strum(serialize_all = "lowercase")] +pub enum MoveAmount { + Integer(i32), + Extreme, +} + +impl Default for MoveAmount { + fn default() -> Self { + MoveAmount::Integer(1) + } +} + #[derive(Display, Clone, Serialize, Deserialize, Debug)] #[strum(serialize_all = "lowercase")] pub enum ShiftMode { @@ -84,7 +97,7 @@ pub enum Command { Back, Open(TargetMode), Goto(GotoMode), - Move(MoveMode, Option), + Move(MoveMode, MoveAmount), Shift(ShiftMode, Option), Search(String), Help, @@ -124,7 +137,15 @@ impl fmt::Display for Command { Command::Back => "back".to_string(), Command::Open(mode) => format!("open {}", mode), Command::Goto(mode) => format!("goto {}", mode), - Command::Move(mode, amount) => format!("move {} {}", mode, amount.unwrap_or(1)), + Command::Move(mode, MoveAmount::Extreme) => { + format!("move {}", match mode { + MoveMode::Up => "top", + MoveMode::Down => "bottom", + MoveMode::Left => "leftmost", + MoveMode::Right => "rightmost", + }) + }, + Command::Move(mode, MoveAmount::Integer(amount)) => format!("move {} {}", mode, amount), Command::Shift(mode, amount) => format!("shift {} {}", mode, amount.unwrap_or(1)), Command::Search(term) => format!("search {}", term), Command::Help => "help".to_string(), @@ -207,17 +228,33 @@ pub fn parse(input: &str) -> Option { .map(|mode| Command::Shift(mode, amount)) } "move" => { - let amount = args.get(1).and_then(|amount| amount.parse().ok()); + let cmd: Option = { + args.get(0) + .and_then(|extreme| match *extreme { + "top" => Some(Command::Move(MoveMode::Up, MoveAmount::Extreme)), + "bottom" => Some(Command::Move(MoveMode::Down, MoveAmount::Extreme)), + "leftmost" => Some(Command::Move(MoveMode::Left, MoveAmount::Extreme)), + "rightmost" => Some(Command::Move(MoveMode::Right, MoveAmount::Extreme)), + _ => None + }) + }; - 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)) + cmd.or({ + let amount = args.get(1) + .and_then(|amount| amount.parse().ok()) + .map(|amount| MoveAmount::Integer(amount)) + .unwrap_or_default(); + + 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) diff --git a/src/commands.rs b/src/commands.rs index d46f36c..d4f4732 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use crate::command::{parse, Command, GotoMode, MoveMode, SeekDirection, ShiftMode, TargetMode}; +use crate::command::{parse, Command, GotoMode, MoveAmount, MoveMode, SeekDirection, ShiftMode, TargetMode}; use crate::library::Library; use crate::queue::{Queue, RepeatSetting}; use crate::spotify::{Spotify, VOLUME_PERCENT}; @@ -262,21 +262,23 @@ impl CommandManager { kb.insert("a".into(), Command::Goto(GotoMode::Album)); kb.insert("A".into(), Command::Goto(GotoMode::Artist)); - kb.insert("Up".into(), Command::Move(MoveMode::Up, None)); - kb.insert("Down".into(), Command::Move(MoveMode::Down, None)); - kb.insert("Left".into(), Command::Move(MoveMode::Left, None)); - kb.insert("Right".into(), Command::Move(MoveMode::Right, None)); - kb.insert("PageUp".into(), Command::Move(MoveMode::Up, Some(5))); - kb.insert("PageDown".into(), Command::Move(MoveMode::Down, Some(5))); - kb.insert("k".into(), Command::Move(MoveMode::Up, None)); - kb.insert("j".into(), Command::Move(MoveMode::Down, None)); - kb.insert("h".into(), Command::Move(MoveMode::Left, None)); - kb.insert("l".into(), Command::Move(MoveMode::Right, None)); + kb.insert("Up".into(), Command::Move(MoveMode::Up, Default::default())); + kb.insert("Down".into(), Command::Move(MoveMode::Down, Default::default())); + kb.insert("Left".into(), Command::Move(MoveMode::Left, Default::default())); + kb.insert("Right".into(), Command::Move(MoveMode::Right, Default::default())); + kb.insert("PageUp".into(), Command::Move(MoveMode::Up, MoveAmount::Integer(5))); + kb.insert("PageDown".into(), Command::Move(MoveMode::Down, MoveAmount::Integer(5))); + kb.insert("Home".into(), Command::Move(MoveMode::Up, MoveAmount::Extreme)); + kb.insert("End".into(), Command::Move(MoveMode::Down, MoveAmount::Extreme)); + kb.insert("k".into(), Command::Move(MoveMode::Up, Default::default())); + kb.insert("j".into(), Command::Move(MoveMode::Down, Default::default())); + kb.insert("h".into(), Command::Move(MoveMode::Left, Default::default())); + kb.insert("l".into(), Command::Move(MoveMode::Right, Default::default())); - kb.insert("Ctrl+p".into(), Command::Move(MoveMode::Up, None)); - kb.insert("Ctrl+n".into(), Command::Move(MoveMode::Down, None)); - kb.insert("Ctrl+a".into(), Command::Move(MoveMode::Left, None)); - kb.insert("Ctrl+e".into(), Command::Move(MoveMode::Right, None)); + kb.insert("Ctrl+p".into(), Command::Move(MoveMode::Up, Default::default())); + kb.insert("Ctrl+n".into(), Command::Move(MoveMode::Down, Default::default())); + kb.insert("Ctrl+a".into(), Command::Move(MoveMode::Left, Default::default())); + kb.insert("Ctrl+e".into(), Command::Move(MoveMode::Right, Default::default())); kb.insert("Shift+Up".into(), Command::Shift(ShiftMode::Up, None)); kb.insert("Shift+Down".into(), Command::Shift(ShiftMode::Down, None)); diff --git a/src/ui/listview.rs b/src/ui/listview.rs index 4d2b37d..5855cd1 100644 --- a/src/ui/listview.rs +++ b/src/ui/listview.rs @@ -9,7 +9,7 @@ use cursive::view::ScrollBase; use cursive::{Cursive, Printer, Rect, Vec2}; use unicode_width::UnicodeWidthStr; -use crate::command::{Command, GotoMode, MoveMode, TargetMode}; +use crate::command::{Command, GotoMode, MoveAmount, MoveMode, TargetMode}; use crate::commands::CommandResult; use crate::library::Library; use crate::queue::Queue; @@ -359,24 +359,25 @@ impl ViewExt for ListView { return Ok(CommandResult::Consumed(None)); } Command::Move(mode, amount) => { - let amount = match amount { - Some(amount) => *amount, - _ => 1, - }; - - let len = self.content.read().unwrap().len(); + let last_idx = self.content.read().unwrap().len().saturating_sub(1); match mode { MoveMode::Up if self.selected > 0 => { - self.move_focus(-(amount as i32)); + match amount { + MoveAmount::Extreme => self.move_focus_to(0), + MoveAmount::Integer(amount) => self.move_focus(-(*amount)), + } return Ok(CommandResult::Consumed(None)); } - MoveMode::Down if self.selected < len.saturating_sub(1) => { - self.move_focus(amount as i32); + MoveMode::Down if self.selected < last_idx => { + match amount { + MoveAmount::Extreme => self.move_focus_to(last_idx), + MoveAmount::Integer(amount) => self.move_focus(*amount), + } return Ok(CommandResult::Consumed(None)); } MoveMode::Down - if self.selected == len.saturating_sub(1) && self.can_paginate() => + if self.selected == last_idx && self.can_paginate() => { self.pagination.call(&self.content); } diff --git a/src/ui/tabview.rs b/src/ui/tabview.rs index 0721998..ef99ec8 100644 --- a/src/ui/tabview.rs +++ b/src/ui/tabview.rs @@ -7,7 +7,7 @@ use cursive::traits::View; use cursive::{Cursive, Printer, Vec2}; use unicode_width::UnicodeWidthStr; -use crate::command::{Command, MoveMode}; +use crate::command::{Command, MoveAmount, MoveMode}; use crate::commands::CommandResult; use crate::traits::{IntoBoxedViewExt, ViewExt}; @@ -105,20 +105,21 @@ impl View for TabView { impl ViewExt for TabView { fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result { if let Command::Move(mode, amount) = cmd { - let amount = match amount { - Some(amount) => *amount, - _ => 1, - }; - - let len = self.tabs.len(); + let last_idx = self.tabs.len() - 1; match mode { MoveMode::Left if self.selected > 0 => { - self.move_focus(-(amount as i32)); + match amount { + MoveAmount::Extreme => self.move_focus_to(0), + MoveAmount::Integer(amount) => self.move_focus(-(*amount)), + } return Ok(CommandResult::Consumed(None)); } - MoveMode::Right if self.selected < len - 1 => { - self.move_focus(amount as i32); + MoveMode::Right if self.selected < last_idx => { + match amount { + MoveAmount::Extreme => self.move_focus_to(last_idx), + MoveAmount::Integer(amount) => self.move_focus(*amount), + } return Ok(CommandResult::Consumed(None)); } _ => {}