File Coverage

blib/lib/Getopt/EX/termcolor/XTerm.pm
Criterion Covered Total %
statement 35 82 42.6
branch 0 30 0.0
condition n/a
subroutine 12 21 57.1
pod 0 9 0.0
total 47 142 33.1


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   1256 use v5.14;
  1         4  
24 1     1   5 use warnings;
  1         2  
  1         33  
25              
26 1     1   5 use Exporter 'import';
  1         2  
  1         43  
27             our @EXPORT_OK = qw(test);
28              
29 1     1   6 use Carp;
  1         2  
  1         52  
30 1     1   6 use Data::Dumper;
  1         19  
  1         57  
31 1     1   6 use IO::Handle;
  1         2  
  1         47  
32 1     1   571 use Term::ReadKey;
  1         1983  
  1         72  
33              
34 1     1   7 use Getopt::EX::termcolor;
  1         2  
  1         200  
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 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         161 CSI => "\e[", # Control Sequence Introducer
59             OSC => "\e]", # Operating System Command
60 1     1   7 };
  1         10  
61              
62             sub osc_command {
63 0     0 0   my($Ps, $Pt) = @_;
64 0           OSC . "$Ps;$Pt" . "\a";
65             }
66              
67 1     1   8 use List::Util qw(pairmap);
  1         3  
  1         589  
68              
69             my @oscPs_map = qw(
70             10 text_foreground
71             11 text_background
72             12 text_cursor
73             13 mouse_foreground
74             14 mouse_background
75             15 Tektronix_foreground
76             16 Tektronix_background
77             17 highlight_background
78             18 Tektronix_cursor
79             19 highlight_foreground
80             );
81             my %oscPs = pairmap { $b => $a, lc $b => $a } @oscPs_map;
82             my @oscPs_names = pairmap { $b } @oscPs_map;
83              
84             sub uncntrl {
85 0     0 0   $_[0] =~ s/([^\040-\176])/sprintf "\\%03o", ord $1/gear;
  0            
86             }
87              
88             # OSC Set Text Parameter
89             sub osc_stp {
90 0     0 0   my $name = shift;
91 0 0         my $color = @_ ? shift : '?';
92 0 0         my $Ps = $oscPs{$name} or croak;
93 0           osc_command $Ps, $color;
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   647 $key =~ /\P{Cc}/ ? $key : uncntrl $key;
  1         15  
  1         18  
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   21208 use List::Util qw(max);
  1         2  
  1         378  
136              
137             sub color_rgb {
138 0     0 0   my $name = shift;
139 0 0         my $rgb = osc_answer ask osc_stp $name or return;
140 0 0         my @rgb = $rgb =~ m{rgb:([\da-f]+)/([\da-f]+)/([\da-f]+)}i or return;
141 0           my $max = (2 ** (length($1) * 4)) - 1;
142 0 0         my @opt = $max == 255 ? () : ( { max => $max } );
143 0           ( @opt, map { hex } @rgb );
  0            
144             }
145              
146             do { test() } if __FILE__ eq $0;
147              
148             sub test {
149 0     0 0   local $Data::Dumper::Indent = 1;
150 0           local $Data::Dumper::Terse = 1;
151 0           my $max = max map { length } @oscPs_names;
  0            
152 0           for my $name (@oscPs_names) {
153 0           my @rgb = color_rgb($name);
154 0 0         printf "%*s: %s",
155             $max, $name,
156             @rgb ? Dumper(\@rgb)=~s/\n(?!\z)\s*/ /gr : "n/a\n";
157             }
158             }
159              
160             1;