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) = @_;

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

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

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

    my @parts = split("_", $str);
    foreach my $p (@parts) {
        my $cmd_num = $cmd_map{$p // 0};

        if    ($cmd_num)                      { $p = $cmd_num;  }
        elsif (defined($p) && $p =~ /^-(.+)/) { $p = "48;5;$p"; }
        elsif (defined($p))                   { $p = "38;5;$p"; }
    }

    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:
Leave A Reply
All content licensed under the Creative Commons License