File Coverage

blib/lib/App/optex/scroll.pm
Criterion Covered Total %
statement 39 94 41.4
branch 1 40 2.5
condition 0 9 0.0
subroutine 15 25 60.0
pod 0 8 0.0
total 55 176 31.2


line stmt bran cond sub pod time code
1             package App::optex::scroll;
2 1     1   333522 use 5.024;
  1         3  
3 1     1   4 use warnings;
  1         1  
  1         69  
4              
5 1     1   5 use Carp;
  1         2  
  1         112  
6 1     1   579 use Data::Dumper;
  1         7074  
  1         87  
7 1     1   668 use IO::Handle;
  1         6322  
  1         60  
8 1     1   705 use Term::ReadKey;
  1         2552  
  1         201  
9 1     1   654 use Term::ANSIColor::Concise qw(:all);
  1         68882  
  1         231  
10 1     1   12 use List::Util qw(first pairmap);
  1         2  
  1         93  
11 1     1   5 use Scalar::Util;
  1         2  
  1         91  
12             *is_number = \&Scalar::Util::looks_like_number;
13              
14             our $VERSION = "0.9902";
15              
16 1     1   645 use App::optex::util::filter qw(interval);
  1         92524  
  1         854  
17              
18             my %opt = (
19             line => 10,
20             wait => \(our $wait = 1),
21             debug => \(our $debug = undef),
22             timeout => \(our $timeout = 0.1),
23             interval => 0,
24             );
25              
26             sub hash_to_spec {
27             pairmap {
28 0     0   0 $a = "$a|${\(uc(substr($a, 0, 1)))}";
  0         0  
29 0         0 my $ref = ref $b;
30 0 0       0 if (not defined $b) { "$a!" }
  0 0       0  
    0          
31 0         0 elsif ($ref eq 'SCALAR') { "$a!" }
32 0         0 elsif (is_number($b)) { "$a=i" }
33 0         0 else { "$a=s" }
34 0     0 0 0 } shift->%*;
35             }
36              
37             sub flush {
38 1     1 0 58 STDERR->printflush(@_);
39             }
40              
41             sub set_region {
42 1     1 0 38 flush join('',
43             csi_code('DECSC'),
44             csi_code('STBM', @_),
45             csi_code('DECRC'));
46             }
47              
48             END {
49 1 50   1   2601 close STDOUT if $wait;
50 1         7 set_region();
51             }
52              
53             sub finalize {
54 0     0 0   our($mod, $argv) = @_;
55             #
56             # private option handling
57             #
58 0 0 0       if (@$argv and $argv->[0] !~ /^-M/ and
      0        
59 0     0     defined(my $i = first { $argv->[$_] eq '--' } keys @$argv)) {
60 0           splice @$argv, $i, 1; # remove '--'
61 0 0         if (local @ARGV = splice @$argv, 0, $i) {
62 1     1   1195 use Getopt::Long qw(GetOptionsFromArray);
  1         18748  
  1         13  
63 0           Getopt::Long::Configure qw(bundling);
64 0 0         GetOptions \%opt, hash_to_spec \%opt or die "Option parse error.\n";
65             }
66             }
67 0     0     my $i = first { $argv->[$_] eq '--' } keys @$argv;
  0            
68 0 0 0       if (defined $i and $argv->[0] !~ /^-M/) {
69 0           splice @$argv, $i, 1; # remove '--'
70 0 0         if (local @ARGV = splice @$argv, 0, $i) {
71 1     1   522 use Getopt::Long qw(GetOptionsFromArray);
  1         4  
  1         7  
72 0           Getopt::Long::Configure qw(bundling);
73 0 0         GetOptions \%opt, hash_to_spec \%opt or die "Option parse error.\n";
74             }
75             }
76              
77 0           my $region = $opt{line};
78 0           flush "\n" x $region;
79 0           flush csi_code(CPL => $region); # CPL: Cursor Previous Line
80 0 0         my($l, $c) = cursor_position() or return;
81 0           set_region($l, $l + $region);
82              
83 0 0         if (my $time = $opt{interval}) {
84 0           interval(time => $time);
85             }
86             }
87              
88             sub cursor_position {
89 0     0 0   my $answer = ask(csi_code(DSR => 6), qr/R\z/); # DSR: Device Status Report
90 0           csi_report(CPR => 2, $answer); # CPR: Cursor Position Report
91             }
92              
93             sub uncntrl {
94 0     0 0   $_[0] =~ s/([^\040-\176])/sprintf "\\%03o", ord $1/gear;
  0            
95             }
96              
97             sub ask {
98 0     0 0   my($request, $end_re) = @_;
99 0 0         if ($debug) {
100 0           flush sprintf "[%s] Request: %s\n",
101             __PACKAGE__,
102             uncntrl $request;
103             }
104 0 0         open my $tty, "+<", "/dev/tty" or return;
105 0           ReadMode "cbreak", $tty;
106 0           $tty->printflush($request);
107 0           my $answer = '';
108 0           while (defined (my $key = ReadKey $timeout, $tty)) {
109 0 0         if ($debug) {
110 0 0         flush sprintf "[%s] ReadKey: \"%s\"\n",
111             __PACKAGE__,
112             $key =~ /\P{Cc}/ ? $key : uncntrl $key;
113             }
114 0           $answer .= $key;
115 0 0         last if $answer =~ /$end_re/;
116             }
117 0           ReadMode "restore", $tty;
118 0 0         if ($debug) {
119 0           flush sprintf "[%s] Answer: %s\n",
120             __PACKAGE__,
121             uncntrl $answer;
122             }
123 0           return $answer;
124             }
125              
126             sub set {
127             pairmap {
128 0 0   0     if (ref $opt{$a} eq 'SCALAR') {
    0          
129 0           $opt{$a}->$* = $b;
130             }
131             elsif (ref $opt{$a} eq 'ARRAY') {
132 0           push $opt{$a}->@*, $b;
133             }
134             else {
135 0           $opt{$a} = $b;
136             }
137 0     0 0   } @_;
138             }
139              
140             1;
141              
142             __END__