Skip to content

Commit 9ef7c34

Browse files
Enable custom colors with environment variables (#248)
* Enable custom colors with environment variables * Rename HEXYL_XYZ env vars to HEXYL_COLOR_XYZ
1 parent 6220cae commit 9ef7c34

File tree

7 files changed

+268
-32
lines changed

7 files changed

+268
-32
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ readme = "README.md"
99
repository = "https://github.com/sharkdp/hexyl"
1010
version = "0.16.0"
1111
edition = "2021"
12-
rust-version = "1.74"
12+
rust-version = "1.80"
1313

1414
[dependencies]
1515
anyhow = "1.0"

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ scoop install hexyl
193193
x env use hexyl
194194
```
195195

196+
## Configuration
197+
198+
`hexyl` colors can be configured via environment variables. The variables used are as follows:
199+
200+
* `HEXYL_COLOR_ASCII_PRINTABLE`: Any non-whitespace printable ASCII character
201+
* `HEXYL_COLOR_ASCII_WHITESPACE`: Whitespace such as space or newline (only visible in middle panel with byte values)
202+
* `HEXYL_COLOR_ASCII_OTHER`: Any other ASCII character (< `0x80`) besides null
203+
* `HEXYL_COLOR_NULL`: The null byte (`0x00`)
204+
* `HEXYL_COLOR_NONASCII`: Any non-ASCII byte (> `0x7F`)
205+
* `HEXYL_COLOR_OFFSET`: The lefthand file offset
206+
207+
The colors can be any of the 8 standard terminal colors: `black`, `blue`, `cyan`, `green`, `magenta`, `red`,
208+
`yellow` and `white`. The "bright" variants are also supported (e.g., `bright blue`). Additionally, you can use
209+
the RGB hex format, `#abcdef`. For example, `HEXYL_COLOR_ASCII_PRINTABLE=blue HEXYL_COLOR_ASCII_WHITESPACE="bright green"
210+
HEXYL_COLOR_ASCII_OTHER="#ff7f99"`.
211+
196212
## License
197213

198214
Licensed under either of

doc/hexyl.1.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ _FILE_
106106
**-V**, **\--version**
107107
: Prints version information.
108108

109+
# ENVIRONMENT VARIABLES
110+
111+
**hexyl** colors can be configured via environment variables. The variables used are as follows:
112+
113+
: - **HEXYL_COLOR_ASCII_PRINTABLE**: Any non-whitespace printable ASCII character
114+
- **HEXYL_COLOR_ASCII_WHITESPACE**: Whitespace such as space or newline (only visible in middle panel with byte values)
115+
- **HEXYL_COLOR_ASCII_OTHER**: Any other ASCII character (< **0x80**) besides null
116+
- **HEXYL_COLOR_NULL**: The null byte (**0x00**)
117+
- **HEXYL_COLOR_NONASCII**: Any non-ASCII byte (> **0x7F**)
118+
- **HEXYL_COLOR_OFFSET**: The lefthand file offset
119+
120+
The colors can be any of the 8 standard terminal colors: **black**, **blue**, **cyan**, **green**, **magenta**, **red**,
121+
**yellow** and **white**. The "bright" variants are also supported (e.g., **bright blue**). Additionally, you can use
122+
the RGB hex format, **#abcdef**. For example, **HEXYL_COLOR_ASCII_PRINTABLE=blue HEXYL_COLOR_ASCII_WHITESPACE="bright green"
123+
HEXYL_COLOR_ASCII_OTHER="#ff7f99"**.
124+
109125
# NOTES
110126

111127
Source repository:

src/colors.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
1-
use owo_colors::{colors, Color};
1+
use owo_colors::{colors, AnsiColors, Color, DynColors, OwoColorize};
2+
use std::str::FromStr;
3+
use std::sync::LazyLock;
24

3-
pub const COLOR_NULL: &[u8] = colors::BrightBlack::ANSI_FG.as_bytes();
4-
pub const COLOR_OFFSET: &[u8] = colors::BrightBlack::ANSI_FG.as_bytes();
5-
pub const COLOR_ASCII_PRINTABLE: &[u8] = colors::Cyan::ANSI_FG.as_bytes();
6-
pub const COLOR_ASCII_WHITESPACE: &[u8] = colors::Green::ANSI_FG.as_bytes();
7-
pub const COLOR_ASCII_OTHER: &[u8] = colors::Green::ANSI_FG.as_bytes();
8-
pub const COLOR_NONASCII: &[u8] = colors::Yellow::ANSI_FG.as_bytes();
9-
pub const COLOR_RESET: &[u8] = colors::Default::ANSI_FG.as_bytes();
5+
pub static COLOR_NULL: LazyLock<String> =
6+
LazyLock::new(|| init_color("NULL", AnsiColors::BrightBlack));
7+
pub static COLOR_OFFSET: LazyLock<String> =
8+
LazyLock::new(|| init_color("OFFSET", AnsiColors::BrightBlack));
9+
pub static COLOR_ASCII_PRINTABLE: LazyLock<String> =
10+
LazyLock::new(|| init_color("ASCII_PRINTABLE", AnsiColors::Cyan));
11+
pub static COLOR_ASCII_WHITESPACE: LazyLock<String> =
12+
LazyLock::new(|| init_color("ASCII_WHITESPACE", AnsiColors::Green));
13+
pub static COLOR_ASCII_OTHER: LazyLock<String> =
14+
LazyLock::new(|| init_color("ASCII_OTHER", AnsiColors::Green));
15+
pub static COLOR_NONASCII: LazyLock<String> =
16+
LazyLock::new(|| init_color("NONASCII", AnsiColors::Yellow));
17+
pub const COLOR_RESET: &str = colors::Default::ANSI_FG;
18+
19+
fn init_color(name: &str, default_ansi: AnsiColors) -> String {
20+
let default = DynColors::Ansi(default_ansi);
21+
let env_var = format!("HEXYL_COLOR_{}", name);
22+
let color = match std::env::var(env_var).as_deref() {
23+
Ok(color) => match DynColors::from_str(color) {
24+
Ok(color) => color,
25+
_ => default,
26+
},
27+
_ => default,
28+
};
29+
// owo_colors' API isn't designed to get the terminal codes directly for
30+
// dynamic colors, so we use this hack to get them from the LHS of some text.
31+
format!("{}", "|".color(color))
32+
.split_once("|")
33+
.unwrap()
34+
.0
35+
.to_owned()
36+
}
1037

1138
#[rustfmt::skip]
1239
pub const CP437: [char; 256] = [

src/lib.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ impl Byte {
8484
fn color(self) -> &'static [u8] {
8585
use crate::ByteCategory::*;
8686
match self.category() {
87-
Null => COLOR_NULL,
88-
AsciiPrintable => COLOR_ASCII_PRINTABLE,
89-
AsciiWhitespace => COLOR_ASCII_WHITESPACE,
90-
AsciiOther => COLOR_ASCII_OTHER,
91-
NonAscii => COLOR_NONASCII,
87+
Null => COLOR_NULL.as_bytes(),
88+
AsciiPrintable => COLOR_ASCII_PRINTABLE.as_bytes(),
89+
AsciiWhitespace => COLOR_ASCII_WHITESPACE.as_bytes(),
90+
AsciiOther => COLOR_ASCII_OTHER.as_bytes(),
91+
NonAscii => COLOR_NONASCII.as_bytes(),
9292
}
9393
}
9494

@@ -440,14 +440,14 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
440440
.as_bytes(),
441441
)?;
442442
if self.show_color {
443-
self.writer.write_all(COLOR_OFFSET)?;
443+
self.writer.write_all(COLOR_OFFSET.as_bytes())?;
444444
}
445445
if self.show_position_panel {
446446
match self.squeezer {
447447
Squeezer::Print => {
448448
self.writer.write_all(b"*")?;
449449
if self.show_color {
450-
self.writer.write_all(COLOR_RESET)?;
450+
self.writer.write_all(COLOR_RESET.as_bytes())?;
451451
}
452452
self.writer.write_all(b" ")?;
453453
}
@@ -462,7 +462,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
462462
.write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?;
463463
}
464464
if self.show_color {
465-
self.writer.write_all(COLOR_RESET)?;
465+
self.writer.write_all(COLOR_RESET.as_bytes())?;
466466
}
467467
}
468468
}
@@ -494,7 +494,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
494494
}
495495
if i == 8 * self.panels - 1 {
496496
if self.show_color {
497-
self.writer.write_all(COLOR_RESET)?;
497+
self.writer.write_all(COLOR_RESET.as_bytes())?;
498498
self.curr_color = None;
499499
}
500500
self.writer.write_all(
@@ -505,7 +505,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
505505
)?;
506506
} else if i % 8 == 7 {
507507
if self.show_color {
508-
self.writer.write_all(COLOR_RESET)?;
508+
self.writer.write_all(COLOR_RESET.as_bytes())?;
509509
self.curr_color = None;
510510
}
511511
self.writer.write_all(
@@ -531,12 +531,12 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
531531
Squeezer::Print => {
532532
if !self.show_position_panel && i == 0 {
533533
if self.show_color {
534-
self.writer.write_all(COLOR_OFFSET)?;
534+
self.writer.write_all(COLOR_OFFSET.as_bytes())?;
535535
}
536536
self.writer
537537
.write_all(self.byte_char_panel[b'*' as usize].as_bytes())?;
538538
if self.show_color {
539-
self.writer.write_all(COLOR_RESET)?;
539+
self.writer.write_all(COLOR_RESET.as_bytes())?;
540540
}
541541
} else if i % (self.group_size as usize) == 0 {
542542
self.writer.write_all(b" ")?;
@@ -562,7 +562,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
562562
if i % 8 == 7 {
563563
if self.show_color {
564564
self.curr_color = None;
565-
self.writer.write_all(COLOR_RESET)?;
565+
self.writer.write_all(COLOR_RESET.as_bytes())?;
566566
}
567567
self.writer.write_all(b" ")?;
568568
// byte is last in last panel

src/main.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -493,32 +493,32 @@ fn print_color_table() -> io::Result<()> {
493493
writeln!(stdout, "hexyl color reference:\n")?;
494494

495495
// NULL bytes
496-
stdout.write_all(COLOR_NULL)?;
496+
stdout.write_all(COLOR_NULL.as_bytes())?;
497497
writeln!(stdout, "⋄ NULL bytes (0x00)")?;
498-
stdout.write_all(COLOR_RESET)?;
498+
stdout.write_all(COLOR_RESET.as_bytes())?;
499499

500500
// ASCII printable
501-
stdout.write_all(COLOR_ASCII_PRINTABLE)?;
501+
stdout.write_all(COLOR_ASCII_PRINTABLE.as_bytes())?;
502502
writeln!(stdout, "a ASCII printable characters (0x20 - 0x7E)")?;
503-
stdout.write_all(COLOR_RESET)?;
503+
stdout.write_all(COLOR_RESET.as_bytes())?;
504504

505505
// ASCII whitespace
506-
stdout.write_all(COLOR_ASCII_WHITESPACE)?;
506+
stdout.write_all(COLOR_ASCII_WHITESPACE.as_bytes())?;
507507
writeln!(stdout, "_ ASCII whitespace (0x09 - 0x0D, 0x20)")?;
508-
stdout.write_all(COLOR_RESET)?;
508+
stdout.write_all(COLOR_RESET.as_bytes())?;
509509

510510
// ASCII other
511-
stdout.write_all(COLOR_ASCII_OTHER)?;
511+
stdout.write_all(COLOR_ASCII_OTHER.as_bytes())?;
512512
writeln!(
513513
stdout,
514514
"• ASCII control characters (except NULL and whitespace)"
515515
)?;
516-
stdout.write_all(COLOR_RESET)?;
516+
stdout.write_all(COLOR_RESET.as_bytes())?;
517517

518518
// Non-ASCII
519-
stdout.write_all(COLOR_NONASCII)?;
519+
stdout.write_all(COLOR_NONASCII.as_bytes())?;
520520
writeln!(stdout, "× Non-ASCII bytes (0x80 - 0xFF)")?;
521-
stdout.write_all(COLOR_RESET)?;
521+
stdout.write_all(COLOR_RESET.as_bytes())?;
522522

523523
Ok(())
524524
}

0 commit comments

Comments
 (0)