| 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 |