From 95c779b105be6813ddad1ed0d5606257cfaff059 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 10 Oct 2023 12:32:05 -0400 Subject: [PATCH] Better terminal color support - Enables ANSI on Windows 10 - Disables colors if unsupported - Supports `--no-color` and env `NO_COLOR` to disable - Supports env `FORCE_COLOR` and `CLICOLOR_FORCE` to enable --- Cargo.lock | 156 ++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 3 + src/cmd/shasum.rs | 15 +++-- src/main.rs | 39 ++++++++++-- 4 files changed, 190 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07a2da2..b3d1878 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -201,6 +201,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.3" @@ -245,7 +251,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim", "textwrap", "unicode-width", @@ -335,6 +341,7 @@ dependencies = [ "byteorder", "cwdemangle", "dol", + "enable-ansi-support", "filetime", "fixedbitset", "flagset", @@ -365,6 +372,7 @@ dependencies = [ "serde_yaml", "sha-1", "smallvec", + "supports-color 2.1.0", "tracing", "tracing-attributes", "tracing-subscriber", @@ -396,12 +404,31 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "enable-ansi-support" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4ff3ae2a9aa54bf7ee0983e59303224de742818c1822d89f07da9856d9bc60" +dependencies = [ + "windows-sys 0.42.0", +] + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "filetime" version = "0.2.22" @@ -411,7 +438,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -488,6 +515,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + [[package]] name = "hex" version = "0.4.3" @@ -504,6 +537,17 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.3", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "is_ci" version = "1.1.1" @@ -537,6 +581,12 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + [[package]] name = "log" version = "0.4.20" @@ -692,7 +742,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" dependencies = [ - "supports-color", + "supports-color 1.3.1", ] [[package]] @@ -758,7 +808,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" dependencies = [ - "bitflags", + "bitflags 1.3.2", "getopts", "memchr", "unicase", @@ -799,7 +849,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -880,6 +930,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "ryu" version = "1.0.15" @@ -989,6 +1052,16 @@ dependencies = [ "is_ci", ] +[[package]] +name = "supports-color" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" +dependencies = [ + "is-terminal", + "is_ci", +] + [[package]] name = "syn" version = "1.0.109" @@ -1194,6 +1267,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1209,51 +1297,93 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" diff --git a/Cargo.toml b/Cargo.toml index bf60da8..376b286 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ build = "build.rs" repository = "https://github.com/encounter/decomp-toolkit" readme = "README.md" categories = ["command-line-utilities"] +rust-version = "1.70.0" [[bin]] name = "dtk" @@ -30,6 +31,7 @@ binrw = "0.12.0" byteorder = "1.5.0" cwdemangle = "0.1.6" dol = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618" } +enable-ansi-support = "0.2.1" filetime = "0.2.22" fixedbitset = "0.4.2" flagset = { version = "0.4.4", features = ["serde"] } @@ -59,6 +61,7 @@ serde_repr = "0.1.16" serde_yaml = "0.9.25" sha-1 = "0.10.1" smallvec = "1.11.1" +supports-color = "2.1.0" tracing = "0.1.37" tracing-attributes = "0.1.26" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } diff --git a/src/cmd/shasum.rs b/src/cmd/shasum.rs index 9796bab..6ae68ed 100644 --- a/src/cmd/shasum.rs +++ b/src/cmd/shasum.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use argp::FromArgs; -use owo_colors::OwoColorize; +use owo_colors::{OwoColorize, Stream}; use sha1::{Digest, Sha1}; use crate::util::file::{open_file, process_rsp, touch}; @@ -71,21 +71,26 @@ fn check(args: &Args, reader: &mut R) -> Result<()> { )?; if hash_bytes == found_hash.as_ref() { if !args.quiet { - println!("{}: {}", file_name, "OK".green()); + println!( + "{}: {}", + file_name, + "OK".if_supports_color(Stream::Stdout, |t| t.green()) + ); } matches += 1; } else { - println!("{}: {}", file_name, "FAILED".red()); + println!("{}: {}", file_name, "FAILED".if_supports_color(Stream::Stdout, |t| t.red())); mismatches += 1; } } if args.quiet && matches > 0 { - println!("{} files {}", matches, "OK".green()); + println!("{} files {}", matches, "OK".if_supports_color(Stream::Stdout, |t| t.green())); } if mismatches != 0 { eprintln!( "{}", - format!("WARNING: {mismatches} computed checksum(s) did NOT match").yellow() + format!("WARNING: {mismatches} computed checksum(s) did NOT match") + .if_supports_color(Stream::Stdout, |t| t.yellow()) ); std::process::exit(1); } diff --git a/src/main.rs b/src/main.rs index fe510f3..9e392b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ -use std::{ffi::OsStr, path::PathBuf, str::FromStr}; +use std::{env, ffi::OsStr, path::PathBuf, process::exit, str::FromStr}; +use anyhow::Error; use argp::{FromArgValue, FromArgs}; +use enable_ansi_support::enable_ansi_support; +use supports_color::Stream; use tracing::level_filters::LevelFilter; use tracing_subscriber::EnvFilter; @@ -69,6 +72,9 @@ struct TopLevel { /// Print version information and exit. #[argp(switch, short = 'V')] version: bool, + /// Disable color output. (env: NO_COLOR) + #[argp(switch)] + no_color: bool, } #[derive(FromArgs, PartialEq, Debug)] @@ -91,9 +97,32 @@ enum SubCommand { Yaz0(cmd::yaz0::Args), } +// Duplicated from supports-color so we can check early. +fn env_no_color() -> bool { + match env::var("NO_COLOR").as_deref() { + Ok("0") | Err(_) => false, + Ok(_) => true, + } +} + fn main() { let args: TopLevel = argp_version::from_env(); - let format = tracing_subscriber::fmt::format().with_target(false).without_time(); + let use_colors = if args.no_color || env_no_color() { + false + } else { + // Try to enable ANSI support on Windows. + let _ = enable_ansi_support(); + // Disable isatty check for supports-color. (e.g. when used with ninja) + env::set_var("IGNORE_IS_TERMINAL", "1"); + supports_color::on(Stream::Stdout).is_some_and(|c| c.has_basic) + }; + // owo-colors uses an old version of supports-color, so we need to override manually. + // Ideally, we'd be able to remove the old version of supports-color, but disabling the feature + // in owo-colors removes set_override and if_supports_color entirely. + owo_colors::set_override(use_colors); + + let format = + tracing_subscriber::fmt::format().with_ansi(use_colors).with_target(false).without_time(); let builder = tracing_subscriber::fmt().event_format(format); if let Some(level) = args.log_level { builder @@ -117,8 +146,8 @@ fn main() { let mut result = Ok(()); if let Some(dir) = &args.chdir { - result = std::env::set_current_dir(dir).map_err(|e| { - anyhow::Error::new(e) + result = env::set_current_dir(dir).map_err(|e| { + Error::new(e) .context(format!("Failed to change working directory to '{}'", dir.display())) }); } @@ -141,6 +170,6 @@ fn main() { }); if let Err(e) = result { eprintln!("Failed: {e:?}"); - std::process::exit(1); + exit(1); } }