File Coverage

blib/lib/Getopt/EX/termcolor/XTerm.pm
Criterion Covered Total %
statement 38 85 44.7
branch 0 30 0.0
condition n/a
subroutine 13 22 59.0
pod 0 9 0.0
total 51 146 34.9


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   1252 use v5.14;
  1         4  
24 1     1   5 use strict;
  1         2  
  1         21  
25 1     1   6 use warnings;
  1         2  
  1         43  
26              
27 1     1   7 use Exporter 'import';
  1         2  
  1         52  
28             our @EXPORT_OK = qw(test);
29              
30 1     1   6 use Carp;
  1         3  
  1         51  
31 1     1   16 use Data::Dumper;
  1         3  
  1         47  
32 1     1   5 use IO::Handle;
  1         2  
  1         42  
33 1     1   538 use Term::ReadKey;
  1         2011  
  1         83  
34              
35 1     1   10 use Getopt::EX::termcolor;
  1         4  
  1         188  
36              
37             sub get_colors {
38             map {
39 0     0 0   my @rgb = get_color($_);
  0            
40 0 0         @rgb ? undef : [ @rgb ];
41             } @_;
42             }
43              
44             my %alias = qw(
45             foreground text_foreground
46             background text_background
47             );
48              
49             sub get_color {
50 0     0 0   my $res = lc shift;
51 0 0         $res = $alias{$res} if $alias{$res};
52 0           return color_rgb($res);
53             }
54              
55             our $debug = $ENV{DEBUG_GETOPTEX};
56              
57             use constant {
58 1         151 CSI => "\e[", # Control Sequence Introducer
59             OSC => "\e]", # Operating System Command
60 1     1   13 };
  1         2  
61              
62             sub osc_command {
63 0     0 0   my($Ps, $Pt) = @_;
64 0           OSC . "$Ps;$Pt" . "\a";
65             }
66              
67 1     1   7 use List::Util qw(pairmap);
  1         2  
  1         665  
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 = 0.1;
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   609 $key =~ /\P{Cc}/ ? $key : uncntrl $key;
  1         15  
  1         19  
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   21337 use List::Util qw(max);
  1         3  
  1         359  
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;