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 | BEGIN@42 | Term::ANSIColor::
1 | 1 | 1 | 132µs | 132µs | CORE:sort (opcode) | Term::ANSIColor::
5 | 1 | 1 | 23µs | 23µs | colorvalid | Term::ANSIColor::
1 | 1 | 1 | 22µs | 22µs | BEGIN@22 | Term::ANSIColor::
1 | 1 | 1 | 8µs | 15µs | BEGIN@24 | Term::ANSIColor::
1 | 1 | 1 | 8µs | 34µs | BEGIN@26 | Term::ANSIColor::
1 | 1 | 1 | 8µs | 22µs | BEGIN@23 | Term::ANSIColor::
1 | 1 | 1 | 4µs | 4µs | BEGIN@27 | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | AUTOLOAD | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | LOCALCOLOR | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | POPCOLOR | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | PUSHCOLOR | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | color | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | coloralias | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | colored | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | colorstrip | Term::ANSIColor::
0 | 0 | 0 | 0s | 0s | uncolor | Term::ANSIColor::
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 |