From 07be9dc48d0172b8566f2adc1e5c093d05274138 Mon Sep 17 00:00:00 2001 From: Marcin Sobczyk Date: Mon, 30 Mar 2020 09:41:52 +0200 Subject: [PATCH] Command::Move: Add support for extreme moves This patch adds a 'MoveAmount' enum that permits movements by integer values or to abstract extremes which loosely translate to "top" for up direction, "bottom" for down direction, etc. The goal behind the effort is to add support for buttons like "Home" and "End". The new enum has a 'Default' impl that yields a value of integer movement by 1 field. This replaces the previous 'Option' wrap, that in fact served the same purpose, with the value of '1' scattered around different places in code. Along with the enum, new commands have been defined to make use of it: - "move top" - "move bottom" - "move leftmost" - "move rightmost" --- src/command.rs | 61 +++++++++++++++++++++++++++++++++++++--------- src/commands.rs | 32 ++++++++++++------------ src/ui/listview.rs | 23 ++++++++--------- src/ui/tabview.rs | 21 ++++++++-------- 4 files changed, 89 insertions(+), 48 deletions(-) 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)); } _ => {}