| Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/5.18.2/Term/ANSIColor.pm |
| Statements | Executed 1451 statements in 5.38ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 289µs | 439µs | Term::ANSIColor::BEGIN@42 |
| 1 | 1 | 1 | 132µs | 132µs | Term::ANSIColor::CORE:sort (opcode) |
| 5 | 1 | 1 | 23µs | 23µs | Term::ANSIColor::colorvalid |
| 1 | 1 | 1 | 22µs | 22µs | Term::ANSIColor::BEGIN@22 |
| 1 | 1 | 1 | 8µs | 15µs | Term::ANSIColor::BEGIN@24 |
| 1 | 1 | 1 | 8µs | 34µs | Term::ANSIColor::BEGIN@26 |
| 1 | 1 | 1 | 8µs | 22µs | Term::ANSIColor::BEGIN@23 |
| 1 | 1 | 1 | 4µs | 4µs | Term::ANSIColor::BEGIN@27 |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::AUTOLOAD |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::LOCALCOLOR |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::POPCOLOR |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::PUSHCOLOR |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::color |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::coloralias |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::colored |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::colorstrip |
| 0 | 0 | 0 | 0s | 0s | Term::ANSIColor::uncolor |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | # Term::ANSIColor -- Color screen output using ANSI escape sequences. | ||||
| 2 | # | ||||
| 3 | # Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2005, 2006, 2008, 2009, 2010, | ||||
| 4 | # 2011, 2012, 2013 Russ Allbery <rra@stanford.edu> | ||||
| 5 | # Copyright 1996 Zenin | ||||
| 6 | # Copyright 2012 Kurt Starsinic <kstarsinic@gmail.com> | ||||
| 7 | # | ||||
| 8 | # This program is free software; you may redistribute it and/or modify it | ||||
| 9 | # under the same terms as Perl itself. | ||||
| 10 | # | ||||
| 11 | # PUSH/POP support submitted 2007 by openmethods.com voice solutions | ||||
| 12 | # | ||||
| 13 | # Ah, September, when the sysadmins turn colors and fall off the trees.... | ||||
| 14 | # -- Dave Van Domelen | ||||
| 15 | |||||
| 16 | ############################################################################## | ||||
| 17 | # Modules and declarations | ||||
| 18 | ############################################################################## | ||||
| 19 | |||||
| 20 | package Term::ANSIColor; | ||||
| 21 | |||||
| 22 | 2 | 104µs | 1 | 22µs | # spent 22µs within Term::ANSIColor::BEGIN@22 which was called:
# once (22µs+0s) by Perl::Critic::Config::_validate_and_save_color_severity at line 22 # spent 22µs making 1 call to Term::ANSIColor::BEGIN@22 |
| 23 | 2 | 23µs | 2 | 36µs | # spent 22µs (8+14) within Term::ANSIColor::BEGIN@23 which was called:
# once (8µs+14µs) by Perl::Critic::Config::_validate_and_save_color_severity at line 23 # spent 22µs making 1 call to Term::ANSIColor::BEGIN@23
# spent 14µs making 1 call to strict::import |
| 24 | 2 | 23µs | 2 | 22µs | # spent 15µs (8+7) within Term::ANSIColor::BEGIN@24 which was called:
# once (8µs+7µs) by Perl::Critic::Config::_validate_and_save_color_severity at line 24 # spent 15µs making 1 call to Term::ANSIColor::BEGIN@24
# spent 7µs making 1 call to warnings::import |
| 25 | |||||
| 26 | 2 | 23µs | 2 | 60µs | # spent 34µs (8+26) within Term::ANSIColor::BEGIN@26 which was called:
# once (8µs+26µs) by Perl::Critic::Config::_validate_and_save_color_severity at line 26 # spent 34µs making 1 call to Term::ANSIColor::BEGIN@26
# spent 26µs making 1 call to Exporter::import |
| 27 | 2 | 246µs | 1 | 4µs | # spent 4µs within Term::ANSIColor::BEGIN@27 which was called:
# once (4µs+0s) by Perl::Critic::Config::_validate_and_save_color_severity at line 27 # spent 4µs making 1 call to Term::ANSIColor::BEGIN@27 |
| 28 | |||||
| 29 | # use Exporter plus @ISA instead of use base for 5.6 compatibility. | ||||
| 30 | ## no critic (ClassHierarchies::ProhibitExplicitISA) | ||||
| 31 | |||||
| 32 | # Declare variables that should be set in BEGIN for robustness. | ||||
| 33 | ## no critic (Modules::ProhibitAutomaticExportation) | ||||
| 34 | 1 | 500ns | our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS, @ISA, $VERSION); | ||
| 35 | |||||
| 36 | # We use autoloading, which sets this variable to the name of the called sub. | ||||
| 37 | 1 | 0s | our $AUTOLOAD; | ||
| 38 | |||||
| 39 | # Set $VERSION and everything export-related in a BEGIN block for robustness | ||||
| 40 | # against circular module loading (not that we load any modules, but | ||||
| 41 | # consistency is good). | ||||
| 42 | # spent 439µs (289+150) within Term::ANSIColor::BEGIN@42 which was called:
# once (289µs+150µs) by Perl::Critic::Config::_validate_and_save_color_severity at line 84 | ||||
| 43 | 1 | 500ns | $VERSION = '4.02'; | ||
| 44 | |||||
| 45 | # All of the basic supported constants, used in %EXPORT_TAGS. | ||||
| 46 | 1 | 7µs | my @colorlist = qw( | ||
| 47 | CLEAR RESET BOLD DARK | ||||
| 48 | FAINT ITALIC UNDERLINE UNDERSCORE | ||||
| 49 | BLINK REVERSE CONCEALED | ||||
| 50 | |||||
| 51 | BLACK RED GREEN YELLOW | ||||
| 52 | BLUE MAGENTA CYAN WHITE | ||||
| 53 | ON_BLACK ON_RED ON_GREEN ON_YELLOW | ||||
| 54 | ON_BLUE ON_MAGENTA ON_CYAN ON_WHITE | ||||
| 55 | |||||
| 56 | BRIGHT_BLACK BRIGHT_RED BRIGHT_GREEN BRIGHT_YELLOW | ||||
| 57 | BRIGHT_BLUE BRIGHT_MAGENTA BRIGHT_CYAN BRIGHT_WHITE | ||||
| 58 | ON_BRIGHT_BLACK ON_BRIGHT_RED ON_BRIGHT_GREEN ON_BRIGHT_YELLOW | ||||
| 59 | ON_BRIGHT_BLUE ON_BRIGHT_MAGENTA ON_BRIGHT_CYAN ON_BRIGHT_WHITE | ||||
| 60 | ); | ||||
| 61 | |||||
| 62 | # 256-color constants, used in %EXPORT_TAGS. | ||||
| 63 | ## no critic (ValuesAndExpressions::ProhibitMagicNumbers) | ||||
| 64 | my @colorlist256 = ( | ||||
| 65 | (map { ("ANSI$_", "ON_ANSI$_") } 0 .. 15), | ||||
| 66 | 1 | 32µs | (map { ("GREY$_", "ON_GREY$_") } 0 .. 23), | ||
| 67 | ); | ||||
| 68 | 1 | 1µs | for my $r (0 .. 5) { | ||
| 69 | 6 | 4µs | for my $g (0 .. 5) { | ||
| 70 | 36 | 200µs | push @colorlist256, map { ("RGB$r$g$_", "ON_RGB$r$g$_") } 0 .. 5; | ||
| 71 | } | ||||
| 72 | } | ||||
| 73 | |||||
| 74 | # Exported symbol configuration. | ||||
| 75 | 1 | 6µs | @ISA = qw(Exporter); | ||
| 76 | 1 | 700ns | @EXPORT = qw(color colored); | ||
| 77 | 1 | 700ns | @EXPORT_OK = qw(uncolor colorstrip colorvalid coloralias); | ||
| 78 | 1 | 20µs | %EXPORT_TAGS = ( | ||
| 79 | constants => \@colorlist, | ||||
| 80 | constants256 => \@colorlist256, | ||||
| 81 | pushpop => [@colorlist, qw(PUSHCOLOR POPCOLOR LOCALCOLOR)], | ||||
| 82 | ); | ||||
| 83 | 1 | 5µs | 1 | 17µs | Exporter::export_ok_tags('pushpop', 'constants256'); # spent 17µs making 1 call to Exporter::export_ok_tags |
| 84 | 1 | 1.49ms | 1 | 439µs | } # spent 439µs making 1 call to Term::ANSIColor::BEGIN@42 |
| 85 | |||||
| 86 | ############################################################################## | ||||
| 87 | # Package variables | ||||
| 88 | ############################################################################## | ||||
| 89 | |||||
| 90 | # If this is set, any color changes will implicitly push the current color | ||||
| 91 | # onto the stack and then pop it at the end of the constant sequence, just as | ||||
| 92 | # if LOCALCOLOR were used. | ||||
| 93 | 1 | 0s | our $AUTOLOCAL; | ||
| 94 | |||||
| 95 | # Caller sets this to force a reset at the end of each constant sequence. | ||||
| 96 | 1 | 0s | our $AUTORESET; | ||
| 97 | |||||
| 98 | # Caller sets this to force colors to be reset at the end of each line. | ||||
| 99 | 1 | 0s | our $EACHLINE; | ||
| 100 | |||||
| 101 | ############################################################################## | ||||
| 102 | # Internal data structures | ||||
| 103 | ############################################################################## | ||||
| 104 | |||||
| 105 | # This module does quite a bit of initialization at the time it is first | ||||
| 106 | # loaded, primarily to set up the package-global %ATTRIBUTES hash. The | ||||
| 107 | # entries for 256-color names are easier to handle programmatically, and | ||||
| 108 | # custom colors are also imported from the environment if any are set. | ||||
| 109 | |||||
| 110 | # All basic supported attributes, including aliases. | ||||
| 111 | #<<< | ||||
| 112 | 1 | 20µs | our %ATTRIBUTES = ( | ||
| 113 | 'clear' => 0, | ||||
| 114 | 'reset' => 0, | ||||
| 115 | 'bold' => 1, | ||||
| 116 | 'dark' => 2, | ||||
| 117 | 'faint' => 2, | ||||
| 118 | 'italic' => 3, | ||||
| 119 | 'underline' => 4, | ||||
| 120 | 'underscore' => 4, | ||||
| 121 | 'blink' => 5, | ||||
| 122 | 'reverse' => 7, | ||||
| 123 | 'concealed' => 8, | ||||
| 124 | |||||
| 125 | 'black' => 30, 'on_black' => 40, | ||||
| 126 | 'red' => 31, 'on_red' => 41, | ||||
| 127 | 'green' => 32, 'on_green' => 42, | ||||
| 128 | 'yellow' => 33, 'on_yellow' => 43, | ||||
| 129 | 'blue' => 34, 'on_blue' => 44, | ||||
| 130 | 'magenta' => 35, 'on_magenta' => 45, | ||||
| 131 | 'cyan' => 36, 'on_cyan' => 46, | ||||
| 132 | 'white' => 37, 'on_white' => 47, | ||||
| 133 | |||||
| 134 | 'bright_black' => 90, 'on_bright_black' => 100, | ||||
| 135 | 'bright_red' => 91, 'on_bright_red' => 101, | ||||
| 136 | 'bright_green' => 92, 'on_bright_green' => 102, | ||||
| 137 | 'bright_yellow' => 93, 'on_bright_yellow' => 103, | ||||
| 138 | 'bright_blue' => 94, 'on_bright_blue' => 104, | ||||
| 139 | 'bright_magenta' => 95, 'on_bright_magenta' => 105, | ||||
| 140 | 'bright_cyan' => 96, 'on_bright_cyan' => 106, | ||||
| 141 | 'bright_white' => 97, 'on_bright_white' => 107, | ||||
| 142 | ); | ||||
| 143 | #>>> | ||||
| 144 | |||||
| 145 | # Generating the 256-color codes involves a lot of codes and offsets that are | ||||
| 146 | # not helped by turning them into constants. | ||||
| 147 | ## no critic (ValuesAndExpressions::ProhibitMagicNumbers) | ||||
| 148 | |||||
| 149 | # The first 16 256-color codes are duplicates of the 16 ANSI colors, | ||||
| 150 | # included for completeness. | ||||
| 151 | 1 | 1µs | for my $code (0 .. 15) { | ||
| 152 | 16 | 11µs | $ATTRIBUTES{"ansi$code"} = "38;5;$code"; | ||
| 153 | 16 | 11µs | $ATTRIBUTES{"on_ansi$code"} = "48;5;$code"; | ||
| 154 | } | ||||
| 155 | |||||
| 156 | # 256-color RGB colors. Red, green, and blue can each be values 0 through 5, | ||||
| 157 | # and the resulting 216 colors start with color 16. | ||||
| 158 | 1 | 600ns | for my $r (0 .. 5) { | ||
| 159 | 6 | 3µs | for my $g (0 .. 5) { | ||
| 160 | 36 | 19µs | for my $b (0 .. 5) { | ||
| 161 | 216 | 47µs | my $code = 16 + (6 * 6 * $r) + (6 * $g) + $b; | ||
| 162 | 216 | 165µs | $ATTRIBUTES{"rgb$r$g$b"} = "38;5;$code"; | ||
| 163 | 216 | 152µs | $ATTRIBUTES{"on_rgb$r$g$b"} = "48;5;$code"; | ||
| 164 | } | ||||
| 165 | } | ||||
| 166 | } | ||||
| 167 | |||||
| 168 | # The last 256-color codes are 24 shades of grey. | ||||
| 169 | 1 | 600ns | for my $n (0 .. 23) { | ||
| 170 | 24 | 2µs | my $code = $n + 232; | ||
| 171 | 24 | 26µs | $ATTRIBUTES{"grey$n"} = "38;5;$code"; | ||
| 172 | 24 | 14µs | $ATTRIBUTES{"on_grey$n"} = "48;5;$code"; | ||
| 173 | } | ||||
| 174 | |||||
| 175 | ## use critic (ValuesAndExpressions::ProhibitMagicNumbers) | ||||
| 176 | |||||
| 177 | # Reverse lookup. Alphabetically first name for a sequence is preferred. | ||||
| 178 | 1 | 100ns | our %ATTRIBUTES_R; | ||
| 179 | 1 | 190µs | 1 | 132µs | for my $attr (reverse sort keys %ATTRIBUTES) { # spent 132µs making 1 call to Term::ANSIColor::CORE:sort |
| 180 | 555 | 2.47ms | $ATTRIBUTES_R{ $ATTRIBUTES{$attr} } = $attr; | ||
| 181 | } | ||||
| 182 | |||||
| 183 | # Import any custom colors set in the environment. | ||||
| 184 | 1 | 200ns | our %ALIASES; | ||
| 185 | 1 | 800ns | if (exists $ENV{ANSI_COLORS_ALIASES}) { | ||
| 186 | my $spec = $ENV{ANSI_COLORS_ALIASES}; | ||||
| 187 | $spec =~ s{\s+}{}xmsg; | ||||
| 188 | |||||
| 189 | # Error reporting here is an interesting question. Use warn rather than | ||||
| 190 | # carp because carp would report the line of the use or require, which | ||||
| 191 | # doesn't help anyone understand what's going on, whereas seeing this code | ||||
| 192 | # will be more helpful. | ||||
| 193 | ## no critic (ErrorHandling::RequireCarping) | ||||
| 194 | for my $definition (split m{,}xms, $spec) { | ||||
| 195 | my ($new, $old) = split m{=}xms, $definition, 2; | ||||
| 196 | if (!$new || !$old) { | ||||
| 197 | warn qq{Bad color mapping "$definition"}; | ||||
| 198 | } else { | ||||
| 199 | my $result = eval { coloralias($new, $old) }; | ||||
| 200 | if (!$result) { | ||||
| 201 | my $error = $@; | ||||
| 202 | $error =~ s{ [ ] at [ ] .* }{}xms; | ||||
| 203 | warn qq{$error in "$definition"}; | ||||
| 204 | } | ||||
| 205 | } | ||||
| 206 | } | ||||
| 207 | } | ||||
| 208 | |||||
| 209 | # Stores the current color stack maintained by PUSHCOLOR and POPCOLOR. This | ||||
| 210 | # is global and therefore not threadsafe. | ||||
| 211 | 1 | 200ns | our @COLORSTACK; | ||
| 212 | |||||
| 213 | ############################################################################## | ||||
| 214 | # Implementation (constant form) | ||||
| 215 | ############################################################################## | ||||
| 216 | |||||
| 217 | # Time to have fun! We now want to define the constant subs, which are named | ||||
| 218 | # the same as the attributes above but in all caps. Each constant sub needs | ||||
| 219 | # to act differently depending on whether $AUTORESET is set. Without | ||||
| 220 | # autoreset: | ||||
| 221 | # | ||||
| 222 | # BLUE "text\n" ==> "\e[34mtext\n" | ||||
| 223 | # | ||||
| 224 | # If $AUTORESET is set, we should instead get: | ||||
| 225 | # | ||||
| 226 | # BLUE "text\n" ==> "\e[34mtext\n\e[0m" | ||||
| 227 | # | ||||
| 228 | # The sub also needs to handle the case where it has no arguments correctly. | ||||
| 229 | # Maintaining all of this as separate subs would be a major nightmare, as well | ||||
| 230 | # as duplicate the %ATTRIBUTES hash, so instead we define an AUTOLOAD sub to | ||||
| 231 | # define the constant subs on demand. To do that, we check the name of the | ||||
| 232 | # called sub against the list of attributes, and if it's an all-caps version | ||||
| 233 | # of one of them, we define the sub on the fly and then run it. | ||||
| 234 | # | ||||
| 235 | # If the environment variable ANSI_COLORS_DISABLED is set to a true value, | ||||
| 236 | # just return the arguments without adding any escape sequences. This is to | ||||
| 237 | # make it easier to write scripts that also work on systems without any ANSI | ||||
| 238 | # support, like Windows consoles. | ||||
| 239 | # | ||||
| 240 | ## no critic (ClassHierarchies::ProhibitAutoloading) | ||||
| 241 | ## no critic (Subroutines::RequireArgUnpacking) | ||||
| 242 | sub AUTOLOAD { | ||||
| 243 | my ($sub, $attr) = $AUTOLOAD =~ m{ \A ([\w:]*::([[:upper:]\d_]+)) \z }xms; | ||||
| 244 | |||||
| 245 | # Check if we were called with something that doesn't look like an | ||||
| 246 | # attribute. | ||||
| 247 | if (!$attr || !defined $ATTRIBUTES{ lc $attr }) { | ||||
| 248 | croak("undefined subroutine &$AUTOLOAD called"); | ||||
| 249 | } | ||||
| 250 | |||||
| 251 | # If colors are disabled, just return the input. Do this without | ||||
| 252 | # installing a sub for (marginal, unbenchmarked) speed. | ||||
| 253 | if ($ENV{ANSI_COLORS_DISABLED}) { | ||||
| 254 | return join q{}, @_; | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | # We've untainted the name of the sub. | ||||
| 258 | $AUTOLOAD = $sub; | ||||
| 259 | |||||
| 260 | # Figure out the ANSI string to set the desired attribute. | ||||
| 261 | my $escape = "\e[" . $ATTRIBUTES{ lc $attr } . 'm'; | ||||
| 262 | |||||
| 263 | # Save the current value of $@. We can't just use local since we want to | ||||
| 264 | # restore it before dispatching to the newly-created sub. (The caller may | ||||
| 265 | # be colorizing output that includes $@.) | ||||
| 266 | my $eval_err = $@; | ||||
| 267 | |||||
| 268 | # Generate the constant sub, which should still recognize some of our | ||||
| 269 | # package variables. Use string eval to avoid a dependency on | ||||
| 270 | # Sub::Install, even though it makes it somewhat less readable. | ||||
| 271 | ## no critic (BuiltinFunctions::ProhibitStringyEval) | ||||
| 272 | ## no critic (ValuesAndExpressions::ProhibitImplicitNewlines) | ||||
| 273 | my $eval_result = eval qq{ | ||||
| 274 | sub $AUTOLOAD { | ||||
| 275 | if (\$ENV{ANSI_COLORS_DISABLED}) { | ||||
| 276 | return join q{}, \@_; | ||||
| 277 | } elsif (\$AUTOLOCAL && \@_) { | ||||
| 278 | return PUSHCOLOR('$escape') . join(q{}, \@_) . POPCOLOR; | ||||
| 279 | } elsif (\$AUTORESET && \@_) { | ||||
| 280 | return '$escape' . join(q{}, \@_) . "\e[0m"; | ||||
| 281 | } else { | ||||
| 282 | return '$escape' . join q{}, \@_; | ||||
| 283 | } | ||||
| 284 | } | ||||
| 285 | 1; | ||||
| 286 | }; | ||||
| 287 | |||||
| 288 | # Failure is an internal error, not a problem with the caller. | ||||
| 289 | ## no critic (ErrorHandling::RequireCarping) | ||||
| 290 | if (!$eval_result) { | ||||
| 291 | die "failed to generate constant $attr: $@"; | ||||
| 292 | } | ||||
| 293 | |||||
| 294 | # Restore $@. | ||||
| 295 | ## no critic (Variables::RequireLocalizedPunctuationVars) | ||||
| 296 | $@ = $eval_err; | ||||
| 297 | |||||
| 298 | # Dispatch to the newly-created sub. | ||||
| 299 | ## no critic (References::ProhibitDoubleSigils) | ||||
| 300 | goto &$AUTOLOAD; | ||||
| 301 | } | ||||
| 302 | ## use critic (Subroutines::RequireArgUnpacking) | ||||
| 303 | |||||
| 304 | # Append a new color to the top of the color stack and return the top of | ||||
| 305 | # the stack. | ||||
| 306 | # | ||||
| 307 | # $text - Any text we're applying colors to, with color escapes prepended | ||||
| 308 | # | ||||
| 309 | # Returns: The text passed in | ||||
| 310 | sub PUSHCOLOR { | ||||
| 311 | my (@text) = @_; | ||||
| 312 | my $text = join q{}, @text; | ||||
| 313 | |||||
| 314 | # Extract any number of color-setting escape sequences from the start of | ||||
| 315 | # the string. | ||||
| 316 | my ($color) = $text =~ m{ \A ( (?:\e\[ [\d;]+ m)+ ) }xms; | ||||
| 317 | |||||
| 318 | # If we already have a stack, append these escapes to the set from the top | ||||
| 319 | # of the stack. This way, each position in the stack stores the complete | ||||
| 320 | # enabled colors for that stage, at the cost of some potential | ||||
| 321 | # inefficiency. | ||||
| 322 | if (@COLORSTACK) { | ||||
| 323 | $color = $COLORSTACK[-1] . $color; | ||||
| 324 | } | ||||
| 325 | |||||
| 326 | # Push the color onto the stack. | ||||
| 327 | push @COLORSTACK, $color; | ||||
| 328 | return $text; | ||||
| 329 | } | ||||
| 330 | |||||
| 331 | # Pop the color stack and return the new top of the stack (or reset, if | ||||
| 332 | # the stack is empty). | ||||
| 333 | # | ||||
| 334 | # @text - Any text we're applying colors to | ||||
| 335 | # | ||||
| 336 | # Returns: The concatenation of @text prepended with the new stack color | ||||
| 337 | sub POPCOLOR { | ||||
| 338 | my (@text) = @_; | ||||
| 339 | pop @COLORSTACK; | ||||
| 340 | if (@COLORSTACK) { | ||||
| 341 | return $COLORSTACK[-1] . join q{}, @text; | ||||
| 342 | } else { | ||||
| 343 | return RESET(@text); | ||||
| 344 | } | ||||
| 345 | } | ||||
| 346 | |||||
| 347 | # Surround arguments with a push and a pop. The effect will be to reset the | ||||
| 348 | # colors to whatever was on the color stack before this sequence of colors was | ||||
| 349 | # applied. | ||||
| 350 | # | ||||
| 351 | # @text - Any text we're applying colors to | ||||
| 352 | # | ||||
| 353 | # Returns: The concatenation of the text and the proper color reset sequence. | ||||
| 354 | sub LOCALCOLOR { | ||||
| 355 | my (@text) = @_; | ||||
| 356 | return PUSHCOLOR(join q{}, @text) . POPCOLOR(); | ||||
| 357 | } | ||||
| 358 | |||||
| 359 | ############################################################################## | ||||
| 360 | # Implementation (attribute string form) | ||||
| 361 | ############################################################################## | ||||
| 362 | |||||
| 363 | # Return the escape code for a given set of color attributes. | ||||
| 364 | # | ||||
| 365 | # @codes - A list of possibly space-separated color attributes | ||||
| 366 | # | ||||
| 367 | # Returns: The escape sequence setting those color attributes | ||||
| 368 | # undef if no escape sequences were given | ||||
| 369 | # Throws: Text exception for any invalid attribute | ||||
| 370 | sub color { | ||||
| 371 | my (@codes) = @_; | ||||
| 372 | @codes = map { split } @codes; | ||||
| 373 | |||||
| 374 | # Return the empty string if colors are disabled. | ||||
| 375 | if ($ENV{ANSI_COLORS_DISABLED}) { | ||||
| 376 | return q{}; | ||||
| 377 | } | ||||
| 378 | |||||
| 379 | # Build the attribute string from semicolon-separated numbers. | ||||
| 380 | my $attribute = q{}; | ||||
| 381 | for my $code (@codes) { | ||||
| 382 | $code = lc $code; | ||||
| 383 | if (defined $ATTRIBUTES{$code}) { | ||||
| 384 | $attribute .= $ATTRIBUTES{$code} . q{;}; | ||||
| 385 | } elsif (defined $ALIASES{$code}) { | ||||
| 386 | $attribute .= $ALIASES{$code} . q{;}; | ||||
| 387 | } else { | ||||
| 388 | croak("Invalid attribute name $code"); | ||||
| 389 | } | ||||
| 390 | } | ||||
| 391 | |||||
| 392 | # We added one too many semicolons for simplicity. Remove the last one. | ||||
| 393 | chop $attribute; | ||||
| 394 | |||||
| 395 | # Return undef if there were no attributes. | ||||
| 396 | return ($attribute ne q{}) ? "\e[${attribute}m" : undef; | ||||
| 397 | } | ||||
| 398 | |||||
| 399 | # Return a list of named color attributes for a given set of escape codes. | ||||
| 400 | # Escape sequences can be given with or without enclosing "\e[" and "m". The | ||||
| 401 | # empty escape sequence '' or "\e[m" gives an empty list of attrs. | ||||
| 402 | # | ||||
| 403 | # There is one special case. 256-color codes start with 38 or 48, followed by | ||||
| 404 | # a 5 and then the 256-color code. | ||||
| 405 | # | ||||
| 406 | # @escapes - A list of escape sequences or escape sequence numbers | ||||
| 407 | # | ||||
| 408 | # Returns: An array of attribute names corresponding to those sequences | ||||
| 409 | # Throws: Text exceptions on invalid escape sequences or unknown colors | ||||
| 410 | sub uncolor { | ||||
| 411 | my (@escapes) = @_; | ||||
| 412 | my (@nums, @result); | ||||
| 413 | |||||
| 414 | # Walk the list of escapes and build a list of attribute numbers. | ||||
| 415 | for my $escape (@escapes) { | ||||
| 416 | $escape =~ s{ \A \e\[ }{}xms; | ||||
| 417 | $escape =~ s{ m \z } {}xms; | ||||
| 418 | my ($attrs) = $escape =~ m{ \A ((?:\d+;)* \d*) \z }xms; | ||||
| 419 | if (!defined $attrs) { | ||||
| 420 | croak("Bad escape sequence $escape"); | ||||
| 421 | } | ||||
| 422 | |||||
| 423 | # Pull off 256-color codes (38;5;n or 48;5;n) as a unit. | ||||
| 424 | push @nums, $attrs =~ m{ ( 0*[34]8;0*5;\d+ | \d+ ) (?: ; | \z ) }xmsg; | ||||
| 425 | } | ||||
| 426 | |||||
| 427 | # Now, walk the list of numbers and convert them to attribute names. | ||||
| 428 | # Strip leading zeroes from any of the numbers. (xterm, at least, allows | ||||
| 429 | # leading zeroes to be added to any number in an escape sequence.) | ||||
| 430 | for my $num (@nums) { | ||||
| 431 | $num =~ s{ ( \A | ; ) 0+ (\d) }{$1$2}xmsg; | ||||
| 432 | my $name = $ATTRIBUTES_R{$num}; | ||||
| 433 | if (!defined $name) { | ||||
| 434 | croak("No name for escape sequence $num"); | ||||
| 435 | } | ||||
| 436 | push @result, $name; | ||||
| 437 | } | ||||
| 438 | |||||
| 439 | # Return the attribute names. | ||||
| 440 | return @result; | ||||
| 441 | } | ||||
| 442 | |||||
| 443 | # Given a string and a set of attributes, returns the string surrounded by | ||||
| 444 | # escape codes to set those attributes and then clear them at the end of the | ||||
| 445 | # string. The attributes can be given either as an array ref as the first | ||||
| 446 | # argument or as a list as the second and subsequent arguments. | ||||
| 447 | # | ||||
| 448 | # If $EACHLINE is set, insert a reset before each occurrence of the string | ||||
| 449 | # $EACHLINE and the starting attribute code after the string $EACHLINE, so | ||||
| 450 | # that no attribute crosses line delimiters (this is often desirable if the | ||||
| 451 | # output is to be piped to a pager or some other program). | ||||
| 452 | # | ||||
| 453 | # $first - An anonymous array of attributes or the text to color | ||||
| 454 | # @rest - The text to color or the list of attributes | ||||
| 455 | # | ||||
| 456 | # Returns: The text, concatenated if necessary, surrounded by escapes to set | ||||
| 457 | # the desired colors and reset them afterwards | ||||
| 458 | # Throws: Text exception on invalid attributes | ||||
| 459 | sub colored { | ||||
| 460 | my ($first, @rest) = @_; | ||||
| 461 | my ($string, @codes); | ||||
| 462 | if (ref($first) && ref($first) eq 'ARRAY') { | ||||
| 463 | @codes = @{$first}; | ||||
| 464 | $string = join q{}, @rest; | ||||
| 465 | } else { | ||||
| 466 | $string = $first; | ||||
| 467 | @codes = @rest; | ||||
| 468 | } | ||||
| 469 | |||||
| 470 | # Return the string unmolested if colors are disabled. | ||||
| 471 | if ($ENV{ANSI_COLORS_DISABLED}) { | ||||
| 472 | return $string; | ||||
| 473 | } | ||||
| 474 | |||||
| 475 | # Find the attribute string for our colors. | ||||
| 476 | my $attr = color(@codes); | ||||
| 477 | |||||
| 478 | # If $EACHLINE is defined, split the string on line boundaries, suppress | ||||
| 479 | # empty segments, and then colorize each of the line sections. | ||||
| 480 | if (defined $EACHLINE) { | ||||
| 481 | my @text = map { ($_ ne $EACHLINE) ? $attr . $_ . "\e[0m" : $_ } | ||||
| 482 | grep { length($_) > 0 } | ||||
| 483 | split m{ (\Q$EACHLINE\E) }xms, $string; | ||||
| 484 | return join q{}, @text; | ||||
| 485 | } else { | ||||
| 486 | return $attr . $string . "\e[0m"; | ||||
| 487 | } | ||||
| 488 | } | ||||
| 489 | |||||
| 490 | # Define a new color alias, or return the value of an existing alias. | ||||
| 491 | # | ||||
| 492 | # $alias - The color alias to define | ||||
| 493 | # $color - The standard color the alias will correspond to (optional) | ||||
| 494 | # | ||||
| 495 | # Returns: The standard color value of the alias | ||||
| 496 | # undef if one argument was given and the alias was not recognized | ||||
| 497 | # Throws: Text exceptions for invalid alias names, attempts to use a | ||||
| 498 | # standard color name as an alias, or an unknown standard color name | ||||
| 499 | sub coloralias { | ||||
| 500 | my ($alias, $color) = @_; | ||||
| 501 | if (!defined $color) { | ||||
| 502 | if (!exists $ALIASES{$alias}) { | ||||
| 503 | return; | ||||
| 504 | } else { | ||||
| 505 | return $ATTRIBUTES_R{ $ALIASES{$alias} }; | ||||
| 506 | } | ||||
| 507 | } | ||||
| 508 | if ($alias !~ m{ \A [\w._-]+ \z }xms) { | ||||
| 509 | croak(qq{Invalid alias name "$alias"}); | ||||
| 510 | } elsif ($ATTRIBUTES{$alias}) { | ||||
| 511 | croak(qq{Cannot alias standard color "$alias"}); | ||||
| 512 | } elsif (!exists $ATTRIBUTES{$color}) { | ||||
| 513 | croak(qq{Invalid attribute name "$color"}); | ||||
| 514 | } | ||||
| 515 | $ALIASES{$alias} = $ATTRIBUTES{$color}; | ||||
| 516 | return $color; | ||||
| 517 | } | ||||
| 518 | |||||
| 519 | # Given a string, strip the ANSI color codes out of that string and return the | ||||
| 520 | # result. This removes only ANSI color codes, not movement codes and other | ||||
| 521 | # escape sequences. | ||||
| 522 | # | ||||
| 523 | # @string - The list of strings to sanitize | ||||
| 524 | # | ||||
| 525 | # Returns: (array) The strings stripped of ANSI color escape sequences | ||||
| 526 | # (scalar) The same, concatenated | ||||
| 527 | sub colorstrip { | ||||
| 528 | my (@string) = @_; | ||||
| 529 | for my $string (@string) { | ||||
| 530 | $string =~ s{ \e\[ [\d;]* m }{}xmsg; | ||||
| 531 | } | ||||
| 532 | return wantarray ? @string : join q{}, @string; | ||||
| 533 | } | ||||
| 534 | |||||
| 535 | # Given a list of color attributes (arguments for color, for instance), return | ||||
| 536 | # true if they're all valid or false if any of them are invalid. | ||||
| 537 | # | ||||
| 538 | # @codes - A list of color attributes, possibly space-separated | ||||
| 539 | # | ||||
| 540 | # Returns: True if all the attributes are valid, false otherwise. | ||||
| 541 | # spent 23µs within Term::ANSIColor::colorvalid which was called 5 times, avg 5µs/call:
# 5 times (23µs+0s) by Perl::Critic::Config::_validate_and_save_color_severity at line 723 of Perl/Critic/Config.pm, avg 5µs/call | ||||
| 542 | 5 | 3µs | my (@codes) = @_; | ||
| 543 | 8 | 7µs | @codes = map { split q{ }, lc $_ } @codes; | ||
| 544 | 5 | 3µs | for my $code (@codes) { | ||
| 545 | 3 | 3µs | if (!defined $ATTRIBUTES{$code} && !defined $ALIASES{$code}) { | ||
| 546 | return; | ||||
| 547 | } | ||||
| 548 | } | ||||
| 549 | 5 | 11µs | return 1; | ||
| 550 | } | ||||
| 551 | |||||
| 552 | ############################################################################## | ||||
| 553 | # Module return value and documentation | ||||
| 554 | ############################################################################## | ||||
| 555 | |||||
| 556 | # Ensure we evaluate to true. | ||||
| 557 | 1 | 33µs | 1; | ||
| 558 | __END__ | ||||
# spent 132µs within Term::ANSIColor::CORE:sort which was called:
# once (132µs+0s) by Perl::Critic::Config::_validate_and_save_color_severity at line 179 |