File Coverage

blib/lib/Dist/Zilla/Chrome/Term.pm
Criterion Covered Total %
statement 34 101 33.6
branch 3 36 8.3
condition 2 22 9.0
subroutine 9 20 45.0
pod 0 3 0.0
total 48 182 26.3


line stmt bran cond sub pod time code
1             # ABSTRACT: chrome used for terminal-based interaction
2              
3             use Moose;
4 4     4   2874  
  4         442590  
  4         37  
5             use Dist::Zilla::Pragmas;
6 4     4   29808  
  4         13  
  4         46  
7             use Digest::MD5 qw(md5);
8 4     4   33 use Dist::Zilla::Types qw(OneZero);
  4         14  
  4         361  
9 4     4   632 use Encode ();
  4         16  
  4         62  
10 4     4   10472 use Log::Dispatchouli 1.102220;
  4         15074  
  4         112  
11 4     4   556  
  4         234202  
  4         185  
12             use namespace::autoclean;
13 4     4   45  
  4         10  
  4         40  
14             #pod =head1 OVERVIEW
15             #pod
16             #pod This class provides a L<Dist::Zilla::Chrome> implementation for use in a
17             #pod terminal environment. It's the default chrome used by L<Dist::Zilla::App>.
18             #pod
19             #pod =cut
20              
21             my ($str) = @_;
22              
23 0     0   0 state %color_for;
24              
25 0         0 # I know, I know, this is ludicrous, but guess what? It's my Sunday and I
26             # can spend it how I want.
27             state $max = ($ENV{COLORTERM}//'') eq 'truecolor' ? 255 : 5;
28             state $min = $max == 255 ? 384 : 5;
29 0 0 0     0 state $inc = $max == 255 ? 16 : 1;
30 0 0       0 state $fmt = $max == 255 ? 'r%ug%ub%u' : 'rgb%u%u%u';
31 0 0       0  
32 0 0       0 return $color_for{$str} //= do {
33             my @rgb = map { $_ % $max } unpack 'CCC', md5($str);
34 0   0     0  
35 0         0 my $i = ($rgb[0] + $rgb[1] + $rgb[2]) % 3;
  0         0  
36             while (1) {
37 0         0 last if $rgb[0] + $rgb[1] + $rgb[2] >= $min;
38 0         0  
39 0 0       0 my $next = $i++ % 3;
40              
41 0         0 $rgb[$next] = abs($max - $rgb[$next]);
42             }
43 0         0  
44             sprintf $fmt, @rgb;
45             }
46 0         0 }
47              
48             has logger => (
49             is => 'ro',
50             isa => 'Log::Dispatchouli',
51             init_arg => undef,
52             writer => '_set_logger',
53             lazy => 1,
54             builder => '_build_logger',
55             );
56              
57             my $self = shift;
58             my $enc = $self->term_enc;
59              
60 20     20   50 if ($enc && Encode::resolve_alias($enc)) {
61 20         602 my $layer = sprintf(":encoding(%s)", $enc);
62             binmode( STDOUT, $layer );
63 20 50 33     187 binmode( STDERR, $layer );
64 20         3105 }
65 3     3   19  
  3         6  
  3         24  
  20         356  
66 20         3511 my $logger = Log::Dispatchouli->new({
67             ident => 'Dist::Zilla',
68             to_stdout => 1,
69             log_pid => 0,
70             to_self => ($ENV{DZIL_TESTING} ? 1 : 0),
71             quiet_fatal => 'stdout',
72             });
73 20 50       1066  
74             my $use_color = $ENV{DZIL_COLOR} // -t *STDOUT;
75              
76             if ($use_color) {
77 20   33     169352 my $stdout = $logger->{dispatcher}->output('stdout');
78              
79 20 50       112 $stdout->add_callback(sub {
80 0         0 require Term::ANSIColor;
81             my $message = {@_}->{message};
82             return $message unless $message =~ s/\A\[([^\]]+)] //;
83 0     0   0 my $prefix = $1;
84 0         0 return sprintf "[%s] %s",
85 0 0       0 Term::ANSIColor::colored([ _str_color($prefix) ], $prefix),
86 0         0 $message;
87 0         0 });
88             }
89              
90 0         0 return $logger;
91             }
92              
93 20         757 has term_ui => (
94             is => 'ro',
95             isa => 'Object',
96             lazy => 1,
97             default => sub {
98             require Term::ReadLine;
99             require Term::UI;
100             Term::ReadLine->new('dzil')
101             },
102             );
103              
104             has term_enc => (
105             is => 'ro',
106             lazy => 1,
107             default => sub {
108             require Term::Encoding;
109             return Term::Encoding::get_encoding();
110             },
111             );
112              
113             my ($self, $prompt, $arg) = @_;
114             $arg ||= {};
115             my $default = $arg->{default};
116             my $check = $arg->{check};
117 0     0 0    
118 0   0       require Encode;
119 0           my $term_enc = $self->term_enc;
120 0            
121             my $encode = $term_enc
122 0           ? sub { Encode::encode($term_enc, shift, Encode::FB_CROAK()) }
123 0           : sub { shift };
124             my $decode = $term_enc
125             ? sub { Encode::decode($term_enc, shift, Encode::FB_CROAK()) }
126 0     0     : sub { shift };
127 0 0   0      
  0            
128             if ($arg->{noecho}) {
129 0     0     require Term::ReadKey;
130 0 0   0     Term::ReadKey::ReadMode('noecho');
  0            
131             }
132 0 0         my $input_bytes = $self->term_ui->get_reply(
133 0           prompt => $encode->($prompt),
134 0           allow => $check || sub { length $_[0] },
135             (defined $default
136             ? (default => $encode->($default))
137             : ()
138 0     0     ),
139 0 0 0       );
140             if ($arg->{noecho}) {
141             Term::ReadKey::ReadMode('normal');
142             # The \n ending user input disappears under noecho; this ensures
143             # the next output ends up on the next line.
144 0 0         print "\n";
145 0           }
146              
147             my $input = $decode->($input_bytes);
148 0           chomp $input;
149              
150             return $input;
151 0           }
152 0            
153             my ($self, $prompt, $arg) = @_;
154 0           $arg ||= {};
155             my $default = $arg->{default};
156              
157             if (! $self->_isa_tty) {
158 0     0 0   if (defined $default) {
159 0   0       return OneZero->coerce($default);
160 0           }
161              
162 0 0         $self->logger->log_fatal(
163 0 0         "want interactive input, but terminal doesn't appear interactive"
164 0           );
165             }
166              
167             my $input = $self->term_ui->ask_yn(
168 0           prompt => $prompt,
169             (defined $default ? (default => OneZero->coerce($default)) : ()),
170             );
171              
172 0 0         return $input;
173             }
174              
175             my $isa_tty = -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT));
176             return $isa_tty;
177 0           }
178              
179             my ($self, $prompt) = @_;
180             $prompt ||= 'press any key to continue';
181 0   0 0      
182 0           my $isa_tty = $self->_isa_tty;
183              
184             if ($isa_tty) {
185             local $| = 1;
186 0     0 0   print $prompt;
187 0   0        
188             require Term::ReadKey;
189 0           Term::ReadKey::ReadMode('cbreak');
190             Term::ReadKey::ReadKey(0);
191 0 0         Term::ReadKey::ReadMode('normal');
192 0           print "\n";
193 0           }
194             }
195 0            
196 0           with 'Dist::Zilla::Role::Chrome';
197 0            
198 0           __PACKAGE__->meta->make_immutable;
199 0           1;
200              
201              
202             =pod
203              
204             =encoding UTF-8
205              
206             =head1 NAME
207              
208             Dist::Zilla::Chrome::Term - chrome used for terminal-based interaction
209              
210             =head1 VERSION
211              
212             version 6.028
213              
214             =head1 OVERVIEW
215              
216             This class provides a L<Dist::Zilla::Chrome> implementation for use in a
217             terminal environment. It's the default chrome used by L<Dist::Zilla::App>.
218              
219             =head1 PERL VERSION
220              
221             This module should work on any version of perl still receiving updates from
222             the Perl 5 Porters. This means it should work on any version of perl released
223             in the last two to three years. (That is, if the most recently released
224             version is v5.40, then this module should work on both v5.40 and v5.38.)
225              
226             Although it may work on older versions of perl, no guarantee is made that the
227             minimum required version will not be increased. The version may be increased
228             for any reason, and there is no promise that patches will be accepted to lower
229             the minimum required perl.
230              
231             =head1 AUTHOR
232              
233             Ricardo SIGNES 😏 <cpan@semiotic.systems>
234              
235             =head1 COPYRIGHT AND LICENSE
236              
237             This software is copyright (c) 2022 by Ricardo SIGNES.
238              
239             This is free software; you can redistribute it and/or modify it under
240             the same terms as the Perl 5 programming language system itself.
241              
242             =cut