line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::ANSITable; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY |
4
|
|
|
|
|
|
|
our $DATE = '2021-02-19'; # DATE |
5
|
|
|
|
|
|
|
our $DIST = 'Text-ANSITable'; # DIST |
6
|
|
|
|
|
|
|
our $VERSION = '0.602'; # VERSION |
7
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
181663
|
use 5.010001; |
|
2
|
|
|
|
|
39
|
|
9
|
2
|
|
|
2
|
|
9
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
117
|
|
10
|
2
|
|
|
2
|
|
3088
|
use Log::ger; |
|
2
|
|
|
|
|
90
|
|
|
2
|
|
|
|
|
7
|
|
11
|
2
|
|
|
2
|
|
1382
|
use Moo; |
|
2
|
|
|
|
|
20101
|
|
|
2
|
|
|
|
|
10
|
|
12
|
2
|
|
|
2
|
|
3454
|
use experimental 'smartmatch'; |
|
2
|
|
|
|
|
6039
|
|
|
2
|
|
|
|
|
12
|
|
13
|
|
|
|
|
|
|
|
14
|
2
|
|
|
2
|
|
1034
|
use ColorThemeUtil::ANSI qw(item_color_to_ansi); |
|
2
|
|
|
|
|
709
|
|
|
2
|
|
|
|
|
103
|
|
15
|
|
|
|
|
|
|
#use List::Util qw(first); |
16
|
2
|
|
|
2
|
|
12
|
use Scalar::Util 'looks_like_number'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
19808
|
|
17
|
|
|
|
|
|
|
require Win32::Console::ANSI if $^O =~ /Win/; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $ATTRS = [qw( |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use_color color_depth use_box_chars use_utf8 columns rows |
22
|
|
|
|
|
|
|
column_filter row_filter show_row_separator show_header |
23
|
|
|
|
|
|
|
show_header cell_width cell_height cell_pad cell_lpad |
24
|
|
|
|
|
|
|
cell_rpad cell_vpad cell_tpad cell_bpad cell_fgcolor |
25
|
|
|
|
|
|
|
cell_bgcolor cell_align cell_valign header_align header_valign |
26
|
|
|
|
|
|
|
header_vpad header_tpad header_bpad header_fgcolor |
27
|
|
|
|
|
|
|
header_bgcolor |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
)]; |
30
|
|
|
|
|
|
|
my $STYLES = $ATTRS; |
31
|
|
|
|
|
|
|
my $COLUMN_STYLES = [qw( |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
type width align valign pad lpad rpad formats fgcolor |
34
|
|
|
|
|
|
|
bgcolor wrap |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
)]; |
37
|
|
|
|
|
|
|
my $ROW_STYLES = [qw( |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
height align valign vpad tpad bpad fgcolor bgcolor |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
)]; |
42
|
|
|
|
|
|
|
my $CELL_STYLES = [qw( |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
align valign formats fgcolor bgcolor |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
)]; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
has border_style => ( |
49
|
|
|
|
|
|
|
is => 'rw', |
50
|
|
|
|
|
|
|
trigger => sub { |
51
|
|
|
|
|
|
|
require Module::Load::Util; |
52
|
|
|
|
|
|
|
my ($self, $val) = @_; |
53
|
|
|
|
|
|
|
$self->{border_style_obj} = |
54
|
|
|
|
|
|
|
Module::Load::Util::instantiate_class_with_optional_args( |
55
|
|
|
|
|
|
|
{ns_prefix=>'BorderStyle'}, $val); |
56
|
|
|
|
|
|
|
}, |
57
|
|
|
|
|
|
|
); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
has color_theme => ( |
60
|
|
|
|
|
|
|
is => 'rw', |
61
|
|
|
|
|
|
|
trigger => sub { |
62
|
|
|
|
|
|
|
require Module::Load::Util; |
63
|
|
|
|
|
|
|
my ($self, $val) = @_; |
64
|
|
|
|
|
|
|
$self->{color_theme_obj} = |
65
|
|
|
|
|
|
|
Module::Load::Util::instantiate_class_with_optional_args( |
66
|
|
|
|
|
|
|
{ns_prefix=>'ColorTheme'}, $val); |
67
|
|
|
|
|
|
|
}, |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
has columns => ( |
71
|
|
|
|
|
|
|
is => 'rw', |
72
|
|
|
|
|
|
|
default => sub { [] }, |
73
|
|
|
|
|
|
|
trigger => sub { |
74
|
|
|
|
|
|
|
my $self = shift; |
75
|
|
|
|
|
|
|
$self->{_columns_set}++; |
76
|
|
|
|
|
|
|
}, |
77
|
|
|
|
|
|
|
); |
78
|
|
|
|
|
|
|
has rows => ( |
79
|
|
|
|
|
|
|
is => 'rw', |
80
|
|
|
|
|
|
|
default => sub { [] }, |
81
|
|
|
|
|
|
|
trigger => sub { |
82
|
|
|
|
|
|
|
my ($self, $rows) = @_; |
83
|
|
|
|
|
|
|
$self->_set_default_cols($rows->[0]); |
84
|
|
|
|
|
|
|
}, |
85
|
|
|
|
|
|
|
); |
86
|
|
|
|
|
|
|
has column_filter => ( |
87
|
|
|
|
|
|
|
is => 'rw', |
88
|
|
|
|
|
|
|
); |
89
|
|
|
|
|
|
|
has column_wrap => ( |
90
|
|
|
|
|
|
|
is => 'rw', |
91
|
|
|
|
|
|
|
); |
92
|
|
|
|
|
|
|
has row_filter => ( |
93
|
|
|
|
|
|
|
is => 'rw', |
94
|
|
|
|
|
|
|
); |
95
|
|
|
|
|
|
|
has _row_separators => ( # [index after which sep should be drawn, ...] sorted |
96
|
|
|
|
|
|
|
is => 'rw', |
97
|
|
|
|
|
|
|
default => sub { [] }, |
98
|
|
|
|
|
|
|
); |
99
|
|
|
|
|
|
|
has show_row_separator => ( |
100
|
|
|
|
|
|
|
is => 'rw', |
101
|
|
|
|
|
|
|
default => sub { 2 }, |
102
|
|
|
|
|
|
|
); |
103
|
|
|
|
|
|
|
has show_header => ( |
104
|
|
|
|
|
|
|
is => 'rw', |
105
|
|
|
|
|
|
|
default => sub { 1 }, |
106
|
|
|
|
|
|
|
); |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
has _column_styles => ( # store per-column styles |
109
|
|
|
|
|
|
|
is => 'rw', |
110
|
|
|
|
|
|
|
default => sub { [] }, |
111
|
|
|
|
|
|
|
); |
112
|
|
|
|
|
|
|
has _row_styles => ( # store per-row styles |
113
|
|
|
|
|
|
|
is => 'rw', |
114
|
|
|
|
|
|
|
default => sub { [] }, |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
has _cell_styles => ( # store per-cell styles |
117
|
|
|
|
|
|
|
is => 'rw', |
118
|
|
|
|
|
|
|
default => sub { [] }, |
119
|
|
|
|
|
|
|
); |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# each element of _cond_*styles is a two-element [$cond, ], where $cond is code |
122
|
|
|
|
|
|
|
# (str|coderef) and the second element is a hashref containing styles. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
has _cond_column_styles => ( # store conditional column styles |
125
|
|
|
|
|
|
|
is => 'rw', |
126
|
|
|
|
|
|
|
default => sub { [] }, |
127
|
|
|
|
|
|
|
); |
128
|
|
|
|
|
|
|
has _cond_row_styles => ( # store conditional row styles |
129
|
|
|
|
|
|
|
is => 'rw', |
130
|
|
|
|
|
|
|
default => sub { [] }, |
131
|
|
|
|
|
|
|
); |
132
|
|
|
|
|
|
|
has _cond_cell_styles => ( # store conditional cell styles |
133
|
|
|
|
|
|
|
is => 'rw', |
134
|
|
|
|
|
|
|
default => sub { [] }, |
135
|
|
|
|
|
|
|
); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
has cell_width => ( |
138
|
|
|
|
|
|
|
is => 'rw', |
139
|
|
|
|
|
|
|
); |
140
|
|
|
|
|
|
|
has cell_height => ( |
141
|
|
|
|
|
|
|
is => 'rw', |
142
|
|
|
|
|
|
|
); |
143
|
|
|
|
|
|
|
has cell_pad => ( |
144
|
|
|
|
|
|
|
is => 'rw', |
145
|
|
|
|
|
|
|
default => sub { 1 }, |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
has cell_lpad => ( |
148
|
|
|
|
|
|
|
is => 'rw', |
149
|
|
|
|
|
|
|
); |
150
|
|
|
|
|
|
|
has cell_rpad => ( |
151
|
|
|
|
|
|
|
is => 'rw', |
152
|
|
|
|
|
|
|
); |
153
|
|
|
|
|
|
|
has cell_vpad => ( |
154
|
|
|
|
|
|
|
is => 'rw', |
155
|
|
|
|
|
|
|
default => sub { 0 }, |
156
|
|
|
|
|
|
|
); |
157
|
|
|
|
|
|
|
has cell_tpad => ( |
158
|
|
|
|
|
|
|
is => 'rw', |
159
|
|
|
|
|
|
|
); |
160
|
|
|
|
|
|
|
has cell_bpad => ( |
161
|
|
|
|
|
|
|
is => 'rw', |
162
|
|
|
|
|
|
|
); |
163
|
|
|
|
|
|
|
has cell_fgcolor => ( |
164
|
|
|
|
|
|
|
is => 'rw', |
165
|
|
|
|
|
|
|
); |
166
|
|
|
|
|
|
|
has cell_bgcolor => ( |
167
|
|
|
|
|
|
|
is => 'rw', |
168
|
|
|
|
|
|
|
); |
169
|
|
|
|
|
|
|
has cell_align => ( |
170
|
|
|
|
|
|
|
is => 'rw', |
171
|
|
|
|
|
|
|
); |
172
|
|
|
|
|
|
|
has cell_valign => ( |
173
|
|
|
|
|
|
|
is => 'rw', |
174
|
|
|
|
|
|
|
); |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
has header_align => ( |
177
|
|
|
|
|
|
|
is => 'rw', |
178
|
|
|
|
|
|
|
); |
179
|
|
|
|
|
|
|
has header_valign => ( |
180
|
|
|
|
|
|
|
is => 'rw', |
181
|
|
|
|
|
|
|
); |
182
|
|
|
|
|
|
|
has header_vpad => ( |
183
|
|
|
|
|
|
|
is => 'rw', |
184
|
|
|
|
|
|
|
); |
185
|
|
|
|
|
|
|
has header_tpad => ( |
186
|
|
|
|
|
|
|
is => 'rw', |
187
|
|
|
|
|
|
|
); |
188
|
|
|
|
|
|
|
has header_bpad => ( |
189
|
|
|
|
|
|
|
is => 'rw', |
190
|
|
|
|
|
|
|
); |
191
|
|
|
|
|
|
|
has header_fgcolor => ( |
192
|
|
|
|
|
|
|
is => 'rw', |
193
|
|
|
|
|
|
|
); |
194
|
|
|
|
|
|
|
has header_bgcolor => ( |
195
|
|
|
|
|
|
|
is => 'rw', |
196
|
|
|
|
|
|
|
); |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
with 'Term::App::Role::Attrs'; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub _color_theme_item_color_to_ansi { |
201
|
8
|
|
|
8
|
|
9038
|
my ($self, $item, $args, $is_bg) = @_; |
202
|
|
|
|
|
|
|
item_color_to_ansi( |
203
|
8
|
|
50
|
|
|
28
|
($self->{color_theme_obj}->get_item_color($item, $args) // undef), # because sometimes get_item_color() might return an empty list |
|
|
|
50
|
|
|
|
|
204
|
|
|
|
|
|
|
$is_bg) |
205
|
|
|
|
|
|
|
// ''; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub BUILD { |
209
|
2
|
|
|
2
|
0
|
13
|
my ($self, $args) = @_; |
210
|
|
|
|
|
|
|
|
211
|
2
|
50
|
|
|
|
8
|
if ($ENV{ANSITABLE_STYLE_SETS}) { |
212
|
0
|
|
|
|
|
0
|
require JSON::MaybeXS; |
213
|
0
|
|
|
|
|
0
|
my $sets = JSON::MaybeXS::decode_json($ENV{ANSITABLE_STYLE_SETS}); |
214
|
0
|
0
|
|
|
|
0
|
croak "ANSITABLE_STYLE_SETS must be an array" |
215
|
|
|
|
|
|
|
unless ref($sets) eq 'ARRAY'; |
216
|
0
|
|
|
|
|
0
|
for my $set (@$sets) { |
217
|
0
|
0
|
|
|
|
0
|
if (ref($set) eq 'ARRAY') { |
218
|
0
|
|
|
|
|
0
|
$self->apply_style_set($set->[0], $set->[1]); |
219
|
|
|
|
|
|
|
} else { |
220
|
0
|
|
|
|
|
0
|
$self->apply_style_set($set); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
2
|
50
|
|
|
|
7
|
if ($ENV{ANSITABLE_STYLE}) { |
226
|
0
|
|
|
|
|
0
|
require JSON::MaybeXS; |
227
|
0
|
|
|
|
|
0
|
my $s = JSON::MaybeXS::decode_json($ENV{ANSITABLE_STYLE}); |
228
|
0
|
|
|
|
|
0
|
for my $k (keys %$s) { |
229
|
0
|
|
|
|
|
0
|
my $v = $s->{$k}; |
230
|
0
|
0
|
|
|
|
0
|
croak "Unknown table style '$k' in ANSITABLE_STYLE environment, ". |
231
|
|
|
|
|
|
|
"please use one of [".join(", ", @$STYLES)."]" |
232
|
|
|
|
|
|
|
unless $k ~~ $STYLES; |
233
|
0
|
|
|
|
|
0
|
$self->{$k} = $v; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# pick a default border style |
238
|
2
|
50
|
|
|
|
7
|
unless ($self->{border_style}) { |
239
|
2
|
|
|
|
|
3
|
my $bs; |
240
|
|
|
|
|
|
|
|
241
|
2
|
|
|
|
|
30
|
my $use_utf8 = $self->use_utf8; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# even though Term::Detect::Software decides that linux virtual console |
244
|
|
|
|
|
|
|
# does not support unicode, it actually can display some uni characters |
245
|
|
|
|
|
|
|
# like single borders, so we use it as the default here instead of |
246
|
|
|
|
|
|
|
# singleo_ascii (linux vc doesn't seem to support box_chars). |
247
|
2
|
|
50
|
|
|
34703
|
my $emu_eng = $self->detect_terminal->{emulator_engine} // ''; |
248
|
2
|
|
33
|
|
|
75
|
my $linux_vc = $emu_eng eq 'linux' && !defined($ENV{UTF8}); |
249
|
2
|
50
|
|
|
|
48
|
if ($linux_vc) { |
250
|
0
|
|
|
|
|
0
|
$use_utf8 = 1; |
251
|
0
|
|
|
|
|
0
|
$bs = 'UTF8::SingleLineOuterOnly'; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
# use statement modifier style to avoid block and make local work |
254
|
2
|
50
|
|
|
|
13
|
local $self->{use_utf8} = 1 if $linux_vc; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# we only default to utf8 border if user has set something like |
257
|
|
|
|
|
|
|
# binmode(STDOUT, ":utf8") to avoid 'Wide character in print' warning. |
258
|
2
|
50
|
|
|
|
22
|
unless (defined $ENV{UTF8}) { |
259
|
2
|
|
|
|
|
50
|
require PerlIO; |
260
|
2
|
|
|
|
|
38
|
my @layers = PerlIO::get_layers(STDOUT); |
261
|
2
|
50
|
|
|
|
26
|
$use_utf8 = 0 unless 'utf8' ~~ @layers; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
2
|
50
|
|
|
|
187
|
if (defined $ENV{ANSITABLE_BORDER_STYLE}) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
265
|
0
|
|
|
|
|
0
|
$bs = $ENV{ANSITABLE_BORDER_STYLE}; |
266
|
|
|
|
|
|
|
} elsif ($use_utf8) { |
267
|
0
|
|
0
|
|
|
0
|
$bs //= 'UTF8::BrickOuterOnly'; |
268
|
|
|
|
|
|
|
} elsif ($self->use_box_chars) { |
269
|
0
|
|
|
|
|
0
|
$bs = 'BoxChar::SingleLineOuterOnly'; |
270
|
|
|
|
|
|
|
} else { |
271
|
2
|
|
|
|
|
2529
|
$bs = 'ASCII::SingleLineOuterOnly'; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
2
|
|
|
|
|
79
|
$self->border_style($bs); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# pick a default color theme |
278
|
2
|
50
|
|
|
|
6852
|
unless ($self->{color_theme}) { |
279
|
2
|
|
|
|
|
15
|
my $ct; |
280
|
2
|
50
|
|
|
|
61
|
if (defined $ENV{ANSITABLE_COLOR_THEME}) { |
|
|
50
|
|
|
|
|
|
281
|
0
|
|
|
|
|
0
|
$ct = $ENV{ANSITABLE_COLOR_THEME}; |
282
|
|
|
|
|
|
|
} elsif ($self->use_color) { |
283
|
0
|
|
0
|
|
|
0
|
my $bg = $self->detect_terminal->{default_bgcolor} // ''; |
284
|
0
|
0
|
|
|
|
0
|
if ($self->color_depth >= 2**24) { |
285
|
0
|
0
|
|
|
|
0
|
$ct = 'Text::ANSITable::Standard::Gradation' . |
286
|
|
|
|
|
|
|
($bg eq 'ffffff' ? 'WhiteBG' : ''); |
287
|
|
|
|
|
|
|
} else { |
288
|
0
|
0
|
|
|
|
0
|
$ct = 'Text::ANSITable::Standard::NoGradation' . |
289
|
|
|
|
|
|
|
($bg eq 'ffffff' ? 'WhiteBG' : '');; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
} else { |
292
|
2
|
|
|
|
|
3226
|
$ct = 'NoColor'; |
293
|
|
|
|
|
|
|
} |
294
|
2
|
|
|
|
|
63
|
$self->color_theme($ct); |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
2
|
50
|
|
|
|
5449
|
unless (defined $self->{wide}) { |
298
|
2
|
50
|
|
|
|
5
|
$self->{wide} = eval { require Text::ANSI::WideUtil; 1 } ? 1:0; |
|
2
|
|
|
|
|
850
|
|
|
2
|
|
|
|
|
122442
|
|
299
|
|
|
|
|
|
|
} |
300
|
2
|
|
|
|
|
1203
|
require Text::ANSI::Util; |
301
|
2
|
|
|
|
|
589
|
$self->{_func_add_color_resets} = \&Text::ANSI::Util::ta_add_color_resets; |
302
|
2
|
50
|
|
|
|
8
|
if ($self->{wide}) { |
303
|
2
|
|
|
|
|
17
|
require Text::ANSI::WideUtil; |
304
|
2
|
|
|
|
|
14
|
$self->{_func_length_height} = \&Text::ANSI::WideUtil::ta_mbswidth_height; |
305
|
2
|
|
|
|
|
6
|
$self->{_func_pad} = \&Text::ANSI::WideUtil::ta_mbpad; |
306
|
2
|
|
|
|
|
61
|
$self->{_func_wrap} = \&Text::ANSI::WideUtil::ta_mbwrap; |
307
|
|
|
|
|
|
|
} else { |
308
|
0
|
|
|
|
|
0
|
$self->{_func_length_height} = \&Text::ANSI::Util::ta_length_height; |
309
|
0
|
|
|
|
|
0
|
$self->{_func_pad} = \&Text::ANSI::Util::ta_pad; |
310
|
0
|
|
|
|
|
0
|
$self->{_func_wrap} = \&Text::ANSI::Util::ta_wrap; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub _set_default_cols { |
315
|
1
|
|
|
1
|
|
3
|
my ($self, $row) = @_; |
316
|
1
|
50
|
|
|
|
4
|
return if $self->{_columns_set}++; |
317
|
0
|
0
|
|
|
|
0
|
$self->columns([map {"col$_"} 0..@$row-1]) if $row; |
|
0
|
|
|
|
|
0
|
|
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub add_row { |
321
|
7
|
|
|
7
|
1
|
1479
|
my ($self, $row, $styles) = @_; |
322
|
7
|
100
|
|
|
|
42
|
croak "Row must be arrayref" unless ref($row) eq 'ARRAY'; |
323
|
6
|
|
|
|
|
13
|
push @{ $self->{rows} }, $row; |
|
6
|
|
|
|
|
14
|
|
324
|
6
|
100
|
|
|
|
26
|
$self->_set_default_cols($row) unless $self->{_columns_set}++; |
325
|
6
|
50
|
|
|
|
12
|
if ($styles) { |
326
|
0
|
|
|
|
|
0
|
my $i = @{ $self->{rows} }-1; |
|
0
|
|
|
|
|
0
|
|
327
|
0
|
|
|
|
|
0
|
for my $s (keys %$styles) { |
328
|
0
|
|
|
|
|
0
|
$self->set_row_style($i, $s, $styles->{$s}); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
6
|
|
|
|
|
11
|
$self; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub add_row_separator { |
335
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
336
|
0
|
|
|
|
|
0
|
my $idx = ~~@{$self->{rows}}-1; |
|
0
|
|
|
|
|
0
|
|
337
|
|
|
|
|
|
|
# ignore duplicate separators |
338
|
0
|
|
|
|
|
0
|
push @{ $self->{_row_separators} }, $idx |
339
|
0
|
|
|
|
|
0
|
unless @{ $self->{_row_separators} } && |
340
|
0
|
0
|
0
|
|
|
0
|
$self->{_row_separators}[-1] == $idx; |
341
|
0
|
|
|
|
|
0
|
$self; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub add_rows { |
345
|
2
|
|
|
2
|
1
|
57
|
my ($self, $rows, $styles) = @_; |
346
|
2
|
100
|
|
|
|
14
|
croak "Rows must be arrayref" unless ref($rows) eq 'ARRAY'; |
347
|
1
|
|
|
|
|
4
|
$self->add_row($_, $styles) for @$rows; |
348
|
1
|
|
|
|
|
3
|
$self; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub _colnum { |
352
|
36
|
|
|
36
|
|
48
|
my $self = shift; |
353
|
36
|
|
|
|
|
41
|
my $colname = shift; |
354
|
|
|
|
|
|
|
|
355
|
36
|
100
|
|
|
|
103
|
return $colname if looks_like_number($colname); |
356
|
10
|
|
|
|
|
18
|
my $cols = $self->{columns}; |
357
|
10
|
|
|
|
|
23
|
for my $i (0..@$cols-1) { |
358
|
14
|
100
|
|
|
|
37
|
return $i if $cols->[$i] eq $colname; |
359
|
|
|
|
|
|
|
} |
360
|
1
|
|
|
|
|
14
|
croak "Unknown column name '$colname'"; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub get_cell { |
364
|
6
|
|
|
6
|
1
|
1556
|
my ($self, $rownum, $col) = @_; |
365
|
|
|
|
|
|
|
|
366
|
6
|
|
|
|
|
17
|
$col = $self->_colnum($col); |
367
|
|
|
|
|
|
|
|
368
|
5
|
|
|
|
|
27
|
$self->{rows}[$rownum][$col]; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub set_cell { |
372
|
1
|
|
|
1
|
1
|
5
|
my ($self, $rownum, $col, $val) = @_; |
373
|
|
|
|
|
|
|
|
374
|
1
|
|
|
|
|
4
|
$col = $self->_colnum($col); |
375
|
|
|
|
|
|
|
|
376
|
1
|
|
|
|
|
3
|
my $oldval = $self->{rows}[$rownum][$col]; |
377
|
1
|
|
|
|
|
3
|
$self->{rows}[$rownum][$col] = $val; |
378
|
1
|
|
|
|
|
4
|
$oldval; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
sub get_column_style { |
382
|
0
|
|
|
0
|
1
|
0
|
my ($self, $col, $style) = @_; |
383
|
|
|
|
|
|
|
|
384
|
0
|
|
|
|
|
0
|
$col = $self->_colnum($col); |
385
|
0
|
|
|
|
|
0
|
$self->{_column_styles}[$col]{$style}; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub set_column_style { |
389
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
390
|
0
|
|
|
|
|
0
|
my $col = shift; |
391
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
0
|
$col = $self->_colnum($col); |
393
|
|
|
|
|
|
|
|
394
|
0
|
0
|
|
|
|
0
|
my %sets = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
395
|
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
0
|
for my $style (keys %sets) { |
397
|
0
|
|
|
|
|
0
|
my $val = $sets{$style}; |
398
|
0
|
0
|
|
|
|
0
|
croak "Unknown per-column style '$style', please use one of [". |
399
|
|
|
|
|
|
|
join(", ", @$COLUMN_STYLES) . "]" unless $style ~~ $COLUMN_STYLES; |
400
|
0
|
|
|
|
|
0
|
$self->{_column_styles}[$col]{$style} = $val; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub get_cond_column_styles { |
405
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
406
|
0
|
|
|
|
|
0
|
$self->{_cond_column_styles}; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
#sub set_cond_column_style { |
410
|
|
|
|
|
|
|
# my ($self, $styles) = @_; |
411
|
|
|
|
|
|
|
# $self->{_cond_column_styles} = $styles; |
412
|
|
|
|
|
|
|
#} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub add_cond_column_style { |
415
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
416
|
0
|
|
|
|
|
0
|
my $cond = shift; |
417
|
0
|
0
|
|
|
|
0
|
if (ref($cond) ne 'CODE') { |
418
|
0
|
|
|
|
|
0
|
croak "cond must be a coderef"; |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
0
|
|
|
|
|
0
|
my $styles; |
422
|
0
|
0
|
|
|
|
0
|
if (ref($_[0]) eq 'HASH') { |
423
|
0
|
|
|
|
|
0
|
$styles = shift; |
424
|
|
|
|
|
|
|
} else { |
425
|
0
|
|
|
|
|
0
|
$styles = { @_ }; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
0
|
|
|
|
|
0
|
for my $style (keys %$styles) { |
429
|
0
|
0
|
|
|
|
0
|
croak "Unknown per-column style '$style', please use one of [". |
430
|
|
|
|
|
|
|
join(", ", @$COLUMN_STYLES) . "]" unless $style ~~ $COLUMN_STYLES; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
0
|
push @{ $self->{_cond_column_styles} }, [$cond, $styles]; |
|
0
|
|
|
|
|
0
|
|
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
#sub clear_cond_column_styles { |
437
|
|
|
|
|
|
|
# my $self = shift; |
438
|
|
|
|
|
|
|
# $self->{_cond_column_styles} = []; |
439
|
|
|
|
|
|
|
#} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub get_eff_column_style { |
442
|
17
|
|
|
17
|
1
|
36
|
my ($self, $col, $style) = @_; |
443
|
|
|
|
|
|
|
|
444
|
17
|
|
|
|
|
31
|
$col = $self->_colnum($col); |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# the result of calculation is cached here |
447
|
17
|
100
|
|
|
|
37
|
if (defined $self->{_draw}{eff_column_styles}[$col]) { |
448
|
16
|
|
|
|
|
127
|
return $self->{_draw}{eff_column_styles}[$col]{$style}; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
1
|
|
|
|
|
2
|
my $cols = $self->{columns}; |
452
|
1
|
|
|
|
|
2
|
my %styles; |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
# apply conditional styles |
455
|
|
|
|
|
|
|
COND: |
456
|
1
|
|
|
|
|
1
|
for my $ei (0..@{ $self->{_cond_column_styles} }-1) { |
|
1
|
|
|
|
|
8
|
|
457
|
0
|
|
|
|
|
0
|
my $e = $self->{_cond_column_styles}[$ei]; |
458
|
0
|
|
|
|
|
0
|
local $_ = $col; |
459
|
0
|
|
|
|
|
0
|
my $res = $e->[0]->( |
460
|
|
|
|
|
|
|
$self, |
461
|
|
|
|
|
|
|
col => $col, |
462
|
|
|
|
|
|
|
colname => $cols->[$col], |
463
|
|
|
|
|
|
|
); |
464
|
0
|
0
|
|
|
|
0
|
next COND unless $res; |
465
|
0
|
0
|
|
|
|
0
|
if (ref($res) eq 'HASH') { |
466
|
0
|
|
|
|
|
0
|
$styles{$_} = $res->{$_} for keys %$res; |
467
|
|
|
|
|
|
|
} |
468
|
0
|
|
|
|
|
0
|
$styles{$_} = $e->[1]{$_} for keys %{ $e->[1] }; |
|
0
|
|
|
|
|
0
|
|
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# apply per-column styles |
472
|
1
|
|
|
|
|
3
|
my $rss = $self->{_column_styles}[$col]; |
473
|
1
|
50
|
|
|
|
3
|
if ($rss) { |
474
|
0
|
|
|
|
|
0
|
$styles{$_} = $rss->{$_} for keys %$rss; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
1
|
|
|
|
|
3
|
$self->{_draw}{eff_column_styles}[$col] = \%styles; |
478
|
|
|
|
|
|
|
|
479
|
1
|
|
|
|
|
6
|
$styles{$style}; |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub get_row_style { |
483
|
0
|
|
|
0
|
1
|
0
|
my ($self, $row, $style) = @_; |
484
|
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
0
|
$self->{_row_styles}[$row]{$style}; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub set_row_style { |
489
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
490
|
0
|
|
|
|
|
0
|
my $row = shift; |
491
|
|
|
|
|
|
|
|
492
|
0
|
0
|
|
|
|
0
|
my %sets = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
493
|
|
|
|
|
|
|
|
494
|
0
|
|
|
|
|
0
|
for my $style (keys %sets) { |
495
|
0
|
|
|
|
|
0
|
my $val = $sets{$style}; |
496
|
0
|
0
|
|
|
|
0
|
croak "Unknown per-row style '$style', please use one of [". |
497
|
|
|
|
|
|
|
join(", ", @$ROW_STYLES) . "]" unless $style ~~ $ROW_STYLES; |
498
|
0
|
|
|
|
|
0
|
$self->{_row_styles}[$row]{$style} = $val; |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
sub get_cond_row_styles { |
503
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
504
|
0
|
|
|
|
|
0
|
$self->{_cond_row_styles}; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
#sub set_cond_row_style { |
508
|
|
|
|
|
|
|
# my ($self, $styles) = @_; |
509
|
|
|
|
|
|
|
# $self->{_cond_row_styles} = $styles; |
510
|
|
|
|
|
|
|
#} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
sub add_cond_row_style { |
513
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
514
|
0
|
|
|
|
|
0
|
my $cond = shift; |
515
|
0
|
0
|
|
|
|
0
|
if (ref($cond) ne 'CODE') { |
516
|
0
|
|
|
|
|
0
|
croak "cond must be a coderef"; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
0
|
my $styles; |
520
|
0
|
0
|
|
|
|
0
|
if (ref($_[0]) eq 'HASH') { |
521
|
0
|
|
|
|
|
0
|
$styles = shift; |
522
|
|
|
|
|
|
|
} else { |
523
|
0
|
|
|
|
|
0
|
$styles = { @_ }; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
0
|
|
|
|
|
0
|
for my $style (keys %$styles) { |
527
|
0
|
0
|
|
|
|
0
|
croak "Unknown per-row style '$style', please use one of [". |
528
|
|
|
|
|
|
|
join(", ", @$ROW_STYLES) . "]" unless $style ~~ $ROW_STYLES; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
0
|
|
|
|
|
0
|
push @{ $self->{_cond_row_styles} }, [$cond, $styles]; |
|
0
|
|
|
|
|
0
|
|
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
#sub clear_cond_row_styles { |
535
|
|
|
|
|
|
|
# my $self = shift; |
536
|
|
|
|
|
|
|
# $self->{_cond_row_styles} = []; |
537
|
|
|
|
|
|
|
#} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub get_eff_row_style { |
540
|
20
|
|
|
20
|
1
|
43
|
my ($self, $row, $style) = @_; |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
# the result of calculation is cached here |
543
|
20
|
100
|
|
|
|
39
|
if (defined $self->{_draw}{eff_row_styles}[$row]) { |
544
|
18
|
|
|
|
|
66
|
return $self->{_draw}{eff_row_styles}[$row]{$style}; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
2
|
|
|
|
|
3
|
my $rows = $self->{rows}; |
548
|
2
|
|
|
|
|
7
|
my %styles; |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# apply conditional styles |
551
|
|
|
|
|
|
|
COND: |
552
|
2
|
|
|
|
|
3
|
for my $ei (0..@{ $self->{_cond_row_styles} }-1) { |
|
2
|
|
|
|
|
9
|
|
553
|
0
|
|
|
|
|
0
|
my $e = $self->{_cond_row_styles}[$ei]; |
554
|
0
|
|
|
|
|
0
|
local $_ = $row; |
555
|
0
|
|
|
|
|
0
|
my $res = $e->[0]->( |
556
|
|
|
|
|
|
|
$self, |
557
|
|
|
|
|
|
|
row => $row, |
558
|
|
|
|
|
|
|
row_data => $rows->[$row], |
559
|
|
|
|
|
|
|
); |
560
|
0
|
0
|
|
|
|
0
|
next COND unless $res; |
561
|
0
|
0
|
|
|
|
0
|
if (ref($res) eq 'HASH') { |
562
|
0
|
|
|
|
|
0
|
$styles{$_} = $res->{$_} for keys %$res; |
563
|
|
|
|
|
|
|
} |
564
|
0
|
|
|
|
|
0
|
$styles{$_} = $e->[1]{$_} for keys %{ $e->[1] }; |
|
0
|
|
|
|
|
0
|
|
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# apply per-row styles |
568
|
2
|
|
|
|
|
5
|
my $rss = $self->{_row_styles}[$row]; |
569
|
2
|
50
|
|
|
|
4
|
if ($rss) { |
570
|
0
|
|
|
|
|
0
|
$styles{$_} = $rss->{$_} for keys %$rss; |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
|
573
|
2
|
|
|
|
|
3
|
$self->{_draw}{eff_row_styles}[$row] = \%styles; |
574
|
|
|
|
|
|
|
|
575
|
2
|
|
|
|
|
13
|
$styles{$style}; |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
sub get_cell_style { |
579
|
0
|
|
|
0
|
1
|
0
|
my ($self, $row, $col, $style) = @_; |
580
|
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
0
|
$col = $self->_colnum($col); |
582
|
0
|
|
|
|
|
0
|
$self->{_cell_styles}[$row][$col]{$style}; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
sub set_cell_style { |
586
|
2
|
|
|
2
|
1
|
30
|
my $self = shift; |
587
|
2
|
|
|
|
|
4
|
my $row = shift; |
588
|
2
|
|
|
|
|
2
|
my $col = shift; |
589
|
|
|
|
|
|
|
|
590
|
2
|
|
|
|
|
10
|
$col = $self->_colnum($col); |
591
|
|
|
|
|
|
|
|
592
|
2
|
50
|
|
|
|
13
|
my %sets = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
593
|
|
|
|
|
|
|
|
594
|
2
|
|
|
|
|
8
|
for my $style (keys %sets) { |
595
|
2
|
|
|
|
|
3
|
my $val = $sets{$style}; |
596
|
2
|
50
|
|
|
|
8
|
croak "Unknown per-cell style '$style', please use one of [". |
597
|
|
|
|
|
|
|
join(", ", @$CELL_STYLES) . "]" unless $style ~~ $CELL_STYLES; |
598
|
2
|
|
|
|
|
8
|
$self->{_cell_styles}[$row][$col]{$style} = $val; |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
sub get_cond_cell_styles { |
603
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
604
|
0
|
|
|
|
|
0
|
$self->{_cond_cell_styles}; |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
#sub set_cond_cell_style { |
608
|
|
|
|
|
|
|
# my ($self, $styles) = @_; |
609
|
|
|
|
|
|
|
# $self->{_cond_cell_styles} = $styles; |
610
|
|
|
|
|
|
|
#} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
sub add_cond_cell_style { |
613
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
614
|
0
|
|
|
|
|
0
|
my $cond = shift; |
615
|
0
|
0
|
|
|
|
0
|
if (ref($cond) ne 'CODE') { |
616
|
0
|
|
|
|
|
0
|
croak "cond must be a coderef"; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
0
|
|
|
|
|
0
|
my $styles; |
620
|
0
|
0
|
|
|
|
0
|
if (ref($_[0]) eq 'HASH') { |
621
|
0
|
|
|
|
|
0
|
$styles = shift; |
622
|
|
|
|
|
|
|
} else { |
623
|
0
|
|
|
|
|
0
|
$styles = { @_ }; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
0
|
|
|
|
|
0
|
for my $style (keys %$styles) { |
627
|
0
|
0
|
|
|
|
0
|
croak "Unknown per-cell style '$style', please use one of [". |
628
|
|
|
|
|
|
|
join(", ", @$CELL_STYLES) . "]" unless $style ~~ $CELL_STYLES; |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
0
|
|
|
|
|
0
|
push @{ $self->{_cond_cell_styles} }, [$cond, $styles]; |
|
0
|
|
|
|
|
0
|
|
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
#sub clear_cond_cell_styles { |
635
|
|
|
|
|
|
|
# my $self = shift; |
636
|
|
|
|
|
|
|
# $self->{_cond_cell_styles} = []; |
637
|
|
|
|
|
|
|
#} |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
sub get_eff_cell_style { |
640
|
10
|
|
|
10
|
1
|
23
|
my ($self, $row, $col, $style) = @_; |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# the result of calculation is cached here |
643
|
10
|
100
|
|
|
|
31
|
if (defined $self->{_draw}{eff_cell_styles}[$row][$col]) { |
644
|
8
|
|
|
|
|
45
|
return $self->{_draw}{eff_cell_styles}[$row][$col]{$style}; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
2
|
|
|
|
|
6
|
my $rows = $self->{rows}; |
648
|
2
|
|
|
|
|
3
|
my %styles; |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
# apply conditional styles |
651
|
|
|
|
|
|
|
COND: |
652
|
2
|
|
|
|
|
4
|
for my $ei (0..@{ $self->{_cond_cell_styles} }-1) { |
|
2
|
|
|
|
|
6
|
|
653
|
0
|
|
|
|
|
0
|
my $e = $self->{_cond_cell_styles}[$ei]; |
654
|
0
|
|
|
|
|
0
|
local $_ = $rows->[$row][$col]; |
655
|
0
|
|
|
|
|
0
|
my $res = $e->[0]->( |
656
|
|
|
|
|
|
|
$self, |
657
|
|
|
|
|
|
|
content => $_, |
658
|
|
|
|
|
|
|
col => $col, |
659
|
|
|
|
|
|
|
row => $row, |
660
|
|
|
|
|
|
|
row_data => $rows->[$row], |
661
|
|
|
|
|
|
|
); |
662
|
0
|
0
|
|
|
|
0
|
next COND unless $res; |
663
|
0
|
0
|
|
|
|
0
|
if (ref($res) eq 'HASH') { |
664
|
0
|
|
|
|
|
0
|
$styles{$_} = $res->{$_} for keys %$res; |
665
|
|
|
|
|
|
|
} |
666
|
0
|
|
|
|
|
0
|
$styles{$_} = $e->[1]{$_} for keys %{ $e->[1] }; |
|
0
|
|
|
|
|
0
|
|
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# apply per-cell styles |
670
|
2
|
|
|
|
|
6
|
my $css = $self->{_cell_styles}[$row][$col]; |
671
|
2
|
50
|
|
|
|
6
|
if ($css) { |
672
|
2
|
|
|
|
|
10
|
$styles{$_} = $css->{$_} for keys %$css; |
673
|
|
|
|
|
|
|
} |
674
|
|
|
|
|
|
|
|
675
|
2
|
|
|
|
|
7
|
$self->{_draw}{eff_cell_styles}[$row][$col] = \%styles; |
676
|
|
|
|
|
|
|
|
677
|
2
|
|
|
|
|
5
|
$styles{$style}; |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
sub apply_style_set { |
681
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
682
|
0
|
|
|
|
|
0
|
my $name = shift; |
683
|
0
|
0
|
|
|
|
0
|
$name =~ /\A[A-Za-z0-9_]+(?:::[A-Za-z0-9_]+)*\z/ |
684
|
|
|
|
|
|
|
or croak "Invalid style set name, please use alphanums only"; |
685
|
|
|
|
|
|
|
{ |
686
|
0
|
|
|
|
|
0
|
my $name = $name; |
|
0
|
|
|
|
|
0
|
|
687
|
0
|
|
|
|
|
0
|
$name =~ s!::!/!g; |
688
|
0
|
|
|
|
|
0
|
require "Text/ANSITable/StyleSet/$name.pm"; |
689
|
|
|
|
|
|
|
} |
690
|
0
|
0
|
|
|
|
0
|
my %args = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
691
|
0
|
|
|
|
|
0
|
my $obj = "Text::ANSITable::StyleSet::$name"->new(%args); |
692
|
0
|
|
|
|
|
0
|
$obj->apply($self); |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
sub list_border_styles { |
696
|
0
|
|
|
0
|
1
|
0
|
require Module::List; |
697
|
0
|
|
|
|
|
0
|
my ($self) = @_; |
698
|
|
|
|
|
|
|
|
699
|
0
|
|
|
|
|
0
|
my $mods = Module::List::list_modules( |
700
|
|
|
|
|
|
|
"BorderStyle::", {list_modules=>1, recurse=>1}); |
701
|
0
|
|
|
|
|
0
|
my @res; |
702
|
0
|
|
|
|
|
0
|
for (sort keys %$mods) { |
703
|
0
|
|
|
|
|
0
|
s/\ABorderStyle:://; |
704
|
0
|
|
|
|
|
0
|
push @res, $_; |
705
|
|
|
|
|
|
|
} |
706
|
0
|
|
|
|
|
0
|
@res; |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
sub list_color_themes { |
710
|
0
|
|
|
0
|
1
|
0
|
require Module::List; |
711
|
0
|
|
|
|
|
0
|
my ($self) = @_; |
712
|
|
|
|
|
|
|
|
713
|
0
|
|
|
|
|
0
|
my $mods = Module::List::list_modules( |
714
|
|
|
|
|
|
|
"ColorTheme::", {list_modules=>1, recurse=>1}); |
715
|
0
|
|
|
|
|
0
|
my @res; |
716
|
0
|
|
|
|
|
0
|
for (sort keys %$mods) { |
717
|
0
|
|
|
|
|
0
|
s/\AColorTheme:://; |
718
|
0
|
|
|
|
|
0
|
push @res, $_; |
719
|
|
|
|
|
|
|
} |
720
|
0
|
|
|
|
|
0
|
@res; |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
sub list_style_sets { |
724
|
0
|
|
|
0
|
1
|
0
|
require Module::List; |
725
|
0
|
|
|
|
|
0
|
require Module::Load; |
726
|
0
|
|
|
|
|
0
|
require Package::MoreUtil; |
727
|
|
|
|
|
|
|
|
728
|
0
|
|
|
|
|
0
|
my ($self, $detail) = @_; |
729
|
|
|
|
|
|
|
|
730
|
0
|
0
|
|
|
|
0
|
my $prefix = (ref($self) ? ref($self) : $self ) . |
731
|
|
|
|
|
|
|
'::StyleSet'; # XXX allow override |
732
|
0
|
|
|
|
|
0
|
my $all_sets = $self->{_all_style_sets}; |
733
|
|
|
|
|
|
|
|
734
|
0
|
0
|
|
|
|
0
|
if (!$all_sets) { |
735
|
0
|
|
|
|
|
0
|
my $mods = Module::List::list_modules("$prefix\::", |
736
|
|
|
|
|
|
|
{list_modules=>1, recurse=>1}); |
737
|
0
|
|
|
|
|
0
|
$all_sets = {}; |
738
|
0
|
|
|
|
|
0
|
for my $mod (sort keys %$mods) { |
739
|
|
|
|
|
|
|
#$log->tracef("Loading style set module '%s' ...", $mod); |
740
|
0
|
|
|
|
|
0
|
Module::Load::load($mod); |
741
|
0
|
|
|
|
|
0
|
my $name = $mod; $name =~ s/\A\Q$prefix\:://; |
|
0
|
|
|
|
|
0
|
|
742
|
0
|
|
|
|
|
0
|
my $summary = $mod->summary; |
743
|
|
|
|
|
|
|
# we don't have meta, so dig it ourselves |
744
|
0
|
|
|
|
|
0
|
my %ct = Package::MoreUtil::list_package_contents($mod); |
745
|
0
|
|
0
|
|
|
0
|
my $args = [sort grep {!/\W/ && !/\A(new|summary|apply)\z/} |
|
0
|
|
|
|
|
0
|
|
746
|
|
|
|
|
|
|
keys %ct]; |
747
|
0
|
|
|
|
|
0
|
$all_sets->{$name} = {name=>$name, summary=>$summary, args=>$args}; |
748
|
|
|
|
|
|
|
} |
749
|
0
|
|
|
|
|
0
|
$self->{_all_style_sets} = $all_sets; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
0
|
0
|
|
|
|
0
|
if ($detail) { |
753
|
0
|
|
|
|
|
0
|
return $all_sets; |
754
|
|
|
|
|
|
|
} else { |
755
|
0
|
|
|
|
|
0
|
return (sort keys %$all_sets); |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
} |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
# read environment variables for style, this will only be done once per object |
760
|
|
|
|
|
|
|
sub _read_style_envs { |
761
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
762
|
|
|
|
|
|
|
|
763
|
1
|
50
|
|
|
|
5
|
return if $self->{_read_style_envs}++; |
764
|
|
|
|
|
|
|
|
765
|
1
|
50
|
|
|
|
3
|
if ($ENV{ANSITABLE_COLUMN_STYLES}) { |
766
|
0
|
|
|
|
|
0
|
require JSON::MaybeXS; |
767
|
0
|
|
|
|
|
0
|
my $ss = JSON::MaybeXS::decode_json($ENV{ANSITABLE_COLUMN_STYLES}); |
768
|
0
|
0
|
|
|
|
0
|
croak "ANSITABLE_COLUMN_STYLES must be a hash" |
769
|
|
|
|
|
|
|
unless ref($ss) eq 'HASH'; |
770
|
0
|
|
|
|
|
0
|
for my $col (keys %$ss) { |
771
|
0
|
|
|
|
|
0
|
my $ci = $self->_colnum($col); |
772
|
0
|
|
|
|
|
0
|
my $s = $ss->{$col}; |
773
|
0
|
|
|
|
|
0
|
for my $k (keys %$s) { |
774
|
0
|
|
|
|
|
0
|
my $v = $s->{$k}; |
775
|
0
|
0
|
|
|
|
0
|
croak "Unknown column style '$k' (for column $col) in ". |
776
|
|
|
|
|
|
|
"ANSITABLE_COLUMN_STYLES environment, ". |
777
|
|
|
|
|
|
|
"please use one of [".join(", ", @$COLUMN_STYLES)."]" |
778
|
|
|
|
|
|
|
unless $k ~~ $COLUMN_STYLES; |
779
|
0
|
|
0
|
|
|
0
|
$self->{_column_styles}[$ci]{$k} //= $v; |
780
|
|
|
|
|
|
|
} |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
} |
783
|
|
|
|
|
|
|
|
784
|
1
|
50
|
|
|
|
3
|
if ($ENV{ANSITABLE_ROW_STYLES}) { |
785
|
0
|
|
|
|
|
0
|
require JSON::MaybeXS; |
786
|
0
|
|
|
|
|
0
|
my $ss = JSON::MaybeXS::decode_json($ENV{ANSITABLE_ROW_STYLES}); |
787
|
0
|
0
|
|
|
|
0
|
croak "ANSITABLE_ROW_STYLES must be a hash" |
788
|
|
|
|
|
|
|
unless ref($ss) eq 'HASH'; |
789
|
0
|
|
|
|
|
0
|
for my $row (keys %$ss) { |
790
|
0
|
|
|
|
|
0
|
my $s = $ss->{$row}; |
791
|
0
|
|
|
|
|
0
|
for my $k (keys %$s) { |
792
|
0
|
|
|
|
|
0
|
my $v = $s->{$k}; |
793
|
0
|
0
|
|
|
|
0
|
croak "Unknown row style '$k' (for row $row) in ". |
794
|
|
|
|
|
|
|
"ANSITABLE_ROW_STYLES environment, ". |
795
|
|
|
|
|
|
|
"please use one of [".join(", ", @$ROW_STYLES)."]" |
796
|
|
|
|
|
|
|
unless $k ~~ $ROW_STYLES; |
797
|
0
|
|
0
|
|
|
0
|
$self->{_row_styles}[$row]{$k} //= $v; |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
1
|
50
|
|
|
|
3
|
if ($ENV{ANSITABLE_CELL_STYLES}) { |
803
|
0
|
|
|
|
|
0
|
require JSON::MaybeXS; |
804
|
0
|
|
|
|
|
0
|
my $ss = JSON::MaybeXS::decode_json($ENV{ANSITABLE_CELL_STYLES}); |
805
|
0
|
0
|
|
|
|
0
|
croak "ANSITABLE_CELL_STYLES must be a hash" |
806
|
|
|
|
|
|
|
unless ref($ss) eq 'HASH'; |
807
|
0
|
|
|
|
|
0
|
for my $cell (keys %$ss) { |
808
|
0
|
0
|
|
|
|
0
|
croak "Invalid cell specification in ANSITABLE_CELL_STYLES: ". |
809
|
|
|
|
|
|
|
"$cell, please use 'row,col'" |
810
|
|
|
|
|
|
|
unless $cell =~ /^(.+),(.+)$/; |
811
|
0
|
|
|
|
|
0
|
my $row = $1; |
812
|
0
|
|
|
|
|
0
|
my $col = $2; |
813
|
0
|
|
|
|
|
0
|
my $ci = $self->_colnum($col); |
814
|
0
|
|
|
|
|
0
|
my $s = $ss->{$cell}; |
815
|
0
|
|
|
|
|
0
|
for my $k (keys %$s) { |
816
|
0
|
|
|
|
|
0
|
my $v = $s->{$k}; |
817
|
0
|
0
|
|
|
|
0
|
croak "Unknown cell style '$k' (for cell $row,$col) in ". |
818
|
|
|
|
|
|
|
"ANSITABLE_CELL_STYLES environment, ". |
819
|
|
|
|
|
|
|
"please use one of [".join(", ", @$CELL_STYLES)."]" |
820
|
|
|
|
|
|
|
unless $k ~~ $CELL_STYLES; |
821
|
0
|
|
0
|
|
|
0
|
$self->{_cell_styles}[$row][$ci]{$k} //= $v; |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
} |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
# determine which columns to show (due to column_filter) |
828
|
|
|
|
|
|
|
sub _calc_fcols { |
829
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
830
|
|
|
|
|
|
|
|
831
|
1
|
|
|
|
|
2
|
my $cols = $self->{columns}; |
832
|
1
|
|
|
|
|
3
|
my $cf = $self->{column_filter}; |
833
|
|
|
|
|
|
|
|
834
|
1
|
|
|
|
|
1
|
my $fcols; |
835
|
1
|
50
|
|
|
|
5
|
if (ref($cf) eq 'CODE') { |
|
|
50
|
|
|
|
|
|
836
|
0
|
|
|
|
|
0
|
$fcols = [grep {$cf->($_)} @$cols]; |
|
0
|
|
|
|
|
0
|
|
837
|
|
|
|
|
|
|
} elsif (ref($cf) eq 'ARRAY') { |
838
|
0
|
0
|
|
|
|
0
|
$fcols = [grep {defined} map {looks_like_number($_) ? |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
839
|
|
|
|
|
|
|
$cols->[$_] : $_} @$cf]; |
840
|
|
|
|
|
|
|
} else { |
841
|
1
|
|
|
|
|
2
|
$fcols = $cols; |
842
|
|
|
|
|
|
|
} |
843
|
1
|
|
|
|
|
2
|
$self->{_draw}{fcols} = $fcols; |
844
|
|
|
|
|
|
|
} |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
# calculate widths/heights of header, store width settings, column [lr]pads |
847
|
|
|
|
|
|
|
sub _calc_header_height { |
848
|
1
|
|
|
1
|
|
1
|
my $self = shift; |
849
|
|
|
|
|
|
|
|
850
|
1
|
|
|
|
|
2
|
my $cols = $self->{columns}; |
851
|
1
|
|
|
|
|
25
|
my $fcols = $self->{_draw}{fcols}; |
852
|
|
|
|
|
|
|
|
853
|
1
|
|
|
|
|
3
|
my $fcol_widths = []; # index = [colnum] |
854
|
1
|
|
|
|
|
1
|
my $header_height = 1; |
855
|
1
|
|
|
|
|
10
|
my $fcol_lpads = []; # index = [colnum] |
856
|
1
|
|
|
|
|
1
|
my $fcol_rpads = []; # ditto |
857
|
1
|
|
|
|
|
2
|
my $fcol_setwidths = []; # index = [colnum], from cell_width/col width |
858
|
1
|
|
|
|
|
1
|
my $frow_setheights = []; # index = [frownum], from cell_height/row height |
859
|
|
|
|
|
|
|
|
860
|
1
|
|
|
|
|
2
|
my %seen; |
861
|
1
|
|
33
|
|
|
7
|
my $lpad = $self->{cell_lpad} // $self->{cell_pad}; # tbl-lvl leftp |
862
|
1
|
|
33
|
|
|
11
|
my $rpad = $self->{cell_rpad} // $self->{cell_pad}; # tbl-lvl rightp |
863
|
1
|
|
|
|
|
8
|
for my $i (0..@$cols-1) { |
864
|
1
|
50
|
|
|
|
5
|
next unless $cols->[$i] ~~ $fcols; |
865
|
1
|
50
|
|
|
|
5
|
next if $seen{$cols->[$i]}++; |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
$fcol_setwidths->[$i] = $self->get_eff_column_style($i, 'width') // |
868
|
1
|
|
33
|
|
|
8
|
$self->{cell_width}; |
869
|
1
|
|
|
|
|
5
|
my $wh = $self->_opt_calc_cell_width_height(undef, $i, $cols->[$i]); |
870
|
1
|
|
|
|
|
2
|
$fcol_widths->[$i] = $wh->[0]; |
871
|
1
|
50
|
33
|
|
|
11
|
$header_height = $wh->[1] |
872
|
|
|
|
|
|
|
if !defined($header_height) || $header_height < $wh->[1]; |
873
|
1
|
|
33
|
|
|
4
|
$fcol_lpads->[$i] = $self->get_eff_column_style($i, 'lpad') // |
|
|
|
33
|
|
|
|
|
874
|
|
|
|
|
|
|
$self->get_eff_column_style($i, 'pad') // $lpad; |
875
|
1
|
|
33
|
|
|
3
|
$fcol_rpads->[$i] = $self->get_eff_column_style($i, 'rpad') // |
|
|
|
33
|
|
|
|
|
876
|
|
|
|
|
|
|
$self->get_eff_column_style($i, 'pad') // $rpad; |
877
|
|
|
|
|
|
|
} |
878
|
|
|
|
|
|
|
|
879
|
1
|
|
|
|
|
2
|
$self->{_draw}{header_height} = $header_height; |
880
|
1
|
|
|
|
|
2
|
$self->{_draw}{fcol_lpads} = $fcol_lpads; |
881
|
1
|
|
|
|
|
2
|
$self->{_draw}{fcol_rpads} = $fcol_rpads; |
882
|
1
|
|
|
|
|
2
|
$self->{_draw}{fcol_setwidths} = $fcol_setwidths; |
883
|
1
|
|
|
|
|
2
|
$self->{_draw}{frow_setheights} = $frow_setheights; |
884
|
1
|
|
|
|
|
3
|
$self->{_draw}{fcol_widths} = $fcol_widths; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
# determine which rows to show, calculate vertical paddings of data rows, store |
888
|
|
|
|
|
|
|
# height settings |
889
|
|
|
|
|
|
|
sub _calc_frows { |
890
|
1
|
|
|
1
|
|
1
|
my $self = shift; |
891
|
|
|
|
|
|
|
|
892
|
1
|
|
|
|
|
2
|
my $rows = $self->{rows}; |
893
|
1
|
|
|
|
|
2
|
my $rf = $self->{row_filter}; |
894
|
1
|
|
|
|
|
2
|
my $frow_setheights = $self->{_draw}{frow_setheights}; |
895
|
|
|
|
|
|
|
|
896
|
1
|
|
|
|
|
2
|
my $frow_tpads = []; # index = [frownum] |
897
|
1
|
|
|
|
|
1
|
my $frow_bpads = []; # ditto |
898
|
1
|
|
|
|
|
2
|
my $frows = []; |
899
|
1
|
|
|
|
|
2
|
my $frow_separators = []; |
900
|
1
|
|
|
|
|
2
|
my $frow_orig_indices = []; # needed when accessing original row data |
901
|
|
|
|
|
|
|
|
902
|
1
|
|
33
|
|
|
8
|
my $tpad = $self->{cell_tpad} // $self->{cell_vpad}; # tbl-lvl top pad |
903
|
1
|
|
33
|
|
|
5
|
my $bpad = $self->{cell_bpad} // $self->{cell_vpad}; # tbl-lvl botom pad |
904
|
1
|
|
|
|
|
2
|
my $i = -1; |
905
|
1
|
|
|
|
|
1
|
my $j = -1; |
906
|
1
|
|
|
|
|
7
|
for my $row (@$rows) { |
907
|
2
|
|
|
|
|
3
|
$i++; |
908
|
2
|
50
|
|
|
|
7
|
if (ref($rf) eq 'CODE') { |
|
|
50
|
|
|
|
|
|
909
|
0
|
0
|
|
|
|
0
|
next unless $rf->($row, $i); |
910
|
|
|
|
|
|
|
} elsif ($rf) { |
911
|
0
|
0
|
|
|
|
0
|
next unless $i ~~ $rf; |
912
|
|
|
|
|
|
|
} |
913
|
2
|
|
|
|
|
3
|
$j++; |
914
|
|
|
|
|
|
|
push @$frow_setheights, $self->get_eff_row_style($i, 'height') // |
915
|
2
|
|
33
|
|
|
5
|
$self->{cell_height}; |
916
|
2
|
|
|
|
|
5
|
push @$frows, [@$row]; # 1-level clone, for storing formatted values |
917
|
2
|
50
|
|
|
|
49
|
push @$frow_separators, $j if $i ~~ $self->{_row_separators}; |
918
|
2
|
|
33
|
|
|
6
|
push @$frow_tpads, $self->get_eff_row_style($i, 'tpad') // |
|
|
|
33
|
|
|
|
|
919
|
|
|
|
|
|
|
$self->get_eff_row_style($i, 'vpad') // $tpad; |
920
|
2
|
|
33
|
|
|
5
|
push @$frow_bpads, $self->get_eff_row_style($i, 'bpad') // |
|
|
|
33
|
|
|
|
|
921
|
|
|
|
|
|
|
$self->get_eff_row_style($i, 'vpad') // $bpad; |
922
|
2
|
|
|
|
|
4
|
push @$frow_orig_indices, $i; |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
|
925
|
1
|
|
|
|
|
2
|
$self->{_draw}{frows} = $frows; |
926
|
1
|
|
|
|
|
2
|
$self->{_draw}{frow_separators} = $frow_separators; |
927
|
1
|
|
|
|
|
2
|
$self->{_draw}{frow_tpads} = $frow_tpads; |
928
|
1
|
|
|
|
|
2
|
$self->{_draw}{frow_bpads} = $frow_bpads; |
929
|
1
|
|
|
|
|
2
|
$self->{_draw}{frow_orig_indices} = $frow_orig_indices; |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
# detect column type from data/header name. assign default column align, valign, |
933
|
|
|
|
|
|
|
# fgcolor, bgcolor, formats. |
934
|
|
|
|
|
|
|
sub _detect_column_types { |
935
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
936
|
|
|
|
|
|
|
|
937
|
1
|
|
|
|
|
1
|
my $cols = $self->{columns}; |
938
|
1
|
|
|
|
|
2
|
my $rows = $self->{rows}; |
939
|
|
|
|
|
|
|
|
940
|
1
|
|
|
|
|
2
|
my $fcol_detect = []; |
941
|
1
|
|
|
|
|
1
|
my %seen; |
942
|
1
|
|
|
|
|
8
|
for my $i (0..@$cols-1) { |
943
|
1
|
|
|
|
|
3
|
my $col = $cols->[$i]; |
944
|
1
|
|
|
|
|
2
|
my $res = {}; |
945
|
1
|
|
|
|
|
2
|
$fcol_detect->[$i] = $res; |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
# optim: skip detecting columns we're not showing |
948
|
1
|
50
|
|
|
|
4
|
next unless $col ~~ $self->{_draw}{fcols}; |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
# but detect from all rows, not just ones we're showing |
951
|
1
|
|
|
|
|
4
|
my $type = $self->get_eff_column_style($col, 'type'); |
952
|
1
|
|
|
|
|
2
|
my $subtype; |
953
|
|
|
|
|
|
|
DETECT: |
954
|
|
|
|
|
|
|
{ |
955
|
1
|
50
|
|
|
|
2
|
last DETECT if $type; |
|
1
|
|
|
|
|
5
|
|
956
|
1
|
50
|
|
|
|
11
|
if ($col =~ /^(can|is|has|does)_|\?$/) { |
957
|
0
|
|
|
|
|
0
|
$type = 'bool'; |
958
|
0
|
|
|
|
|
0
|
last DETECT; |
959
|
|
|
|
|
|
|
} |
960
|
|
|
|
|
|
|
|
961
|
1
|
|
|
|
|
426
|
require Parse::VarName; |
962
|
1
|
|
|
|
|
361
|
my @words = map {lc} @{ Parse::VarName::split_varname_words( |
|
1
|
|
|
|
|
29
|
|
|
1
|
|
|
|
|
4
|
|
963
|
|
|
|
|
|
|
varname=>$col) }; |
964
|
1
|
|
|
|
|
4
|
for (qw/date time ctime mtime utime atime stime/) { |
965
|
7
|
50
|
|
|
|
15
|
if ($_ ~~ @words) { |
966
|
0
|
|
|
|
|
0
|
$type = 'date'; |
967
|
0
|
|
|
|
|
0
|
last DETECT; |
968
|
|
|
|
|
|
|
} |
969
|
|
|
|
|
|
|
} |
970
|
|
|
|
|
|
|
|
971
|
1
|
|
|
|
|
2
|
my $pass = 1; |
972
|
1
|
|
|
|
|
3
|
for my $j (0..@$rows) { |
973
|
1
|
|
|
|
|
3
|
my $v = $rows->[$j][$i]; |
974
|
1
|
50
|
|
|
|
2
|
next unless defined($v); |
975
|
1
|
50
|
|
|
|
4
|
do { $pass=0; last } unless looks_like_number($v); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2
|
|
976
|
|
|
|
|
|
|
} |
977
|
1
|
50
|
|
|
|
3
|
if ($pass) { |
978
|
0
|
|
|
|
|
0
|
$type = 'num'; |
979
|
0
|
0
|
|
|
|
0
|
if ($col =~ /(pct|percent(?:age))\b|\%/) { |
980
|
0
|
|
|
|
|
0
|
$subtype = 'pct'; |
981
|
|
|
|
|
|
|
} |
982
|
0
|
|
|
|
|
0
|
last DETECT; |
983
|
|
|
|
|
|
|
} |
984
|
1
|
|
|
|
|
2
|
$type = 'str'; |
985
|
|
|
|
|
|
|
} # DETECT |
986
|
|
|
|
|
|
|
|
987
|
1
|
|
|
|
|
3
|
$res->{type} = $type; |
988
|
1
|
50
|
|
|
|
16
|
if ($type eq 'bool') { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
989
|
0
|
|
|
|
|
0
|
$res->{align} = 'center'; |
990
|
0
|
|
|
|
|
0
|
$res->{valign} = 'center'; |
991
|
0
|
|
|
|
|
0
|
$res->{fgcolor} = $self->{color_theme_obj}->get_item_color('bool_data'); |
992
|
|
|
|
|
|
|
$res->{formats} = [[bool => {style => $self->{use_utf8} ? |
993
|
0
|
0
|
|
|
|
0
|
"check_cross" : "Y_N"}]]; |
994
|
|
|
|
|
|
|
} elsif ($type eq 'date') { |
995
|
0
|
|
|
|
|
0
|
$res->{align} = 'middle'; |
996
|
0
|
|
|
|
|
0
|
$res->{fgcolor} = $self->{color_theme_obj}->get_item_color('date_data'); |
997
|
0
|
|
|
|
|
0
|
$res->{formats} = [['date' => {}]]; |
998
|
|
|
|
|
|
|
} elsif ($type =~ /\A(num|float|int)\z/) { |
999
|
0
|
|
|
|
|
0
|
$res->{align} = 'right'; |
1000
|
0
|
|
|
|
|
0
|
$res->{fgcolor} = $self->{color_theme_obj}->get_item_color('num_data'); |
1001
|
0
|
0
|
0
|
|
|
0
|
if (($subtype//"") eq 'pct') { |
1002
|
0
|
|
|
|
|
0
|
$res->{formats} = [[num => {style=>'percent'}]]; |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
} else { |
1005
|
1
|
|
|
|
|
12
|
$res->{fgcolor} = $self->{color_theme_obj}->get_item_color('str_data'); |
1006
|
1
|
|
50
|
|
|
37
|
$res->{wrap} = $ENV{WRAP} // 1; |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
#use Data::Dump; print "D:fcol_detect: "; dd $fcol_detect; |
1011
|
1
|
|
|
|
|
3
|
$self->{_draw}{fcol_detect} = $fcol_detect; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
# calculate width and height of a cell, but skip calculating (to save some |
1015
|
|
|
|
|
|
|
# cycles) if width is already set by frow_setheights / fcol_setwidths. |
1016
|
|
|
|
|
|
|
sub _opt_calc_cell_width_height { |
1017
|
3
|
|
|
3
|
|
8
|
my ($self, $frownum, $col, $text) = @_; |
1018
|
|
|
|
|
|
|
|
1019
|
3
|
|
|
|
|
6
|
$col = $self->_colnum($col); |
1020
|
3
|
|
|
|
|
7
|
my $setw = $self->{_draw}{fcol_setwidths}[$col]; |
1021
|
3
|
|
33
|
|
|
8
|
my $calcw = !defined($setw) || $setw < 0; |
1022
|
|
|
|
|
|
|
my $seth = defined($frownum) ? |
1023
|
3
|
100
|
|
|
|
8
|
$self->{_draw}{frow_setheights}[$frownum] : undef; |
1024
|
3
|
|
33
|
|
|
8
|
my $calch = !defined($seth) || $seth < 0; |
1025
|
|
|
|
|
|
|
|
1026
|
3
|
|
|
|
|
5
|
my $wh; |
1027
|
3
|
50
|
|
|
|
5
|
if ($calcw) { |
|
|
0
|
|
|
|
|
|
1028
|
3
|
|
|
|
|
11
|
$wh = $self->{_func_length_height}->($text); |
1029
|
3
|
0
|
33
|
|
|
149
|
$wh->[0] = -$setw if defined($setw) && $setw<0 && $wh->[0] < -$setw; |
|
|
|
33
|
|
|
|
|
1030
|
3
|
50
|
|
|
|
6
|
$wh->[1] = $seth if !$calch; |
1031
|
3
|
0
|
33
|
|
|
8
|
$wh->[1] = -$seth if defined($seth) && $seth<0 && $wh->[1] < -$seth; |
|
|
|
33
|
|
|
|
|
1032
|
|
|
|
|
|
|
} elsif ($calch) { |
1033
|
0
|
|
|
|
|
0
|
my $h = 1; $h++ while $text =~ /\n/go; |
|
0
|
|
|
|
|
0
|
|
1034
|
0
|
0
|
0
|
|
|
0
|
$h = -$seth if defined($seth) && $seth<0 && $h < -$seth; |
|
|
|
0
|
|
|
|
|
1035
|
0
|
|
|
|
|
0
|
$wh = [$setw, $h]; |
1036
|
|
|
|
|
|
|
} else { |
1037
|
0
|
|
|
|
|
0
|
$wh = [$setw, $seth]; |
1038
|
|
|
|
|
|
|
} |
1039
|
|
|
|
|
|
|
#say "D:_opt_calc_cell_width_height(", $frownum//"undef", ", $col) = $wh->[0], $wh->[1]"; |
1040
|
3
|
|
|
|
|
6
|
$wh; |
1041
|
|
|
|
|
|
|
} |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
sub _apply_column_formats { |
1044
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
1045
|
|
|
|
|
|
|
|
1046
|
1
|
|
|
|
|
2
|
my $cols = $self->{columns}; |
1047
|
1
|
|
|
|
|
2
|
my $frows = $self->{_draw}{frows}; |
1048
|
1
|
|
|
|
|
2
|
my $fcols = $self->{_draw}{fcols}; |
1049
|
1
|
|
|
|
|
2
|
my $fcol_detect = $self->{_draw}{fcol_detect}; |
1050
|
|
|
|
|
|
|
|
1051
|
1
|
|
|
|
|
1
|
my %seen; |
1052
|
1
|
|
|
|
|
7
|
for my $i (0..@$cols-1) { |
1053
|
1
|
50
|
|
|
|
5
|
next unless $cols->[$i] ~~ $fcols; |
1054
|
1
|
50
|
|
|
|
5
|
next if $seen{$cols->[$i]}++; |
1055
|
1
|
|
|
|
|
1
|
my @fmts = @{ $self->get_eff_column_style($i, 'formats') // |
1056
|
1
|
|
33
|
|
|
4
|
$fcol_detect->[$i]{formats} // [] }; |
|
|
|
50
|
|
|
|
|
1057
|
1
|
50
|
|
|
|
4
|
if (@fmts) { |
1058
|
0
|
|
|
|
|
0
|
require Data::Unixish::Apply; |
1059
|
|
|
|
|
|
|
my $res = Data::Unixish::Apply::apply( |
1060
|
0
|
|
|
|
|
0
|
in => [map {$frows->[$_][$i]} 0..@$frows-1], |
|
0
|
|
|
|
|
0
|
|
1061
|
|
|
|
|
|
|
functions => \@fmts, |
1062
|
|
|
|
|
|
|
); |
1063
|
0
|
0
|
|
|
|
0
|
croak "Can't format column $cols->[$i]: $res->[0] - $res->[1]" |
1064
|
|
|
|
|
|
|
unless $res->[0] == 200; |
1065
|
0
|
|
|
|
|
0
|
$res = $res->[2]; |
1066
|
0
|
|
0
|
|
|
0
|
for (0..@$frows-1) { $frows->[$_][$i] = $res->[$_] // "" } |
|
0
|
|
|
|
|
0
|
|
1067
|
|
|
|
|
|
|
} else { |
1068
|
|
|
|
|
|
|
# change null to '' |
1069
|
1
|
|
50
|
|
|
4
|
for (0..@$frows-1) { $frows->[$_][$i] //= "" } |
|
2
|
|
|
|
|
6
|
|
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
} |
1072
|
|
|
|
|
|
|
} |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
sub _apply_cell_formats { |
1075
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
1076
|
|
|
|
|
|
|
|
1077
|
1
|
|
|
|
|
2
|
my $cols = $self->{columns}; |
1078
|
1
|
|
|
|
|
2
|
my $rows = $self->{rows}; |
1079
|
1
|
|
|
|
|
2
|
my $fcols = $self->{_draw}{fcols}; |
1080
|
1
|
|
|
|
|
2
|
my $frows = $self->{_draw}{frows}; |
1081
|
1
|
|
|
|
|
1
|
my $frow_orig_indices = $self->{_draw}{frow_orig_indices}; |
1082
|
|
|
|
|
|
|
|
1083
|
1
|
|
|
|
|
8
|
for my $i (0..@$frows-1) { |
1084
|
2
|
|
|
|
|
5
|
my %seen; |
1085
|
2
|
|
|
|
|
4
|
my $origi = $frow_orig_indices->[$i]; |
1086
|
2
|
|
|
|
|
7
|
for my $j (0..@$cols-1) { |
1087
|
2
|
50
|
|
|
|
8
|
next unless $cols->[$j] ~~ $fcols; |
1088
|
2
|
50
|
|
|
|
8
|
next if $seen{$cols->[$j]}++; |
1089
|
|
|
|
|
|
|
|
1090
|
2
|
|
|
|
|
10
|
my $fmts = $self->get_eff_cell_style($origi, $j, 'formats'); |
1091
|
2
|
50
|
|
|
|
5
|
if (defined $fmts) { |
1092
|
2
|
|
|
|
|
12
|
require Data::Unixish::Apply; |
1093
|
2
|
|
|
|
|
16
|
my $res = Data::Unixish::Apply::apply( |
1094
|
|
|
|
|
|
|
in => [ $frows->[$i][$j] ], |
1095
|
|
|
|
|
|
|
functions => $fmts, |
1096
|
|
|
|
|
|
|
); |
1097
|
2
|
50
|
|
|
|
24263
|
croak "Can't format cell ($origi, $cols->[$j]): ". |
1098
|
|
|
|
|
|
|
"$res->[0] - $res->[1]" unless $res->[0] == 200; |
1099
|
2
|
|
50
|
|
|
14
|
$frows->[$i][$j] = $res->[2][0] // ""; |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
} # col |
1102
|
|
|
|
|
|
|
} |
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
sub _calc_row_widths_heights { |
1106
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
1107
|
|
|
|
|
|
|
|
1108
|
1
|
|
|
|
|
2
|
my $cols = $self->{columns}; |
1109
|
1
|
|
|
|
|
2
|
my $fcols = $self->{_draw}{fcols}; |
1110
|
1
|
|
|
|
|
3
|
my $frows = $self->{_draw}{frows}; |
1111
|
|
|
|
|
|
|
|
1112
|
1
|
|
|
|
|
2
|
my $frow_heights = []; |
1113
|
1
|
|
|
|
|
2
|
my $fcol_widths = $self->{_draw}{fcol_widths}; |
1114
|
1
|
|
|
|
|
2
|
my $frow_orig_indices = $self->{_draw}{frow_orig_indices}; |
1115
|
|
|
|
|
|
|
|
1116
|
1
|
|
|
|
|
2
|
my $height = $self->{cell_height}; |
1117
|
1
|
|
33
|
|
|
5
|
my $tpad = $self->{cell_tpad} // $self->{cell_vpad}; # tbl-lvl tpad |
1118
|
1
|
|
33
|
|
|
11
|
my $bpad = $self->{cell_bpad} // $self->{cell_vpad}; # tbl-lvl bpad |
1119
|
1
|
|
|
|
|
5
|
my $cswidths = [map {$self->get_eff_column_style($_, 'width')} 0..@$cols-1]; |
|
1
|
|
|
|
|
3
|
|
1120
|
1
|
|
|
|
|
8
|
for my $i (0..@$frows-1) { |
1121
|
2
|
|
|
|
|
5
|
my %seen; |
1122
|
2
|
|
|
|
|
3
|
my $origi = $frow_orig_indices->[$i]; |
1123
|
2
|
|
|
|
|
7
|
my $rsheight = $self->get_eff_row_style($origi, 'height'); |
1124
|
2
|
|
|
|
|
6
|
for my $j (0..@$cols-1) { |
1125
|
2
|
50
|
|
|
|
8
|
next unless $cols->[$j] ~~ $fcols; |
1126
|
2
|
50
|
|
|
|
7
|
next if $seen{$cols->[$j]}++; |
1127
|
|
|
|
|
|
|
|
1128
|
2
|
|
|
|
|
6
|
my $wh = $self->_opt_calc_cell_width_height($i,$j,$frows->[$i][$j]); |
1129
|
|
|
|
|
|
|
|
1130
|
2
|
50
|
|
|
|
6
|
$fcol_widths->[$j] = $wh->[0] if $fcol_widths->[$j] < $wh->[0]; |
1131
|
2
|
50
|
33
|
|
|
10
|
$frow_heights->[$i] = $wh->[1] if !defined($frow_heights->[$i]) |
1132
|
|
|
|
|
|
|
|| $frow_heights->[$i] < $wh->[1]; |
1133
|
|
|
|
|
|
|
} # col |
1134
|
|
|
|
|
|
|
} |
1135
|
1
|
|
|
|
|
4
|
$self->{_draw}{frow_heights} = $frow_heights; |
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub _wrap_wrappable_columns { |
1139
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
1140
|
|
|
|
|
|
|
|
1141
|
1
|
|
|
|
|
3
|
my $cols = $self->{columns}; |
1142
|
1
|
|
|
|
|
2
|
my $fcols = $self->{_draw}{fcols}; |
1143
|
1
|
|
|
|
|
3
|
my $frows = $self->{_draw}{frows}; |
1144
|
1
|
|
|
|
|
3
|
my $fcol_detect = $self->{_draw}{fcol_detect}; |
1145
|
1
|
|
|
|
|
14
|
my $fcol_setwidths = $self->{_draw}{fcol_setwidths}; |
1146
|
|
|
|
|
|
|
|
1147
|
1
|
|
|
|
|
3
|
my %seen; |
1148
|
1
|
|
|
|
|
5
|
for my $i (0..@$cols-1) { |
1149
|
1
|
50
|
|
|
|
5
|
next unless $cols->[$i] ~~ $fcols; |
1150
|
1
|
50
|
|
|
|
5
|
next if $seen{$cols->[$i]}++; |
1151
|
|
|
|
|
|
|
|
1152
|
1
|
50
|
33
|
|
|
5
|
if (($self->get_eff_column_style($i, 'wrap') // $self->{column_wrap} // |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1153
|
|
|
|
|
|
|
$fcol_detect->[$i]{wrap}) && |
1154
|
|
|
|
|
|
|
defined($fcol_setwidths->[$i]) && |
1155
|
|
|
|
|
|
|
$fcol_setwidths->[$i]>0) { |
1156
|
0
|
|
|
|
|
0
|
for (0..@$frows-1) { |
1157
|
0
|
|
|
|
|
0
|
$frows->[$_][$i] = $self->{_func_wrap}->( |
1158
|
|
|
|
|
|
|
$frows->[$_][$i], $fcol_setwidths->[$i]); |
1159
|
|
|
|
|
|
|
} |
1160
|
|
|
|
|
|
|
} |
1161
|
|
|
|
|
|
|
} |
1162
|
|
|
|
|
|
|
} |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
sub _calc_table_width_height { |
1165
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
1166
|
|
|
|
|
|
|
|
1167
|
1
|
|
|
|
|
3
|
my $cols = $self->{columns}; |
1168
|
1
|
|
|
|
|
2
|
my $fcols = $self->{_draw}{fcols}; |
1169
|
1
|
|
|
|
|
2
|
my $frows = $self->{_draw}{frows}; |
1170
|
1
|
|
|
|
|
2
|
my $fcol_widths = $self->{_draw}{fcol_widths}; |
1171
|
1
|
|
|
|
|
2
|
my $fcol_lpads = $self->{_draw}{fcol_lpads}; |
1172
|
1
|
|
|
|
|
2
|
my $fcol_rpads = $self->{_draw}{fcol_rpads}; |
1173
|
1
|
|
|
|
|
2
|
my $frow_tpads = $self->{_draw}{frow_tpads}; |
1174
|
1
|
|
|
|
|
2
|
my $frow_bpads = $self->{_draw}{frow_bpads}; |
1175
|
1
|
|
|
|
|
3
|
my $frow_heights = $self->{_draw}{frow_heights}; |
1176
|
|
|
|
|
|
|
|
1177
|
1
|
|
|
|
|
1
|
my $w = 0; |
1178
|
1
|
50
|
|
|
|
14
|
$w += 1 if length($self->{border_style_obj}->get_border_char(3, 0)); |
1179
|
1
|
|
|
|
|
44
|
my $has_vsep = length($self->{border_style_obj}->get_border_char(3, 1)); |
1180
|
1
|
|
|
|
|
26
|
for my $i (0..@$cols-1) { |
1181
|
1
|
50
|
|
|
|
6
|
next unless $cols->[$i] ~~ $fcols; |
1182
|
1
|
|
|
|
|
3
|
$w += $fcol_lpads->[$i] + $fcol_widths->[$i] + $fcol_rpads->[$i]; |
1183
|
1
|
50
|
|
|
|
5
|
if ($i < @$cols-1) { |
1184
|
0
|
0
|
|
|
|
0
|
$w += 1 if $has_vsep; |
1185
|
|
|
|
|
|
|
} |
1186
|
|
|
|
|
|
|
} |
1187
|
1
|
50
|
|
|
|
4
|
$w += 1 if length($self->{border_style_obj}->get_border_char(3, 2)); |
1188
|
1
|
|
|
|
|
23
|
$self->{_draw}{table_width} = $w; |
1189
|
|
|
|
|
|
|
|
1190
|
1
|
|
|
|
|
2
|
my $h = 0; |
1191
|
1
|
50
|
|
|
|
3
|
$h += 1 if length($self->{border_style_obj}->get_border_char(0, 0)); # top border line |
1192
|
|
|
|
|
|
|
$h += $self->{header_tpad} // $self->{header_vpad} // |
1193
|
1
|
|
33
|
|
|
27
|
$self->{cell_tpad} // $self->{cell_vpad}; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1194
|
1
|
|
50
|
|
|
4
|
$h += $self->{_draw}{header_height} // 0; |
1195
|
|
|
|
|
|
|
$h += $self->{header_bpad} // $self->{header_vpad} // |
1196
|
1
|
|
33
|
|
|
16
|
$self->{cell_bpad} // $self->{cell_vpad}; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1197
|
1
|
50
|
|
|
|
4
|
$h += 1 if length($self->{border_style_obj}->get_border_char(2, 0)); |
1198
|
1
|
|
|
|
|
23
|
for my $i (0..@$frows-1) { |
1199
|
2
|
|
50
|
|
|
11
|
$h += ($frow_tpads->[$i] // 0) + |
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
1200
|
|
|
|
|
|
|
($frow_heights->[$i] // 0) + |
1201
|
|
|
|
|
|
|
($frow_bpads->[$i] // 0); |
1202
|
2
|
50
|
|
|
|
7
|
$h += 1 if $self->_should_draw_row_separator($i); |
1203
|
|
|
|
|
|
|
} |
1204
|
1
|
50
|
|
|
|
3
|
$h += 1 if length($self->{border_style_obj}->get_border_char(5, 0)); |
1205
|
1
|
|
|
|
|
22
|
$self->{_draw}{table_height} = $h; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
# if there are text columns with no width set, and the column width is wider |
1209
|
|
|
|
|
|
|
# than terminal, try to adjust widths so it fit into the terminal, if possible. |
1210
|
|
|
|
|
|
|
# return 1 if widths (fcol_widths) adjusted. |
1211
|
|
|
|
|
|
|
sub _adjust_column_widths { |
1212
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
# try to find wrappable columns that do not have their widths set. currently |
1215
|
|
|
|
|
|
|
# the algorithm is not proper, it just targets columns which are wider than |
1216
|
|
|
|
|
|
|
# a hard-coded value (30). it should take into account the longest word in |
1217
|
|
|
|
|
|
|
# the content/header, but this will require another pass at the text to |
1218
|
|
|
|
|
|
|
# analyze it. |
1219
|
|
|
|
|
|
|
|
1220
|
1
|
|
|
|
|
2
|
my $fcols = $self->{_draw}{fcols}; |
1221
|
1
|
|
|
|
|
2
|
my $frows = $self->{_draw}{frows}; |
1222
|
1
|
|
|
|
|
3
|
my $fcol_setwidths = $self->{_draw}{fcol_setwidths}; |
1223
|
1
|
|
|
|
|
2
|
my $fcol_detect = $self->{_draw}{fcol_detect}; |
1224
|
1
|
|
|
|
|
1
|
my $fcol_widths = $self->{_draw}{fcol_widths}; |
1225
|
1
|
|
|
|
|
3
|
my %acols; |
1226
|
|
|
|
|
|
|
my %origw; |
1227
|
1
|
|
|
|
|
3
|
for my $i (0..@$fcols-1) { |
1228
|
1
|
|
|
|
|
3
|
my $ci = $self->_colnum($fcols->[$i]); |
1229
|
1
|
50
|
33
|
|
|
44
|
next if defined($fcol_setwidths->[$ci]) && $fcol_setwidths->[$ci]>0; |
1230
|
1
|
50
|
|
|
|
5
|
next if $fcol_widths->[$ci] < 30; |
1231
|
|
|
|
|
|
|
next unless $self->get_eff_column_style($ci, 'wrap') // |
1232
|
0
|
0
|
0
|
|
|
0
|
$self->{column_wrap} // $fcol_detect->[$ci]{wrap}; |
|
|
|
0
|
|
|
|
|
1233
|
0
|
|
|
|
|
0
|
$acols{$ci}++; |
1234
|
0
|
|
|
|
|
0
|
$origw{$ci} = $fcol_widths->[$ci]; |
1235
|
|
|
|
|
|
|
} |
1236
|
1
|
50
|
|
|
|
5
|
return 0 unless %acols; |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
# only do this if table width exceeds terminal width |
1239
|
0
|
|
|
|
|
0
|
my $termw = $self->term_width; |
1240
|
0
|
0
|
|
|
|
0
|
return 0 unless $termw > 0; |
1241
|
0
|
|
|
|
|
0
|
my $excess = $self->{_draw}{table_width} - $termw; |
1242
|
0
|
0
|
|
|
|
0
|
return 0 unless $excess > 0; |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
# reduce text columns proportionally |
1245
|
0
|
|
|
|
|
0
|
my $w = 0; # total width of all to-be-adjusted columns |
1246
|
0
|
|
|
|
|
0
|
$w += $fcol_widths->[$_] for keys %acols; |
1247
|
0
|
0
|
|
|
|
0
|
return 0 unless $w > 0; |
1248
|
0
|
|
|
|
|
0
|
my $reduced = 0; |
1249
|
|
|
|
|
|
|
REDUCE: |
1250
|
0
|
|
|
|
|
0
|
while (1) { |
1251
|
0
|
|
|
|
|
0
|
my $has_reduced; |
1252
|
0
|
|
|
|
|
0
|
for my $ci (keys %acols) { |
1253
|
0
|
0
|
|
|
|
0
|
last REDUCE if $reduced >= $excess; |
1254
|
0
|
0
|
|
|
|
0
|
if ($fcol_widths->[$ci] > 30) { |
1255
|
0
|
|
|
|
|
0
|
$fcol_widths->[$ci]--; |
1256
|
0
|
|
|
|
|
0
|
$reduced++; |
1257
|
0
|
|
|
|
|
0
|
$has_reduced++; |
1258
|
|
|
|
|
|
|
} |
1259
|
|
|
|
|
|
|
} |
1260
|
0
|
0
|
|
|
|
0
|
last if !$has_reduced; |
1261
|
|
|
|
|
|
|
} |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
# reset widths |
1264
|
0
|
|
|
|
|
0
|
for my $ci (keys %acols) { |
1265
|
0
|
|
|
|
|
0
|
$fcol_setwidths->[$ci] = $fcol_widths->[$ci]; |
1266
|
0
|
|
|
|
|
0
|
$fcol_widths->[$ci] = 0; # reset |
1267
|
|
|
|
|
|
|
} |
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
# wrap and set setwidths so it doesn't grow again during recalculate |
1270
|
0
|
|
|
|
|
0
|
for my $ci (keys %acols) { |
1271
|
0
|
0
|
|
|
|
0
|
next unless $origw{$ci} != $fcol_widths->[$ci]; |
1272
|
0
|
|
|
|
|
0
|
for (0..@$frows-1) { |
1273
|
0
|
|
|
|
|
0
|
$frows->[$_][$ci] = $self->{_func_wrap}->( |
1274
|
|
|
|
|
|
|
$frows->[$_][$ci], $fcol_setwidths->[$ci]); |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
} |
1277
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
# recalculate column widths |
1279
|
0
|
|
|
|
|
0
|
$self->_calc_row_widths_heights; |
1280
|
0
|
|
|
|
|
0
|
$self->_calc_table_width_height; |
1281
|
0
|
|
|
|
|
0
|
1; |
1282
|
|
|
|
|
|
|
} |
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
# filter columns & rows, calculate widths/paddings, format data, put the results |
1285
|
|
|
|
|
|
|
# in _draw (draw data) attribute. |
1286
|
|
|
|
|
|
|
sub _prepare_draw { |
1287
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
1288
|
|
|
|
|
|
|
|
1289
|
1
|
|
|
|
|
3
|
$self->{_draw} = {}; |
1290
|
|
|
|
|
|
|
|
1291
|
1
|
|
|
|
|
12
|
$self->_read_style_envs; |
1292
|
1
|
|
|
|
|
8
|
$self->_calc_fcols; |
1293
|
1
|
|
|
|
|
5
|
$self->_calc_header_height; |
1294
|
1
|
|
|
|
|
4
|
$self->_calc_frows; |
1295
|
1
|
|
|
|
|
3
|
$self->_detect_column_types; |
1296
|
1
|
|
|
|
|
9
|
$self->_apply_column_formats; |
1297
|
1
|
|
|
|
|
4
|
$self->_apply_cell_formats; |
1298
|
1
|
|
|
|
|
12
|
$self->_wrap_wrappable_columns; |
1299
|
1
|
|
|
|
|
6
|
$self->_calc_row_widths_heights; |
1300
|
1
|
|
|
|
|
11
|
$self->_calc_table_width_height; |
1301
|
1
|
|
|
|
|
3
|
$self->_adjust_column_widths; |
1302
|
|
|
|
|
|
|
} |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
# push string into the drawing buffer. also updates "cursor" position. |
1305
|
|
|
|
|
|
|
sub draw_str { |
1306
|
24
|
|
|
24
|
0
|
282
|
my $self = shift; |
1307
|
|
|
|
|
|
|
# currently x position is not recorded because this involves doing |
1308
|
|
|
|
|
|
|
# ta_mbswidth() (or ta_mbswidth_height()) for every string, which is rather |
1309
|
|
|
|
|
|
|
# expensive. so only the y position is recorded by counting newlines. |
1310
|
|
|
|
|
|
|
|
1311
|
24
|
|
|
|
|
33
|
for (@_) { |
1312
|
24
|
|
|
|
|
25
|
my $num_nl = 0; |
1313
|
24
|
|
|
|
|
100
|
$num_nl++ while /\r?\n/og; |
1314
|
24
|
|
|
|
|
40
|
push @{$self->{_draw}{buf}}, $_; |
|
24
|
|
|
|
|
51
|
|
1315
|
24
|
|
|
|
|
42
|
$self->{_draw}{y} += $num_nl; |
1316
|
|
|
|
|
|
|
} |
1317
|
24
|
|
|
|
|
30
|
$self; |
1318
|
|
|
|
|
|
|
} |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
sub draw_theme_color { |
1321
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
1322
|
0
|
|
|
|
|
0
|
my $c = $self->_color_theme_item_color_to_ansi(@_); |
1323
|
0
|
0
|
|
|
|
0
|
$self->draw_str($c) if length($c); |
1324
|
|
|
|
|
|
|
} |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
sub get_color_reset { |
1327
|
18
|
|
|
18
|
0
|
23
|
my $self = shift; |
1328
|
18
|
50
|
|
|
|
293
|
return "" unless $self->use_color; |
1329
|
0
|
0
|
|
|
|
0
|
return "" if $self->{color_theme_obj}->get_struct->{_no_color}; |
1330
|
0
|
|
|
|
|
0
|
"\e[0m"; |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
sub draw_color_reset { |
1334
|
18
|
|
|
18
|
0
|
20
|
my $self = shift; |
1335
|
18
|
|
|
|
|
33
|
my $c = $self->get_color_reset; |
1336
|
18
|
50
|
|
|
|
141
|
$self->draw_str($c) if length($c); |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
# draw border character(s). drawing border character involves setting border |
1340
|
|
|
|
|
|
|
# color, aside from drawing the actual characters themselves. arguments are list |
1341
|
|
|
|
|
|
|
# of (y, x, n) tuples where y and x are the row and col number of border |
1342
|
|
|
|
|
|
|
# character, n is the number of characters to print. n defaults to 1 if not |
1343
|
|
|
|
|
|
|
# specified. |
1344
|
|
|
|
|
|
|
sub draw_border_char { |
1345
|
9
|
|
|
9
|
0
|
12
|
my $self = shift; |
1346
|
9
|
100
|
|
|
|
10
|
my $args; $args = shift if ref($_[0]) eq 'HASH'; |
|
9
|
|
|
|
|
19
|
|
1347
|
|
|
|
|
|
|
|
1348
|
9
|
|
|
|
|
26
|
while (my ($y, $x, $n) = splice @_, 0, 3) { |
1349
|
15
|
|
100
|
|
|
38
|
$n //= 1; |
1350
|
15
|
50
|
|
|
|
26
|
if (!$self->{use_color}) { |
|
|
0
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
# save some CPU cycles |
1352
|
|
|
|
|
|
|
} elsif ($args) { |
1353
|
0
|
|
|
|
|
0
|
$self->draw_theme_color('border', |
1354
|
|
|
|
|
|
|
{table=>$self, border=>[$y, $x, $n], %$args}); |
1355
|
|
|
|
|
|
|
} else { |
1356
|
0
|
|
|
|
|
0
|
$self->draw_theme_color('border', |
1357
|
|
|
|
|
|
|
{table=>$self, border=>[$y, $x, $n]}); |
1358
|
|
|
|
|
|
|
} |
1359
|
15
|
|
|
|
|
37
|
$self->draw_str($self->{border_style_obj}->get_border_char($y, $x, $n)); |
1360
|
15
|
|
|
|
|
29
|
$self->draw_color_reset; |
1361
|
|
|
|
|
|
|
} |
1362
|
|
|
|
|
|
|
} |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
sub _should_draw_row_separator { |
1365
|
4
|
|
|
4
|
|
10
|
my ($self, $i) = @_; |
1366
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
return $i < @{$self->{_draw}{frows}}-1 && |
1368
|
|
|
|
|
|
|
(($self->{show_row_separator}==2 && $i~~$self->{_draw}{frow_separators}) |
1369
|
4
|
|
66
|
|
|
5
|
|| $self->{show_row_separator}==1); |
1370
|
|
|
|
|
|
|
} |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
# apply align/valign, apply padding, apply default fgcolor/bgcolor to text, |
1373
|
|
|
|
|
|
|
# truncate to specified cell's width & height |
1374
|
|
|
|
|
|
|
sub _get_cell_lines { |
1375
|
3
|
|
|
3
|
|
5
|
my $self = shift; |
1376
|
|
|
|
|
|
|
#say "D: get_cell_lines ".join(", ", map{$_//""} @_); |
1377
|
3
|
|
|
|
|
8
|
my ($text, $width, $height, $align, $valign, |
1378
|
|
|
|
|
|
|
$lpad, $rpad, $tpad, $bpad, $color) = @_; |
1379
|
|
|
|
|
|
|
|
1380
|
3
|
|
|
|
|
4
|
my @lines; |
1381
|
3
|
|
|
|
|
7
|
push @lines, "" for 1..$tpad; |
1382
|
3
|
|
|
|
|
10
|
my @dlines = split(/\r?\n/, $text); |
1383
|
3
|
50
|
|
|
|
8
|
@dlines = ("") unless @dlines; |
1384
|
3
|
|
|
|
|
5
|
my ($la, $lb); |
1385
|
3
|
|
50
|
|
|
5
|
$valign //= 'top'; |
1386
|
3
|
50
|
|
|
|
12
|
if ($valign =~ /^[Bb]/o) { # bottom |
|
|
50
|
|
|
|
|
|
1387
|
0
|
|
|
|
|
0
|
$la = $height-@dlines; |
1388
|
0
|
|
|
|
|
0
|
$lb = 0; |
1389
|
|
|
|
|
|
|
} elsif ($valign =~ /^[MmCc]/o) { # middle/center |
1390
|
0
|
|
|
|
|
0
|
$la = int(($height-@dlines)/2); |
1391
|
0
|
|
|
|
|
0
|
$lb = $height-@dlines-$la; |
1392
|
|
|
|
|
|
|
} else { # top |
1393
|
3
|
|
|
|
|
4
|
$la = 0; |
1394
|
3
|
|
|
|
|
6
|
$lb = $height-@dlines; |
1395
|
|
|
|
|
|
|
} |
1396
|
3
|
|
|
|
|
4
|
push @lines, "" for 1..$la; |
1397
|
3
|
|
|
|
|
6
|
push @lines, @dlines; |
1398
|
3
|
|
|
|
|
5
|
push @lines, "" for 1..$lb; |
1399
|
3
|
|
|
|
|
6
|
push @lines, "" for 1..$bpad; |
1400
|
|
|
|
|
|
|
|
1401
|
3
|
|
50
|
|
|
4
|
$align //= 'left'; |
1402
|
3
|
0
|
|
|
|
15
|
my $pad = $align =~ /^[Ll]/o ? "right" : |
|
|
50
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
($align =~ /^[Rr]/o ? "left" : "center"); |
1404
|
|
|
|
|
|
|
|
1405
|
3
|
|
|
|
|
7
|
for (@lines) { |
1406
|
3
|
|
|
|
|
12
|
$_ = (" "x$lpad) . $self->{_func_pad}->($_, $width, $pad, " ", 1) . (" "x$rpad); |
1407
|
3
|
50
|
|
|
|
139
|
if ($self->{use_color}) { |
1408
|
|
|
|
|
|
|
# add default color |
1409
|
0
|
0
|
|
|
|
0
|
s/\e\[0m(?=.)/\e[0m$color/g if length($color); |
1410
|
0
|
|
|
|
|
0
|
$_ = $color . $_; |
1411
|
|
|
|
|
|
|
} |
1412
|
|
|
|
|
|
|
} |
1413
|
|
|
|
|
|
|
|
1414
|
3
|
|
|
|
|
14
|
\@lines; |
1415
|
|
|
|
|
|
|
} |
1416
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
sub _get_header_cell_lines { |
1418
|
1
|
|
|
1
|
|
3
|
my ($self, $i) = @_; |
1419
|
|
|
|
|
|
|
|
1420
|
1
|
|
|
|
|
2
|
my $ct = $self->{color_theme}; |
1421
|
|
|
|
|
|
|
|
1422
|
1
|
|
|
|
|
2
|
my $tmp; |
1423
|
|
|
|
|
|
|
my $fgcolor; |
1424
|
1
|
50
|
|
|
|
7
|
if (defined $self->{header_fgcolor}) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1425
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($self->{header_fgcolor}); |
1426
|
|
|
|
|
|
|
} elsif (defined $self->{cell_fgcolor}) { |
1427
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($self->{cell_fgcolor}); |
1428
|
|
|
|
|
|
|
#} elsif (defined $self->{_draw}{fcol_detect}[$i]{fgcolor}) { |
1429
|
|
|
|
|
|
|
# $fgcolor = item_color_to_ansi($self->{_draw}{fcol_detect}[$i]{fgcolor}); |
1430
|
|
|
|
|
|
|
} elsif ($tmp = $self->_color_theme_item_color_to_ansi('header')) { |
1431
|
0
|
|
|
|
|
0
|
$fgcolor = $tmp; |
1432
|
|
|
|
|
|
|
} elsif ($tmp = $self->_color_theme_item_color_to_ansi('cell')) { |
1433
|
0
|
|
|
|
|
0
|
$fgcolor = $tmp; |
1434
|
|
|
|
|
|
|
} else { |
1435
|
1
|
|
|
|
|
25
|
$fgcolor = ""; |
1436
|
|
|
|
|
|
|
} |
1437
|
|
|
|
|
|
|
|
1438
|
1
|
|
|
|
|
2
|
my $bgcolor; |
1439
|
1
|
50
|
|
|
|
21
|
if (defined $self->{header_bgcolor}) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1440
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($self->{header_bgcolor}, 'bg'); |
1441
|
|
|
|
|
|
|
} elsif (defined $self->{cell_bgcolor}) { |
1442
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($self->{cell_bgcolor}, 'bg'); |
1443
|
|
|
|
|
|
|
} elsif (defined $self->{_draw}{fcol_detect}[$i]{bgcolor}) { |
1444
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($self->{_draw}{fcol_detect}[$i]{bgcolor}, 'bg'); |
1445
|
|
|
|
|
|
|
} elsif ($tmp = $self->_color_theme_item_color_to_ansi('header_bg', undef, 'bg')) { |
1446
|
0
|
|
|
|
|
0
|
$bgcolor = $tmp; |
1447
|
|
|
|
|
|
|
} elsif ($tmp = $self->_color_theme_item_color_to_ansi('cell_bg', undef, 'bg')) { |
1448
|
0
|
|
|
|
|
0
|
$bgcolor = $tmp; |
1449
|
|
|
|
|
|
|
} else { |
1450
|
1
|
|
|
|
|
17
|
$bgcolor = ""; |
1451
|
|
|
|
|
|
|
} |
1452
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
my $align = |
1454
|
|
|
|
|
|
|
$self->{header_align} // |
1455
|
|
|
|
|
|
|
$self->{cell_align} // |
1456
|
|
|
|
|
|
|
$self->{_draw}{fcol_detect}[$i]{align} // |
1457
|
1
|
|
33
|
|
|
58
|
'left'; |
|
|
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
1458
|
|
|
|
|
|
|
my $valign = |
1459
|
|
|
|
|
|
|
$self->{header_valign} // |
1460
|
|
|
|
|
|
|
$self->{cell_valign} // |
1461
|
|
|
|
|
|
|
$self->{_draw}{fcol_detect}[$i]{valign} // |
1462
|
1
|
|
33
|
|
|
9
|
'top'; |
|
|
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
1463
|
|
|
|
|
|
|
|
1464
|
1
|
|
|
|
|
2
|
my $lpad = $self->{_draw}{fcol_lpads}[$i]; |
1465
|
1
|
|
|
|
|
2
|
my $rpad = $self->{_draw}{fcol_rpads}[$i]; |
1466
|
1
|
|
33
|
|
|
11
|
my $tpad = $self->{header_tpad} // $self->{header_vpad} // 0; |
|
|
|
50
|
|
|
|
|
1467
|
1
|
|
33
|
|
|
7
|
my $bpad = $self->{header_bpad} // $self->{header_vpad} // 0; |
|
|
|
50
|
|
|
|
|
1468
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
#use Data::Dump; print "D:header cell: "; dd {i=>$i, col=>$self->{columns}[$i], fgcolor=>$fgcolor, bgcolor=>$bgcolor}; |
1470
|
|
|
|
|
|
|
my $res = $self->_get_cell_lines( |
1471
|
|
|
|
|
|
|
$self->{columns}[$i], # text |
1472
|
|
|
|
|
|
|
$self->{_draw}{fcol_widths}[$i], # width |
1473
|
|
|
|
|
|
|
$self->{_draw}{header_height}, # height |
1474
|
1
|
|
|
|
|
7
|
$align, $valign, # aligns |
1475
|
|
|
|
|
|
|
$lpad, $rpad, $tpad, $bpad, # paddings |
1476
|
|
|
|
|
|
|
$fgcolor . $bgcolor); |
1477
|
|
|
|
|
|
|
#use Data::Dump; print "D:res: "; dd $res; |
1478
|
1
|
|
|
|
|
6
|
$res; |
1479
|
|
|
|
|
|
|
} |
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
sub _get_data_cell_lines { |
1482
|
2
|
|
|
2
|
|
4
|
my ($self, $y, $x) = @_; |
1483
|
|
|
|
|
|
|
|
1484
|
2
|
|
|
|
|
4
|
my $ct = $self->{color_theme}; |
1485
|
2
|
|
|
|
|
3
|
my $oy = $self->{_draw}{frow_orig_indices}[$y]; |
1486
|
2
|
|
|
|
|
4
|
my $cell = $self->{_draw}{frows}[$y][$x]; |
1487
|
|
|
|
|
|
|
my $args = {table=>$self, rownum=>$y, colnum=>$x, data=>$cell, |
1488
|
2
|
|
|
|
|
17
|
orig_data=>$self->{rows}[$oy][$x]}; |
1489
|
|
|
|
|
|
|
|
1490
|
2
|
|
|
|
|
6
|
my $tmp; |
1491
|
|
|
|
|
|
|
my $fgcolor; |
1492
|
2
|
50
|
|
|
|
4
|
if (defined ($tmp = $self->get_eff_cell_style($oy, $x, 'fgcolor'))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1493
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($tmp); |
1494
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->get_eff_row_style($oy, 'fgcolor'))) { |
1495
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($tmp); |
1496
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->get_eff_column_style($x, 'fgcolor'))) { |
1497
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($tmp); |
1498
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->{cell_fgcolor})) { |
1499
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($tmp); |
1500
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->{_draw}{fcol_detect}[$x]{fgcolor})) { |
1501
|
0
|
|
|
|
|
0
|
$fgcolor = item_color_to_ansi($tmp); |
1502
|
|
|
|
|
|
|
} elsif ($tmp = $self->_color_theme_item_color_to_ansi('cell', $args)) { |
1503
|
0
|
|
|
|
|
0
|
$fgcolor = $tmp; |
1504
|
|
|
|
|
|
|
} else { |
1505
|
2
|
|
|
|
|
54
|
$fgcolor = ""; |
1506
|
|
|
|
|
|
|
} |
1507
|
|
|
|
|
|
|
|
1508
|
2
|
|
|
|
|
6
|
my $bgcolor; |
1509
|
2
|
50
|
|
|
|
4
|
if (defined ($tmp = $self->get_eff_cell_style($oy, $x, 'bgcolor'))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1510
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($tmp, 'bg'); |
1511
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->get_eff_row_style($oy, 'bgcolor'))) { |
1512
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($tmp, 'bg'); |
1513
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->get_eff_column_style($x, 'bgcolor'))) { |
1514
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($tmp, 'bg'); |
1515
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->{cell_bgcolor})) { |
1516
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($tmp, 'bg'); |
1517
|
|
|
|
|
|
|
} elsif (defined ($tmp = $self->{_draw}{fcol_detect}[$x]{bgcolor})) { |
1518
|
0
|
|
|
|
|
0
|
$bgcolor = item_color_to_ansi($tmp, 'bg'); |
1519
|
|
|
|
|
|
|
} elsif ($tmp = $self->_color_theme_item_color_to_ansi('cell_bg', $args, 'bg')) { |
1520
|
0
|
|
|
|
|
0
|
$bgcolor = $tmp; |
1521
|
|
|
|
|
|
|
} else { |
1522
|
2
|
|
|
|
|
30
|
$bgcolor = ""; |
1523
|
|
|
|
|
|
|
} |
1524
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
my $align = |
1526
|
|
|
|
|
|
|
$self->get_eff_cell_style($oy, $x, 'align') // |
1527
|
|
|
|
|
|
|
$self->get_eff_row_style($oy, 'align') // |
1528
|
|
|
|
|
|
|
$self->get_eff_column_style($x, 'align') // |
1529
|
|
|
|
|
|
|
$self->{cell_align} // |
1530
|
|
|
|
|
|
|
$self->{_draw}{fcol_detect}[$x]{align} // |
1531
|
2
|
|
33
|
|
|
17
|
'left'; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
1532
|
|
|
|
|
|
|
my $valign = |
1533
|
|
|
|
|
|
|
$self->get_eff_cell_style($oy, $x, 'valign') // |
1534
|
|
|
|
|
|
|
$self->get_eff_row_style($oy, 'valign') // |
1535
|
|
|
|
|
|
|
$self->get_eff_column_style($x, 'valign') // |
1536
|
|
|
|
|
|
|
$self->{cell_valign} // |
1537
|
|
|
|
|
|
|
$self->{_draw}{fcol_detect}[$x]{valign} // |
1538
|
2
|
|
33
|
|
|
6
|
'top'; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
1539
|
|
|
|
|
|
|
#say "D:y=$y, x=$x, align=$align, valign=$valign"; |
1540
|
|
|
|
|
|
|
|
1541
|
2
|
|
|
|
|
4
|
my $lpad = $self->{_draw}{fcol_lpads}[$x]; |
1542
|
2
|
|
|
|
|
3
|
my $rpad = $self->{_draw}{fcol_rpads}[$x]; |
1543
|
2
|
|
|
|
|
4
|
my $tpad = $self->{_draw}{frow_tpads}[$y]; |
1544
|
2
|
|
|
|
|
3
|
my $bpad = $self->{_draw}{frow_bpads}[$y]; |
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
my $res = $self->_get_cell_lines( |
1547
|
|
|
|
|
|
|
$cell, # text |
1548
|
|
|
|
|
|
|
$self->{_draw}{fcol_widths}[$x], # width |
1549
|
2
|
|
|
|
|
8
|
$self->{_draw}{frow_heights}[$y], # height |
1550
|
|
|
|
|
|
|
$align, $valign, # aligns |
1551
|
|
|
|
|
|
|
$lpad, $rpad, $tpad, $bpad, # paddings |
1552
|
|
|
|
|
|
|
$fgcolor . $bgcolor); |
1553
|
2
|
|
|
|
|
9
|
$res; |
1554
|
|
|
|
|
|
|
} |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
sub draw { |
1557
|
1
|
|
|
1
|
1
|
13
|
my ($self) = @_; |
1558
|
|
|
|
|
|
|
|
1559
|
1
|
|
|
|
|
5
|
$self->_prepare_draw; |
1560
|
|
|
|
|
|
|
|
1561
|
1
|
|
|
|
|
3
|
$self->{_draw}{buf} = []; # output buffer |
1562
|
1
|
|
|
|
|
3
|
$self->{_draw}{y} = 0; # current line |
1563
|
|
|
|
|
|
|
|
1564
|
1
|
|
|
|
|
27
|
my $cols = $self->{columns}; |
1565
|
1
|
|
|
|
|
5
|
my $fcols = $self->{_draw}{fcols}; |
1566
|
1
|
|
|
|
|
2
|
my $frows = $self->{_draw}{frows}; |
1567
|
1
|
|
|
|
|
2
|
my $frow_heights = $self->{_draw}{frow_heights}; |
1568
|
1
|
|
|
|
|
2
|
my $frow_tpads = $self->{_draw}{frow_tpads}; |
1569
|
1
|
|
|
|
|
1
|
my $frow_bpads = $self->{_draw}{frow_bpads}; |
1570
|
1
|
|
|
|
|
2
|
my $fcol_lpads = $self->{_draw}{fcol_lpads}; |
1571
|
1
|
|
|
|
|
2
|
my $fcol_rpads = $self->{_draw}{fcol_rpads}; |
1572
|
1
|
|
|
|
|
2
|
my $fcol_widths = $self->{_draw}{fcol_widths}; |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
# draw border top line |
1575
|
|
|
|
|
|
|
{ |
1576
|
1
|
50
|
|
|
|
2
|
last unless length($self->{border_style_obj}->get_border_char(0, 0)); |
|
1
|
|
|
|
|
4
|
|
1577
|
1
|
|
|
|
|
22
|
my @b; |
1578
|
1
|
|
|
|
|
3
|
push @b, 0, 0, 1; |
1579
|
1
|
|
|
|
|
8
|
for my $i (0..@$fcols-1) { |
1580
|
1
|
|
|
|
|
6
|
my $ci = $self->_colnum($fcols->[$i]); |
1581
|
1
|
|
|
|
|
5
|
push @b, 0, 1, |
1582
|
|
|
|
|
|
|
$fcol_lpads->[$ci] + $fcol_widths->[$ci] + $fcol_rpads->[$ci]; |
1583
|
1
|
50
|
|
|
|
9
|
push @b, 0, 2, 1 if $i < @$fcols-1; |
1584
|
|
|
|
|
|
|
} |
1585
|
1
|
|
|
|
|
4
|
push @b, 0, 3, 1; |
1586
|
1
|
|
|
|
|
5
|
$self->draw_border_char(@b); |
1587
|
1
|
|
|
|
|
3
|
$self->draw_str("\n"); |
1588
|
|
|
|
|
|
|
} |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
# draw header |
1591
|
1
|
50
|
|
|
|
3
|
if ($self->{show_header}) { |
1592
|
1
|
|
|
|
|
3
|
my %seen; |
1593
|
1
|
|
|
|
|
2
|
my $hcell_lines = []; # index = [fcolnum] |
1594
|
1
|
50
|
|
|
|
3
|
if (@$fcols) { |
1595
|
1
|
|
|
|
|
4
|
for my $i (0..@$fcols-1) { |
1596
|
1
|
|
|
|
|
3
|
my $ci = $self->_colnum($fcols->[$i]); |
1597
|
1
|
50
|
|
|
|
4
|
if (defined($seen{$i})) { |
1598
|
0
|
|
|
|
|
0
|
$hcell_lines->[$i] = $hcell_lines->[$seen{$i}]; |
1599
|
|
|
|
|
|
|
} |
1600
|
1
|
|
|
|
|
2
|
$seen{$i} = $ci; |
1601
|
1
|
|
|
|
|
4
|
$hcell_lines->[$i] = $self->_get_header_cell_lines($ci); |
1602
|
|
|
|
|
|
|
} |
1603
|
|
|
|
|
|
|
} else { |
1604
|
|
|
|
|
|
|
# so we can still draw header |
1605
|
0
|
|
|
|
|
0
|
$hcell_lines->[0] = [""]; |
1606
|
|
|
|
|
|
|
} |
1607
|
|
|
|
|
|
|
#use Data::Dump; print "D:hcell_lines: "; dd $hcell_lines; |
1608
|
1
|
|
|
|
|
2
|
for my $l (0..@{ $hcell_lines->[0] }-1) { |
|
1
|
|
|
|
|
12
|
|
1609
|
1
|
|
|
|
|
6
|
$self->draw_border_char(1, 0); |
1610
|
1
|
|
|
|
|
4
|
for my $i (0..@$fcols-1) { |
1611
|
1
|
|
|
|
|
4
|
$self->draw_str($hcell_lines->[$i][$l]); |
1612
|
1
|
|
|
|
|
3
|
$self->draw_color_reset; |
1613
|
1
|
50
|
|
|
|
5
|
$self->draw_border_char(1, 1) unless $i == @$fcols-1; |
1614
|
|
|
|
|
|
|
} |
1615
|
1
|
|
|
|
|
2
|
$self->draw_border_char(1, 2); |
1616
|
1
|
|
|
|
|
3
|
$self->draw_str("\n"); |
1617
|
|
|
|
|
|
|
} |
1618
|
|
|
|
|
|
|
} |
1619
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
# draw header-data row separator |
1621
|
1
|
50
|
33
|
|
|
13
|
if ($self->{show_header} && length($self->{border_style_obj}->get_border_char(2, 0))) { |
1622
|
1
|
|
|
|
|
22
|
my @b; |
1623
|
1
|
|
|
|
|
2
|
push @b, 2, 0, 1; |
1624
|
1
|
|
|
|
|
4
|
for my $i (0..@$fcols-1) { |
1625
|
1
|
|
|
|
|
3
|
my $ci = $self->_colnum($fcols->[$i]); |
1626
|
1
|
|
|
|
|
10
|
push @b, 2, 1, |
1627
|
|
|
|
|
|
|
$fcol_lpads->[$ci] + $fcol_widths->[$ci] + $fcol_rpads->[$ci]; |
1628
|
1
|
50
|
|
|
|
5
|
push @b, 2, 2, 1 unless $i==@$fcols-1; |
1629
|
|
|
|
|
|
|
} |
1630
|
1
|
|
|
|
|
3
|
push @b, 2, 3, 1; |
1631
|
1
|
|
|
|
|
3
|
$self->draw_border_char(@b); |
1632
|
1
|
|
|
|
|
3
|
$self->draw_str("\n"); |
1633
|
|
|
|
|
|
|
} |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
# draw data rows |
1636
|
|
|
|
|
|
|
{ |
1637
|
1
|
|
|
|
|
3
|
for my $r (0..@$frows-1) { |
1638
|
|
|
|
|
|
|
#$self->draw_str("r$r"); |
1639
|
2
|
|
|
|
|
5
|
my $dcell_lines = []; # index = [fcolnum] |
1640
|
2
|
|
|
|
|
2
|
my %seen; |
1641
|
2
|
50
|
|
|
|
7
|
if (@$fcols) { |
1642
|
2
|
|
|
|
|
5
|
for my $i (0..@$fcols-1) { |
1643
|
2
|
|
|
|
|
6
|
my $ci = $self->_colnum($fcols->[$i]); |
1644
|
2
|
50
|
|
|
|
6
|
if (defined($seen{$i})) { |
1645
|
0
|
|
|
|
|
0
|
$dcell_lines->[$i] = $dcell_lines->[$seen{$i}]; |
1646
|
|
|
|
|
|
|
} |
1647
|
2
|
|
|
|
|
4
|
$seen{$i} = $ci; |
1648
|
2
|
|
|
|
|
6
|
$dcell_lines->[$i] = $self->_get_data_cell_lines($r, $ci); |
1649
|
|
|
|
|
|
|
} |
1650
|
|
|
|
|
|
|
} else { |
1651
|
|
|
|
|
|
|
# so we can still print row |
1652
|
0
|
|
|
|
|
0
|
$dcell_lines->[0] = [" "]; |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
#use Data::Dump; print "TMP: dcell_lines: "; dd $dcell_lines; |
1655
|
2
|
|
|
|
|
3
|
for my $l (0..@{ $dcell_lines->[0] }-1) { |
|
2
|
|
|
|
|
12
|
|
1656
|
2
|
|
|
|
|
10
|
$self->draw_border_char({rownum=>$r}, 3, 0); |
1657
|
2
|
|
|
|
|
6
|
for my $i (0..@$fcols-1) { |
1658
|
2
|
|
|
|
|
16
|
$self->draw_str($dcell_lines->[$i][$l]); |
1659
|
2
|
|
|
|
|
4
|
$self->draw_color_reset; |
1660
|
2
|
50
|
|
|
|
7
|
$self->draw_border_char({rownum=>$r}, 3, 1) |
1661
|
|
|
|
|
|
|
unless $i == @$fcols-1; |
1662
|
|
|
|
|
|
|
} |
1663
|
2
|
|
|
|
|
7
|
$self->draw_border_char({rownum=>$r}, 3, 2); |
1664
|
2
|
|
|
|
|
5
|
$self->draw_str("\n"); |
1665
|
|
|
|
|
|
|
} |
1666
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
# draw separators between row |
1668
|
2
|
50
|
|
|
|
13
|
if ($self->_should_draw_row_separator($r)) { |
1669
|
0
|
|
|
|
|
0
|
my @b; |
1670
|
0
|
|
|
|
|
0
|
push @b, 4, 0, 1; |
1671
|
0
|
|
|
|
|
0
|
for my $i (0..@$fcols-1) { |
1672
|
0
|
|
|
|
|
0
|
my $ci = $self->_colnum($fcols->[$i]); |
1673
|
0
|
|
|
|
|
0
|
push @b, 4, 1, |
1674
|
|
|
|
|
|
|
$fcol_lpads->[$ci] + $fcol_widths->[$ci] + |
1675
|
|
|
|
|
|
|
$fcol_rpads->[$ci]; |
1676
|
0
|
0
|
|
|
|
0
|
push @b, 4, $i==@$fcols-1 ? 3:2, 1; |
1677
|
|
|
|
|
|
|
} |
1678
|
0
|
|
|
|
|
0
|
$self->draw_border_char({rownum=>$r}, @b); |
1679
|
0
|
|
|
|
|
0
|
$self->draw_str("\n"); |
1680
|
|
|
|
|
|
|
} |
1681
|
|
|
|
|
|
|
} # for frow |
1682
|
|
|
|
|
|
|
} |
1683
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
# draw border bottom line |
1685
|
|
|
|
|
|
|
{ |
1686
|
1
|
50
|
|
|
|
3
|
last unless length($self->{border_style_obj}->get_border_char(5, 0)); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
4
|
|
1687
|
1
|
|
|
|
|
19
|
my @b; |
1688
|
1
|
|
|
|
|
3
|
push @b, 5, 0, 1; |
1689
|
1
|
|
|
|
|
2
|
for my $i (0..@$fcols-1) { |
1690
|
1
|
|
|
|
|
3
|
my $ci = $self->_colnum($fcols->[$i]); |
1691
|
1
|
|
|
|
|
4
|
push @b, 5, 1, |
1692
|
|
|
|
|
|
|
$fcol_lpads->[$ci] + $fcol_widths->[$ci] + $fcol_rpads->[$ci]; |
1693
|
1
|
50
|
|
|
|
3
|
push @b, 5, 2, 1 unless $i == @$fcols-1; |
1694
|
|
|
|
|
|
|
} |
1695
|
1
|
|
|
|
|
3
|
push @b, 5, 3, 1; |
1696
|
1
|
|
|
|
|
3
|
$self->draw_border_char(@b); |
1697
|
1
|
|
|
|
|
3
|
$self->draw_str("\n"); |
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
|
1700
|
1
|
|
|
|
|
2
|
join "", @{$self->{_draw}{buf}}; |
|
1
|
|
|
|
|
8
|
|
1701
|
|
|
|
|
|
|
} |
1702
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
1; |
1704
|
|
|
|
|
|
|
# ABSTRACT: Create nice formatted tables using extended ASCII and ANSI colors |
1705
|
|
|
|
|
|
|
|
1706
|
|
|
|
|
|
|
__END__ |
1707
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
=pod |
1709
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
=encoding UTF-8 |
1711
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
=head1 NAME |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
Text::ANSITable - Create nice formatted tables using extended ASCII and ANSI colors |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
=head1 VERSION |
1717
|
|
|
|
|
|
|
|
1718
|
|
|
|
|
|
|
This document describes version 0.602 of Text::ANSITable (from Perl distribution Text-ANSITable), released on 2021-02-19. |
1719
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1721
|
|
|
|
|
|
|
|
1722
|
|
|
|
|
|
|
use 5.010; |
1723
|
|
|
|
|
|
|
use Text::ANSITable; |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
# don't forget this if you want to output utf8 characters |
1726
|
|
|
|
|
|
|
binmode(STDOUT, ":utf8"); |
1727
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
my $t = Text::ANSITable->new; |
1729
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
# set styles |
1731
|
|
|
|
|
|
|
$t->border_style('UTF8::SingleLineBold'); # if not, a nice default is picked |
1732
|
|
|
|
|
|
|
$t->color_theme('Text::ANSITable::Standard::NoGradation'); # if not, a nice default is picked |
1733
|
|
|
|
|
|
|
|
1734
|
|
|
|
|
|
|
# fill data |
1735
|
|
|
|
|
|
|
$t->columns(["name" , "color" , "price"]); |
1736
|
|
|
|
|
|
|
$t->add_row(["chiki" , "yellow", 2000]); |
1737
|
|
|
|
|
|
|
$t->add_row(["lays" , "green" , 7000]); |
1738
|
|
|
|
|
|
|
$t->add_row(["tao kae noi", "blue" , 18500]); |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
# draw it! |
1741
|
|
|
|
|
|
|
print $t->draw; |
1742
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
Samples of output: |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
This module is yet another text table formatter module like L<Text::ASCIITable> |
1748
|
|
|
|
|
|
|
or L<Text::SimpleTable>, with the following differences: |
1749
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
=over |
1751
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
=item * Colors and color themes |
1753
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
ANSI color codes will be used by default (even 256 and 24bit colors), but will |
1755
|
|
|
|
|
|
|
degrade to lower color depth and black/white according to terminal support. |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
=item * Box-drawing characters |
1758
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
Box-drawing characters will be used by default, but will degrade to using normal |
1760
|
|
|
|
|
|
|
ASCII characters if terminal does not support them. |
1761
|
|
|
|
|
|
|
|
1762
|
|
|
|
|
|
|
=item * Unicode and wide character support |
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
Border styles using Unicode characters (double lines, bold/heavy lines, brick |
1765
|
|
|
|
|
|
|
style, etc). Columns containing wide characters stay aligned. (Note: support for |
1766
|
|
|
|
|
|
|
wide characters requires L<Text::ANSI::WideUtil> which is currently set as an |
1767
|
|
|
|
|
|
|
optional prereq, so you'll need to install it explicitly or set your CPAN client |
1768
|
|
|
|
|
|
|
to install 'recommends' prereq). |
1769
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
=back |
1771
|
|
|
|
|
|
|
|
1772
|
|
|
|
|
|
|
Compared to Text::ASCIITable, it uses C<lower_case> method/attr names instead of |
1773
|
|
|
|
|
|
|
C<CamelCase>, and it uses arrayref for C<columns> and C<add_row>. When |
1774
|
|
|
|
|
|
|
specifying border styles, the order of characters are slightly different. More |
1775
|
|
|
|
|
|
|
fine-grained options to customize appearance. |
1776
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
=for Pod::Coverage ^(BUILD|draw_.+|get_color_reset)$ |
1778
|
|
|
|
|
|
|
|
1779
|
|
|
|
|
|
|
=begin HTML |
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
<p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable1.png" /></p> |
1782
|
|
|
|
|
|
|
|
1783
|
|
|
|
|
|
|
<p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable2.png" /></p> |
1784
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
<p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable3.png" /></p> |
1786
|
|
|
|
|
|
|
|
1787
|
|
|
|
|
|
|
<p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable4.png" /></p> |
1788
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
<p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable5.png" /></p> |
1790
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
=end HTML |
1792
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
=head1 REFERRING TO COLUMNS |
1794
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
Columns can be referred to be integer number (0-based) or name (string). You |
1796
|
|
|
|
|
|
|
should not have integer numbers as column names because that will be confusing. |
1797
|
|
|
|
|
|
|
Example: |
1798
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
$t->columns(["col1", "col2", "col3"]); # col1=0, col2=1, col3=2 |
1800
|
|
|
|
|
|
|
$t->add_row([...]); |
1801
|
|
|
|
|
|
|
... |
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
# set visible columns |
1804
|
|
|
|
|
|
|
$t->column_filter([1,2,1]); # col2, col3, col2 |
1805
|
|
|
|
|
|
|
$t->column_filter(["col2","col3","col2"]); # same thing |
1806
|
|
|
|
|
|
|
|
1807
|
|
|
|
|
|
|
See also: L</REFERRING TO ROWS>. |
1808
|
|
|
|
|
|
|
|
1809
|
|
|
|
|
|
|
=head1 REFERRING TO ROWS |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
Rows are referred to by integer number (0-based). |
1812
|
|
|
|
|
|
|
|
1813
|
|
|
|
|
|
|
$t->columns(["name", "age", "gender"]); |
1814
|
|
|
|
|
|
|
$t->add_row(["marty", ...]); # first row (0) |
1815
|
|
|
|
|
|
|
$t->add_row(["wendy", ...]); # second row (1) |
1816
|
|
|
|
|
|
|
$t->add_row(["charlotte", ...]); # third row (2) |
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
# set visible rows |
1819
|
|
|
|
|
|
|
$t->row_filter([0,2]); # marty & charlotte |
1820
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
See also: L</REFERRING TO COLUMNS>. |
1822
|
|
|
|
|
|
|
|
1823
|
|
|
|
|
|
|
=head1 BORDER STYLES |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
To list available border styles, just list the C<BorderStyle::*> modules. You |
1826
|
|
|
|
|
|
|
can use the provided method: |
1827
|
|
|
|
|
|
|
|
1828
|
|
|
|
|
|
|
say $_ for $t->list_border_styles; |
1829
|
|
|
|
|
|
|
|
1830
|
|
|
|
|
|
|
Or you can also try out borders using the provided |
1831
|
|
|
|
|
|
|
L<ansitable-list-border-styles> script. |
1832
|
|
|
|
|
|
|
|
1833
|
|
|
|
|
|
|
To choose border style, set the C<border_style> attribute to an available border |
1834
|
|
|
|
|
|
|
style name (which is the BorderStyle::* module name without the prefix) with |
1835
|
|
|
|
|
|
|
optional arguments. |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
# during construction |
1838
|
|
|
|
|
|
|
my $t = Text::ANSITable->new( |
1839
|
|
|
|
|
|
|
... |
1840
|
|
|
|
|
|
|
border_style => "UTF8::SingleLineBold", |
1841
|
|
|
|
|
|
|
... |
1842
|
|
|
|
|
|
|
); |
1843
|
|
|
|
|
|
|
|
1844
|
|
|
|
|
|
|
# after the object is constructed |
1845
|
|
|
|
|
|
|
$t->border_style("UTF8::SingleLineBold"); |
1846
|
|
|
|
|
|
|
$t->border_style("Test::CustomChar=character,x"); |
1847
|
|
|
|
|
|
|
$t->border_style(["Test::CustomChar", {character=>"x"}]); |
1848
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
If no border style is selected explicitly, a nice default will be chosen. You |
1850
|
|
|
|
|
|
|
can also set the C<ANSITABLE_BORDER_STYLE> environment variable to set the |
1851
|
|
|
|
|
|
|
default. |
1852
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
To create a new border style, see L<BorderStyle>. |
1854
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
=head1 COLOR THEMES |
1856
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
To list available color themes, just list the C<ColorTheme::*> modules (usually |
1858
|
|
|
|
|
|
|
you want to use color themes specifically created for Text::ANSITable in |
1859
|
|
|
|
|
|
|
C<ColorTheme::Text::ANSITable::*> namespace). You can use the provided method: |
1860
|
|
|
|
|
|
|
|
1861
|
|
|
|
|
|
|
say $_ for $t->list_color_themes; |
1862
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
Or you can also run the provided L<ansitable-list-color-themes> script. |
1864
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
To choose a color theme, set the C<color_theme> attribute to an available color |
1866
|
|
|
|
|
|
|
theme (which is the ColorTheme::* module name without the prefix) with optional |
1867
|
|
|
|
|
|
|
arguments: |
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
# during construction |
1870
|
|
|
|
|
|
|
my $t = Text::ANSITable->new( |
1871
|
|
|
|
|
|
|
... |
1872
|
|
|
|
|
|
|
color_theme => "Text::ANSITable::Standard::NoGradation", |
1873
|
|
|
|
|
|
|
... |
1874
|
|
|
|
|
|
|
); |
1875
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
# after the object is constructed |
1877
|
|
|
|
|
|
|
$t->color_theme("Text::ANSITable::Standard::NoGradation"); |
1878
|
|
|
|
|
|
|
$t->color_theme(["Lens::Darken", {theme=>"Text::ANSITable::Standard::NoGradation"}]); |
1879
|
|
|
|
|
|
|
|
1880
|
|
|
|
|
|
|
If no color theme is selected explicitly, a nice default will be chosen. You can |
1881
|
|
|
|
|
|
|
also set the C<ANSITABLE_COLOR_THEME> environment variable to set the default. |
1882
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
To create a new color theme, see L<ColorTheme> and an existing |
1884
|
|
|
|
|
|
|
C<ColorTheme::Text::ANSITable::*> module. |
1885
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
=head1 COLUMN WIDTHS |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
By default column width is set just so it is enough to show the widest data. |
1889
|
|
|
|
|
|
|
This can be customized in the following ways (in order of precedence, from |
1890
|
|
|
|
|
|
|
lowest): |
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
=over |
1893
|
|
|
|
|
|
|
|
1894
|
|
|
|
|
|
|
=item * table-level C<cell_width> attribute |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
This sets width for all columns. |
1897
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
=item * conditional column styles |
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
The example below sets column width to 10 for columns whose names matching |
1901
|
|
|
|
|
|
|
C</[acm]time/>, else sets the column width to 20. |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
$t->add_cond_column_style(sub { /[acm]time/ }, width => 10); |
1904
|
|
|
|
|
|
|
$t->add_cond_column_style(sub { !/[acm]time/ }, width => 20); |
1905
|
|
|
|
|
|
|
|
1906
|
|
|
|
|
|
|
=item * per-column C<width> style |
1907
|
|
|
|
|
|
|
|
1908
|
|
|
|
|
|
|
$t->set_column_style('colname', width => 20); |
1909
|
|
|
|
|
|
|
|
1910
|
|
|
|
|
|
|
=back |
1911
|
|
|
|
|
|
|
|
1912
|
|
|
|
|
|
|
You can use negative number to mean I<minimum> width. |
1913
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
=head1 ROW HEIGHTS |
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
This can be customized in the following ways (in order of precedence, from |
1917
|
|
|
|
|
|
|
lowest): |
1918
|
|
|
|
|
|
|
|
1919
|
|
|
|
|
|
|
=over |
1920
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
=item * table-level C<cell_height> attribute |
1922
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
This sets height for all rows. |
1924
|
|
|
|
|
|
|
|
1925
|
|
|
|
|
|
|
=item * conditional row styles |
1926
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
The example below sets row height to 2 for every odd rows, and 1 for even rows. |
1928
|
|
|
|
|
|
|
|
1929
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { $_ % 2 == 0 }, height => 2); |
1930
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { $_ % 2 }, height => 1); |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
=item * per-row C<height> style |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
$t->set_row_style(1, height => 2); |
1935
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
=back |
1937
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
You can use negative number to mean I<minimum> height. |
1939
|
|
|
|
|
|
|
|
1940
|
|
|
|
|
|
|
=head1 CELL (HORIZONTAL) PADDING |
1941
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
By default cell (horizontal) padding is 1. This can be customized in the |
1943
|
|
|
|
|
|
|
following ways (in order of precedence, from lowest): |
1944
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
=over |
1946
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
=item * table-level C<cell_pad> attribute |
1948
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
This sets left and right padding for all columns. |
1950
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
=item * table-level C<cell_lpad> and C<cell_rpad> attributes |
1952
|
|
|
|
|
|
|
|
1953
|
|
|
|
|
|
|
They set left and right padding for all columns, respectively. |
1954
|
|
|
|
|
|
|
|
1955
|
|
|
|
|
|
|
=item * conditional column C<pad> style |
1956
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
$t->add_cond_column_style($cond, pad => 0); |
1958
|
|
|
|
|
|
|
|
1959
|
|
|
|
|
|
|
=item * conditional column C<lpad>/C<rpad> style |
1960
|
|
|
|
|
|
|
|
1961
|
|
|
|
|
|
|
$t->add_cond_column_style($cond, lpad => 1, rpad => 2); |
1962
|
|
|
|
|
|
|
|
1963
|
|
|
|
|
|
|
=item * per-column C<pad> style |
1964
|
|
|
|
|
|
|
|
1965
|
|
|
|
|
|
|
$t->set_column_style($colname, pad => 0); |
1966
|
|
|
|
|
|
|
|
1967
|
|
|
|
|
|
|
=item * per-column C<lpad>/C<rpad> style |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
$t->set_column_style($colname, lpad => 1); |
1970
|
|
|
|
|
|
|
$t->set_column_style($colname, rpad => 2); |
1971
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
=back |
1973
|
|
|
|
|
|
|
|
1974
|
|
|
|
|
|
|
=head1 ROW VERTICAL PADDING |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
Default vertical padding is 0. This can be changed in the following ways (in |
1977
|
|
|
|
|
|
|
order of precedence, from lowest): |
1978
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
=over |
1980
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
=item * table-level C<cell_vpad> attribute |
1982
|
|
|
|
|
|
|
|
1983
|
|
|
|
|
|
|
This sets top and bottom padding for all rows. |
1984
|
|
|
|
|
|
|
|
1985
|
|
|
|
|
|
|
=item * table-level C<cell_tpad>/C<cell_bpad> attributes |
1986
|
|
|
|
|
|
|
|
1987
|
|
|
|
|
|
|
They set top/bottom padding separately for all rows. |
1988
|
|
|
|
|
|
|
|
1989
|
|
|
|
|
|
|
=item * conditional row C<vpad> style |
1990
|
|
|
|
|
|
|
|
1991
|
|
|
|
|
|
|
Example: |
1992
|
|
|
|
|
|
|
|
1993
|
|
|
|
|
|
|
$t->add_cond_row_style($cond, vpad => 1); |
1994
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
=item * per-row C<vpad> style |
1996
|
|
|
|
|
|
|
|
1997
|
|
|
|
|
|
|
Example: |
1998
|
|
|
|
|
|
|
|
1999
|
|
|
|
|
|
|
$t->set_row_style($rownum, vpad => 1); |
2000
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
When adding row: |
2002
|
|
|
|
|
|
|
|
2003
|
|
|
|
|
|
|
$t->add_row($rownum, {vpad=>1}); |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
=item * per-row C<tpad>/C<bpad> style |
2006
|
|
|
|
|
|
|
|
2007
|
|
|
|
|
|
|
Example: |
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
$t->set_row_style($rownum, tpad => 1); |
2010
|
|
|
|
|
|
|
$t->set_row_style($rownum, bpad => 2); |
2011
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
When adding row: |
2013
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
$t->add_row($row, {tpad=>1, bpad=>2}); |
2015
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
=back |
2017
|
|
|
|
|
|
|
|
2018
|
|
|
|
|
|
|
=head1 CELL COLORS |
2019
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
By default data format colors are used, e.g. cyan/green for text (using the |
2021
|
|
|
|
|
|
|
default color scheme, items C<num_data>, C<bool_data>, etc). In absense of that, |
2022
|
|
|
|
|
|
|
C<cell_fgcolor> and C<cell_bgcolor> from the color scheme are used. You can |
2023
|
|
|
|
|
|
|
customize colors in the following ways (ordered by precedence, from lowest): |
2024
|
|
|
|
|
|
|
|
2025
|
|
|
|
|
|
|
=over |
2026
|
|
|
|
|
|
|
|
2027
|
|
|
|
|
|
|
=item * table-level C<cell_fgcolor> and C<cell_bgcolor> attributes |
2028
|
|
|
|
|
|
|
|
2029
|
|
|
|
|
|
|
Sets all cells' colors. Color should be specified using 6-hexdigit RGB which |
2030
|
|
|
|
|
|
|
will be converted to the appropriate terminal color. |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
Can also be set to a coderef which will receive ($rownum, $colname) and should |
2033
|
|
|
|
|
|
|
return an RGB color. |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
=item * conditional column C<fgcolor> and C<bgcolor> style |
2036
|
|
|
|
|
|
|
|
2037
|
|
|
|
|
|
|
Example: |
2038
|
|
|
|
|
|
|
|
2039
|
|
|
|
|
|
|
$t->add_cond_column_style($cond, fgcolor => 'fa8888', bgcolor => '202020'); |
2040
|
|
|
|
|
|
|
|
2041
|
|
|
|
|
|
|
=item * per-column C<fgcolor> and C<bgcolor> styles |
2042
|
|
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
Example: |
2044
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
$t->set_column_style('colname', fgcolor => 'fa8888'); |
2046
|
|
|
|
|
|
|
$t->set_column_style('colname', bgcolor => '202020'); |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
=item * conditional row C<fgcolor> and C<bgcolor> style |
2049
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
Example: |
2051
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
$t->add_cond_row_style($cond, fgcolor => 'fa8888', bgcolor => '202020'); |
2053
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
=item * per-row C<fgcolor> and C<bgcolor> styles |
2055
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
Example: |
2057
|
|
|
|
|
|
|
|
2058
|
|
|
|
|
|
|
$t->set_row_style($rownum, {fgcolor => 'fa8888', bgcolor => '202020'}); |
2059
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
When adding row/rows: |
2061
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
$t->add_row($row, {fgcolor=>..., bgcolor=>...}); |
2063
|
|
|
|
|
|
|
$t->add_rows($rows, {bgcolor=>...}); |
2064
|
|
|
|
|
|
|
|
2065
|
|
|
|
|
|
|
=item * conditional cell C<fgcolor> and C<bgcolor> style |
2066
|
|
|
|
|
|
|
|
2067
|
|
|
|
|
|
|
$t->add_cond_cell_style($cond, fgcolor=>..., bgcolor=>...); |
2068
|
|
|
|
|
|
|
|
2069
|
|
|
|
|
|
|
=item * per-cell C<fgcolor> and C<bgcolor> styles |
2070
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
Example: |
2072
|
|
|
|
|
|
|
|
2073
|
|
|
|
|
|
|
$t->set_cell_style($rownum, $colname, fgcolor => 'fa8888'); |
2074
|
|
|
|
|
|
|
$t->set_cell_style($rownum, $colname, bgcolor => '202020'); |
2075
|
|
|
|
|
|
|
|
2076
|
|
|
|
|
|
|
=back |
2077
|
|
|
|
|
|
|
|
2078
|
|
|
|
|
|
|
For flexibility, all colors can be specified as coderef. See L</"COLOR THEMES"> |
2079
|
|
|
|
|
|
|
for more details. |
2080
|
|
|
|
|
|
|
|
2081
|
|
|
|
|
|
|
=head1 CELL (HORIZONTAL AND VERTICAL) ALIGNMENT |
2082
|
|
|
|
|
|
|
|
2083
|
|
|
|
|
|
|
By default, numbers are right-aligned, dates and bools are centered, and the |
2084
|
|
|
|
|
|
|
other data types (text including) are left-aligned. All data are top-valigned. |
2085
|
|
|
|
|
|
|
This can be customized in the following ways (in order of precedence, from |
2086
|
|
|
|
|
|
|
lowest): |
2087
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
=over |
2089
|
|
|
|
|
|
|
|
2090
|
|
|
|
|
|
|
=item * table-level C<cell_align> and C<cell_valign> attribute |
2091
|
|
|
|
|
|
|
|
2092
|
|
|
|
|
|
|
=item * conditional column C<align> and <valign> styles |
2093
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
$t->add_cond_column_style($cond, align=>..., valign=>...); |
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
=item * per-column C<align> and C<valign> styles |
2097
|
|
|
|
|
|
|
|
2098
|
|
|
|
|
|
|
Example: |
2099
|
|
|
|
|
|
|
|
2100
|
|
|
|
|
|
|
$t->set_column_style($colname, align => 'middle'); # or left, or right |
2101
|
|
|
|
|
|
|
$t->set_column_style($colname, valign => 'top'); # or bottom, or middle |
2102
|
|
|
|
|
|
|
|
2103
|
|
|
|
|
|
|
=item * conditional row C<align> and <valign> styles |
2104
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
$t->add_cond_row_style($cond, align=>..., valign=>...); |
2106
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
=item * per-row C<align> and C<valign> styles |
2108
|
|
|
|
|
|
|
|
2109
|
|
|
|
|
|
|
=item * conditional cell C<align> and <valign> styles |
2110
|
|
|
|
|
|
|
|
2111
|
|
|
|
|
|
|
$t->add_cond_cell_style($cond, align=>..., valign=>...); |
2112
|
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
=item * per-cell C<align> and C<valign> styles |
2114
|
|
|
|
|
|
|
|
2115
|
|
|
|
|
|
|
$t->set_cell_style($rownum, $colname, align => 'middle'); |
2116
|
|
|
|
|
|
|
$t->set_cell_style($rownum, $colname, valign => 'top'); |
2117
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
=back |
2119
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
=head1 CELL FORMATS |
2121
|
|
|
|
|
|
|
|
2122
|
|
|
|
|
|
|
The per-column- and per-cell- C<formats> style regulates how to format data. The |
2123
|
|
|
|
|
|
|
value for this style setting will be passed to L<Data::Unixish::Apply>'s |
2124
|
|
|
|
|
|
|
C<apply()>, as the C<functions> argument. So it should be a single string (like |
2125
|
|
|
|
|
|
|
C<date>) or an array (like C<< ['date', ['centerpad', {width=>20}]] >>). |
2126
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
L<Data::Unixish::Apply> is an optional prerequisite, so you will need to install |
2128
|
|
|
|
|
|
|
it separately if you need this feature. |
2129
|
|
|
|
|
|
|
|
2130
|
|
|
|
|
|
|
To see what functions are available, install L<App::dux> and then run C<dux -l>. |
2131
|
|
|
|
|
|
|
Functions of interest to formatting data include: C<bool>, C<num>, C<sprintf>, |
2132
|
|
|
|
|
|
|
C<sprintfn>, C<wrap>, C<ANSI::*> (in L<Data::Unixish::ANSI> distribution), |
2133
|
|
|
|
|
|
|
(among others). |
2134
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
=head1 CONDITIONAL STYLES |
2136
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
As an alternative to setting styles for specific {column,row,cell}, you can also |
2138
|
|
|
|
|
|
|
create conditional styles. You specify a Perl code for the condition, then if |
2139
|
|
|
|
|
|
|
the condition evaluates to true, the corresponding styles are applied to the |
2140
|
|
|
|
|
|
|
corresponding {column,row,cell}. |
2141
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
To add a conditional style, use the C<add_cond_{column,row,cell}_style> methods. |
2143
|
|
|
|
|
|
|
These methods accept condition code as its first argument and one or more styles |
2144
|
|
|
|
|
|
|
in the subsequent argument(s). For example: |
2145
|
|
|
|
|
|
|
|
2146
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { $_ % 2 }, bgcolor=>'202020'); |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
The above example will set row bgcolor for odd rows. You can add more |
2149
|
|
|
|
|
|
|
conditional styles: |
2150
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { $_ % 2 == 0 }, bgcolor=>'404040'); |
2152
|
|
|
|
|
|
|
|
2153
|
|
|
|
|
|
|
All the conditions will be evaluated and the applicable styles will be merged |
2154
|
|
|
|
|
|
|
together. For example, if we add a third conditional row style: |
2155
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { $_ % 10 == 0 }, height=>2, fgcolor=>'ffff00'); |
2157
|
|
|
|
|
|
|
|
2158
|
|
|
|
|
|
|
then every tenth row will have its height set to 2, fgcolor set to ffff00, and |
2159
|
|
|
|
|
|
|
bgcolor set to 404040 (from the second conditional). |
2160
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
Condition coderef will be called with these arguments: |
2162
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
($self, %args) |
2164
|
|
|
|
|
|
|
|
2165
|
|
|
|
|
|
|
Available keys in C<%args> for conditional column styles: C<col> (int, column |
2166
|
|
|
|
|
|
|
index), C<colname> (str, column name). Additionally, C<$_> will be set locally |
2167
|
|
|
|
|
|
|
to the column index. |
2168
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
Available keys in C<%args> for conditional row styles: C<row> (int, row index), |
2170
|
|
|
|
|
|
|
C<row_data> (array). Additionally, C<$_> will be set locally to the row index. |
2171
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
Available keys in C<%args> for conditional cell styles: C<content> (str), C<col> |
2173
|
|
|
|
|
|
|
(int, column index), C<row> (int, row index). Additionally, C<$_> will be set |
2174
|
|
|
|
|
|
|
locally to the cell content. |
2175
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
Coderef should return boolean indicating whether style should be applied to a |
2177
|
|
|
|
|
|
|
particular column/row/cell. When returning a true value, coderef can also return |
2178
|
|
|
|
|
|
|
a hashref to return additional styles that will be merged/applied too. |
2179
|
|
|
|
|
|
|
|
2180
|
|
|
|
|
|
|
=head1 STYLE SETS |
2181
|
|
|
|
|
|
|
|
2182
|
|
|
|
|
|
|
A style set is just a collection of style settings that can be applied. |
2183
|
|
|
|
|
|
|
Organizing styles into style sets makes applying the styles simpler and more |
2184
|
|
|
|
|
|
|
reusable. |
2185
|
|
|
|
|
|
|
|
2186
|
|
|
|
|
|
|
More than one style sets can be applied. |
2187
|
|
|
|
|
|
|
|
2188
|
|
|
|
|
|
|
Style set module accepts arguments. |
2189
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
For example, the L<Text::ANSITable::StyleSet::AltRow> style set defines this: |
2191
|
|
|
|
|
|
|
|
2192
|
|
|
|
|
|
|
has odd_bgcolor => (is => 'rw'); |
2193
|
|
|
|
|
|
|
has even_bgcolor => (is => 'rw'); |
2194
|
|
|
|
|
|
|
has odd_fgcolor => (is => 'rw'); |
2195
|
|
|
|
|
|
|
has even_fgcolor => (is => 'rw'); |
2196
|
|
|
|
|
|
|
|
2197
|
|
|
|
|
|
|
sub apply { |
2198
|
|
|
|
|
|
|
my ($self, $table) = @_; |
2199
|
|
|
|
|
|
|
|
2200
|
|
|
|
|
|
|
$table->add_cond_row_style(sub { |
2201
|
|
|
|
|
|
|
my ($t, %args) = @_; |
2202
|
|
|
|
|
|
|
my %styles; |
2203
|
|
|
|
|
|
|
if ($_ % 2) { |
2204
|
|
|
|
|
|
|
$styles{bgcolor} = $self->odd_bgcolor |
2205
|
|
|
|
|
|
|
if defined $self->odd_bgcolor; |
2206
|
|
|
|
|
|
|
$styles{fgcolor} = $self->odd_fgcolor |
2207
|
|
|
|
|
|
|
if defined $self->odd_bgcolor; |
2208
|
|
|
|
|
|
|
} else { |
2209
|
|
|
|
|
|
|
$styles{bgcolor} = $self->even_bgcolor |
2210
|
|
|
|
|
|
|
if defined $self->even_bgcolor; |
2211
|
|
|
|
|
|
|
$styles{fgcolor} = $self->even_fgcolor |
2212
|
|
|
|
|
|
|
if defined $self->even_bgcolor; |
2213
|
|
|
|
|
|
|
} |
2214
|
|
|
|
|
|
|
\%styles; |
2215
|
|
|
|
|
|
|
}); |
2216
|
|
|
|
|
|
|
} |
2217
|
|
|
|
|
|
|
|
2218
|
|
|
|
|
|
|
To apply this style set: |
2219
|
|
|
|
|
|
|
|
2220
|
|
|
|
|
|
|
$t->apply_style_set("AltRow", odd_bgcolor=>"003300", even_bgcolor=>"000000"); |
2221
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
To create a new style set, create a module under C<Text::ANSITable::StyleSet::> |
2223
|
|
|
|
|
|
|
like the above example. Please see the other existing style set modules for more |
2224
|
|
|
|
|
|
|
examples. |
2225
|
|
|
|
|
|
|
|
2226
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
2227
|
|
|
|
|
|
|
|
2228
|
|
|
|
|
|
|
=head2 columns => ARRAY OF STR |
2229
|
|
|
|
|
|
|
|
2230
|
|
|
|
|
|
|
Store column names. Note that when drawing, you can omit some columns, reorder |
2231
|
|
|
|
|
|
|
them, or display some more than once (see C<column_filter> attribute). |
2232
|
|
|
|
|
|
|
|
2233
|
|
|
|
|
|
|
Caveat: Since, for convenience, a column can be referred to using its name or |
2234
|
|
|
|
|
|
|
position, weird/unecxpected thing can happen if you name a column with a number |
2235
|
|
|
|
|
|
|
(e.g. 0, 1, 2, ...). So don't do that. |
2236
|
|
|
|
|
|
|
|
2237
|
|
|
|
|
|
|
=head2 rows => ARRAY OF ARRAY OF STR |
2238
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
Store row data. You can set this attribute directly, or add rows incrementally |
2240
|
|
|
|
|
|
|
using C<add_row()> and C<add_rows()> methods. |
2241
|
|
|
|
|
|
|
|
2242
|
|
|
|
|
|
|
=head2 row_filter => CODE|ARRAY OF INT |
2243
|
|
|
|
|
|
|
|
2244
|
|
|
|
|
|
|
When drawing, only show rows that match this. Can be an array containing indices |
2245
|
|
|
|
|
|
|
of rows which should be shown, or a coderef which will be called for each row |
2246
|
|
|
|
|
|
|
with arguments C<< ($row, $rownum) >> and should return a bool value indicating |
2247
|
|
|
|
|
|
|
whether that row should be displayed. |
2248
|
|
|
|
|
|
|
|
2249
|
|
|
|
|
|
|
Internal note: During drawing, rows will be filtered and put into C<< |
2250
|
|
|
|
|
|
|
$t->{_draw}{frows} >>. |
2251
|
|
|
|
|
|
|
|
2252
|
|
|
|
|
|
|
=head2 column_filter => CODE|ARRAY OF STR |
2253
|
|
|
|
|
|
|
|
2254
|
|
|
|
|
|
|
When drawing, only show columns that match this. Can be an array containing |
2255
|
|
|
|
|
|
|
names of columns that should be displayed (column names can be in different |
2256
|
|
|
|
|
|
|
order or duplicate, column can also be referred to with its numeric index). Can |
2257
|
|
|
|
|
|
|
also be a coderef which will be called with C<< ($colname, $colnum) >> for |
2258
|
|
|
|
|
|
|
every column and should return a bool value indicating whether that column |
2259
|
|
|
|
|
|
|
should be displayed. The coderef version is more limited in that it cannot |
2260
|
|
|
|
|
|
|
reorder the columns or instruct for the same column to be displayed more than |
2261
|
|
|
|
|
|
|
once. |
2262
|
|
|
|
|
|
|
|
2263
|
|
|
|
|
|
|
Internal note: During drawing, column names will be filtered and put into C<< |
2264
|
|
|
|
|
|
|
$t->{_draw}{fcols} >>. |
2265
|
|
|
|
|
|
|
|
2266
|
|
|
|
|
|
|
=head2 column_wrap => BOOL |
2267
|
|
|
|
|
|
|
|
2268
|
|
|
|
|
|
|
Set column wrapping for all columns. Can be overriden by per-column C<wrap> |
2269
|
|
|
|
|
|
|
style. By default column wrapping will only be done for text columns and when |
2270
|
|
|
|
|
|
|
width is explicitly set to a positive value. |
2271
|
|
|
|
|
|
|
|
2272
|
|
|
|
|
|
|
=head2 use_color => BOOL |
2273
|
|
|
|
|
|
|
|
2274
|
|
|
|
|
|
|
Whether to output color. Default is taken from C<NO_COLOR> environment variable, |
2275
|
|
|
|
|
|
|
C<COLOR> environment variable, or detected via C<(-t STDOUT)>. If C<use_color> |
2276
|
|
|
|
|
|
|
is set to 0, an attempt to use a colored color theme (i.e. anything that is not |
2277
|
|
|
|
|
|
|
the C<no_color> theme) will result in an exception. |
2278
|
|
|
|
|
|
|
|
2279
|
|
|
|
|
|
|
(In the future, setting C<use_color> to 0 might opt the module to use |
2280
|
|
|
|
|
|
|
normal/plain string routines instead of the slower ta_* functions from |
2281
|
|
|
|
|
|
|
L<Text::ANSI::Util>; this also means that the module won't handle ANSI escape |
2282
|
|
|
|
|
|
|
codes in the content text.) |
2283
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
=head2 color_depth => INT |
2285
|
|
|
|
|
|
|
|
2286
|
|
|
|
|
|
|
Terminal's color depth. Either 16, 256, or 2**24 (16777216). Default will be |
2287
|
|
|
|
|
|
|
retrieved from C<COLOR_DEPTH> environment or detected using L<Term::Detect>. |
2288
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
=head2 use_box_chars => BOOL |
2290
|
|
|
|
|
|
|
|
2291
|
|
|
|
|
|
|
Whether to use box drawing characters. Drawing box drawing characters can be |
2292
|
|
|
|
|
|
|
problematic in some places because it uses ANSI escape codes to switch to (and |
2293
|
|
|
|
|
|
|
back from) line drawing mode (C<"\e(0"> and C<"\e(B">, respectively). |
2294
|
|
|
|
|
|
|
|
2295
|
|
|
|
|
|
|
Default is taken from C<BOX_CHARS> environment variable, or 1. If |
2296
|
|
|
|
|
|
|
C<use_box_chars> is set to 0, an attempt to use a border style that uses box |
2297
|
|
|
|
|
|
|
drawing chararacters will result in an exception. |
2298
|
|
|
|
|
|
|
|
2299
|
|
|
|
|
|
|
=head2 use_utf8 => BOOL |
2300
|
|
|
|
|
|
|
|
2301
|
|
|
|
|
|
|
Whether to use Unicode (UTF8) characters. Default is taken from C<UTF8> |
2302
|
|
|
|
|
|
|
environment variable, or detected using L<Term::Detect>, or guessed via L<LANG> |
2303
|
|
|
|
|
|
|
environment variable. If C<use_utf8> is set to 0, an attempt to select a border |
2304
|
|
|
|
|
|
|
style that uses Unicode characters will result in an exception. |
2305
|
|
|
|
|
|
|
|
2306
|
|
|
|
|
|
|
(In the future, setting C<use_utf8> to 0 might opt the module to use the |
2307
|
|
|
|
|
|
|
non-"mb_*" version of functions from L<Text::ANSI::Util>, e.g. C<ta_wrap()> |
2308
|
|
|
|
|
|
|
instead of C<ta_mbwrap()>, and so on). |
2309
|
|
|
|
|
|
|
|
2310
|
|
|
|
|
|
|
=head2 wide => BOOL |
2311
|
|
|
|
|
|
|
|
2312
|
|
|
|
|
|
|
Whether to support wide characters. The default is to check for the existence of |
2313
|
|
|
|
|
|
|
L<Text::ANSI::WideUtil> (an optional prereq). You can explicitly enable or |
2314
|
|
|
|
|
|
|
disable wide-character support here. |
2315
|
|
|
|
|
|
|
|
2316
|
|
|
|
|
|
|
=head2 border_style => STR |
2317
|
|
|
|
|
|
|
|
2318
|
|
|
|
|
|
|
Border style name to use. |
2319
|
|
|
|
|
|
|
|
2320
|
|
|
|
|
|
|
=head2 color_theme => STR |
2321
|
|
|
|
|
|
|
|
2322
|
|
|
|
|
|
|
Color theme name to use. |
2323
|
|
|
|
|
|
|
|
2324
|
|
|
|
|
|
|
=head2 show_header => BOOL (default: 1) |
2325
|
|
|
|
|
|
|
|
2326
|
|
|
|
|
|
|
When drawing, whether to show header. |
2327
|
|
|
|
|
|
|
|
2328
|
|
|
|
|
|
|
=head2 show_row_separator => INT (default: 2) |
2329
|
|
|
|
|
|
|
|
2330
|
|
|
|
|
|
|
When drawing, whether to show separator lines between rows. The default (2) is |
2331
|
|
|
|
|
|
|
to only show separators drawn using C<add_row_separator()>. If you set this to |
2332
|
|
|
|
|
|
|
1, lines will be drawn after every data row. If you set this attribute to 0, no |
2333
|
|
|
|
|
|
|
lines will be drawn whatsoever. |
2334
|
|
|
|
|
|
|
|
2335
|
|
|
|
|
|
|
=head2 cell_width => INT |
2336
|
|
|
|
|
|
|
|
2337
|
|
|
|
|
|
|
Set width for all cells. Can be overriden by per-column C<width> style. |
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
=head2 cell_height => INT |
2340
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
Set height for all cell. Can be overriden by per-row C<height> style. |
2342
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
=head2 cell_align => STR |
2344
|
|
|
|
|
|
|
|
2345
|
|
|
|
|
|
|
Set (horizontal) alignment for all cells. Either C<left>, C<middle>, or |
2346
|
|
|
|
|
|
|
C<right>. Can be overriden by per-column/per-row/per-cell C<align> style. |
2347
|
|
|
|
|
|
|
|
2348
|
|
|
|
|
|
|
=head2 cell_valign => STR |
2349
|
|
|
|
|
|
|
|
2350
|
|
|
|
|
|
|
Set (horizontal) alignment for all cells. Either C<top>, C<middle>, or |
2351
|
|
|
|
|
|
|
C<bottom>. Can be overriden by per-column/per-row/per-cell C<align> style. |
2352
|
|
|
|
|
|
|
|
2353
|
|
|
|
|
|
|
=head2 cell_pad => INT |
2354
|
|
|
|
|
|
|
|
2355
|
|
|
|
|
|
|
Set (horizontal) padding for all cells. Can be overriden by per-column C<pad> |
2356
|
|
|
|
|
|
|
style. |
2357
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
=head2 cell_lpad => INT |
2359
|
|
|
|
|
|
|
|
2360
|
|
|
|
|
|
|
Set left padding for all cells. Overrides the C<cell_pad> attribute. Can be |
2361
|
|
|
|
|
|
|
overriden by per-column C<lpad> style. |
2362
|
|
|
|
|
|
|
|
2363
|
|
|
|
|
|
|
=head2 cell_rpad => INT |
2364
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
Set right padding for all cells. Overrides the C<cell_pad> attribute. Can be |
2366
|
|
|
|
|
|
|
overriden by per-column C<rpad> style. |
2367
|
|
|
|
|
|
|
|
2368
|
|
|
|
|
|
|
=head2 cell_vpad => INT |
2369
|
|
|
|
|
|
|
|
2370
|
|
|
|
|
|
|
Set vertical padding for all cells. Can be overriden by per-row C<vpad> style. |
2371
|
|
|
|
|
|
|
|
2372
|
|
|
|
|
|
|
=head2 cell_tpad => INT |
2373
|
|
|
|
|
|
|
|
2374
|
|
|
|
|
|
|
Set top padding for all cells. Overrides the C<cell_vpad> attribute. Can be |
2375
|
|
|
|
|
|
|
overriden by per-row C<tpad> style. |
2376
|
|
|
|
|
|
|
|
2377
|
|
|
|
|
|
|
=head2 cell_bpad => INT |
2378
|
|
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
Set bottom padding for all cells. Overrides the C<cell_vpad> attribute. Can be |
2380
|
|
|
|
|
|
|
overriden by per-row C<bpad> style. |
2381
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
=head2 cell_fgcolor => RGB|CODE |
2383
|
|
|
|
|
|
|
|
2384
|
|
|
|
|
|
|
Set foreground color for all cells. Value should be 6-hexdigit RGB. Can also be |
2385
|
|
|
|
|
|
|
a coderef that will receive %args (e.g. rownum, col_name, colnum) and should |
2386
|
|
|
|
|
|
|
return an RGB color. Can be overriden by per-cell C<fgcolor> style. |
2387
|
|
|
|
|
|
|
|
2388
|
|
|
|
|
|
|
=head2 cell_bgcolor => RGB|CODE |
2389
|
|
|
|
|
|
|
|
2390
|
|
|
|
|
|
|
Like C<cell_fgcolor> but for background color. |
2391
|
|
|
|
|
|
|
|
2392
|
|
|
|
|
|
|
=head2 header_fgcolor => RGB|CODE |
2393
|
|
|
|
|
|
|
|
2394
|
|
|
|
|
|
|
Set foreground color for all headers. Overrides C<cell_fgcolor> for headers. |
2395
|
|
|
|
|
|
|
Value should be a 6-hexdigit RGB. Can also be a coderef that will receive %args |
2396
|
|
|
|
|
|
|
(e.g. col_name, colnum) and should return an RGB color. |
2397
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
=head2 header_bgcolor => RGB|CODE |
2399
|
|
|
|
|
|
|
|
2400
|
|
|
|
|
|
|
Like C<header_fgcolor> but for background color. |
2401
|
|
|
|
|
|
|
|
2402
|
|
|
|
|
|
|
=head2 header_align => STR |
2403
|
|
|
|
|
|
|
|
2404
|
|
|
|
|
|
|
=head2 header_valign => STR |
2405
|
|
|
|
|
|
|
|
2406
|
|
|
|
|
|
|
=head2 header_vpad => INT |
2407
|
|
|
|
|
|
|
|
2408
|
|
|
|
|
|
|
=head2 header_tpad => INT |
2409
|
|
|
|
|
|
|
|
2410
|
|
|
|
|
|
|
=head2 header_bpad => INT |
2411
|
|
|
|
|
|
|
|
2412
|
|
|
|
|
|
|
=head1 METHODS |
2413
|
|
|
|
|
|
|
|
2414
|
|
|
|
|
|
|
=head2 $t = Text::ANSITable->new(%attrs) => OBJ |
2415
|
|
|
|
|
|
|
|
2416
|
|
|
|
|
|
|
Constructor. |
2417
|
|
|
|
|
|
|
|
2418
|
|
|
|
|
|
|
=head2 $t->list_border_styles => LIST |
2419
|
|
|
|
|
|
|
|
2420
|
|
|
|
|
|
|
Return the names of available border styles. Border styles will be searched in |
2421
|
|
|
|
|
|
|
C<BorderStyle::*> modules. |
2422
|
|
|
|
|
|
|
|
2423
|
|
|
|
|
|
|
=head2 $t->list_color_themes => LIST |
2424
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
Return the names of available color themes. Color themes will be searched in |
2426
|
|
|
|
|
|
|
C<ColorTheme::*> modules. |
2427
|
|
|
|
|
|
|
|
2428
|
|
|
|
|
|
|
=head2 $t->list_style_sets => LIST |
2429
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
Return the names of available style sets. Style set names are retrieved by |
2431
|
|
|
|
|
|
|
listing modules under C<Text::ANSITable::StyleSet::*> namespace. |
2432
|
|
|
|
|
|
|
|
2433
|
|
|
|
|
|
|
=head2 $t->get_border_style($name) => HASH |
2434
|
|
|
|
|
|
|
|
2435
|
|
|
|
|
|
|
Can also be called as a static method: C<< |
2436
|
|
|
|
|
|
|
Text::ANSITable->get_border_style($name) >>. |
2437
|
|
|
|
|
|
|
|
2438
|
|
|
|
|
|
|
=head2 $t->get_color_theme($name) => HASH |
2439
|
|
|
|
|
|
|
|
2440
|
|
|
|
|
|
|
Can also be called as a static method: C<< |
2441
|
|
|
|
|
|
|
Text::ANSITable->get_color_theme($name) >>. |
2442
|
|
|
|
|
|
|
|
2443
|
|
|
|
|
|
|
=head2 $t->add_row(\@row[, \%styles]) => OBJ |
2444
|
|
|
|
|
|
|
|
2445
|
|
|
|
|
|
|
Add a row. Note that row data is not copied, only referenced. |
2446
|
|
|
|
|
|
|
|
2447
|
|
|
|
|
|
|
Can also add per-row styles (which can also be done using C<row_style()>). |
2448
|
|
|
|
|
|
|
|
2449
|
|
|
|
|
|
|
=head2 $t->add_rows(\@rows[, \%styles]) => OBJ |
2450
|
|
|
|
|
|
|
|
2451
|
|
|
|
|
|
|
Add multiple rows. Note that row data is not copied, only referenced. |
2452
|
|
|
|
|
|
|
|
2453
|
|
|
|
|
|
|
Can also add per-row styles (which can also be done using C<row_style()>). |
2454
|
|
|
|
|
|
|
|
2455
|
|
|
|
|
|
|
=head2 $t->add_row_separator() => OBJ |
2456
|
|
|
|
|
|
|
|
2457
|
|
|
|
|
|
|
Add a row separator line. |
2458
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
=head2 $t->get_cell($rownum, $col) => VAL |
2460
|
|
|
|
|
|
|
|
2461
|
|
|
|
|
|
|
Get cell value at row #C<$rownum> (starts from zero) and column named/numbered |
2462
|
|
|
|
|
|
|
C<$col>. |
2463
|
|
|
|
|
|
|
|
2464
|
|
|
|
|
|
|
=head2 $t->set_cell($rownum, $col, $newval) => VAL |
2465
|
|
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
Set cell value at row #C<$rownum> (starts from zero) and column named/numbered |
2467
|
|
|
|
|
|
|
C<$col>. Return old value. |
2468
|
|
|
|
|
|
|
|
2469
|
|
|
|
|
|
|
=head2 $t->get_column_style($col, $style) => VAL |
2470
|
|
|
|
|
|
|
|
2471
|
|
|
|
|
|
|
Get per-column style for column named/numbered C<$col>. |
2472
|
|
|
|
|
|
|
|
2473
|
|
|
|
|
|
|
=head2 $t->set_column_style($col, $style=>$val[, $style2=>$val2, ...]) |
2474
|
|
|
|
|
|
|
|
2475
|
|
|
|
|
|
|
Set per-column style(s) for column named/numbered C<$col>. Available values for |
2476
|
|
|
|
|
|
|
C<$style>: C<align>, C<valign>, C<pad>, C<lpad>, C<rpad>, C<width>, C<formats>, |
2477
|
|
|
|
|
|
|
C<fgcolor>, C<bgcolor>, C<type>, C<wrap>. |
2478
|
|
|
|
|
|
|
|
2479
|
|
|
|
|
|
|
=head2 $t->get_cond_column_styles => ARRAY |
2480
|
|
|
|
|
|
|
|
2481
|
|
|
|
|
|
|
Get all the conditional column styles set so far. |
2482
|
|
|
|
|
|
|
|
2483
|
|
|
|
|
|
|
=head2 $t->add_cond_column_style($cond, $style=>$val[, $style2=>$val2 ...]) |
2484
|
|
|
|
|
|
|
|
2485
|
|
|
|
|
|
|
Add a new conditional column style. See L</"CONDITIONAL STYLES"> for more |
2486
|
|
|
|
|
|
|
details on conditional style. |
2487
|
|
|
|
|
|
|
|
2488
|
|
|
|
|
|
|
=for comment | =head2 $t->clear_cond_column_styles | Clear all the conditional column styles. |
2489
|
|
|
|
|
|
|
|
2490
|
|
|
|
|
|
|
=head2 $t->get_eff_column_style($col, $style) => VAL |
2491
|
|
|
|
|
|
|
|
2492
|
|
|
|
|
|
|
Get "effective" column style named C<$style> for a particular column. Effective |
2493
|
|
|
|
|
|
|
column style is calculated from all the conditional column styles and the |
2494
|
|
|
|
|
|
|
per-column styles then merged together. This is the per-column style actually |
2495
|
|
|
|
|
|
|
applied. |
2496
|
|
|
|
|
|
|
|
2497
|
|
|
|
|
|
|
=head2 $t->get_row_style($rownum) => VAL |
2498
|
|
|
|
|
|
|
|
2499
|
|
|
|
|
|
|
Get per-row style for row numbered C<$rownum>. |
2500
|
|
|
|
|
|
|
|
2501
|
|
|
|
|
|
|
=head2 $t->set_row_style($rownum, $style=>$newval[, $style2=>$newval2, ...]) |
2502
|
|
|
|
|
|
|
|
2503
|
|
|
|
|
|
|
Set per-row style(s) for row numbered C<$rownum>. Available values for |
2504
|
|
|
|
|
|
|
C<$style>: C<align>, C<valign>, C<height>, C<vpad>, C<tpad>, C<bpad>, |
2505
|
|
|
|
|
|
|
C<fgcolor>, C<bgcolor>. |
2506
|
|
|
|
|
|
|
|
2507
|
|
|
|
|
|
|
=head2 $t->get_cond_row_styles => ARRAY |
2508
|
|
|
|
|
|
|
|
2509
|
|
|
|
|
|
|
Get all the conditional row styles set so far. |
2510
|
|
|
|
|
|
|
|
2511
|
|
|
|
|
|
|
=head2 $t->add_cond_row_style($cond, $style=>$val[, $style2=>$val2 ...]) |
2512
|
|
|
|
|
|
|
|
2513
|
|
|
|
|
|
|
Add a new conditional row style. See L</"CONDITIONAL STYLES"> for more details |
2514
|
|
|
|
|
|
|
on conditional style. |
2515
|
|
|
|
|
|
|
|
2516
|
|
|
|
|
|
|
=for comment | =head2 $t->clear_cond_row_styles | Clear all the conditional row styles. |
2517
|
|
|
|
|
|
|
|
2518
|
|
|
|
|
|
|
=head2 $t->get_eff_row_style($rownum, $style) => VAL |
2519
|
|
|
|
|
|
|
|
2520
|
|
|
|
|
|
|
Get "effective" row style named C<$style> for a particular row. Effective row |
2521
|
|
|
|
|
|
|
style is calculated from all the conditional row styles and the per-row styles |
2522
|
|
|
|
|
|
|
then merged together. This is the per-row style actually applied. |
2523
|
|
|
|
|
|
|
|
2524
|
|
|
|
|
|
|
=head2 $t->get_cell_style($rownum, $col, $style) => VAL |
2525
|
|
|
|
|
|
|
|
2526
|
|
|
|
|
|
|
Get per-cell style named C<$style> for a particular cell. Return undef if there |
2527
|
|
|
|
|
|
|
is no per-cell style with that name. |
2528
|
|
|
|
|
|
|
|
2529
|
|
|
|
|
|
|
=head2 $t->set_cell_style($rownum, $col, $style=>$newval[, $style2=>$newval2, ...]) |
2530
|
|
|
|
|
|
|
|
2531
|
|
|
|
|
|
|
Set per-cell style(s). Available values for C<$style>: C<align>, C<valign>, |
2532
|
|
|
|
|
|
|
C<formats>, C<fgcolor>, C<bgcolor>. |
2533
|
|
|
|
|
|
|
|
2534
|
|
|
|
|
|
|
=head2 $t->get_cond_cell_styles => ARRAY |
2535
|
|
|
|
|
|
|
|
2536
|
|
|
|
|
|
|
Get all the conditional cell styles set so far. |
2537
|
|
|
|
|
|
|
|
2538
|
|
|
|
|
|
|
=head2 $t->add_cond_cell_style($cond, $style=>$val[, $style2=>$val2 ...]) |
2539
|
|
|
|
|
|
|
|
2540
|
|
|
|
|
|
|
Add a new conditional cell style. See L</"CONDITIONAL STYLES"> for more details |
2541
|
|
|
|
|
|
|
on conditional style. |
2542
|
|
|
|
|
|
|
|
2543
|
|
|
|
|
|
|
=for comment | =head2 $t->clear_cond_cell_styles | Clear all the conditional cell styles. |
2544
|
|
|
|
|
|
|
|
2545
|
|
|
|
|
|
|
=head2 $t->get_eff_cell_style($rownum, $col, $style) => VAL |
2546
|
|
|
|
|
|
|
|
2547
|
|
|
|
|
|
|
Get "effective" cell style named C<$style> for a particular cell. Effective cell |
2548
|
|
|
|
|
|
|
style is calculated from all the conditional cell styles and the per-cell styles |
2549
|
|
|
|
|
|
|
then merged together. This is the per-cell style actually applied. |
2550
|
|
|
|
|
|
|
|
2551
|
|
|
|
|
|
|
=head2 $t->apply_style_set($name, %args) |
2552
|
|
|
|
|
|
|
|
2553
|
|
|
|
|
|
|
Apply a style set. See L</"STYLE SETS"> for more details. |
2554
|
|
|
|
|
|
|
|
2555
|
|
|
|
|
|
|
=head2 $t->draw => STR |
2556
|
|
|
|
|
|
|
|
2557
|
|
|
|
|
|
|
Render table. |
2558
|
|
|
|
|
|
|
|
2559
|
|
|
|
|
|
|
=head1 FAQ |
2560
|
|
|
|
|
|
|
|
2561
|
|
|
|
|
|
|
=head2 General |
2562
|
|
|
|
|
|
|
|
2563
|
|
|
|
|
|
|
=head3 I don't see my data! |
2564
|
|
|
|
|
|
|
|
2565
|
|
|
|
|
|
|
This might be caused by you not defining columns first, e.g.: |
2566
|
|
|
|
|
|
|
|
2567
|
|
|
|
|
|
|
my $t = Text::ANSITable->new; |
2568
|
|
|
|
|
|
|
$t->add_row([1,2,3]); |
2569
|
|
|
|
|
|
|
print $t->draw; |
2570
|
|
|
|
|
|
|
|
2571
|
|
|
|
|
|
|
You need to do this first before adding rows: |
2572
|
|
|
|
|
|
|
|
2573
|
|
|
|
|
|
|
$t->columns(["col1", "col2", "col3"]); |
2574
|
|
|
|
|
|
|
|
2575
|
|
|
|
|
|
|
=head3 All the rows are the same! |
2576
|
|
|
|
|
|
|
|
2577
|
|
|
|
|
|
|
my $t = Text::ANSITable->new; |
2578
|
|
|
|
|
|
|
$t->columns(["col"]); |
2579
|
|
|
|
|
|
|
my @row; |
2580
|
|
|
|
|
|
|
for (1..3) { |
2581
|
|
|
|
|
|
|
@row = ($_); |
2582
|
|
|
|
|
|
|
$t->add_row(\@row); |
2583
|
|
|
|
|
|
|
} |
2584
|
|
|
|
|
|
|
print $t->draw; |
2585
|
|
|
|
|
|
|
|
2586
|
|
|
|
|
|
|
will print: |
2587
|
|
|
|
|
|
|
|
2588
|
|
|
|
|
|
|
col |
2589
|
|
|
|
|
|
|
3 |
2590
|
|
|
|
|
|
|
3 |
2591
|
|
|
|
|
|
|
3 |
2592
|
|
|
|
|
|
|
|
2593
|
|
|
|
|
|
|
You need to add row in this way instead of adding the same reference everytime: |
2594
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
$t->add_row([@row]); |
2596
|
|
|
|
|
|
|
|
2597
|
|
|
|
|
|
|
=head3 Output is too fancy! I just want to generate some plain (Text::ASCIITable-like) output to be copy-pasted to my document. |
2598
|
|
|
|
|
|
|
|
2599
|
|
|
|
|
|
|
$t->use_utf8(0); |
2600
|
|
|
|
|
|
|
$t->use_box_chars(0); |
2601
|
|
|
|
|
|
|
$t->use_color(0); |
2602
|
|
|
|
|
|
|
$t->border_style('ASCII::SingleLine'); |
2603
|
|
|
|
|
|
|
|
2604
|
|
|
|
|
|
|
and you're good to go. Alternatively you can set environment UTF8=0, |
2605
|
|
|
|
|
|
|
BOX_CHARS=0, COLOR=0, and ANSITABLE_BORDER_STYLE=ASCII::SingleLine. |
2606
|
|
|
|
|
|
|
|
2607
|
|
|
|
|
|
|
=head3 Why am I getting 'Wide character in print' warning? |
2608
|
|
|
|
|
|
|
|
2609
|
|
|
|
|
|
|
You are probably using a utf8 border style, and you haven't done something like |
2610
|
|
|
|
|
|
|
this to your output: |
2611
|
|
|
|
|
|
|
|
2612
|
|
|
|
|
|
|
binmode(STDOUT, ":utf8"); |
2613
|
|
|
|
|
|
|
|
2614
|
|
|
|
|
|
|
=head3 My table looks garbled when viewed through pager like B<less>! |
2615
|
|
|
|
|
|
|
|
2616
|
|
|
|
|
|
|
That's because B<less> by default escapes ANSI color and box_char codes. Try |
2617
|
|
|
|
|
|
|
using C<-R> option of B<less> to display ANSI color codes raw. |
2618
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
Or, try not using colors and box_char border styles: |
2620
|
|
|
|
|
|
|
|
2621
|
|
|
|
|
|
|
$t->use_color(0); |
2622
|
|
|
|
|
|
|
$t->use_box_chars(0); |
2623
|
|
|
|
|
|
|
|
2624
|
|
|
|
|
|
|
Note that as of this writing, B<less -R> does not interpret box_char codes so |
2625
|
|
|
|
|
|
|
you'll need to avoid using box_char border styles if you want your output to |
2626
|
|
|
|
|
|
|
display properly under B<less>. |
2627
|
|
|
|
|
|
|
|
2628
|
|
|
|
|
|
|
=head3 How do I hide some columns/rows when drawing? |
2629
|
|
|
|
|
|
|
|
2630
|
|
|
|
|
|
|
Use the C<column_filter> and C<row_filter> attributes. For example, given this |
2631
|
|
|
|
|
|
|
table: |
2632
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
my $t = Text::ANSITable->new; |
2634
|
|
|
|
|
|
|
$t->columns([qw/one two three/]); |
2635
|
|
|
|
|
|
|
$t->add_row([$_, $_, $_]) for 1..10; |
2636
|
|
|
|
|
|
|
|
2637
|
|
|
|
|
|
|
Doing this: |
2638
|
|
|
|
|
|
|
|
2639
|
|
|
|
|
|
|
$t->row_filter([0, 1, 4]); |
2640
|
|
|
|
|
|
|
print $t->draw; |
2641
|
|
|
|
|
|
|
|
2642
|
|
|
|
|
|
|
will show: |
2643
|
|
|
|
|
|
|
|
2644
|
|
|
|
|
|
|
one | two | three |
2645
|
|
|
|
|
|
|
-----+-----+------- |
2646
|
|
|
|
|
|
|
1 | 1 | 1 |
2647
|
|
|
|
|
|
|
2 | 2 | 2 |
2648
|
|
|
|
|
|
|
5 | 5 | 5 |
2649
|
|
|
|
|
|
|
|
2650
|
|
|
|
|
|
|
Doing this: |
2651
|
|
|
|
|
|
|
|
2652
|
|
|
|
|
|
|
$t->row_filter(sub { my ($row, $idx) = @_; $row->[0] % 2 } |
2653
|
|
|
|
|
|
|
|
2654
|
|
|
|
|
|
|
will display: |
2655
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
one | two | three |
2657
|
|
|
|
|
|
|
-----+-----+------- |
2658
|
|
|
|
|
|
|
1 | 1 | 1 |
2659
|
|
|
|
|
|
|
3 | 3 | 3 |
2660
|
|
|
|
|
|
|
5 | 5 | 5 |
2661
|
|
|
|
|
|
|
7 | 7 | 7 |
2662
|
|
|
|
|
|
|
9 | 9 | 9 |
2663
|
|
|
|
|
|
|
|
2664
|
|
|
|
|
|
|
Doing this: |
2665
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
$t->column_filter([qw/two one 0/]); |
2667
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
will display: |
2669
|
|
|
|
|
|
|
|
2670
|
|
|
|
|
|
|
two | one | one |
2671
|
|
|
|
|
|
|
-----+-----+----- |
2672
|
|
|
|
|
|
|
1 | 1 | 1 |
2673
|
|
|
|
|
|
|
2 | 2 | 2 |
2674
|
|
|
|
|
|
|
3 | 3 | 3 |
2675
|
|
|
|
|
|
|
4 | 4 | 4 |
2676
|
|
|
|
|
|
|
5 | 5 | 5 |
2677
|
|
|
|
|
|
|
6 | 6 | 6 |
2678
|
|
|
|
|
|
|
7 | 7 | 7 |
2679
|
|
|
|
|
|
|
8 | 8 | 8 |
2680
|
|
|
|
|
|
|
9 | 9 | 9 |
2681
|
|
|
|
|
|
|
10 | 10 | 10 |
2682
|
|
|
|
|
|
|
|
2683
|
|
|
|
|
|
|
Doing this: |
2684
|
|
|
|
|
|
|
|
2685
|
|
|
|
|
|
|
$t->column_filter(sub { my ($colname, $idx) = @_; $colname =~ /t/ }); |
2686
|
|
|
|
|
|
|
|
2687
|
|
|
|
|
|
|
will display: |
2688
|
|
|
|
|
|
|
|
2689
|
|
|
|
|
|
|
two | three |
2690
|
|
|
|
|
|
|
-----+------- |
2691
|
|
|
|
|
|
|
1 | 1 |
2692
|
|
|
|
|
|
|
2 | 2 |
2693
|
|
|
|
|
|
|
3 | 3 |
2694
|
|
|
|
|
|
|
4 | 4 |
2695
|
|
|
|
|
|
|
5 | 5 |
2696
|
|
|
|
|
|
|
6 | 6 |
2697
|
|
|
|
|
|
|
7 | 7 |
2698
|
|
|
|
|
|
|
8 | 8 |
2699
|
|
|
|
|
|
|
9 | 9 |
2700
|
|
|
|
|
|
|
10 | 10 |
2701
|
|
|
|
|
|
|
|
2702
|
|
|
|
|
|
|
=head2 Formatting data |
2703
|
|
|
|
|
|
|
|
2704
|
|
|
|
|
|
|
=head3 How do I format data? |
2705
|
|
|
|
|
|
|
|
2706
|
|
|
|
|
|
|
Use the C<formats> per-column style or per-cell style. For example: |
2707
|
|
|
|
|
|
|
|
2708
|
|
|
|
|
|
|
$t->set_column_style('available', formats => [[bool=>{style=>'check_cross'}], |
2709
|
|
|
|
|
|
|
[centerpad=>{width=>10}]]); |
2710
|
|
|
|
|
|
|
$t->set_column_style('amount' , formats => [[num=>{decimal_digits=>2}]]); |
2711
|
|
|
|
|
|
|
$t->set_column_style('size' , formats => [[num=>{style=>'kilo'}]]); |
2712
|
|
|
|
|
|
|
|
2713
|
|
|
|
|
|
|
See L<Data::Unixish::Apply> and L<Data::Unixish> for more details on the |
2714
|
|
|
|
|
|
|
available formatting functions. |
2715
|
|
|
|
|
|
|
|
2716
|
|
|
|
|
|
|
=head3 How does the module determine column data type? |
2717
|
|
|
|
|
|
|
|
2718
|
|
|
|
|
|
|
Currently: if column name has the word C<date> or C<time> in it, the column is |
2719
|
|
|
|
|
|
|
assumed to contain B<date> data. If column name has C<?> in it, the column is |
2720
|
|
|
|
|
|
|
assumed to be B<bool>. If a column contains only numbers (or undefs), it is |
2721
|
|
|
|
|
|
|
B<num>. Otherwise, it is B<str>. |
2722
|
|
|
|
|
|
|
|
2723
|
|
|
|
|
|
|
=head3 How does the module format data types? |
2724
|
|
|
|
|
|
|
|
2725
|
|
|
|
|
|
|
Currently: B<num> will be right aligned and applied C<num_data> color (cyan in |
2726
|
|
|
|
|
|
|
the default theme). B<date> will be centered and applied C<date_data> color |
2727
|
|
|
|
|
|
|
(gold in the default theme). B<bool> will be centered and formatted as |
2728
|
|
|
|
|
|
|
check/cross symbol and applied C<bool_data> color (red/green depending on |
2729
|
|
|
|
|
|
|
whether the data is false/true). B<str> will be applied C<str_data> color (no |
2730
|
|
|
|
|
|
|
color in the default theme). |
2731
|
|
|
|
|
|
|
|
2732
|
|
|
|
|
|
|
Other color themes might use different colors. |
2733
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
=head3 How do I force column to be of a certain data type? |
2735
|
|
|
|
|
|
|
|
2736
|
|
|
|
|
|
|
For example, you have a column named C<deleted> but want to display it as |
2737
|
|
|
|
|
|
|
B<bool>. You can do: |
2738
|
|
|
|
|
|
|
|
2739
|
|
|
|
|
|
|
$t->set_column_style(deleted => type => 'bool'); |
2740
|
|
|
|
|
|
|
|
2741
|
|
|
|
|
|
|
=head3 How do I wrap long text? |
2742
|
|
|
|
|
|
|
|
2743
|
|
|
|
|
|
|
The C<wrap> dux function can be used to wrap text (see: L<Data::Unixish::wrap>). |
2744
|
|
|
|
|
|
|
You'll want to set C<ansi> and C<mb> both to 1 to handle ANSI escape codes and |
2745
|
|
|
|
|
|
|
wide characters in your text (unless you are sure that your text does not |
2746
|
|
|
|
|
|
|
contain those): |
2747
|
|
|
|
|
|
|
|
2748
|
|
|
|
|
|
|
$t->set_column_style('description', formats=>[[wrap => {width=>60, ansi=>1, mb=>1}]]); |
2749
|
|
|
|
|
|
|
|
2750
|
|
|
|
|
|
|
=head3 How do I highlight text with color? |
2751
|
|
|
|
|
|
|
|
2752
|
|
|
|
|
|
|
The C<ansi::highlight> dux function can be used to highlight text (see: |
2753
|
|
|
|
|
|
|
L<Data::Unixish::ANSI::highlight>). |
2754
|
|
|
|
|
|
|
|
2755
|
|
|
|
|
|
|
$t->set_column_style(2, formats => [[highlight => {pattern=>$pat}]]); |
2756
|
|
|
|
|
|
|
|
2757
|
|
|
|
|
|
|
=head3 I want to change the default bool cross/check sign representation! |
2758
|
|
|
|
|
|
|
|
2759
|
|
|
|
|
|
|
By default, bool columns are shown as cross/check sign. This can be changed, |
2760
|
|
|
|
|
|
|
e.g.: |
2761
|
|
|
|
|
|
|
|
2762
|
|
|
|
|
|
|
$t->set_column_style($colname, type => 'bool', |
2763
|
|
|
|
|
|
|
formats => [[bool => {style=>"Y_N"}]]); |
2764
|
|
|
|
|
|
|
|
2765
|
|
|
|
|
|
|
See L<Data::Unixish::bool> for more details. |
2766
|
|
|
|
|
|
|
|
2767
|
|
|
|
|
|
|
=head3 How do I do conditional cell formatting? |
2768
|
|
|
|
|
|
|
|
2769
|
|
|
|
|
|
|
There are several ways. |
2770
|
|
|
|
|
|
|
|
2771
|
|
|
|
|
|
|
First, you can use the C<cond> dux function through C<formats> style. For |
2772
|
|
|
|
|
|
|
example, if the cell contains the string "Cuti", you want to color the cell |
2773
|
|
|
|
|
|
|
yellow. Otherwise, you want to color the cell red: |
2774
|
|
|
|
|
|
|
|
2775
|
|
|
|
|
|
|
$t->set_column_style($colname, formats => [ |
2776
|
|
|
|
|
|
|
[cond => { |
2777
|
|
|
|
|
|
|
if => sub { $_ =~ /Cuti/ }, |
2778
|
|
|
|
|
|
|
then => ["ansi::color", {color=>"yellow"}], |
2779
|
|
|
|
|
|
|
else => ["ansi::color", {color=>"red"}], |
2780
|
|
|
|
|
|
|
}] |
2781
|
|
|
|
|
|
|
]); |
2782
|
|
|
|
|
|
|
|
2783
|
|
|
|
|
|
|
Another way is to use the C<add_cond_{cell,row,column}> methods. See |
2784
|
|
|
|
|
|
|
L</"CONDITIONAL STYLES"> for more details. An example: |
2785
|
|
|
|
|
|
|
|
2786
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { |
2787
|
|
|
|
|
|
|
my %args = @_; |
2788
|
|
|
|
|
|
|
$args{colname} =~ /Cuti/ ? {bgcolor=>"ffff00"} : {bgcolor=>"ff0000"}; |
2789
|
|
|
|
|
|
|
}); |
2790
|
|
|
|
|
|
|
|
2791
|
|
|
|
|
|
|
And another way is to use (or create) style set, which is basically a packaging |
2792
|
|
|
|
|
|
|
of the above ways. An advantage of using style set is, because you do not |
2793
|
|
|
|
|
|
|
specify coderef directly, you can specify it from the environment variable. See |
2794
|
|
|
|
|
|
|
L</"STYLE SETS"> for more details. |
2795
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
=head2 Border |
2797
|
|
|
|
|
|
|
|
2798
|
|
|
|
|
|
|
=head3 How to hide borders? |
2799
|
|
|
|
|
|
|
|
2800
|
|
|
|
|
|
|
There is currently no C<show_border> attribute. Choose border styles like |
2801
|
|
|
|
|
|
|
C<ASCII::Space>, C<ASCII::None>, C<UTF8::None>: |
2802
|
|
|
|
|
|
|
|
2803
|
|
|
|
|
|
|
$t->border_style("UTF8::None"); |
2804
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
=head3 Why are there 'ASCII::None' as well 'UTF8::None' and 'BoxChar::None' border styles? |
2806
|
|
|
|
|
|
|
|
2807
|
|
|
|
|
|
|
Because of the row separator, that can still be drawn if C<add_row_separator()> |
2808
|
|
|
|
|
|
|
is used. See next question. |
2809
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
=head3 I want to hide borders, and I do not want row separators to be shown! |
2811
|
|
|
|
|
|
|
|
2812
|
|
|
|
|
|
|
The default is for separator lines to be drawn if drawn using |
2813
|
|
|
|
|
|
|
C<add_row_separator()>, e.g.: |
2814
|
|
|
|
|
|
|
|
2815
|
|
|
|
|
|
|
$t->add_row(['row1']); |
2816
|
|
|
|
|
|
|
$t->add_row(['row2']); |
2817
|
|
|
|
|
|
|
$t->add_row_separator; |
2818
|
|
|
|
|
|
|
$t->add_row(['row3']); |
2819
|
|
|
|
|
|
|
|
2820
|
|
|
|
|
|
|
The result will be: |
2821
|
|
|
|
|
|
|
|
2822
|
|
|
|
|
|
|
row1 |
2823
|
|
|
|
|
|
|
row2 |
2824
|
|
|
|
|
|
|
-------- |
2825
|
|
|
|
|
|
|
row3 |
2826
|
|
|
|
|
|
|
|
2827
|
|
|
|
|
|
|
However, if you set C<show_row_separator> to 0, no separator lines will be drawn |
2828
|
|
|
|
|
|
|
whatsoever: |
2829
|
|
|
|
|
|
|
|
2830
|
|
|
|
|
|
|
row1 |
2831
|
|
|
|
|
|
|
row2 |
2832
|
|
|
|
|
|
|
row3 |
2833
|
|
|
|
|
|
|
|
2834
|
|
|
|
|
|
|
=head3 I want to separate each row with a line! |
2835
|
|
|
|
|
|
|
|
2836
|
|
|
|
|
|
|
Set C<show_row_separator> to 1, or alternatively, set |
2837
|
|
|
|
|
|
|
C<ANSITABLE_STYLE='{"show_row_separator":1}>. |
2838
|
|
|
|
|
|
|
|
2839
|
|
|
|
|
|
|
=head2 Color |
2840
|
|
|
|
|
|
|
|
2841
|
|
|
|
|
|
|
=head3 How to disable colors? |
2842
|
|
|
|
|
|
|
|
2843
|
|
|
|
|
|
|
Set C<use_color> attribute or C<COLOR> environment to 0. |
2844
|
|
|
|
|
|
|
|
2845
|
|
|
|
|
|
|
=head3 How to specify colors using names (e.g. red, 'navy blue') instead of RGB? |
2846
|
|
|
|
|
|
|
|
2847
|
|
|
|
|
|
|
Use modules like L<Graphics::ColorNames>. |
2848
|
|
|
|
|
|
|
|
2849
|
|
|
|
|
|
|
=head3 I'm not seeing colors when output is piped (e.g. to a pager)! |
2850
|
|
|
|
|
|
|
|
2851
|
|
|
|
|
|
|
The default is to disable colors when (-t STDOUT) is false. You can force-enable |
2852
|
|
|
|
|
|
|
colors by setting C<use_color> attribute or C<COLOR> environment to 1. |
2853
|
|
|
|
|
|
|
|
2854
|
|
|
|
|
|
|
=head3 How to enable 256 colors? I'm seeing only 16 colors. |
2855
|
|
|
|
|
|
|
|
2856
|
|
|
|
|
|
|
Use terminal emulators that support 256 colors, e.g. Konsole, xterm, |
2857
|
|
|
|
|
|
|
gnome-terminal, PuTTY/pterm (but the last one has minimal Unicode support). |
2858
|
|
|
|
|
|
|
Better yet, use Konsole or Konsole-based emulators which supports 24bit colors. |
2859
|
|
|
|
|
|
|
|
2860
|
|
|
|
|
|
|
=head3 How to enable 24bit colors (true color)? |
2861
|
|
|
|
|
|
|
|
2862
|
|
|
|
|
|
|
Currently only B<Konsole> and the Konsole-based B<Yakuake> terminal emulator |
2863
|
|
|
|
|
|
|
software support 24bit colors. |
2864
|
|
|
|
|
|
|
|
2865
|
|
|
|
|
|
|
=head3 How to force lower color depth? (e.g. I use Konsole but want 16 colors) |
2866
|
|
|
|
|
|
|
|
2867
|
|
|
|
|
|
|
Set C<COLOR_DEPTH> to 16. |
2868
|
|
|
|
|
|
|
|
2869
|
|
|
|
|
|
|
=head3 How to change border gradation color? |
2870
|
|
|
|
|
|
|
|
2871
|
|
|
|
|
|
|
The default color theme applies vertical color gradation to borders from white |
2872
|
|
|
|
|
|
|
(ffffff) to gray (444444). To change this, set C<border1> and C<border2> theme |
2873
|
|
|
|
|
|
|
arguments: |
2874
|
|
|
|
|
|
|
|
2875
|
|
|
|
|
|
|
$t->color_theme_args({border1=>'ff0000', border2=>'00ff00'}); # red to green |
2876
|
|
|
|
|
|
|
|
2877
|
|
|
|
|
|
|
=head3 I'm using terminal emulator with white background, the texts are not very visible! |
2878
|
|
|
|
|
|
|
|
2879
|
|
|
|
|
|
|
Try using the "*_whitebg" themes, as the other themes are geared towards |
2880
|
|
|
|
|
|
|
terminal emulators with black background. |
2881
|
|
|
|
|
|
|
|
2882
|
|
|
|
|
|
|
=head3 How to set different background colors for odd/even rows? |
2883
|
|
|
|
|
|
|
|
2884
|
|
|
|
|
|
|
Aside from doing C<< $t->set_row_style($rownum, bgcolor=>...) >> for each row, |
2885
|
|
|
|
|
|
|
you can also do this: |
2886
|
|
|
|
|
|
|
|
2887
|
|
|
|
|
|
|
$t->cell_bgcolor(sub { my ($self, %args) = @_; $args{rownum} % 2 ? '202020' : undef }); |
2888
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
Or, you can use conditional row styles: |
2890
|
|
|
|
|
|
|
|
2891
|
|
|
|
|
|
|
$t->add_cond_row_style(sub { $_ % 2 }, {bgcolor=>'202020'}); |
2892
|
|
|
|
|
|
|
|
2893
|
|
|
|
|
|
|
Or, you can use the L<Text::ANSITable::StyleSet::AltRow> style set: |
2894
|
|
|
|
|
|
|
|
2895
|
|
|
|
|
|
|
$t->apply_style_set(AltRow => {even_bgcolor=>'202020'}); |
2896
|
|
|
|
|
|
|
|
2897
|
|
|
|
|
|
|
=head1 ENVIRONMENT |
2898
|
|
|
|
|
|
|
|
2899
|
|
|
|
|
|
|
=head2 COLOR => BOOL |
2900
|
|
|
|
|
|
|
|
2901
|
|
|
|
|
|
|
Can be used to set default value for the C<color> attribute. |
2902
|
|
|
|
|
|
|
|
2903
|
|
|
|
|
|
|
=head2 COLOR_DEPTH => INT |
2904
|
|
|
|
|
|
|
|
2905
|
|
|
|
|
|
|
Can be used to set default value for the C<color_depth> attribute. |
2906
|
|
|
|
|
|
|
|
2907
|
|
|
|
|
|
|
=head2 BOX_CHARS => BOOL |
2908
|
|
|
|
|
|
|
|
2909
|
|
|
|
|
|
|
Can be used to set default value for the C<box_chars> attribute. |
2910
|
|
|
|
|
|
|
|
2911
|
|
|
|
|
|
|
=head2 UTF8 => BOOL |
2912
|
|
|
|
|
|
|
|
2913
|
|
|
|
|
|
|
Can be used to set default value for the C<utf8> attribute. |
2914
|
|
|
|
|
|
|
|
2915
|
|
|
|
|
|
|
=head2 COLUMNS => INT |
2916
|
|
|
|
|
|
|
|
2917
|
|
|
|
|
|
|
Can be used to override terminal width detection. |
2918
|
|
|
|
|
|
|
|
2919
|
|
|
|
|
|
|
=head2 ANSITABLE_BORDER_STYLE => STR |
2920
|
|
|
|
|
|
|
|
2921
|
|
|
|
|
|
|
Can be used to set default value for C<border_style> attribute. |
2922
|
|
|
|
|
|
|
|
2923
|
|
|
|
|
|
|
=head2 ANSITABLE_COLOR_THEME => STR |
2924
|
|
|
|
|
|
|
|
2925
|
|
|
|
|
|
|
Can be used to set default value for C<border_style> attribute. |
2926
|
|
|
|
|
|
|
|
2927
|
|
|
|
|
|
|
=head2 ANSITABLE_STYLE => str(json) |
2928
|
|
|
|
|
|
|
|
2929
|
|
|
|
|
|
|
Can be used to set table's most attributes. Value should be a JSON-encoded hash |
2930
|
|
|
|
|
|
|
of C<< attr => val >> pairs. Example: |
2931
|
|
|
|
|
|
|
|
2932
|
|
|
|
|
|
|
% ANSITABLE_STYLE='{"show_row_separator":1}' ansitable-list-border-styles |
2933
|
|
|
|
|
|
|
|
2934
|
|
|
|
|
|
|
will display table with row separator lines after every row. |
2935
|
|
|
|
|
|
|
|
2936
|
|
|
|
|
|
|
=head2 WRAP => BOOL |
2937
|
|
|
|
|
|
|
|
2938
|
|
|
|
|
|
|
Can be used to set default value for the C<wrap> column style. |
2939
|
|
|
|
|
|
|
|
2940
|
|
|
|
|
|
|
=head2 ANSITABLE_COLUMN_STYLES => str(json) |
2941
|
|
|
|
|
|
|
|
2942
|
|
|
|
|
|
|
Can be used to set per-column styles. Interpreted right before draw(). Value |
2943
|
|
|
|
|
|
|
should be a JSON-encoded hash of C<< col => {style => val, ...} >> pairs. |
2944
|
|
|
|
|
|
|
Example: |
2945
|
|
|
|
|
|
|
|
2946
|
|
|
|
|
|
|
% ANSITABLE_COLUMN_STYLES='{"2":{"type":"num"},"3":{"type":"str"}}' ansitable-list-border-styles |
2947
|
|
|
|
|
|
|
|
2948
|
|
|
|
|
|
|
will display the bool columns as num and str instead. |
2949
|
|
|
|
|
|
|
|
2950
|
|
|
|
|
|
|
=head2 ANSITABLE_ROW_STYLES => str(json) |
2951
|
|
|
|
|
|
|
|
2952
|
|
|
|
|
|
|
Can be used to set per-row styles. Interpreted right before draw(). Value should |
2953
|
|
|
|
|
|
|
be a JSON-encoded a hash of C<< rownum => {style => val, ...} >> pairs. |
2954
|
|
|
|
|
|
|
Example: |
2955
|
|
|
|
|
|
|
|
2956
|
|
|
|
|
|
|
% ANSITABLE_ROW_STYLES='{"0":{"bgcolor":"000080","vpad":1}}' ansitable-list-border-styles |
2957
|
|
|
|
|
|
|
|
2958
|
|
|
|
|
|
|
will display the first row with blue background color and taller height. |
2959
|
|
|
|
|
|
|
|
2960
|
|
|
|
|
|
|
=head2 ANSITABLE_CELL_STYLES => str(json) |
2961
|
|
|
|
|
|
|
|
2962
|
|
|
|
|
|
|
Can be used to set per-cell styles. Interpreted right before draw(). Value |
2963
|
|
|
|
|
|
|
should be a JSON-encoded a hash of C<< "rownum,col" => {style => val, ...} >> |
2964
|
|
|
|
|
|
|
pairs. Example: |
2965
|
|
|
|
|
|
|
|
2966
|
|
|
|
|
|
|
% ANSITABLE_CELL_STYLES='{"1,1":{"bgcolor":"008000"}}' ansitable-list-border-styles |
2967
|
|
|
|
|
|
|
|
2968
|
|
|
|
|
|
|
will display the second-on-the-left, second-on-the-top cell with green |
2969
|
|
|
|
|
|
|
background color. |
2970
|
|
|
|
|
|
|
|
2971
|
|
|
|
|
|
|
=head2 ANSITABLE_STYLE_SETS => str(json) |
2972
|
|
|
|
|
|
|
|
2973
|
|
|
|
|
|
|
Can be used to apply style sets. Value should be a JSON-encoded array. Each |
2974
|
|
|
|
|
|
|
element must be a style set name or a 2-element array containing style set name |
2975
|
|
|
|
|
|
|
and its arguments (C<< [$name, \%args] >>). Example: |
2976
|
|
|
|
|
|
|
|
2977
|
|
|
|
|
|
|
% ANSITABLE_STYLE_SETS='[["AltRow",{"odd_bgcolor":"003300"}]]' |
2978
|
|
|
|
|
|
|
|
2979
|
|
|
|
|
|
|
will display table with row separator lines after every row. |
2980
|
|
|
|
|
|
|
|
2981
|
|
|
|
|
|
|
=head1 HOMEPAGE |
2982
|
|
|
|
|
|
|
|
2983
|
|
|
|
|
|
|
Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSITable>. |
2984
|
|
|
|
|
|
|
|
2985
|
|
|
|
|
|
|
=head1 SOURCE |
2986
|
|
|
|
|
|
|
|
2987
|
|
|
|
|
|
|
Source repository is at L<https://github.com/perlancar/perl-Text-ANSITable>. |
2988
|
|
|
|
|
|
|
|
2989
|
|
|
|
|
|
|
=head1 BUGS |
2990
|
|
|
|
|
|
|
|
2991
|
|
|
|
|
|
|
Please report any bugs or feature requests on the bugtracker website L<https://github.com/perlancar/perl-Text-ANSITable/issues> |
2992
|
|
|
|
|
|
|
|
2993
|
|
|
|
|
|
|
When submitting a bug or request, please include a test-file or a |
2994
|
|
|
|
|
|
|
patch to an existing test-file that illustrates the bug or desired |
2995
|
|
|
|
|
|
|
feature. |
2996
|
|
|
|
|
|
|
|
2997
|
|
|
|
|
|
|
=head1 SEE ALSO |
2998
|
|
|
|
|
|
|
|
2999
|
|
|
|
|
|
|
=head2 Border styles |
3000
|
|
|
|
|
|
|
|
3001
|
|
|
|
|
|
|
For collections of border styles, search for C<BorderStyle::*> modules. |
3002
|
|
|
|
|
|
|
|
3003
|
|
|
|
|
|
|
=head2 Color themes |
3004
|
|
|
|
|
|
|
|
3005
|
|
|
|
|
|
|
For collections of color themes, search for C<ColorTheme::*> modules. |
3006
|
|
|
|
|
|
|
|
3007
|
|
|
|
|
|
|
=head2 Other table-formatting CPAN modules |
3008
|
|
|
|
|
|
|
|
3009
|
|
|
|
|
|
|
L<Text::ASCIITable> is one of the most popular table-formatting modules on CPAN. |
3010
|
|
|
|
|
|
|
There are a couple of "extensions" for Text::ASCIITable: |
3011
|
|
|
|
|
|
|
L<Text::ASCIITable::TW>, L<Text::ASCIITable::Wrap>; Text::ANSITable can be an |
3012
|
|
|
|
|
|
|
alternative for all those modules since it can already handle wide-characters as |
3013
|
|
|
|
|
|
|
well as multiline text in cells. |
3014
|
|
|
|
|
|
|
|
3015
|
|
|
|
|
|
|
L<Text::TabularDisplay> |
3016
|
|
|
|
|
|
|
|
3017
|
|
|
|
|
|
|
L<Text::Table> |
3018
|
|
|
|
|
|
|
|
3019
|
|
|
|
|
|
|
L<Text::SimpleTable> |
3020
|
|
|
|
|
|
|
|
3021
|
|
|
|
|
|
|
L<Text::UnicodeTable::Simple> |
3022
|
|
|
|
|
|
|
|
3023
|
|
|
|
|
|
|
L<Table::Simple> |
3024
|
|
|
|
|
|
|
|
3025
|
|
|
|
|
|
|
L<Acme::CPANModules::TextTable> catalogs text table modules. |
3026
|
|
|
|
|
|
|
|
3027
|
|
|
|
|
|
|
=head2 Front-ends |
3028
|
|
|
|
|
|
|
|
3029
|
|
|
|
|
|
|
L<Text::Table::Any> and its CLI L<texttable> can use Text::ANSITable as one of |
3030
|
|
|
|
|
|
|
the backends. |
3031
|
|
|
|
|
|
|
|
3032
|
|
|
|
|
|
|
=head2 Other related modules |
3033
|
|
|
|
|
|
|
|
3034
|
|
|
|
|
|
|
L<App::TextTableUtils> includes utilities like L<csv2ansitable> or |
3035
|
|
|
|
|
|
|
L<json2ansitable> which can convert a CSV or array-of-array structure to a table |
3036
|
|
|
|
|
|
|
rendered using Text::ANSITable. |
3037
|
|
|
|
|
|
|
|
3038
|
|
|
|
|
|
|
=head2 Other |
3039
|
|
|
|
|
|
|
|
3040
|
|
|
|
|
|
|
Unix command B<column> (e.g. C<column -t>). |
3041
|
|
|
|
|
|
|
|
3042
|
|
|
|
|
|
|
=head1 AUTHOR |
3043
|
|
|
|
|
|
|
|
3044
|
|
|
|
|
|
|
perlancar <perlancar@cpan.org> |
3045
|
|
|
|
|
|
|
|
3046
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
3047
|
|
|
|
|
|
|
|
3048
|
|
|
|
|
|
|
This software is copyright (c) 2021, 2020, 2018, 2017, 2016, 2015, 2014, 2013 by perlancar@cpan.org. |
3049
|
|
|
|
|
|
|
|
3050
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
3051
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
3052
|
|
|
|
|
|
|
|
3053
|
|
|
|
|
|
|
=cut |