line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
1388
|
use 5.005; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
120
|
|
2
|
|
|
|
|
|
|
package Term::ANSIScreen; |
3
|
|
|
|
|
|
|
$Term::ANSIScreen::VERSION = '1.50'; |
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
97
|
|
6
|
2
|
|
|
|
|
322
|
use vars qw/@ISA @EXPORT %EXPORT_TAGS $VERSION $AUTOLOAD |
7
|
2
|
|
|
2
|
|
10
|
%attributes %attributes_r %sequences $AUTORESET $EACHLINE/; |
|
2
|
|
|
|
|
4
|
|
8
|
2
|
|
|
2
|
|
11
|
use Exporter; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
722
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Term::ANSIScreen - Terminal control using ANSI escape sequences |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 SYNOPSIS |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# qw/:color/ is exported by default, i.e. color() & colored() |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use Term::ANSIScreen qw/:color :cursor :screen :keyboard/; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
print setmode(1), setkey('a','b'); |
21
|
|
|
|
|
|
|
print "40x25 mode now, with 'a' mapped to 'b'."; |
22
|
|
|
|
|
|
|
; resetkey; setmode 3; cls; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
locate 1, 1; print "@ This is (1,1)", savepos; |
25
|
|
|
|
|
|
|
print locate(24,60), "@ This is (24,60)"; loadpos; |
26
|
|
|
|
|
|
|
print down(2), clline, "@ This is (3,15)\n"; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
setscroll 1, 20; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
color 'black on white'; clline; |
31
|
|
|
|
|
|
|
print "This line is black on white.\n"; |
32
|
|
|
|
|
|
|
print color 'reset'; print "This text is normal.\n"; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
print colored ("This text is bold blue.\n", 'bold blue'); |
35
|
|
|
|
|
|
|
print "This text is normal.\n"; |
36
|
|
|
|
|
|
|
print colored ['bold blue'], "This text is bold blue.\n"; |
37
|
|
|
|
|
|
|
print "This text is normal.\n"; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
use Term::ANSIScreen qw/:constants/; # constants mode |
40
|
|
|
|
|
|
|
print BLUE ON GREEN . "Blue on green.\n"; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
$Term::ANSIScreen::AUTORESET = 1; |
43
|
|
|
|
|
|
|
print BOLD GREEN . ON_BLUE "Bold green on blue.", CLEAR; |
44
|
|
|
|
|
|
|
print "\nThis text is normal.\n"; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Win32::Console emulation mode |
47
|
|
|
|
|
|
|
# this returns a Win32::Console object on a Win32 platform |
48
|
|
|
|
|
|
|
my $console = Term::ANSIScreen->new; |
49
|
|
|
|
|
|
|
$console->Cls; # also works on non-Win32 platform |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=cut |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# ----------------------- |
54
|
|
|
|
|
|
|
# Internal data structure |
55
|
|
|
|
|
|
|
# ----------------------- |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
%attributes = ( |
58
|
|
|
|
|
|
|
'clear' => 0, 'reset' => 0, |
59
|
|
|
|
|
|
|
'bold' => 1, 'dark' => 2, |
60
|
|
|
|
|
|
|
'underline' => 4, 'underscore' => 4, |
61
|
|
|
|
|
|
|
'blink' => 5, 'reverse' => 7, |
62
|
|
|
|
|
|
|
'concealed' => 8, |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
'black' => 30, 'on_black' => 40, |
65
|
|
|
|
|
|
|
'red' => 31, 'on_red' => 41, |
66
|
|
|
|
|
|
|
'green' => 32, 'on_green' => 42, |
67
|
|
|
|
|
|
|
'yellow' => 33, 'on_yellow' => 43, |
68
|
|
|
|
|
|
|
'blue' => 34, 'on_blue' => 44, |
69
|
|
|
|
|
|
|
'magenta' => 35, 'on_magenta' => 45, |
70
|
|
|
|
|
|
|
'cyan' => 36, 'on_cyan' => 46, |
71
|
|
|
|
|
|
|
'white' => 37, 'on_white' => 47, |
72
|
|
|
|
|
|
|
); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
%sequences = ( |
75
|
|
|
|
|
|
|
'up' => '?A', 'down' => '?B', |
76
|
|
|
|
|
|
|
'right' => '?C', 'left' => '?D', |
77
|
|
|
|
|
|
|
'savepos' => 's', 'loadpos' => 'u', |
78
|
|
|
|
|
|
|
'cls' => '2J', 'clline' => 'K', |
79
|
|
|
|
|
|
|
'cldown' => '0J', 'clup' => '1J', |
80
|
|
|
|
|
|
|
'locate' => '?;?H', 'setmode' => '?h', |
81
|
|
|
|
|
|
|
'wrapon' => '7h', 'wrapoff' => '7l', |
82
|
|
|
|
|
|
|
'setscroll' => '?;?r', |
83
|
|
|
|
|
|
|
); |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
my %mapped; |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# ---------------- |
88
|
|
|
|
|
|
|
# Exporter section |
89
|
|
|
|
|
|
|
# ---------------- |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
@ISA = qw/Exporter/; |
92
|
|
|
|
|
|
|
%EXPORT_TAGS = ( |
93
|
|
|
|
|
|
|
'color' => [qw/color colored uncolor/], |
94
|
|
|
|
|
|
|
'cursor' => [qw/locate up down right left savepos loadpos/], |
95
|
|
|
|
|
|
|
'screen' => [qw/cls clline cldown clup setmode wrapon wrapoff setscroll/], |
96
|
|
|
|
|
|
|
'keyboard' => [qw/setkey resetkey/], |
97
|
|
|
|
|
|
|
'constants' => [map {uc($_)} keys(%attributes), 'ON'], |
98
|
|
|
|
|
|
|
); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
$EXPORT_TAGS{all} = [map {@{$_}} values (%EXPORT_TAGS)]; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
@EXPORT = qw(color colored); |
103
|
|
|
|
|
|
|
Exporter::export_ok_tags (keys(%EXPORT_TAGS)); |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub new { |
106
|
1
|
|
|
1
|
0
|
19
|
my $class = shift; |
107
|
|
|
|
|
|
|
|
108
|
1
|
50
|
33
|
|
|
9
|
if ($^O eq 'MSWin32' and eval { require Win32::Console } ) { |
|
0
|
|
|
|
|
0
|
|
109
|
0
|
|
|
|
|
0
|
return Win32::Console->new(@_); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
2
|
|
|
2
|
|
12
|
no strict 'refs'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
3171
|
|
113
|
1
|
50
|
|
|
|
3
|
unless ($main::FG_WHITE) { |
114
|
1
|
|
|
|
|
10
|
foreach my $color (grep { $attributes{$_} >= 30 } keys %attributes) { |
|
25
|
|
|
|
|
40
|
|
115
|
16
|
|
|
|
|
27
|
my $name = "FG_\U$color"; |
116
|
16
|
|
|
|
|
30
|
$name =~ s/^FG_ON_/BG_/; |
117
|
16
|
|
|
|
|
26
|
${"main::$name"} = color($color); |
|
16
|
|
|
|
|
97
|
|
118
|
16
|
|
|
|
|
39
|
$name =~ s/_/_LIGHT/; |
119
|
16
|
|
|
|
|
28
|
${"main::$name"} = color('bold', $color); |
|
16
|
|
|
|
|
75
|
|
120
|
|
|
|
|
|
|
} |
121
|
1
|
|
|
|
|
3
|
$main::FG_LIGHTWHITE = $main::FG_WHITE; |
122
|
1
|
|
|
|
|
2
|
$main::FG_BROWN = $main::FG_YELLOW; |
123
|
1
|
|
|
|
|
2
|
$main::FG_YELLOW = $main::FG_LIGHTYELLOW; |
124
|
1
|
|
|
|
|
10
|
$main::FG_WHITE = color('clear'); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
1
|
|
|
|
|
12
|
return bless([ @_ ], $class); |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub Attr { |
131
|
0
|
|
|
0
|
0
|
0
|
shift; |
132
|
0
|
|
|
|
|
0
|
print STDERR @_; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub Cls { |
136
|
0
|
|
|
0
|
0
|
0
|
print STDERR cls(); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub Cursor { |
140
|
0
|
|
|
0
|
0
|
0
|
shift; |
141
|
0
|
|
|
|
|
0
|
print STDERR locate($_[1]+1, $_[0]+1); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub Write { |
145
|
0
|
|
|
0
|
0
|
0
|
shift; |
146
|
0
|
|
|
|
|
0
|
print STDERR @_; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
0
|
0
|
0
|
sub Display { |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# -------------- |
154
|
|
|
|
|
|
|
# Implementation |
155
|
|
|
|
|
|
|
# -------------- |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub AUTOLOAD { |
158
|
13
|
|
|
13
|
|
191
|
my $enable_colors = !defined $ENV{ANSI_COLORS_DISABLED}; |
159
|
13
|
|
|
|
|
16
|
my $sub = $AUTOLOAD; |
160
|
13
|
|
|
|
|
59
|
$sub =~ s/^.*:://; |
161
|
|
|
|
|
|
|
|
162
|
13
|
100
|
33
|
|
|
106
|
if (my $seq = $sequences{$sub}) { |
|
|
50
|
|
|
|
|
|
163
|
4
|
50
|
|
|
|
9
|
return '' unless $enable_colors; |
164
|
|
|
|
|
|
|
|
165
|
4
|
50
|
|
|
|
7
|
$seq =~ s/\?/defined($_[0]) ? shift(@_) : 1/eg; |
|
2
|
|
|
|
|
6
|
|
166
|
4
|
50
|
|
|
|
16
|
return((defined wantarray) ? "\e[$seq" |
167
|
|
|
|
|
|
|
: print("\e[$seq")); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
elsif (defined(my $attr = $attributes{lc($sub)}) and $sub =~ /^[A-Z_]+$/) { |
170
|
9
|
|
|
|
|
23
|
my $out = "@_"; |
171
|
9
|
100
|
|
|
|
21
|
if ($enable_colors) { |
172
|
8
|
|
|
|
|
23
|
$out = "\e[${attr}m" . $out; |
173
|
8
|
100
|
66
|
|
|
50
|
$out .= "\e[0m" if ($AUTORESET and @_ and $out !~ /\e\[0m$/s); |
|
|
|
100
|
|
|
|
|
174
|
|
|
|
|
|
|
} |
175
|
9
|
50
|
|
|
|
43
|
return((defined wantarray) ? $out |
176
|
|
|
|
|
|
|
: print($out)); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
else { |
179
|
0
|
|
|
|
|
0
|
require Carp; |
180
|
0
|
|
|
|
|
0
|
Carp::croak("Undefined subroutine &$AUTOLOAD called"); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# ------------------------------------------------ |
185
|
|
|
|
|
|
|
# Convert foreground constants to background ones, |
186
|
|
|
|
|
|
|
# for sequences like (XXX ON YYY "text") |
187
|
|
|
|
|
|
|
# ------------------------------------------------ |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub ON { |
190
|
1
|
50
|
|
1
|
0
|
5
|
return '' if defined $ENV{ANSI_COLORS_DISABLED}; |
191
|
|
|
|
|
|
|
|
192
|
1
|
|
|
|
|
4
|
my $out = "@_"; |
193
|
1
|
|
|
|
|
19
|
$out =~ s/^\e\[3(\d)m/\e\[4$1m/; |
194
|
1
|
|
|
|
|
6
|
return $out; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# --------------------------------------- |
198
|
|
|
|
|
|
|
# Color subroutines, from Term::ANSIColor |
199
|
|
|
|
|
|
|
# --------------------------------------- |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub color { |
202
|
40
|
100
|
|
40
|
1
|
152
|
return '' if defined $ENV{ANSI_COLORS_DISABLED}; |
203
|
|
|
|
|
|
|
|
204
|
38
|
|
|
|
|
46
|
my @codes = map { split } @_; |
|
57
|
|
|
|
|
128
|
|
205
|
38
|
|
|
|
|
43
|
my $attribute; |
206
|
|
|
|
|
|
|
|
207
|
2
|
|
|
2
|
|
19
|
no warnings 'uninitialized'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1717
|
|
208
|
38
|
|
|
|
|
89
|
while (my $code = lc(shift(@codes))) { |
209
|
58
|
50
|
|
|
|
95
|
$code .= '_' . shift(@codes) if ($code eq 'on'); |
210
|
|
|
|
|
|
|
|
211
|
58
|
50
|
|
|
|
125
|
if (defined $attributes{$code}) { |
212
|
58
|
|
|
|
|
181
|
$attribute .= $attributes{$code} . ';'; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
else { |
215
|
0
|
|
|
|
|
0
|
warn "Invalid attribute name $code"; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
38
|
50
|
|
|
|
81
|
if ($attribute) { |
220
|
38
|
|
|
|
|
44
|
chop $attribute; |
221
|
38
|
50
|
|
|
|
105
|
return (defined wantarray) ? "\e[${attribute}m" |
222
|
|
|
|
|
|
|
: print("\e[${attribute}m"); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub colored { |
227
|
5
|
|
|
5
|
1
|
44
|
my $output; |
228
|
1
|
|
|
|
|
4
|
my ($string, $attr) = (ref $_[0]) |
229
|
5
|
100
|
|
|
|
18
|
? (join('', @_[1..$#_]), color(@{$_[0]})) |
230
|
|
|
|
|
|
|
: (+shift, color(@_)); |
231
|
|
|
|
|
|
|
|
232
|
5
|
100
|
|
|
|
17
|
return $string if defined $ENV{ANSI_COLORS_DISABLED}; |
233
|
|
|
|
|
|
|
|
234
|
4
|
100
|
|
|
|
9
|
if (defined $EACHLINE) { |
235
|
14
|
100
|
100
|
|
|
76
|
$output = join '', |
236
|
3
|
|
|
|
|
59
|
map { ($_ && $_ ne $EACHLINE) ? $attr . $_ . "\e[0m" : $_ } |
237
|
|
|
|
|
|
|
split (/(\Q$EACHLINE\E)/, $string); |
238
|
|
|
|
|
|
|
} else { |
239
|
1
|
|
|
|
|
4
|
$output = "$attr$string\e[0m"; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
4
|
50
|
|
|
|
22
|
return (defined wantarray) ? $output |
243
|
|
|
|
|
|
|
: print($output); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub uncolor { |
247
|
1
|
|
|
1
|
0
|
13
|
my (@nums, @result); |
248
|
|
|
|
|
|
|
|
249
|
1
|
|
|
|
|
3
|
foreach my $seq (@_) { |
250
|
4
|
|
|
|
|
7
|
my $escape = $seq; |
251
|
4
|
|
|
|
|
10
|
$escape =~ s/^\e\[//; |
252
|
4
|
|
|
|
|
10
|
$escape =~ s/m$//; |
253
|
4
|
50
|
|
|
|
20
|
unless ($escape =~ /^((?:\d+;)*\d*)$/) { |
254
|
0
|
|
|
|
|
0
|
require Carp; |
255
|
0
|
|
|
|
|
0
|
Carp::croak("Bad escape sequence $seq"); |
256
|
|
|
|
|
|
|
} |
257
|
4
|
|
|
|
|
14
|
push (@nums, split (/;/, $1)); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
1
|
|
|
|
|
4
|
_init_attributes_r(); |
261
|
|
|
|
|
|
|
|
262
|
1
|
|
|
|
|
3
|
foreach my $num (@nums) { |
263
|
3
|
|
|
|
|
7
|
$num += 0; # Strip leading zeroes |
264
|
3
|
|
|
|
|
4
|
my $name = $attributes_r{$num}; |
265
|
3
|
50
|
|
|
|
15
|
if (!defined $name) { |
266
|
0
|
|
|
|
|
0
|
require Carp; |
267
|
0
|
|
|
|
|
0
|
Carp::croak("No name for escape sequence $num" ); |
268
|
|
|
|
|
|
|
} |
269
|
3
|
|
|
|
|
7
|
push (@result, $name); |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
1
|
|
|
|
|
5
|
return @result; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub _init_attributes_r { |
276
|
1
|
50
|
|
1
|
|
4
|
return if %attributes_r; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
# Reverse lookup. Alphabetically first name for a sequence is preferred. |
279
|
1
|
|
|
|
|
21
|
for (reverse sort keys %attributes) { |
280
|
25
|
|
|
|
|
84
|
$attributes_r{$attributes{$_}} = $_; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub setkey { |
285
|
0
|
|
|
0
|
1
|
|
my ($key, $mapto) = @_; |
286
|
|
|
|
|
|
|
|
287
|
0
|
0
|
|
|
|
|
if ($key eq $mapto) { |
288
|
0
|
0
|
|
|
|
|
delete $mapped{$key} if exists $mapped{$key}; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
else { |
291
|
0
|
|
|
|
|
|
$mapped{$key} = 1; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
0
|
0
|
|
|
|
|
$key = ord($key) unless ($key =~ /^\d+;\d+$/); |
295
|
0
|
0
|
|
|
|
|
$mapto = qq("$mapto") unless ($mapto =~ /^\d+;\d+$/); |
296
|
|
|
|
|
|
|
|
297
|
0
|
0
|
|
|
|
|
return (defined wantarray) ? "\e[$key;${mapto}p" |
298
|
|
|
|
|
|
|
: print("\e[$key;${mapto}p"); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub resetkey { |
302
|
0
|
|
|
0
|
1
|
|
my $output; |
303
|
|
|
|
|
|
|
|
304
|
0
|
0
|
|
|
|
|
foreach my $key (@_ ? @_ : keys(%mapped)) { |
305
|
0
|
|
|
|
|
|
$output .= setkey($key, $key); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
0
|
0
|
|
|
|
|
return (defined wantarray) ? $output |
309
|
|
|
|
|
|
|
: print($output); |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub DESTROY { |
313
|
0
|
|
|
0
|
|
|
return; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
1; |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
__END__ |