Added autcompletions.
Description: - Added autocompletions for some shells. - Fixed styles. - Fixed possible bugs with clippy. Signed-off-by: Pavel Kirilin <win10@list.ru>
This commit is contained in:
115
Cargo.lock
generated
115
Cargo.lock
generated
@ -24,6 +24,18 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -35,12 +47,19 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "awatch"
|
name = "awatch"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alphanumeric-sort",
|
"alphanumeric-sort",
|
||||||
"colored",
|
"colored",
|
||||||
|
"dirs",
|
||||||
"failure",
|
"failure",
|
||||||
"failure_derive",
|
"failure_derive",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -75,12 +94,29 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2b_simd"
|
||||||
|
version = "0.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"arrayvec",
|
||||||
|
"constant_time_eq",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.50"
|
version = "1.0.50"
|
||||||
@ -119,6 +155,45 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_users",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "failure"
|
name = "failure"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -141,6 +216,17 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -248,6 +334,17 @@ dependencies = [
|
|||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"redox_syscall",
|
||||||
|
"rust-argon2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.3.5"
|
version = "1.3.5"
|
||||||
@ -266,6 +363,18 @@ version = "0.6.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-argon2"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"blake2b_simd",
|
||||||
|
"constant_time_eq",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
@ -439,6 +548,12 @@ version = "0.9.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -11,6 +11,7 @@ structopt = "0.3" # Used to build CLI.
|
|||||||
serde = "1.0" # A generic serialization/deserialization framework.
|
serde = "1.0" # A generic serialization/deserialization framework.
|
||||||
serde_derive = "1.0.105" # Used to configure json config stucture.
|
serde_derive = "1.0.105" # Used to configure json config stucture.
|
||||||
serde_json = "1.0" # Used to store config.
|
serde_json = "1.0" # Used to store config.
|
||||||
|
dirs = "2.0.2" # Dirs for locating home directory.
|
||||||
failure = "0.1.7" # Experimental error handling abstraction.
|
failure = "0.1.7" # Experimental error handling abstraction.
|
||||||
failure_derive = "0.1.7" # Used to create new error type.
|
failure_derive = "0.1.7" # Used to create new error type.
|
||||||
lazy_static = "1.4" # Define lazy static vars.
|
lazy_static = "1.4" # Define lazy static vars.
|
||||||
|
101
src/cli.rs
101
src/cli.rs
@ -8,6 +8,35 @@ pub struct Opt {
|
|||||||
pub mode: Option<RunMode>
|
pub mode: Option<RunMode>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(StructOpt, Debug)]
|
||||||
|
pub enum ShellType {
|
||||||
|
#[structopt(
|
||||||
|
about = "Generates a .bash completion file for the Bourne Again SHell (BASH)",
|
||||||
|
name = "bash"
|
||||||
|
)]
|
||||||
|
Bash,
|
||||||
|
#[structopt(
|
||||||
|
about = "Generates a .fish completion file for the Friendly Interactive SHell (fish)",
|
||||||
|
name = "fish"
|
||||||
|
)]
|
||||||
|
Fish,
|
||||||
|
#[structopt(
|
||||||
|
about = "Generates a completion file for the Z SHell (ZSH)",
|
||||||
|
name = "zsh"
|
||||||
|
)]
|
||||||
|
Zsh,
|
||||||
|
#[structopt(
|
||||||
|
about = "Generates a completion file for PowerShell",
|
||||||
|
name = "ps"
|
||||||
|
)]
|
||||||
|
PowerShell,
|
||||||
|
#[structopt(
|
||||||
|
about = "Generates a completion file for Elvish",
|
||||||
|
name = "elvish"
|
||||||
|
)]
|
||||||
|
Elvish,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
pub enum RunMode {
|
pub enum RunMode {
|
||||||
#[structopt(name = "init", about = "Initialize config")]
|
#[structopt(name = "init", about = "Initialize config")]
|
||||||
@ -22,4 +51,76 @@ pub enum RunMode {
|
|||||||
Update,
|
Update,
|
||||||
#[structopt(name = "reset", about = "Set episode to 0")]
|
#[structopt(name = "reset", about = "Set episode to 0")]
|
||||||
Reset,
|
Reset,
|
||||||
|
#[structopt(name = "completion", about = "Generate autocompletion \
|
||||||
|
for your shell. If no shell was specified, then it will try \
|
||||||
|
to recognize it automatically.")]
|
||||||
|
Completion {
|
||||||
|
#[structopt(subcommand)]
|
||||||
|
shell: Option<ShellType>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ShellType> for Shell {
|
||||||
|
fn from(shell: ShellType) -> Self {
|
||||||
|
match shell {
|
||||||
|
ShellType::Bash => { Shell::Bash }
|
||||||
|
ShellType::Fish => { Shell::Fish }
|
||||||
|
ShellType::Zsh => { Shell::Zsh }
|
||||||
|
ShellType::PowerShell => { Shell::PowerShell }
|
||||||
|
ShellType::Elvish => { Shell::Elvish }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recognize_shell() -> AppResult<Shell> {
|
||||||
|
println!("Started auto shell recognition.");
|
||||||
|
let shell_var = std::env::var("SHELL").map_err(|_| {
|
||||||
|
AppError::RuntimeError(String::from(
|
||||||
|
"$SHELL env variable not found please specify shell by yourself",
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
let shell_split: Vec<_> = shell_var.split('/').collect();
|
||||||
|
if shell_split.is_empty() {
|
||||||
|
return Err(AppError::RuntimeError(String::from(
|
||||||
|
"Can't recognize shell please specify it by yourself.",
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let shell_name = shell_split.last().unwrap();
|
||||||
|
Shell::from_str(shell_name).map_err(|_| AppError::RuntimeError(String::from("Unknown shell")))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_completion(shell: Option<ShellType>) -> AppResult<()> {
|
||||||
|
let shell = if let Some(shell_val) = shell {
|
||||||
|
Shell::from(shell_val)
|
||||||
|
} else {
|
||||||
|
let current_shell = recognize_shell()?;
|
||||||
|
println!("Recognized shell: {}", current_shell.to_string());
|
||||||
|
current_shell
|
||||||
|
};
|
||||||
|
let home_dir = dirs::home_dir();
|
||||||
|
let mut target_dir = String::from(".");
|
||||||
|
if let Some(home_dir) = home_dir {
|
||||||
|
target_dir = match shell {
|
||||||
|
Shell::Bash => {
|
||||||
|
String::from("/etc/bash_completion.d")
|
||||||
|
}
|
||||||
|
Shell::Fish => {
|
||||||
|
let fish_dir = format!("{}/.config/fish/completions/", home_dir.display());
|
||||||
|
fish_dir
|
||||||
|
}
|
||||||
|
Shell::Zsh => {
|
||||||
|
let zsh_dir = std::env::var("ZSH")
|
||||||
|
.map_err(|_| AppError::RuntimeError(String::from(
|
||||||
|
"Please install oh-my-zsh for rich autocompletions."
|
||||||
|
)))?;
|
||||||
|
format!("{}/completions", zsh_dir)
|
||||||
|
}
|
||||||
|
Shell::PowerShell => { String::from(".") }
|
||||||
|
Shell::Elvish => { String::from(".") }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
std::fs::create_dir_all(target_dir.as_str()).ok();
|
||||||
|
Opt::clap().gen_completions(env!("CARGO_PKG_NAME"), shell, target_dir.as_str());
|
||||||
|
println!("Completion file saved at {}", target_dir);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use crate::result::{AppResult, AppError};
|
use crate::result::{AppError, AppResult};
|
||||||
|
use crate::tty_stuff::{choose_command, choose_episode, choose_pattern};
|
||||||
use crate::CONFIG_PATH;
|
use crate::CONFIG_PATH;
|
||||||
use std::io::{Write, Read};
|
use std::io::{Read, Write};
|
||||||
use crate::tty_stuff::{choose_pattern, choose_command, choose_episode};
|
|
||||||
|
|
||||||
#[derive(Serialize, Default, Clone, Deserialize)]
|
#[derive(Serialize, Default, Clone, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -19,9 +19,9 @@ impl Config {
|
|||||||
pub fn new(pattern: String, maybe_command: String) -> AppResult<Self> {
|
pub fn new(pattern: String, maybe_command: String) -> AppResult<Self> {
|
||||||
let mut command = maybe_command;
|
let mut command = maybe_command;
|
||||||
if pattern.is_empty() {
|
if pattern.is_empty() {
|
||||||
return Err(AppError::RuntimeError(
|
return Err(AppError::RuntimeError(String::from(
|
||||||
String::from("Pattern can't be empty")
|
"Pattern can't be empty",
|
||||||
));
|
)));
|
||||||
}
|
}
|
||||||
if command.is_empty() {
|
if command.is_empty() {
|
||||||
command = default_command();
|
command = default_command();
|
||||||
@ -43,9 +43,7 @@ impl Config {
|
|||||||
pub fn read() -> AppResult<Self> {
|
pub fn read() -> AppResult<Self> {
|
||||||
let config_path = std::path::Path::new(CONFIG_PATH.as_str());
|
let config_path = std::path::Path::new(CONFIG_PATH.as_str());
|
||||||
if !config_path.exists() {
|
if !config_path.exists() {
|
||||||
return Err(
|
return Err(AppError::StdErr(String::from("Run 'awatch init' first.")));
|
||||||
AppError::StdErr(String::from("Run 'awatch init' first."))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let mut file = std::fs::File::open(CONFIG_PATH.as_str())?;
|
let mut file = std::fs::File::open(CONFIG_PATH.as_str())?;
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use crate::result::AppResult;
|
|
||||||
use crate::tty_stuff::{choose_pattern, choose_command};
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
use crate::result::AppResult;
|
||||||
|
use crate::tty_stuff::{choose_command, choose_pattern};
|
||||||
|
|
||||||
pub fn init_config() -> AppResult<()> {
|
pub fn init_config() -> AppResult<()> {
|
||||||
let pattern = choose_pattern(String::new())?;
|
let pattern = choose_pattern(String::new())?;
|
||||||
let command = choose_command(String::from("mpv --fullscreen \"{}\""))?.trim().to_string();
|
let command = choose_command(String::from("mpv --fullscreen \"{}\""))?
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
let config = Config::new(pattern, command)?;
|
let config = Config::new(pattern, command)?;
|
||||||
config.save()?;
|
config.save()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
13
src/main.rs
13
src/main.rs
@ -13,22 +13,25 @@ lazy_static! {
|
|||||||
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use crate::result::{AppError, AppResult};
|
||||||
use crate::run_modes::run;
|
use crate::run_modes::run;
|
||||||
use crate::result::AppResult;
|
use colored::{Color, Colorize};
|
||||||
use colored::{Colorize, Color};
|
|
||||||
|
|
||||||
pub mod result;
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod initialization;
|
||||||
|
pub mod result;
|
||||||
pub mod run_modes;
|
pub mod run_modes;
|
||||||
pub mod tty_stuff;
|
pub mod tty_stuff;
|
||||||
pub mod initialization;
|
use std::str::FromStr;
|
||||||
|
use structopt::clap::Shell;
|
||||||
|
|
||||||
include!("cli.rs");
|
include!("cli.rs");
|
||||||
|
|
||||||
fn main() -> AppResult<()> {
|
fn main() -> AppResult<()> {
|
||||||
let opt: Opt = Opt::from_args();
|
let opt: Opt = Opt::from_args();
|
||||||
if let Err(error) = run(opt) {
|
if let Err(error) = run(opt) {
|
||||||
println!("{dashes} {title} {dashes}",
|
println!(
|
||||||
|
"{dashes} {title} {dashes}",
|
||||||
dashes = "#######".color(Color::BrightRed),
|
dashes = "#######".color(Color::BrightRed),
|
||||||
title = "Error".color(Color::BrightRed)
|
title = "Error".color(Color::BrightRed)
|
||||||
);
|
);
|
||||||
|
@ -1,30 +1,19 @@
|
|||||||
use crate::{Opt, RunMode};
|
use crate::config::{update_config, update_episode, Config};
|
||||||
use crate::result::{AppResult, AppError};
|
|
||||||
use crate::initialization::init_config;
|
use crate::initialization::init_config;
|
||||||
use crate::config::{update_episode, update_config, Config};
|
use crate::result::{AppError, AppResult};
|
||||||
|
use crate::{generate_completion, Opt, RunMode};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn run(opts: Opt) -> AppResult<()> {
|
pub fn run(opts: Opt) -> AppResult<()> {
|
||||||
let mode = opts.mode.unwrap_or_else(|| RunMode::Play);
|
let mode = opts.mode.unwrap_or_else(|| RunMode::Play);
|
||||||
match mode {
|
match mode {
|
||||||
RunMode::Init => {
|
RunMode::Init => init_config(),
|
||||||
init_config()
|
RunMode::Play => play(),
|
||||||
}
|
RunMode::Prev => update_episode(prev_episode),
|
||||||
RunMode::Play => {
|
RunMode::Next => update_episode(next_episode),
|
||||||
play()
|
RunMode::Update => update_config(),
|
||||||
}
|
RunMode::Reset => update_episode(|_| Ok(0)),
|
||||||
RunMode::Prev => {
|
RunMode::Completion { shell } => generate_completion(shell),
|
||||||
update_episode(prev_episode)
|
|
||||||
}
|
|
||||||
RunMode::Next => {
|
|
||||||
update_episode(next_episode)
|
|
||||||
}
|
|
||||||
RunMode::Update => {
|
|
||||||
update_config()
|
|
||||||
}
|
|
||||||
RunMode::Reset => {
|
|
||||||
update_episode(|_| { Ok(0) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,9 +21,9 @@ pub fn prev_episode(current: usize) -> AppResult<usize> {
|
|||||||
if let Some(episode) = current.checked_sub(1) {
|
if let Some(episode) = current.checked_sub(1) {
|
||||||
Ok(episode)
|
Ok(episode)
|
||||||
} else {
|
} else {
|
||||||
Err(AppError::RuntimeError(
|
Err(AppError::RuntimeError(String::from(
|
||||||
String::from("Episode can't be less than zero.")
|
"Episode can't be less than zero.",
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,9 +31,9 @@ pub fn next_episode(current: usize) -> AppResult<usize> {
|
|||||||
if let Some(episode) = current.checked_add(1) {
|
if let Some(episode) = current.checked_add(1) {
|
||||||
Ok(episode)
|
Ok(episode)
|
||||||
} else {
|
} else {
|
||||||
Err(AppError::RuntimeError(
|
Err(AppError::RuntimeError(String::from(
|
||||||
String::from("Reached usize limit. Sorry.")
|
"Reached usize limit. Sorry.",
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +47,8 @@ fn add_leading_zero(n: usize) -> String {
|
|||||||
|
|
||||||
fn prepare_command(conf: Config) -> AppResult<String> {
|
fn prepare_command(conf: Config) -> AppResult<String> {
|
||||||
let index = conf.current_episode_count;
|
let index = conf.current_episode_count;
|
||||||
Ok(conf.command
|
Ok(conf
|
||||||
|
.command
|
||||||
.replace("{}", conf.get_current_episode()?.as_str())
|
.replace("{}", conf.get_current_episode()?.as_str())
|
||||||
.replace("{n}", format!("{}", index).as_str())
|
.replace("{n}", format!("{}", index).as_str())
|
||||||
.replace("{n+}", format!("{}", index + 1).as_str())
|
.replace("{n+}", format!("{}", index + 1).as_str())
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use crate::result::AppResult;
|
|
||||||
use crate::config::get_matched_files;
|
use crate::config::get_matched_files;
|
||||||
use termion::input::TermRead;
|
use crate::result::AppResult;
|
||||||
use std::io::{Write, stdout, stdin, Stdout};
|
use std::io::{stdin, stdout, Stdout, Write};
|
||||||
use termion::event::Key;
|
|
||||||
use termion::raw::{IntoRawMode, RawTerminal};
|
|
||||||
use term_grid::{Grid, GridOptions, Filling, Direction, Cell};
|
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
||||||
|
use termion::event::Key;
|
||||||
|
use termion::input::TermRead;
|
||||||
|
use termion::raw::{IntoRawMode, RawTerminal};
|
||||||
|
|
||||||
pub fn get_matched_files_grid(pattern: String, screen_width: u16) -> AppResult<String> {
|
pub fn get_matched_files_grid(pattern: String, screen_width: u16) -> AppResult<String> {
|
||||||
let mut grid = Grid::new(GridOptions {
|
let mut grid = Grid::new(GridOptions {
|
||||||
@ -32,16 +32,20 @@ pub fn choose_pattern(current_pattern: String) -> AppResult<String> {
|
|||||||
current_pattern,
|
current_pattern,
|
||||||
|stdout, pattern| {
|
|stdout, pattern| {
|
||||||
if !pattern.is_empty() {
|
if !pattern.is_empty() {
|
||||||
write!(stdout, "{}------Matched files------", termion::cursor::Goto(1, 3))?;
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}------Matched files------",
|
||||||
|
termion::cursor::Goto(1, 3)
|
||||||
|
)?;
|
||||||
let (col, _) = termion::terminal_size()?;
|
let (col, _) = termion::terminal_size()?;
|
||||||
let grid = get_matched_files_grid(pattern, col)?;
|
let grid = get_matched_files_grid(pattern, col)?;
|
||||||
if grid.is_empty() {
|
if grid.is_empty() {
|
||||||
write!(stdout, "{}No matches found",
|
write!(stdout, "{}No matches found", termion::cursor::Goto(1, 4))?;
|
||||||
termion::cursor::Goto(1, 4)
|
|
||||||
)?;
|
|
||||||
} else {
|
} else {
|
||||||
for line in grid.lines() {
|
for line in grid.lines() {
|
||||||
write!(stdout, "{}{}{}{}",
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}{}{}{}",
|
||||||
termion::cursor::Down(1),
|
termion::cursor::Down(1),
|
||||||
termion::clear::CurrentLine,
|
termion::clear::CurrentLine,
|
||||||
termion::cursor::Left(col),
|
termion::cursor::Left(col),
|
||||||
@ -63,7 +67,7 @@ pub fn choose_command(current_command: String) -> AppResult<String> {
|
|||||||
&mut stdout,
|
&mut stdout,
|
||||||
"Command to execute files.",
|
"Command to execute files.",
|
||||||
current_command,
|
current_command,
|
||||||
|_, _| { Ok(()) },
|
|_, _| Ok(()),
|
||||||
);
|
);
|
||||||
stdout.suspend_raw_mode()?;
|
stdout.suspend_raw_mode()?;
|
||||||
res
|
res
|
||||||
@ -75,15 +79,13 @@ pub fn choose_episode(current_episode: usize) -> AppResult<usize> {
|
|||||||
&mut stdout,
|
&mut stdout,
|
||||||
"Choose episode.",
|
"Choose episode.",
|
||||||
format!("{}", current_episode),
|
format!("{}", current_episode),
|
||||||
|_, _| { Ok(()) },
|
|_, _| Ok(()),
|
||||||
).map(|s| {
|
)
|
||||||
usize::from_str(s.as_str()).unwrap_or_else(|_| current_episode)
|
.map(|s| usize::from_str(s.as_str()).unwrap_or_else(|_| current_episode));
|
||||||
});
|
|
||||||
stdout.suspend_raw_mode()?;
|
stdout.suspend_raw_mode()?;
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn read_tty_line(
|
pub fn read_tty_line(
|
||||||
stdout: &mut RawTerminal<Stdout>,
|
stdout: &mut RawTerminal<Stdout>,
|
||||||
prompt: &str,
|
prompt: &str,
|
||||||
@ -93,7 +95,9 @@ pub fn read_tty_line(
|
|||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
// Get the standard output stream and go to raw mode.
|
// Get the standard output stream and go to raw mode.
|
||||||
|
|
||||||
write!(stdout, "{}{}{}{}",
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}{}{}{}",
|
||||||
termion::clear::All,
|
termion::clear::All,
|
||||||
termion::cursor::Goto(1, 1),
|
termion::cursor::Goto(1, 1),
|
||||||
prompt,
|
prompt,
|
||||||
@ -104,14 +108,15 @@ pub fn read_tty_line(
|
|||||||
let mut buffer = current_value;
|
let mut buffer = current_value;
|
||||||
let mut current_pos = buffer.len() + 1;
|
let mut current_pos = buffer.len() + 1;
|
||||||
if !buffer.is_empty() {
|
if !buffer.is_empty() {
|
||||||
write!(stdout, "{}{}{}",
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}{}{}",
|
||||||
termion::cursor::Goto(1, 2),
|
termion::cursor::Goto(1, 2),
|
||||||
termion::clear::AfterCursor,
|
termion::clear::AfterCursor,
|
||||||
buffer)?;
|
buffer
|
||||||
after_key_press(stdout, buffer.clone())?;
|
|
||||||
write!(stdout, "{}",
|
|
||||||
termion::cursor::Goto(current_pos as u16, 2)
|
|
||||||
)?;
|
)?;
|
||||||
|
after_key_press(stdout, buffer.clone())?;
|
||||||
|
write!(stdout, "{}", termion::cursor::Goto(current_pos as u16, 2))?;
|
||||||
stdout.flush()?;
|
stdout.flush()?;
|
||||||
}
|
}
|
||||||
for c in stdin.keys() {
|
for c in stdin.keys() {
|
||||||
@ -122,7 +127,7 @@ pub fn read_tty_line(
|
|||||||
}
|
}
|
||||||
// Update pattern
|
// Update pattern
|
||||||
Key::Char(c) => {
|
Key::Char(c) => {
|
||||||
buffer.insert(current_pos - 1, c.clone());
|
buffer.insert(current_pos - 1, c);
|
||||||
current_pos += 1;
|
current_pos += 1;
|
||||||
}
|
}
|
||||||
Key::Backspace => {
|
Key::Backspace => {
|
||||||
@ -158,18 +163,24 @@ pub fn read_tty_line(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// Clear the current line.
|
// Clear the current line.
|
||||||
write!(stdout, "{}{}{}",
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}{}{}",
|
||||||
termion::cursor::Goto(1, 2),
|
termion::cursor::Goto(1, 2),
|
||||||
termion::clear::AfterCursor,
|
termion::clear::AfterCursor,
|
||||||
buffer)?;
|
buffer
|
||||||
|
)?;
|
||||||
// Print matched files
|
// Print matched files
|
||||||
after_key_press(stdout, buffer.clone())?;
|
after_key_press(stdout, buffer.clone())?;
|
||||||
write!(stdout, "{}",
|
write!(stdout, "{}", termion::cursor::Goto(current_pos as u16, 2))?;
|
||||||
termion::cursor::Goto(current_pos as u16, 2)
|
|
||||||
)?;
|
|
||||||
stdout.flush()?;
|
stdout.flush()?;
|
||||||
}
|
}
|
||||||
write!(stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1, 1))?;
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}{}",
|
||||||
|
termion::clear::All,
|
||||||
|
termion::cursor::Goto(1, 1)
|
||||||
|
)?;
|
||||||
stdout.flush()?;
|
stdout.flush()?;
|
||||||
// Show the cursor again before we exit.
|
// Show the cursor again before we exit.
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
|
Reference in New Issue
Block a user