From 28902116a5078d1f8e0349c0aa570deb9e4fbff0 Mon Sep 17 00:00:00 2001
From: Pavel Kirilin <win10@list.ru>
Date: Wed, 6 May 2020 03:40:08 +0400
Subject: [PATCH] Added autcompletions. Description: - Added autocompletions
 for some shells. - Fixed styles. - Fixed possible bugs with clippy.

Signed-off-by: Pavel Kirilin <win10@list.ru>
---
 Cargo.lock            | 115 ++++++++++++++++++++++++++++++++++++++++++
 Cargo.toml            |   1 +
 src/cli.rs            | 101 +++++++++++++++++++++++++++++++++++++
 src/config.rs         |  18 +++----
 src/initialization.rs |  10 ++--
 src/main.rs           |  17 ++++---
 src/result.rs         |   2 +-
 src/run_modes.rs      |  48 +++++++-----------
 src/tty_stuff.rs      |  97 +++++++++++++++++++----------------
 9 files changed, 315 insertions(+), 94 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 60fc49e..1ca0db6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index a2eb793..3aadb10 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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.
diff --git a/src/cli.rs b/src/cli.rs
index 55e7eeb..6050449 100644
--- a/src/cli.rs
+++ b/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(())
 }
\ No newline at end of file
diff --git a/src/config.rs b/src/config.rs
index 8cccdf7..6809df4 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -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)
-}
\ No newline at end of file
+}
diff --git a/src/initialization.rs b/src/initialization.rs
index 3eca02e..2a085b8 100644
--- a/src/initialization.rs
+++ b/src/initialization.rs
@@ -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(())
-}
\ No newline at end of file
+}
diff --git a/src/main.rs b/src/main.rs
index 0c41364..ea862af 100644
--- a/src/main.rs
+++ b/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);
     }
diff --git a/src/result.rs b/src/result.rs
index c8aff76..3ed3dbe 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -26,4 +26,4 @@ impl From<regex::Error> for AppError {
     fn from(err: regex::Error) -> Self {
         Self::RuntimeError(err.to_string())
     }
-}
\ No newline at end of file
+}
diff --git a/src/run_modes.rs b/src/run_modes.rs
index a2d910a..ec956ce 100644
--- a/src/run_modes.rs
+++ b/src/run_modes.rs
@@ -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(())
-}
\ No newline at end of file
+}
diff --git a/src/tty_stuff.rs b/src/tty_stuff.rs
index b89ead4..7d3f8d1 100644
--- a/src/tty_stuff.rs
+++ b/src/tty_stuff.rs
@@ -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)
-}
\ No newline at end of file
+}
-- 
GitLab