File Coverage

blib/lib/Getopt/EX/termcolor.pm
Criterion Covered Total %
statement 31 100 31.0
branch 3 48 6.2
condition 2 18 11.1
subroutine 10 24 41.6
pod 1 14 7.1
total 47 204 23.0


line stmt bran cond sub pod time code
1             =encoding utf-8
2              
3             =head1 NAME
4              
5             Getopt::EX::termcolor - Getopt::EX termcolor module
6              
7             =head1 SYNOPSIS
8              
9             use Getopt::EX::Loader;
10             my $rcloader = Getopt::EX::Loader->new(
11             BASECLASS => [ 'App::command', 'Getopt::EX' ],
12             );
13              
14             or
15              
16             use Getopt::EX::Long qw(:DEFAULT ExConfigure);
17             ExConfigure BASECLASS => [ "App::command", "Getopt::EX" ];
18              
19             then
20              
21             $ command -Mtermcolor::bg=
22              
23             =head1 VERSION
24              
25             Version 1.08
26              
27             =head1 DESCRIPTION
28              
29             This is a common module for command using L to manipulate
30             system dependent terminal color.
31              
32             Actual action is done by sub-module under L,
33             such as L.
34              
35             Each sub-module is expected to have C<&get_color> function which
36             return the list of RGB values for requested name, but currently name
37             C is only supported. Each RGB values are expected in a
38             range of 0 to 255 by default. If the first entry of the list is a
39             HASH reference, it may include maximum number indication like C<< {
40             max => 65535 } >>.
41              
42             Terminal luminance is calculated from RGB values by this equation and
43             produces decimal value from 0 to 100.
44              
45             ( 30 * R + 59 * G + 11 * B ) / MAX
46              
47             =begin comment
48              
49             If the environment variable C is defined, its value is
50             used as a luminance without calling sub-modules. The value of
51             C is expected in range of 0 to 100.
52              
53             =end comment
54              
55             If the environment variable C is defined, it is used as
56             a background RGB value without calling sub-modules. RGB value is a
57             combination of integer described in 24bit/12bit hex, 24bit decimal or
58             6x6x6 216 color format. RGB color notation is compatible with
59             L.
60              
61             24bit hex #000000 .. #FFFFFF
62             12bit hex #000 .. #FFF
63             24bit decimal 0,0,0 .. 255,255,255
64             6x6x6 216 000 .. 555
65              
66             You can set C in you start up file of shell. This
67             module has utility function C which can be used like this:
68              
69             export TERM_BGCOLOR=`perl -MGetopt::EX::termcolor=bgcolor -e bgcolor`
70             : ${TERM_BGCOLOR:=#FFFFFF}
71              
72             =head1 MODULE FUNCTION
73              
74             =over 7
75              
76             =item B
77              
78             Call this function with module option:
79              
80             $ command -Mtermcolor::bg=
81              
82             If the terminal luminance is unknown, nothing happens. Otherwise, the
83             module insert B<--light-terminal> or B<--dark-terminal> option
84             according to the luminance value.
85              
86             You can change the behavior by optional parameters:
87              
88             threshold : threshold of light/dark (default 50)
89             default : default luminance value (default none)
90             light : light terminal option (default "--light-terminal")
91             dark : dark terminal option (default "--dark-terminal")
92              
93             Use like this:
94              
95             option default \
96             -Mtermcolor::bg(default=100,light=--light,dark=--dark)
97              
98             =back
99              
100             =head1 SEE ALSO
101              
102             L
103              
104             L
105              
106             L
107              
108             L
109              
110             =head1 AUTHOR
111              
112             Kazumasa Utashiro
113              
114             =head1 LICENSE
115              
116             Copyright 2020-2021 Kazumasa Utashiro.
117              
118             You can redistribute it and/or modify it under the same terms
119             as Perl itself.
120              
121             =cut
122              
123 2     2   59989 use v5.14;
  2         14  
124             package Getopt::EX::termcolor;
125              
126             our $VERSION = '1.08';
127              
128 2     2   11 use warnings;
  2         3  
  2         44  
129 2     2   9 use Carp;
  2         4  
  2         102  
130 2     2   1044 use Data::Dumper;
  2         11533  
  2         124  
131              
132 2     2   13 use Exporter 'import';
  2         4  
  2         298  
133             our @EXPORT = qw();
134             our @EXPORT_OK = qw(rgb_to_luminance rgb_to_brightness luminance bgcolor);
135             our %EXPORT_TAGS = (all => [ @EXPORT_OK ]);
136              
137             #
138             # For backward compatibility.
139             #
140             sub rgb_to_brightness {
141 0     0 0 0 goto &rgb_to_luminance;
142             }
143              
144             sub rgb_to_luminance {
145 15 50   15 0 106 @_ or return;
146 15 100       35 my $opt = ref $_[0] ? shift : {};
147 15   100     52 my $max = $opt->{max} || 255;
148 15         23 my($r, $g, $b) = @_;
149 2     2   823 use integer;
  2         26  
  2         10  
150 15         59 ($r * 30 + $g * 59 + $b * 11) / $max; # 0 .. 100
151             }
152              
153             my $mod;
154             my $argv;
155              
156             sub initialize {
157 0     0 0   ($mod, $argv) = @_;
158 0           set_luminance();
159             }
160              
161             our $debug = 0;
162              
163             sub debug {
164 0     0 0   $debug ^= 1;
165             }
166              
167             sub call_mod_sub {
168 0     0 0   my($mod, $name, @arg) = @_;
169 0           my $call = "$mod\::$name";
170 0 0 0       if (eval "require $mod" and defined &$call) {
171 2     2   263 no strict 'refs';
  2         3  
  2         215  
172 0           $call->(@arg);
173             } else {
174 0 0         if ($@ !~ /^Can't locate /) {
175 0           croak $@;
176             }
177             }
178             }
179              
180             sub rgb255 {
181 2     2   13 use integer;
  2         4  
  2         6  
182 0 0   0 0   my $opt = ref $_[0] ? shift : {};
183 0   0       my $max = $opt->{max} // 255;
184 0           map { $_ * 255 / $max } @_;
  0            
185             }
186              
187             sub get_rgb {
188 0     0 0   my $cat = shift;
189 0           my @rgb;
190             RGB:
191             {
192             # TERM=xterm
193 0 0 0       if (($ENV{TERM} // '') =~ /^xterm/) {
  0            
194 0           my $mod = __PACKAGE__ . "::XTerm";
195 0           @rgb = call_mod_sub $mod, 'get_color', $cat;
196 0 0         last if @rgb >= 3;
197             }
198             # TERM_PROGRAM
199 0 0         if (my $term_program = $ENV{TERM_PROGRAM}) {
200 0 0         warn "TERM_PROGRAM=$ENV{TERM_PROGRAM}\n" if $debug;
201 0           my $submod = $term_program =~ s/\.app$//r;
202 0           my $mod = __PACKAGE__ . "::$submod";
203 0           @rgb = call_mod_sub $mod, 'get_color', $cat;
204 0 0         last if @rgb >= 3;
205             }
206 0           return ();
207             }
208             GOTCHA:
209 0           rgb255 @rgb;
210             }
211              
212             sub set_luminance {
213 0     0 0   my $luminance;
214 0 0         if (defined $ENV{TERM_LUMINANCE}) {
215 0 0         warn "TERM_LUMINANCE=$ENV{TERM_LUMINANCE}\n" if $debug;
216 0           return;
217             }
218 0           if ("BACKWARD COMPATIBILITY") {
219 0 0         if (defined (my $env = $ENV{BRIGHTNESS})) {
220 0 0         warn "BRIGHTNESS=$env\n" if $debug;
221 0           $ENV{TERM_LUMINANCE} = $env;
222 0           return;
223             }
224             }
225 0 0         if (my $bgcolor = $ENV{TERM_BGCOLOR}) {
226 0 0         warn "TERM_BGCOLOR=$bgcolor\n" if $debug;
227 0 0         if (my @rgb = parse_rgb($bgcolor)) {
228 0           $luminance = rgb_to_luminance @rgb;
229             } else {
230 0           warn "Invalid format: TERM_BGCOLOR=$bgcolor\n";
231             }
232             } else {
233 0           $luminance = get_luminance();
234             }
235 0   0       $ENV{TERM_LUMINANCE} = $luminance // return;
236             }
237              
238             sub get_luminance {
239 0     0 0   rgb_to_luminance get_rgb "background";
240             }
241              
242 2     2   923 use List::Util qw(pairgrep);
  2         4  
  2         1120  
243              
244             #
245             # FOR BACKWARD COMPATIBILITY
246             # DEPELICATED IN THE FUTURE
247             #
248 0     0 0   sub set { goto &bg }
249              
250             my %bg_param = (
251             light => "--light-terminal",
252             dark => "--dark-terminal",
253             default => undef,
254             threshold => 50,
255             );
256              
257             sub bg {
258             my %param =
259 0     0 1   (%bg_param, pairgrep { exists $bg_param{$a} } @_);
  0     0      
260             my $luminance =
261 0   0       $ENV{TERM_LUMINANCE} // $param{default} // return;
      0        
262             my $option = $luminance > $param{threshold} ?
263             $param{light} : $param{dark}
264 0 0         or return;
    0          
265              
266             # $mod->setopt($option => '$');
267 0           $mod->setopt(default => $option);
268             }
269              
270             sub parse_rgb {
271 0     0 0   my $rgb = shift;
272 0           my @rgb = do {
273 0 0         if ($rgb =~ /^\#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i) {
    0          
    0          
    0          
274 0           map { hex } $1, $2, $3;
  0            
275             }
276             elsif ($rgb =~ /^\#([\da-f])([\da-f])([\da-f])$/i) {
277 0           map { 0x11 * hex } $1, $2, $3;
  0            
278             }
279             elsif ($rgb =~ /^([0-5])([0-5])([0-5])$/) {
280 0           map { 0x33 * int } $1, $2, $3;
  0            
281             }
282             elsif ($rgb =~ /^(\d+),(\d+),(\d+)$/) {
283 0           map { int } $1, $2, $3;
  0            
284             }
285             else {
286 0           return ();
287             }
288             };
289 0           @rgb;
290             }
291              
292             sub luminance {
293 0   0 0 0   my $v = get_luminance() // return;
294 0           say $v;
295             }
296              
297             sub bgcolor {
298 0 0   0 0   my @rgb = get_rgb "background" or return;
299 0           printf "#%02X%02X%02X\n", @rgb;
300             }
301              
302             1;
303              
304             __DATA__