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