File Coverage

blib/lib/Pinto/Chrome/Term.pm
Criterion Covered Total %
statement 71 94 75.5
branch 27 60 45.0
condition 4 7 57.1
subroutine 17 19 89.4
pod 0 9 0.0
total 119 189 62.9


line stmt bran cond sub pod time code
1             # ABSTRACT: Interface for terminal-based interaction
2              
3             package Pinto::Chrome::Term;
4              
5 57     57   49202 use Moose;
  57         422278  
  57         441  
6 57     57   342514 use MooseX::StrictConstructor;
  57         29024  
  57         479  
7 57     57   173128 use MooseX::Types::Moose qw(Bool ArrayRef Str);
  57         52824  
  57         600  
8 57     57   276654 use MooseX::MarkAsMethods ( autoclean => 1 );
  57         10718  
  57         461  
9              
10 57     57   215873 use Term::ANSIColor;
  57         42034  
  57         4232  
11 57     57   20128 use File::Which qw(which);
  57         48381  
  57         2953  
12              
13 57     57   14374 use Pinto::Editor;
  57         226  
  57         2200  
14 57     57   2905 use Pinto::Types qw(Io ANSIColorPalette);
  57         143  
  57         548  
15 57     57   346212 use Pinto::Util qw(user_palette itis throw is_interactive);
  57         148  
  57         55320  
16              
17             #-----------------------------------------------------------------------------
18              
19             our $VERSION = '0.13'; # VERSION
20              
21             #-----------------------------------------------------------------------------
22              
23             extends qw( Pinto::Chrome );
24              
25             #-----------------------------------------------------------------------------
26              
27             has color => (
28             is => 'ro',
29             isa => Bool,
30             default => sub { !$ENV{PINTO_NO_COLOR} },
31             );
32              
33             has palette => (
34             is => 'ro',
35             isa => ANSIColorPalette,
36             default => sub { user_palette() },
37             lazy => 1,
38             );
39              
40             has stdout => (
41             is => 'ro',
42             isa => Io,
43             builder => '_build_stdout',
44             coerce => 1,
45             lazy => 1,
46             );
47              
48             has stderr => (
49             is => 'ro',
50             isa => Io,
51             default => sub { [ fileno(*STDERR), '>' ] },
52             coerce => 1,
53             lazy => 1,
54             );
55              
56             has has_made_progress => (
57             is => 'rw',
58             isa => Bool,
59             default => 0,
60             );
61              
62             #-----------------------------------------------------------------------------
63              
64             sub _build_stdout {
65 0     0   0 my ($self) = @_;
66              
67 0   0     0 my $pager = $ENV{PINTO_PAGER} || $ENV{PAGER};
68 0         0 my $stdout = [ fileno(*STDOUT), '>' ];
69              
70 0 0       0 return $stdout if not -t STDOUT;
71 0 0       0 return $stdout if not $pager;
72              
73             my @pager_options = $ENV{PINTO_PAGER_OPTIONS} ?
74 0 0       0 ( $ENV{PINTO_PAGER_OPTIONS} ) : ();
75              
76 0 0       0 open my $pager_fh, q<|->, $pager, @pager_options
77             or throw "Failed to open pipe to pager $pager: $!";
78              
79              
80 0         0 my $io = bless $pager_fh, 'IO::Handle'; # HACK!
81 0         0 $io->autoflush(1);
82              
83 0         0 return $io;
84             }
85              
86             #------------------------------------------------------------------------------
87              
88             sub show {
89 34     34 0 505 my ( $self, $msg, $opts ) = @_;
90              
91 34   100     120 $opts ||= {};
92              
93 34         162 $msg = $self->colorize( $msg, $opts->{color} );
94              
95 34 100       147 $msg .= "\n" unless $opts->{no_newline};
96              
97 34 50       61 print { $self->stdout } $msg or croak $!;
  34         764  
98              
99 34         1388 return $self;
100             }
101              
102             #-----------------------------------------------------------------------------
103              
104             sub diag {
105 518     518 0 2262 my ( $self, $msg, $opts ) = @_;
106              
107 518   100     3707 $opts ||= {};
108              
109 518 50       11816 return if $self->quiet;
110              
111 518 50       2269 $msg = $msg->() if ref $msg eq 'CODE';
112              
113 518 100       3261 if ( itis( $msg, 'Pinto::Exception' ) ) {
114              
115             # Show full stack trace if we are debugging
116 42 50       498 $msg = $ENV{PINTO_DEBUG} ? $msg->as_string : $msg->message;
117             }
118              
119 518         1877 chomp $msg;
120 518         16506 $msg = $self->colorize( $msg, $opts->{color} );
121 518 50       2708 $msg .= "\n" unless $opts->{no_newline};
122              
123 518 50       1107 print { $self->stderr } $msg or croak $!;
  518         14969  
124             }
125              
126             #-----------------------------------------------------------------------------
127              
128             sub show_progress {
129 70     70 0 306 my ($self) = @_;
130              
131 70 50       468 return if not $self->should_render_progress;
132              
133 0         0 $self->stderr->autoflush; # Make sure pipes are hot
134              
135 0 0       0 print { $self->stderr } '.' or croak $!;
  0         0  
136              
137 0         0 $self->has_made_progress(1);
138             }
139              
140             #-----------------------------------------------------------------------------
141              
142             sub progress_done {
143 141     141 0 523 my ($self) = @_;
144              
145 141 50       4332 return unless $self->has_made_progress;
146 0 0       0 return unless $self->should_render_progress;
147              
148 0 0       0 print { $self->stderr } "\n" or croak $!;
  0         0  
149             }
150              
151             #-----------------------------------------------------------------------------
152              
153             sub should_render_progress {
154 73     73 0 258 my ($self) = @_;
155              
156 73 100       2575 return 0 if $self->verbose;
157 2 100       40 return 0 if $self->quiet;
158 1 50       6 return 0 if not is_interactive;
159 0         0 return 1;
160             }
161              
162             #-----------------------------------------------------------------------------
163              
164             sub edit {
165 0     0 0 0 my ( $self, $document ) = @_;
166              
167 0 0       0 local $ENV{VISUAL} = $self->find_editor
168             or throw 'Unable to find an editor. Please set PINTO_EDITOR';
169              
170             # If this command is reading input from a pipe or file, then
171             # STDIN will not be connected to a terminal. This causes vim
172             # and emacs to behave oddly (or even segfault). After searching
173             # the internets, this seems to a portable way to reconnect STDIN
174             # to the actual terminal. I haven't actually tried it on Windows.
175             # I'm not sure if/how I should be localizing STDIN here.
176              
177 0 0       0 my $term = ( $^O eq 'MSWin32' ) ? 'CON' : '/dev/tty';
178 0 0       0 open( STDIN, '<', $term ) or throw $!;
179              
180 0         0 return Pinto::Editor->edit( document => $document );
181             }
182              
183             #-----------------------------------------------------------------------------
184              
185             sub colorize {
186 557     557 0 2475 my ( $self, $string, $color_number ) = @_;
187              
188 557 50       2336 return '' if not $string;
189 557 100       2536 return $string if not defined $color_number;
190 95 100       2723 return $string if not $self->color;
191              
192 5         134 my $color = $self->get_color($color_number);
193              
194 5         188 return $color . $string . Term::ANSIColor::color('reset');
195             }
196              
197             #-----------------------------------------------------------------------------
198              
199             sub get_color {
200 5     5 0 29 my ( $self, $color_number ) = @_;
201              
202 5 50       19 return '' if not defined $color_number;
203              
204 5         200 my $color = $self->palette->[$color_number];
205              
206 5 50       28 throw "Invalid color number: $color_number" if not defined $color;
207              
208 5         51 return Term::ANSIColor::color($color);
209             }
210              
211             #-----------------------------------------------------------------------------
212              
213             sub find_editor {
214 4     4 0 26 my ($self) = @_;
215              
216             # Try unsing environment variables first
217 4         11 for my $env_var (qw(PINTO_EDITOR VISUAL EDITOR)) {
218 9 100       32 return $ENV{$env_var} if $ENV{$env_var};
219             }
220              
221             # Then try typical editor commands
222 1         3 for my $cmd (qw(nano pico vi)) {
223 3         9 my $found_cmd = which($cmd);
224 3 50       87 return $found_cmd if $found_cmd;
225             }
226              
227 1         4 return;
228             }
229              
230             #-----------------------------------------------------------------------------
231              
232             my %color_map = ( warning => 1, error => 2 );
233             while ( my ( $level, $color ) = each %color_map ) {
234             around $level => sub {
235             my ( $orig, $self, $msg, $opts ) = @_;
236             $opts ||= {};
237             $opts->{color} = $color;
238             return $self->$orig( $msg, $opts );
239             };
240             }
241              
242             #-----------------------------------------------------------------------------
243              
244             __PACKAGE__->meta->make_immutable;
245              
246             #-----------------------------------------------------------------------------
247             1;
248              
249             __END__
250              
251             =pod
252              
253             =encoding UTF-8
254              
255             =for :stopwords Jeffrey Ryan Thalhammer
256              
257             =head1 NAME
258              
259             Pinto::Chrome::Term - Interface for terminal-based interaction
260              
261             =head1 VERSION
262              
263             version 0.13
264              
265             =head1 AUTHOR
266              
267             Jeffrey Ryan Thalhammer <jeff@stratopan.com>
268              
269             =head1 COPYRIGHT AND LICENSE
270              
271             This software is copyright (c) 2015 by Jeffrey Ryan Thalhammer.
272              
273             This is free software; you can redistribute it and/or modify it under
274             the same terms as the Perl 5 programming language system itself.
275              
276             =cut