File Coverage

blib/lib/Getopt/EX/termcolor.pm
Criterion Covered Total %
statement 34 103 33.0
branch 3 48 6.2
condition 2 18 11.1
subroutine 11 25 44.0
pod 1 14 7.1
total 51 208 24.5


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 VERSION
8              
9             Version 1.06
10              
11             =head1 SYNOPSIS
12              
13             use Getopt::EX::Loader;
14             my $rcloader = new Getopt::EX::Loader
15             BASECLASS => [ 'App::command', 'Getopt::EX' ];
16              
17             or
18              
19             use Getopt::EX::Long qw(:DEFAULT ExConfigure);
20             ExConfigure BASECLASS => [ "App::command", "Getopt::EX" ];
21              
22             then
23              
24             $ command -Mtermcolor::bg=
25              
26             =head1 DESCRIPTION
27              
28             This is a common module for command using L to manipulate
29             system dependent terminal color.
30              
31             Actual action is done by sub-module under L,
32             such as L.
33              
34             Each sub-module is expected to have C<&get_color> function which
35             return the list of RGB values for requested name, but currently name
36             C is only supported. Each RGB values are expected in a
37             range of 0 to 255 by default. If the list first entry is a HASH
38             reference, it may include maximum number indication like C<< { max =>
39             65535 } >>.
40              
41             Terminal luminance is calculated from RGB values by this equation and
42             produces decimal value from 0 to 100.
43              
44             ( 30 * R + 59 * G + 11 * B ) / MAX
45              
46             =begin comment
47              
48             If the environment variable C is defined, its value is
49             used as a luminance without calling sub-modules. The value of
50             C is expected in range of 0 to 100.
51              
52             =end comment
53              
54             If the environment variable C is defined, it is used as
55             a background RGB value without calling sub-modules. RGB value is a
56             combination of integer described in 24bit/12bit hex, 24bit decimal or
57             6x6x6 216 color format. RGB color notation is compatible with
58             L.
59              
60             24bit hex #000000 .. #FFFFFF
61             12bit hex #000 .. #FFF
62             24bit decimal 0,0,0 .. 255,255,255
63             6x6x6 216 000 .. 555
64              
65             You can set C in you start up file of shell. This
66             module has utility function C which can be used like this:
67              
68             export TERM_BGCOLOR=`perl -MGetopt::EX::termcolor=bgcolor -e bgcolor`
69             : ${TERM_BGCOLOR:=#FFFFFF}
70              
71             =head1 MODULE FUNCTION
72              
73             =over 7
74              
75             =item B
76              
77             Call this function with module option:
78              
79             $ command -Mtermcolor::bg=
80              
81             If the terminal luminance is unknown, nothing happens. Otherwise, the
82             module insert B<--light-terminal> or B<--dark-terminal> option
83             according to the luminance value.
84              
85             You can change the behavior by optional parameters:
86              
87             threshold : threshold of light/dark (default 50)
88             default : default luminance value (default none)
89             light : light terminal option (default "--light-terminal")
90             dark : dark terminal option (default "--dark-terminal")
91              
92             Use like this:
93              
94             option default \
95             -Mtermcolor::bg(default=100,light=--light,dark=--dark)
96              
97             =back
98              
99             =head1 SEE ALSO
100              
101             L
102              
103             L
104              
105             L
106              
107             L
108              
109             =head1 AUTHOR
110              
111             Kazumasa Utashiro
112              
113             =head1 LICENSE
114              
115             Copyright (C) 2020 Kazumasa Utashiro.
116              
117             You can redistribute it and/or modify it under the same terms
118             as Perl itself.
119              
120             =cut
121              
122             package Getopt::EX::termcolor;
123              
124 2     2   70831 use v5.14;
  2         17  
125 2     2   10 use strict;
  2         13  
  2         40  
126 2     2   10 use warnings;
  2         3  
  2         45  
127 2     2   9 use Carp;
  2         3  
  2         135  
128 2     2   1290 use Data::Dumper;
  2         14130  
  2         154  
129              
130             our $VERSION = "1.06";
131              
132 2     2   16 use Exporter 'import';
  2         2  
  2         268  
133             our @EXPORT = qw();
134             our %EXPORT_TAGS = ();
135             our @EXPORT_OK = qw(rgb_to_luminance rgb_to_brightness luminance bgcolor);
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 143 @_ or return;
146 15 100       44 my $opt = ref $_[0] ? shift : {};
147 15   100     48 my $max = $opt->{max} || 255;
148 15         28 my($r, $g, $b) = @_;
149 2     2   1080 use integer;
  2         30  
  2         11  
150 15         87 ($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   334 no strict 'refs';
  2         5  
  2         259  
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   28 use integer;
  2         5  
  2         7  
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   1229 use List::Util qw(pairgrep);
  2         5  
  2         1387  
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__