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",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
@ -35,12 +47,19 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "awatch"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"alphanumeric-sort",
|
||||
"colored",
|
||||
"dirs",
|
||||
"failure",
|
||||
"failure_derive",
|
||||
"lazy_static",
|
||||
@ -75,12 +94,29 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "cc"
|
||||
version = "1.0.50"
|
||||
@ -119,6 +155,45 @@ dependencies = [
|
||||
"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]]
|
||||
name = "failure"
|
||||
version = "0.1.7"
|
||||
@ -141,6 +216,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
@ -248,6 +334,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "regex"
|
||||
version = "1.3.5"
|
||||
@ -266,6 +363,18 @@ version = "0.6.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.16"
|
||||
@ -439,6 +548,12 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
|
@ -11,6 +11,7 @@ structopt = "0.3" # Used to build CLI.
|
||||
serde = "1.0" # A generic serialization/deserialization framework.
|
||||
serde_derive = "1.0.105" # Used to configure json config stucture.
|
||||
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_derive = "0.1.7" # Used to create new error type.
|
||||
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>
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub enum RunMode {
|
||||
#[structopt(name = "init", about = "Initialize config")]
|
||||
@ -22,4 +51,76 @@ pub enum RunMode {
|
||||
Update,
|
||||
#[structopt(name = "reset", about = "Set episode to 0")]
|
||||
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 std::io::{Write, Read};
|
||||
use crate::tty_stuff::{choose_pattern, choose_command, choose_episode};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
#[derive(Serialize, Default, Clone, Deserialize)]
|
||||
pub struct Config {
|
||||
@ -19,9 +19,9 @@ impl Config {
|
||||
pub fn new(pattern: String, maybe_command: String) -> AppResult<Self> {
|
||||
let mut command = maybe_command;
|
||||
if pattern.is_empty() {
|
||||
return Err(AppError::RuntimeError(
|
||||
String::from("Pattern can't be empty")
|
||||
));
|
||||
return Err(AppError::RuntimeError(String::from(
|
||||
"Pattern can't be empty",
|
||||
)));
|
||||
}
|
||||
if command.is_empty() {
|
||||
command = default_command();
|
||||
@ -43,9 +43,7 @@ impl Config {
|
||||
pub fn read() -> AppResult<Self> {
|
||||
let config_path = std::path::Path::new(CONFIG_PATH.as_str());
|
||||
if !config_path.exists() {
|
||||
return Err(
|
||||
AppError::StdErr(String::from("Run 'awatch init' first."))
|
||||
);
|
||||
return Err(AppError::StdErr(String::from("Run 'awatch init' first.")));
|
||||
}
|
||||
let mut file = std::fs::File::open(CONFIG_PATH.as_str())?;
|
||||
let mut buffer = String::new();
|
||||
@ -100,4 +98,4 @@ pub fn get_matched_files(pattern: String) -> AppResult<Vec<String>> {
|
||||
}
|
||||
alphanumeric_sort::sort_str_slice(names.as_mut_slice());
|
||||
Ok(names)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
use crate::result::AppResult;
|
||||
use crate::tty_stuff::{choose_pattern, choose_command};
|
||||
use crate::config::Config;
|
||||
use crate::result::AppResult;
|
||||
use crate::tty_stuff::{choose_command, choose_pattern};
|
||||
|
||||
pub fn init_config() -> AppResult<()> {
|
||||
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)?;
|
||||
config.save()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
17
src/main.rs
17
src/main.rs
@ -13,24 +13,27 @@ lazy_static! {
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
use crate::result::{AppError, AppResult};
|
||||
use crate::run_modes::run;
|
||||
use crate::result::AppResult;
|
||||
use colored::{Colorize, Color};
|
||||
use colored::{Color, Colorize};
|
||||
|
||||
pub mod result;
|
||||
pub mod config;
|
||||
pub mod initialization;
|
||||
pub mod result;
|
||||
pub mod run_modes;
|
||||
pub mod tty_stuff;
|
||||
pub mod initialization;
|
||||
use std::str::FromStr;
|
||||
use structopt::clap::Shell;
|
||||
|
||||
include!("cli.rs");
|
||||
|
||||
fn main() -> AppResult<()> {
|
||||
let opt: Opt = Opt::from_args();
|
||||
if let Err(error) = run(opt) {
|
||||
println!("{dashes} {title} {dashes}",
|
||||
dashes = "#######".color(Color::BrightRed),
|
||||
title= "Error".color(Color::BrightRed)
|
||||
println!(
|
||||
"{dashes} {title} {dashes}",
|
||||
dashes = "#######".color(Color::BrightRed),
|
||||
title = "Error".color(Color::BrightRed)
|
||||
);
|
||||
println!("{}", error);
|
||||
}
|
||||
|
@ -26,4 +26,4 @@ impl From<regex::Error> for AppError {
|
||||
fn from(err: regex::Error) -> Self {
|
||||
Self::RuntimeError(err.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,19 @@
|
||||
use crate::{Opt, RunMode};
|
||||
use crate::result::{AppResult, AppError};
|
||||
use crate::config::{update_config, update_episode, 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;
|
||||
|
||||
pub fn run(opts: Opt) -> AppResult<()> {
|
||||
let mode = opts.mode.unwrap_or_else(|| RunMode::Play);
|
||||
match mode {
|
||||
RunMode::Init => {
|
||||
init_config()
|
||||
}
|
||||
RunMode::Play => {
|
||||
play()
|
||||
}
|
||||
RunMode::Prev => {
|
||||
update_episode(prev_episode)
|
||||
}
|
||||
RunMode::Next => {
|
||||
update_episode(next_episode)
|
||||
}
|
||||
RunMode::Update => {
|
||||
update_config()
|
||||
}
|
||||
RunMode::Reset => {
|
||||
update_episode(|_| { Ok(0) })
|
||||
}
|
||||
RunMode::Init => init_config(),
|
||||
RunMode::Play => play(),
|
||||
RunMode::Prev => update_episode(prev_episode),
|
||||
RunMode::Next => update_episode(next_episode),
|
||||
RunMode::Update => update_config(),
|
||||
RunMode::Reset => update_episode(|_| Ok(0)),
|
||||
RunMode::Completion { shell } => generate_completion(shell),
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,9 +21,9 @@ pub fn prev_episode(current: usize) -> AppResult<usize> {
|
||||
if let Some(episode) = current.checked_sub(1) {
|
||||
Ok(episode)
|
||||
} else {
|
||||
Err(AppError::RuntimeError(
|
||||
String::from("Episode can't be less than zero.")
|
||||
))
|
||||
Err(AppError::RuntimeError(String::from(
|
||||
"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) {
|
||||
Ok(episode)
|
||||
} else {
|
||||
Err(AppError::RuntimeError(
|
||||
String::from("Reached usize limit. Sorry.")
|
||||
))
|
||||
Err(AppError::RuntimeError(String::from(
|
||||
"Reached usize limit. Sorry.",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +47,8 @@ fn add_leading_zero(n: usize) -> String {
|
||||
|
||||
fn prepare_command(conf: Config) -> AppResult<String> {
|
||||
let index = conf.current_episode_count;
|
||||
Ok(conf.command
|
||||
Ok(conf
|
||||
.command
|
||||
.replace("{}", conf.get_current_episode()?.as_str())
|
||||
.replace("{n}", format!("{}", index).as_str())
|
||||
.replace("{n+}", format!("{}", index + 1).as_str())
|
||||
@ -80,4 +70,4 @@ pub fn play() -> AppResult<()> {
|
||||
episode = conf.get_current_episode()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::result::AppResult;
|
||||
use crate::config::get_matched_files;
|
||||
use termion::input::TermRead;
|
||||
use std::io::{Write, stdout, stdin, Stdout};
|
||||
use termion::event::Key;
|
||||
use termion::raw::{IntoRawMode, RawTerminal};
|
||||
use term_grid::{Grid, GridOptions, Filling, Direction, Cell};
|
||||
use crate::result::AppResult;
|
||||
use std::io::{stdin, stdout, Stdout, Write};
|
||||
use std::process::exit;
|
||||
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> {
|
||||
let mut grid = Grid::new(GridOptions {
|
||||
@ -32,20 +32,24 @@ pub fn choose_pattern(current_pattern: String) -> AppResult<String> {
|
||||
current_pattern,
|
||||
|stdout, pattern| {
|
||||
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 grid = get_matched_files_grid(pattern, col)?;
|
||||
if grid.is_empty() {
|
||||
write!(stdout, "{}No matches found",
|
||||
termion::cursor::Goto(1, 4)
|
||||
)?;
|
||||
write!(stdout, "{}No matches found", termion::cursor::Goto(1, 4))?;
|
||||
} else {
|
||||
for line in grid.lines() {
|
||||
write!(stdout, "{}{}{}{}",
|
||||
termion::cursor::Down(1),
|
||||
termion::clear::CurrentLine,
|
||||
termion::cursor::Left(col),
|
||||
line
|
||||
write!(
|
||||
stdout,
|
||||
"{}{}{}{}",
|
||||
termion::cursor::Down(1),
|
||||
termion::clear::CurrentLine,
|
||||
termion::cursor::Left(col),
|
||||
line
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -63,7 +67,7 @@ pub fn choose_command(current_command: String) -> AppResult<String> {
|
||||
&mut stdout,
|
||||
"Command to execute files.",
|
||||
current_command,
|
||||
|_, _| { Ok(()) },
|
||||
|_, _| Ok(()),
|
||||
);
|
||||
stdout.suspend_raw_mode()?;
|
||||
res
|
||||
@ -75,15 +79,13 @@ pub fn choose_episode(current_episode: usize) -> AppResult<usize> {
|
||||
&mut stdout,
|
||||
"Choose episode.",
|
||||
format!("{}", current_episode),
|
||||
|_, _| { Ok(()) },
|
||||
).map(|s| {
|
||||
usize::from_str(s.as_str()).unwrap_or_else(|_| current_episode)
|
||||
});
|
||||
|_, _| Ok(()),
|
||||
)
|
||||
.map(|s| usize::from_str(s.as_str()).unwrap_or_else(|_| current_episode));
|
||||
stdout.suspend_raw_mode()?;
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
pub fn read_tty_line(
|
||||
stdout: &mut RawTerminal<Stdout>,
|
||||
prompt: &str,
|
||||
@ -93,25 +95,28 @@ pub fn read_tty_line(
|
||||
let stdin = stdin();
|
||||
// Get the standard output stream and go to raw mode.
|
||||
|
||||
write!(stdout, "{}{}{}{}",
|
||||
termion::clear::All,
|
||||
termion::cursor::Goto(1, 1),
|
||||
prompt,
|
||||
termion::cursor::Goto(1, 2)
|
||||
write!(
|
||||
stdout,
|
||||
"{}{}{}{}",
|
||||
termion::clear::All,
|
||||
termion::cursor::Goto(1, 1),
|
||||
prompt,
|
||||
termion::cursor::Goto(1, 2)
|
||||
)?;
|
||||
// Flush stdout (i.e. make the output appear).
|
||||
stdout.flush()?;
|
||||
let mut buffer = current_value;
|
||||
let mut current_pos = buffer.len() + 1;
|
||||
if !buffer.is_empty() {
|
||||
write!(stdout, "{}{}{}",
|
||||
termion::cursor::Goto(1, 2),
|
||||
termion::clear::AfterCursor,
|
||||
buffer)?;
|
||||
after_key_press(stdout, buffer.clone())?;
|
||||
write!(stdout, "{}",
|
||||
termion::cursor::Goto(current_pos as u16, 2)
|
||||
write!(
|
||||
stdout,
|
||||
"{}{}{}",
|
||||
termion::cursor::Goto(1, 2),
|
||||
termion::clear::AfterCursor,
|
||||
buffer
|
||||
)?;
|
||||
after_key_press(stdout, buffer.clone())?;
|
||||
write!(stdout, "{}", termion::cursor::Goto(current_pos as u16, 2))?;
|
||||
stdout.flush()?;
|
||||
}
|
||||
for c in stdin.keys() {
|
||||
@ -122,7 +127,7 @@ pub fn read_tty_line(
|
||||
}
|
||||
// Update pattern
|
||||
Key::Char(c) => {
|
||||
buffer.insert(current_pos - 1, c.clone());
|
||||
buffer.insert(current_pos - 1, c);
|
||||
current_pos += 1;
|
||||
}
|
||||
Key::Backspace => {
|
||||
@ -158,19 +163,25 @@ pub fn read_tty_line(
|
||||
_ => {}
|
||||
}
|
||||
// Clear the current line.
|
||||
write!(stdout, "{}{}{}",
|
||||
termion::cursor::Goto(1, 2),
|
||||
termion::clear::AfterCursor,
|
||||
buffer)?;
|
||||
write!(
|
||||
stdout,
|
||||
"{}{}{}",
|
||||
termion::cursor::Goto(1, 2),
|
||||
termion::clear::AfterCursor,
|
||||
buffer
|
||||
)?;
|
||||
// Print matched files
|
||||
after_key_press(stdout, buffer.clone())?;
|
||||
write!(stdout, "{}",
|
||||
termion::cursor::Goto(current_pos as u16, 2)
|
||||
)?;
|
||||
write!(stdout, "{}", termion::cursor::Goto(current_pos as u16, 2))?;
|
||||
stdout.flush()?;
|
||||
}
|
||||
write!(stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1, 1))?;
|
||||
write!(
|
||||
stdout,
|
||||
"{}{}",
|
||||
termion::clear::All,
|
||||
termion::cursor::Goto(1, 1)
|
||||
)?;
|
||||
stdout.flush()?;
|
||||
// Show the cursor again before we exit.
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user