Perl: ANSI colors

Perl's Term::ANSIColor is good but sometime it's overkill. I wrote a function to change colors before your print.

$color = color("13_on_5");
$reset = color("reset");

print $color . "Pink on purple" . $reset . "\n";

# or

print color('yellow', "Warning:"); # Print text and reset

The ANSI color numbers can be determined using term-colors.pl.

# String format: '115', '165_bold', '10_on_140', 'reset', 'on_173', 'red', 'white_on_blue'
sub color {
    my ($str, $txt) = @_;

    state $notty = !-t STDOUT;                                   # Cache the TTY check
    if ($notty || $ENV{NO_COLOR})         { return $txt // ""; } # No interactive terminal
    if (!length($str) || $str eq 'reset') { return "\e[0m";    } # No string = RESET

    # Some predefined colors/commands
    state %color_map = qw(red 160 blue 27 green 34 yellow 226 orange 214 purple 93 white 15 black 0);
    state %cmd_map   = qw(bold 1 italic 3 underline 4 blink 5 inverse 7);

    # Pre-process the string
    $str =~ s/on_/-/g;                             # "on_" becomes a negative number
    $str =~ s|([A-Za-z]+)|$color_map{$1} // $1|eg; # color name -> number

    my @parts = map { # If it's negative it's a background color, otherwise foreground
        $cmd_map{$_} // ($_ =~ /^-(.+)/ ? "48;5;$1" : "38;5;$_")
    } split("_", $str);

    my $ret = "\e[" . join(";", @parts) . "m";

    if (defined $txt) { $ret .= $txt . "\e[0m"; }

    return $ret;
}

Note: You can test if you're outputting to a TTY which supports ANSI colors, or a file using the -t test.

See also: Regexp to check for ANSI color codes
See also: Tests

Tags:
All content licensed under the Creative Commons License