#!/usr/bin/env perl
# progress - summarize line-based stdout to one dynamic progress line
use feature qw(state);
use warnings;
use strict;
use Getopt::Long qw(:config bundling no_ignore_case);
use POSIX qw(ceil);
use Time::HiRes qw(time);

if (eval {require Text::CharWidth}) {
	Text::CharWidth->import("mbswidth");
} else {
	sub mbswidth { length shift; }
}

my ($terse, $things, $width, $count, $last);

sub ttywidth {
	int(`stty size </dev/tty | awk '{print \$2}'`);
}

sub status {
	state $last_lines = 0;
	my ($raw_msg, $fmt_msg, $fmt) = @_;
	my $out = "";
	$out .= "\e[".($last_lines-1)."A" if $last_lines > 1; # cursor up
	$out .= "\e[1G"; # cursor to column 1
	$out .= "\e[0J"; # erase below
	$out .= sprintf($fmt // "%s", $fmt_msg // $raw_msg);
	$last_lines = ceil(mbswidth($raw_msg) / $width);
	print $out;
}

$| = 1;

$terse = 0;
$things = "items";
$width = ttywidth();
$count = 0;
$last = time;

GetOptions(
	"l|label=s" => \$things,
	"q|terse!" => \$terse,
);

$SIG{INT} = sub {
	status("$count $things (interrupted)", undef, "%s\n");
	exit 1;
};

$SIG{WINCH} = sub {
	$width = ttywidth();
};

while (++$count, my $str = <STDIN>) {
	my ($now, $pre);

	$now = time;
	next if $now - $last < 0.1;
	$last = $now;

	if ($terse) {
		status("$count $things", "\e[33m$count\e[m $things");
	} else {
		chomp($str);
		status("$count $str", "\e[33m$count\e[m $str");
	}
}

status("$count $things", undef, "%s\n");
