File Coverage

blib/lib/Getopt/EX/termcolor/XTerm.pm
Criterion Covered Total %
statement 35 84 41.6
branch 0 32 0.0
condition n/a
subroutine 12 22 54.5
pod 0 10 0.0
total 47 148 31.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Getopt::EX::termcolor::XTerm
4              
5             =head1 SYNOPSIS
6              
7             use Getopt::EX::termcolor::XTerm;
8              
9             =head1 DESCRIPTION
10              
11             This is a L module for XTerm.
12              
13             =head1 SEE ALSO
14              
15             L
16              
17             L
18              
19             =cut
20              
21             package Getopt::EX::termcolor::XTerm;
22              
23 1     1   958 use v5.14;
  1         4  
24 1     1   5 use warnings;
  1         1  
  1         29  
25              
26 1     1   4 use Exporter 'import';
  1         1  
  1         45  
27             our @EXPORT_OK = qw(test);
28              
29 1     1   6 use Carp;
  1         1  
  1         58  
30 1     1   6 use Data::Dumper;
  1         1  
  1         37  
31 1     1   10 use IO::Handle;
  1         3  
  1         41  
32 1     1   387 use Term::ReadKey;
  1         1929  
  1         60  
33              
34 1     1   6 use Getopt::EX::termcolor;
  1         2  
  1         153  
35              
36             sub get_colors {
37             map {
38 0     0 0   my @rgb = get_color($_);
  0            
39 0 0         @rgb ? undef : [ @rgb ];
40             } @_;
41             }
42              
43             my %alias = qw(
44             foreground text_foreground
45             background text_background
46             );
47              
48             sub get_color {
49 0     0 0   my $res = lc shift;
50 0 0         $res = $alias{$res} if $alias{$res};
51 0           return ask_color_rgb($res);
52             }
53              
54             our $debug = $ENV{DEBUG_GETOPTEX};
55             our $TIMEOUT = $ENV{TERMCOLOR_XTERM_TIMEOUT} || 0.1;
56              
57             use constant {
58 1         126 CSI => "\e[", # Control Sequence Introducer
59             OSC => "\e]", # Operating System Command
60 1     1   6 };
  1         2  
61              
62             sub osc_command {
63 0     0 0   OSC . join(';', @_) . "\a";
64             }
65              
66 1     1   7 use List::Util qw(pairmap);
  1         2  
  1         526  
67              
68             my @oscPs_map = qw(
69             10 text_foreground
70             11 text_background
71             12 text_cursor
72             13 mouse_foreground
73             14 mouse_background
74             15 Tektronix_foreground
75             16 Tektronix_background
76             17 highlight_background
77             18 Tektronix_cursor
78             19 highlight_foreground
79             );
80             my %oscPs = pairmap { $b => $a, lc $b => $a } @oscPs_map;
81             my @oscPs_names = pairmap { $b } @oscPs_map;
82              
83             sub uncntrl {
84 0     0 0   $_[0] =~ s/([^\040-\176])/sprintf "\\%03o", ord $1/gear;
  0            
85             }
86              
87             # OSC Set Text Parameter
88             sub osc_stp {
89 0     0 0   my $Ps = shift;
90 0 0         if ($Ps !~ /^\d+$/) {
91 0 0         $Ps = $oscPs{$Ps} or die "$Ps: invalid";
92             }
93 0           osc_command $Ps, @_;
94             }
95              
96             my $osc_st_re = qr/[\a\x9c]|\e\\/;
97             my $osc_answer_re = qr/\e\]\d+;(?[\x08-\x13\x20-\x7d]*)$osc_st_re/;
98              
99             sub osc_answer {
100 0 0   0 0   @_ or return;
101 0 0         defined $_[0] or return;
102 0 0         $_[0] =~ $osc_answer_re and $+{answer};
103             }
104              
105             sub ask {
106 0     0 0   my $request = shift;
107 0 0         if ($debug) {
108 0           printf STDERR "[%s] Request: %s\n",
109             __PACKAGE__,
110             uncntrl $request;
111             }
112 0 0         open my $tty, "+<", "/dev/tty" or return;
113 0           ReadMode "cbreak", $tty;
114 0           printflush $tty $request;
115 0           my $timeout = $TIMEOUT;
116 0           my $answer = '';
117 0           while (defined (my $key = ReadKey $timeout, $tty)) {
118 0           if (0 and $debug) {
119             printf STDERR "[%s] ReadKey: \"%s\"\n",
120             __PACKAGE__,
121 1     1   8 $key =~ /\P{Cc}/ ? $key : uncntrl $key;
  1         3  
  1         22  
122             }
123 0           $answer .= $key;
124 0 0         last if $answer =~ /$osc_st_re\z/;
125             }
126 0           ReadMode "restore", $tty;
127 0 0         if ($debug) {
128 0           printf STDERR "[%s] Answer: %s\n",
129             __PACKAGE__,
130             uncntrl $answer;
131             }
132 0           return $answer;
133             }
134              
135 1     1   16776 use List::Util qw(max);
  1         2  
  1         357  
136              
137             sub set_color_rgb {
138 0 0   0 0   my $rgb = osc_answer ask osc_stp @_ or return;
139 0 0         my @rgb = $rgb =~ m{rgb:([\da-f]+)/([\da-f]+)/([\da-f]+)}i or return;
140 0           my $max = (2 ** (length($1) * 4)) - 1;
141 0 0         my @opt = $max == 255 ? () : ( { max => $max } );
142 0           ( @opt, map { hex } @rgb );
  0            
143             }
144              
145             sub ask_color_rgb {
146 0     0 0   set_color_rgb @_, '?';
147             }
148              
149             do { test() } if __FILE__ eq $0;
150              
151             sub test {
152 0     0 0   local $Data::Dumper::Indent = 1;
153 0           local $Data::Dumper::Terse = 1;
154 0           my $max = max map { length } @oscPs_names;
  0            
155 0           for my $name (@oscPs_names) {
156 0           my @rgb = ask_color_rgb $name;
157 0 0         printf "%*s: %s",
158             $max, $name,
159             @rgb ? Dumper(\@rgb)=~s/\n(?!\z)\s*/ /gr : "n/a\n";
160             }
161 0           for my $number (0 .. 255) {
162 0           my @rgb = ask_color_rgb(4, $number);
163 0 0         printf "%*d: %s",
164             $max, $number,
165             @rgb ? Dumper(\@rgb)=~s/\n(?!\z)\s*/ /gr : "n/a\n";
166             }
167             }
168              
169             1;