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"
This commit is contained in:
Marcin Sobczyk
2020-03-30 09:41:52 +02:00
committed by Henrik Friedrichsen
parent 1b0ac4d5cc
commit 07be9dc48d
4 changed files with 89 additions and 48 deletions

View File

@@ -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<i32>),
Move(MoveMode, MoveAmount),
Shift(ShiftMode, Option<i32>),
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<Command> {
.map(|mode| Command::Shift(mode, amount))
}
"move" => {
let amount = args.get(1).and_then(|amount| amount.parse().ok());
let cmd: Option<Command> = {
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)

View File

@@ -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));

View File

@@ -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<I: ListItem + Clone> ViewExt for ListView<I> {
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);
}

View File

@@ -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<CommandResult, String> {
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));
}
_ => {}