#!perl
our
$DATE
=
'2019-07-06'
;
our
$VERSION
=
'0.041'
;
use
5.010001;
use
Getopt::Long
qw(:config gnu_getopt no_ignore_case auto_version)
;
my
%opts
= (
update_delay
=> 0.02,
banner_size
=> 0,
start_stopped
=> 0,
start_at
=> 0,
);
Getopt::Long::Configure(
"bundling"
);
GetOptions(
'update-delay|d=f'
=> \
$opts
{update_delay},
'banner-size|b=i'
=> \
$opts
{banner_size},
'start-stopped|S'
=> \
$opts
{start_stopped},
'start-at|s=f'
=> \
$opts
{start_at},
'help|h|?'
=>
sub
{
print
<<'_';
Usage:
stopw [options]
Options:
--banner-size=i (-b). Set 1-5 print large ASCII-art letters.
--start-at=f (-s). Start timer at particular time in seconds.
--start-stopped, -S. Start in stopped state.
--update-delay=f (-d). Defaults to 0.02.
For more details, see manpage.
_
exit
0;
},
'version|v'
=>
sub
{
no
warnings
'once'
;
say
"stopw version "
.(${__PACKAGE__.
"::VERSION"
} //
"dev"
);
exit
0;
},
);
sub
read_key {
my
$self
=
shift
;
state
@keys
;
if
(
@keys
) {
return
shift
@keys
;
}
my
$char
;
my
$packet
=
''
;
while
(
defined
(
$char
= ReadKey -1)) {
$packet
.=
$char
;
}
while
(
$packet
=~ m(
\G(
\e \[
[\x30-\x3f]*
[\x20-\x2f]*
[\x40-\x7e]
|
.
)
)gsx) {
push
@keys
, $1;
}
return
shift
@keys
;
}
$|++;
ReadMode
"cbreak"
;
my
$now
=
time
();
my
$time0
=
$now
-
$opts
{start_at};
my
$time
=
$now
;
my
$stop_time
=
$now
;
my
$stopped
=
$opts
{start_stopped};
if
(
$opts
{banner_size} > 0) {
$opts
{update_delay} = 1;
}
TIMER:
while
(1) {
my
$str
;
my
$size
;
while
(
defined
(
my
$key
= read_key())) {
if
(
$key
eq
'q'
||
$key
eq
'Q'
) {
if
(
$opts
{banner_size} > 0) {
if
(
$str
) {
for
(1..
$size
->[1]) {
print
"\n"
}
}
}
else
{
print
"\n"
;
}
last
TIMER;
}
elsif
(
$key
eq
' '
||
$key
eq
'r'
||
$key
eq
'R'
) {
print
"\n"
unless
$opts
{banner_size} > 0;
}
elsif
(
$key
eq
'z'
||
$key
eq
'Z'
) {
$time0
=
time
();
$time
=
$time0
if
$stopped
;
$stop_time
=
$time0
if
$stopped
;
}
elsif
(
$key
eq
"\n"
||
$key
eq
's'
||
$key
eq
'S'
) {
$stopped
= !
$stopped
;
$stop_time
=
time
()
if
$stopped
;
$time0
+= (
time
()-
$stop_time
)
if
!
$stopped
;
}
}
{
$time
=
time
()
unless
$stopped
;
my
$elapsed
=
$time
-
$time0
;
my
$hours
=
int
(
$elapsed
/3600);
my
$minutes
=
int
((
$elapsed
-
$hours
*3600)/60);
my
$seconds
=
int
(
$elapsed
-
$hours
*3600-
$minutes
*60);
my
$millis
=
int
((
$elapsed
-
$hours
*3600-
$minutes
*60-
$seconds
)*1000);
if
(
$opts
{banner_size} > 0) {
my
$str2
=
sprintf
(
"%02d:%02d"
,
$minutes
,
$seconds
);
my
$ban
= Text::Banner->new;
$ban
->set(
$str2
);
$ban
->size(
$opts
{banner_size});
$ban
->fill(
'*'
);
$str
=
$ban
->get;
print
$str
;
sleep
$opts
{update_delay};
$size
= Text::NonWideChar::Util::length_height(
$str
);
print
"\x08"
x
$size
->[0];
printf
"\e[%dA"
, (
$size
->[1]-1);
}
else
{
$str
=
sprintf
(
"%02d:%02d:%02d.%03d "
,
$hours
,
$minutes
,
$seconds
,
$millis
);
print
$str
;
sleep
$opts
{update_delay};
print
"\x08"
x
length
(
$str
);
}
}
}
ReadMode
"normal"
;