diff --git a/Cargo.lock b/Cargo.lock index bb04cde..fb8ad5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,6 +171,7 @@ dependencies = [ "rayon", "sha1", "sha2", + "termcolor", ] [[package]] @@ -345,6 +346,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + [[package]] name = "typenum" version = "1.16.0" @@ -417,6 +427,37 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index ab110e8..164b289 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] parallel = ["dep:rayon"] +color = ["dep:termcolor"] [dependencies] chrono = "0.4" @@ -14,3 +15,4 @@ md-5 = "0.10" rayon = { version = "1.7", optional = true } sha1 = "0.10" sha2 = "0.10" +termcolor = { version = "1.4", optional = true } diff --git a/src/listing.rs b/src/listing.rs index 554691d..8ff2b93 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -1,3 +1,9 @@ +#[cfg(feature = "color")] +use { + std::io::Write, + termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}, +}; + use { crate::{filetype::Flag, Error, Special}, chrono::NaiveDateTime, @@ -109,10 +115,11 @@ impl Ord for Listing { } impl fmt::Display for Listing { + #[allow(clippy::cast_possible_wrap)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "{}{}{}{}{}{}{}{}{}{} {:>4}:{:<4} {:>10} {} ", + "{}{}{}{}{}{}{}{}{}{} {:>4}:{:<4} {:>10} ", match self.kind { Kind::Normal(_) => "-", Kind::HardLink(_) => "L", @@ -168,8 +175,11 @@ impl fmt::Display for Listing { Kind::Normal(s) => s, _ => 0, }, - NaiveDateTime::from_timestamp_opt(self.mtime as i64, 0).unwrap(), )?; + match NaiveDateTime::from_timestamp_opt(self.mtime as i64, 0) { + Some(dt) => write!(f, "{dt}")?, + _ => write!(f, "{:>19} ", self.mtime)?, + } match self.kind { Kind::Directory | Kind::Fifo | Kind::Normal(_) => write!(f, "{}", self.name), Kind::HardLink(ref tgt) => write!(f, "{}=>{}", self.name, tgt), @@ -223,6 +233,134 @@ impl Listing { kind, }) } + + #[allow(clippy::cast_possible_wrap)] + #[cfg(feature = "color")] + pub fn print_color(&self) -> Result<(), Error> { + print!( + "{}{}{}{}{}{}{}{}{}{} {:>4}:{:<4} {:>10} ", + match self.kind { + Kind::Normal(_) => "-", + Kind::HardLink(_) => "L", + Kind::SoftLink(_) => "l", + Kind::Directory => "d", + Kind::Character(_) => "c", + Kind::Block(_) => "b", + Kind::Fifo => "p", + Kind::Eof => return Ok(()), + }, + match self.mode { + m if m & 0o400 != 0 => "r", + _ => "-", + }, + match self.mode { + m if m & 0o200 != 0 => "w", + _ => "-", + }, + match self.mode { + m if m & 0o4000 != 0 => "S", + m if m & 0o100 != 0 => "x", + _ => "-", + }, + match self.mode { + m if m & 0o40 != 0 => "r", + _ => "-", + }, + match self.mode { + m if m & 0o20 != 0 => "w", + _ => "-", + }, + match self.mode { + m if m & 0o2000 != 0 => "S", + m if m & 0o10 != 0 => "x", + _ => "-", + }, + match self.mode { + m if m & 0o4 != 0 => "r", + _ => "-", + }, + match self.mode { + m if m & 0o2 != 0 => "w", + _ => "-", + }, + match self.mode { + m if m & 0o1000 != 0 => "t", + m if m & 0o1 != 0 => "x", + _ => "-", + }, + self.uid, + self.gid, + match self.kind { + Kind::Normal(s) => s, + _ => 0, + }, + ); + match NaiveDateTime::from_timestamp_opt(self.mtime as i64, 0) { + Some(dt) => print!("{dt}"), + _ => print!("{:>19} ", self.mtime), + } + let mut stdout = StandardStream::stdout(ColorChoice::Auto); + match self.kind { + Kind::Normal(_) => println!("{}", self.name), + Kind::Directory => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Blue)))?; + writeln!(&mut stdout, "{}", self.name)?; + stdout.reset()?; + } + Kind::Fifo => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + writeln!(&mut stdout, "{}", self.name)?; + stdout.reset()?; + } + Kind::HardLink(ref tgt) => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(&mut stdout, "{}", self.name)?; + stdout.reset()?; + println!(" => {tgt}"); + } + Kind::SoftLink(ref tgt) => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(&mut stdout, "{}", self.name)?; + stdout.reset()?; + println!(" -> {tgt}"); + } + Kind::Character(ref sp) | Kind::Block(ref sp) => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(&mut stdout, "{}", self.name)?; + stdout.reset()?; + println!(" {},{}", sp.major, sp.minor); + } + Kind::Eof => unreachable!(), + } + Ok(()) + } + + #[cfg(feature = "color")] + pub fn print_color_simple(&self) -> Result<(), Error> { + let mut stdout = StandardStream::stdout(ColorChoice::Auto); + match self.kind { + Kind::Normal(_) => println!("{}", self.name), + Kind::Directory => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Blue)))?; + writeln!(&mut stdout, "{}", self.name)?; + } + Kind::Fifo => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + writeln!(&mut stdout, "{}", self.name)?; + } + Kind::HardLink(_) | Kind::SoftLink(_) => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(&mut stdout, "{}", self.name)?; + } + Kind::Character(_) | Kind::Block(_) => { + stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(&mut stdout, "{}", self.name)?; + } + Kind::Eof => unreachable!(), + } + stdout.reset()?; + Ok(()) + } } #[cfg(test)]