diff --git a/Cargo.lock b/Cargo.lock index c17191d2..b8cf2bde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,10 +90,10 @@ dependencies = [ "indicatif", "itertools", "log", + "owo-colors", "pretty_env_logger", "serde", "serde_json", - "tabwriter", "termion", "tokio", "tracing-subscriber", @@ -1381,6 +1381,12 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + [[package]] name = "parking_lot" version = "0.11.2" @@ -2180,15 +2186,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" -[[package]] -name = "tabwriter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36205cfc997faadcc4b0b87aaef3fbedafe20d38d4959a7ca6ff803564051111" -dependencies = [ - "unicode-width", -] - [[package]] name = "termcolor" version = "1.1.3" diff --git a/Cargo.toml b/Cargo.toml index e6dd5da3..51302f23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,12 +60,12 @@ chrono-english = "0.1.4" cli-table = "0.4" base64 = "0.13.0" humantime = "2.1.0" -tabwriter = "1.2.1" crossbeam-channel = "0.5.1" clap = { version = "3.1.11", features = ["derive"] } clap_complete = "3.1.2" fs-err = "2.7" whoami = "1.1.2" +owo-colors = "3.4.0" [dependencies.tracing-subscriber] version = "0.3" diff --git a/atuin-client/src/sync.rs b/atuin-client/src/sync.rs index 36f713ae..23f552e5 100644 --- a/atuin-client/src/sync.rs +++ b/atuin-client/src/sync.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use chrono::prelude::*; use eyre::Result; -use atuin_common::{api::AddHistoryRequest}; +use atuin_common::api::AddHistoryRequest; use crate::api_client; use crate::database::Database; @@ -11,7 +11,7 @@ use crate::encryption::{encrypt, load_encoded_key, load_key}; use crate::settings::{Settings, HISTORY_PAGE_SIZE}; pub fn hash_str(string: &str) -> String { - use sha2::{Sha256, Digest}; + use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); hasher.update(string.as_bytes()); hex::encode(hasher.finalize()) diff --git a/src/command/client/history.rs b/src/command/client/history.rs index 4f96c444..6bc99dda 100644 --- a/src/command/client/history.rs +++ b/src/command/client/history.rs @@ -1,10 +1,9 @@ use std::env; -use std::io::Write; +use std::io::{StdoutLock, Write}; use std::time::Duration; use clap::Subcommand; use eyre::Result; -use tabwriter::TabWriter; use atuin_client::database::{current_context, Database}; use atuin_client::history::History; @@ -12,6 +11,7 @@ use atuin_client::settings::Settings; #[cfg(feature = "sync")] use atuin_client::sync; +use owo_colors::OwoColorize; #[derive(Subcommand)] #[clap(infer_subcommands = true)] @@ -55,42 +55,62 @@ pub enum Cmd { #[allow(clippy::cast_sign_loss)] pub fn print_list(h: &[History], human: bool, cmd_only: bool) { - let mut writer = TabWriter::new(std::io::stdout()).padding(2); + let w = std::io::stdout(); + let mut w = w.lock(); - let lines = h.iter().rev().map(|h| { - if human { - let duration = humantime::format_duration(Duration::from_nanos(std::cmp::max( - h.duration, 0, - ) as u64)) - .to_string(); - let duration: Vec<&str> = duration.split(' ').collect(); - let duration = duration[0]; - - format!( - "{}\t{}\t{}\n", - h.timestamp.format("%Y-%m-%d %H:%M:%S"), - h.command.trim(), - duration, - ) - } else if cmd_only { - format!("{}\n", h.command.trim()) - } else { - format!( - "{}\t{}\t{}\n", - h.timestamp.timestamp_nanos(), - h.command.trim(), - h.duration - ) - } - }); - - for i in lines { - writer - .write_all(i.as_bytes()) - .expect("failed to write to tab writer"); + if human { + print_human_list(&mut w, h); + } else if cmd_only { + print_cmd_only(&mut w, h); + } else { + print_basic(&mut w, h); } - writer.flush().expect("failed to flush tab writer"); + w.flush().expect("failed to flush history"); +} + +#[allow(clippy::cast_sign_loss)] +pub fn print_human_list(w: &mut StdoutLock, h: &[History]) { + for h in h.iter().rev() { + let duration = + humantime::format_duration(Duration::from_nanos(std::cmp::max(h.duration, 0) as u64)) + .to_string(); + let duration: Vec<&str> = duration.split(' ').collect(); + let duration = duration[0]; + + let time = h.timestamp.format("%Y-%m-%d %H:%M:%S"); + let cmd = h.command.trim(); + + let duration = if h.exit == 0 { + duration.color(owo_colors::AnsiColors::Green) + } else { + duration.color(owo_colors::AnsiColors::Red) + }; + + writeln!(w, "{time} ยท {duration}\t{cmd}").expect("failed to write history"); + } +} + +#[allow(clippy::cast_sign_loss)] +pub fn print_basic(w: &mut StdoutLock, h: &[History]) { + for h in h.iter().rev() { + let duration = + humantime::format_duration(Duration::from_nanos(std::cmp::max(h.duration, 0) as u64)) + .to_string(); + let duration: Vec<&str> = duration.split(' ').collect(); + let duration = duration[0]; + + let time = h.timestamp.format("%Y-%m-%d %H:%M:%S"); + let cmd = h.command.trim(); + + writeln!(w, "{time}\t{cmd}\t{duration}").expect("failed to write history"); + } +} + +pub fn print_cmd_only(w: &mut StdoutLock, h: &[History]) { + for h in h.iter().rev() { + writeln!(w, "{}", h.command.trim()).expect("failed to write history"); + } } impl Cmd {