File Coverage

blib/lib/ByteBeat/Shell.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package ByteBeat::Shell;
2 1     1   1215 use Mo;
  1         1  
  1         5  
3              
4 1     1   282 use Curses();
  0            
  0            
5             use Term::ReadKey;
6             use IPC::Run();
7             use Time::HiRes;
8              
9             my ($y, $x) = (0, 0);
10             my $byte = [{pos => 0, play => 0, start => 0}];
11             my $beat = [[]];
12             my $curr = 0;
13             my $bytes = '';
14             my $t = 1;
15             my $out;
16             my $err;
17              
18             sub run {
19             my ($self) = @_;
20             $self->init;
21              
22             my $key = '';
23             while(1) {
24             defined($key = ReadKey) || next;
25             last if $key eq 'Q';
26             if ($key =~ m{[-+*/<>^|&t 0-9]}) {
27             $self->insert($key);
28             }
29             elsif (ord($key) == 127) {
30             $self->delete;
31             }
32             elsif (ord($key) == 13) {
33             $self->play_pause;
34             }
35             elsif (ord($key) == 27) {
36             if (ord(ReadKey || next) == 91) {
37             my $arrow = ord(ReadKey);
38             if ($arrow == 67) {
39             $self->right;
40             }
41             elsif ($arrow == 68) {
42             $self->left;
43             }
44             }
45             }
46             else {
47             $self->insert(ord($key) . " ");
48             }
49             $self->draw;
50             }
51             $self->destroy;
52             }
53              
54             sub play_pause {
55             my ($self) = @_;
56             my $info = $byte->[$curr];
57             if ($info->{play}) {
58             IPC::Run::kill_kill($info->{play}{process});
59             $info->{play} = 0;
60             }
61             else {
62             $self->start;
63             }
64             }
65              
66             sub start {
67             my ($self) = @_;
68             my $info = $byte->[$curr];
69             my $expr = join '', @{$beat->[$curr]};
70              
71             my $function = eval {
72             ByteBeat::Compiler->new(code => $expr)->compile;
73             };
74             return 0 if $@;
75              
76             my $process = IPC::Run::start(
77             ['bytebeat', $expr, '-p'], \$bytes, \$out, \$err,
78             );
79             $info->{play} = {process => $process, function => $function};
80             }
81              
82             sub insert {
83             my ($self, $key) = @_;
84             my $info = $byte->[$curr];
85             my $expr = $beat->[$curr];
86             splice @$expr, $info->{pos}++, 0, $key;
87             }
88              
89             sub delete {
90             my ($self) = @_;
91             my $info = $byte->[$curr];
92             my $expr = $beat->[$curr];
93             return unless $info->{pos} > 0;
94             splice @$expr, --$info->{pos}, 1;
95             }
96              
97             sub left {
98             my ($self) = @_;
99             my $info = $byte->[$curr];
100             $info->{pos}-- if $info->{pos} > 0;
101             }
102              
103             sub right {
104             my ($self) = @_;
105             my $info = $byte->[$curr];
106             my $expr = $beat->[$curr];
107             $info->{pos}++ if $info->{pos} < @$expr;
108             }
109              
110             sub draw {
111             my ($self) = @_;
112             my $info = $byte->[$curr];
113             my $pos = $info->{pos};
114              
115             $self->to;
116             $self->out("ByteBeat: p:play/pause Q:quit");
117             $self->to(1);
118             $self->out("Curr: $curr; Pos: $pos");
119              
120             for (my $i = 0; $i < @$beat; $i++) {
121             $self->to(1);
122             Curses::clrtoeol;
123             $self->out(join '', @{$beat->[$i]});
124             }
125              
126             $self->set_cursor;
127             Curses::refresh();
128             }
129              
130             sub set_cursor {
131             my ($self) = @_;
132             my $info = $byte->[$curr];
133             $self->to;
134             $self->to($curr + 2, $info->{pos});
135             }
136              
137             sub init {
138             my ($self) = @_;
139             Curses::initscr();
140             ReadMode(3);
141             $self->draw;
142             }
143              
144             sub destroy {
145             my ($self) = @_;
146             ReadMode(0);
147             Curses::endwin();
148             }
149              
150             sub out {
151             my ($self, $text, $yy, $xx) = @_;
152             if (defined $yy) {
153             $xx ||= 0;
154             Curses::addstr($yy, $xx, $text);
155             }
156             else {
157             Curses::addstr($y, $x, $text);
158             $self->to(0, length($text));
159             }
160             }
161              
162             sub to {
163             my ($self, $yy, $xx) = @_;
164             $y = defined($yy) ? $y + $yy : 0;
165             $x = defined($xx) ? $x + $xx : 0;
166             Curses::move($y, $x);
167             }
168              
169             1;