Skip to content

Instantly share code, notes, and snippets.

@ltriant
Created January 6, 2026 21:42
Show Gist options
  • Select an option

  • Save ltriant/53a7eafda1197d31de4a70b1b929c53a to your computer and use it in GitHub Desktop.

Select an option

Save ltriant/53a7eafda1197d31de4a70b1b929c53a to your computer and use it in GitHub Desktop.
simple hex viewer
#!/usr/bin/env raku
# hexdump.raku -- simple hex viewer
# @[email protected]
# no-color.org
my constant $NO_COLOR = %*ENV<NO_COLOR>:exists;
my $color_reset = "\x1b[0m";
my $color_bold = "\x1b[1m";
sub color_black(Str $s) { "\x1b[90m" ~ $s ~ $color_reset }
sub color_red(Str $s) { "\x1b[91m" ~ $s ~ $color_reset }
sub color_green(Str $s) { "\x1b[92m" ~ $s ~ $color_reset }
sub color_yellow(Str $s) { "\x1b[93m" ~ $s ~ $color_reset }
sub color_blue(Str $s) { "\x1b[94m" ~ $s ~ $color_reset }
sub color_purple(Str $s) { "\x1b[95m" ~ $s ~ $color_reset }
sub color_cyan(Str $s) { "\x1b[96m" ~ $s ~ $color_reset }
sub color_white(Str $s) { "\x1b[97m" ~ $s ~ $color_reset }
sub color_printable(Str $s) {
$NO_COLOR
?? $color_bold ~ $s ~ $color_reset
!! $color_bold ~ color_yellow($s)
}
sub color_nonprintable(Str $s) {
$NO_COLOR ?? $s !! color_black($s)
}
my $offset = 0;
my $total_size = 0;
my constant $MAX_LINE_LENGTH = 16 * 2 + 7;
sub hexdump(@octets) {
$total_size += @octets.elems;
for @octets.rotor(16, :partial) -> @bits {
my $lineLength = 0;
my $line;
$line ~= sprintf "%08x \x2502 ", $offset;
for @bits.kv -> $i, $bit {
my $c = $bit.ord.fmt("%02x");
$line ~= sprintf "%02s%s",
$bit ~~ /^<print>$/
?? color_printable($c)
!! color_nonprintable($c),
$i !%% 2 ?? " " !! "";
$lineLength += 2 + ($i !%% 2 ?? 1 !! 0);
}
if (@bits.elems < 16) {
$line ~= " " x ($MAX_LINE_LENGTH - $lineLength + 1);
}
$line ~= "\x2502 ";
for @bits -> $bit {
if ($bit ~~ /^<print>$/) {
$line ~= color_printable($bit);
} else {
$line ~= color_nonprintable(".");
}
}
$line ~= "\n";
print $line;
$offset += @bits.elems;
}
}
unit sub MAIN();
# How many bytes to read from stdin at any time
my constant $BUF_SIZE = 16 * 512; # 8192 bytes / 8KB
my @bytes;
repeat {
@bytes = $*IN.read($BUF_SIZE).list.map(*.chr).Array;
hexdump(@bytes);
} while (@bytes.elems == $BUF_SIZE);
printf "\nTotal size: %d %s\n", $total_size, $total_size == 1 ?? "byte" !! "bytes";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment