t: report missing output as TODO
[barcat.git] / barcat
diff --git a/barcat b/barcat
index 5863c4c952b527438ef29accfc93b9681de71272..1818493a8af4603898a2e4b7f1265c6bcfda948d 100755 (executable)
--- a/barcat
+++ b/barcat
@@ -1,4 +1,4 @@
-#!/usr/bin/env perl
+#!/usr/bin/perl -CA
 use 5.018;
 use warnings;
 use utf8;
 use 5.018;
 use warnings;
 use utf8;
@@ -6,13 +6,9 @@ use List::Util qw( min max sum );
 use open qw( :std :utf8 );
 use experimental qw( lexical_subs );
 
 use open qw( :std :utf8 );
 use experimental qw( lexical_subs );
 
-our $VERSION = '1.04';
+our $VERSION = '1.05';
 
 use Getopt::Long '2.33', qw( :config gnu_getopt );
 
 use Getopt::Long '2.33', qw( :config gnu_getopt );
-sub podexit {
-       require Pod::Usage;
-       Pod::Usage::pod2usage(-exitval => 0, -perldocopt => '-oman', @_);
-}
 my %opt;
 GetOptions(\%opt,
        'color|c!',
 my %opt;
 GetOptions(\%opt,
        'color|c!',
@@ -47,11 +43,34 @@ GetOptions(\%opt,
                );
        },
        'markers|m=s',
                );
        },
        'markers|m=s',
+       'spark:s' => sub {
+               $opt{spark} = [split //, $_[1] || '⎽▁▂▃▄▅▆▇█'];
+       },
        'stat|s!',
        'unmodified|u!',
        'width|w=i',
        'stat|s!',
        'unmodified|u!',
        'width|w=i',
-       'usage|h' => sub { podexit() },
-       'help'    => sub { podexit(-verbose => 2) },
+       'usage|h' => sub {
+               local $/;
+               my $pod = readline *DATA;
+               $pod =~ s/^=over\K/ 22/m;  # indent options list
+               $pod =~ s/^=item \N*\n\n\N*\n\K(?:(?:^=over.*?^=back\n)?(?!=)\N*\n)*/\n/msg;
+
+               require Pod::Usage;
+               my $parser = Pod::Usage->new;
+               $parser->select('SYNOPSIS', 'OPTIONS');
+               $parser->output_string(\my $contents);
+               $parser->parse_string_document($pod);
+
+               $contents =~ s/\n(?=\n\h)//msg;  # strip space between items
+               print $contents;
+               exit;
+       },
+       'help|?'  => sub {
+               require Pod::Usage;
+               Pod::Usage::pod2usage(
+                       -exitval => 0, -perldocopt => '-oman', -verbose => 2,
+               );
+       },
 ) or exit 64;  # EX_USAGE
 
 $opt{width} ||= $ENV{COLUMNS} || 80;
 ) or exit 64;  # EX_USAGE
 
 $opt{width} ||= $ENV{COLUMNS} || 80;
@@ -60,6 +79,7 @@ $opt{trim}   *= $opt{width} / 100 if $opt{trimpct};
 $opt{units}   = [split //, ' kMGTPEZYyzafpnμm'] if $opt{'human-readable'};
 $opt{anchor} //= qr/\A/;
 $opt{'value-length'} = 6 if $opt{units};
 $opt{units}   = [split //, ' kMGTPEZYyzafpnμm'] if $opt{'human-readable'};
 $opt{anchor} //= qr/\A/;
 $opt{'value-length'} = 6 if $opt{units};
+$opt{'value-length'} = 1 if $opt{unmodified};
 
 my (@lines, @values, @order);
 
 
 my (@lines, @values, @order);
 
@@ -90,8 +110,9 @@ while (readline) {
        push @order, $1 if length $1;
        if (defined $opt{trim} and defined $1) {
                my $trimpos = abs $opt{trim};
        push @order, $1 if length $1;
        if (defined $opt{trim} and defined $1) {
                my $trimpos = abs $opt{trim};
+               $trimpos -= length $1 if $opt{unmodified};
                if ($trimpos <= 1) {
                if ($trimpos <= 1) {
-                       $_ = substr $_, 0, 1;
+                       $_ = substr $_, 0, 2;
                }
                elsif (length > $trimpos) {
                        substr($_, $trimpos - 1) = '…';
                }
                elsif (length > $trimpos) {
                        substr($_, $trimpos - 1) = '…';
@@ -164,6 +185,12 @@ sub sival {
 while ($nr <= $#lines) {
        $nr >= $opt{hidemax} and last if defined $opt{hidemax};
        my $val = $values[$nr];
 while ($nr <= $#lines) {
        $nr >= $opt{hidemax} and last if defined $opt{hidemax};
        my $val = $values[$nr];
+
+       if ($opt{spark}) {
+               print $opt{spark}->[ ($val - $minval) / $maxval * $#{$opt{spark}} ];
+               next;
+       }
+
        if (length $val) {
                my $color = !$opt{color} ? undef :
                        $val == $order[0] ? 32 : # max
        if (length $val) {
                my $color = !$opt{color} ? undef :
                        $val == $order[0] ? 32 : # max
@@ -176,9 +203,11 @@ while ($nr <= $#lines) {
        printf '%-*s', $len + length($val), $line;
        print $barmark[$_] // '-' for 1 .. $size && (($values[$nr] || 0) - $minval) * $size + .5;
        say '';
        printf '%-*s', $len + length($val), $line;
        print $barmark[$_] // '-' for 1 .. $size && (($values[$nr] || 0) - $minval) * $size + .5;
        say '';
-
+}
+continue {
        $nr++;
 }
        $nr++;
 }
+say '' if $opt{spark};
 
 }
 show_lines();
 
 }
 show_lines();
@@ -191,10 +220,13 @@ if ($opt{stat}) {
        }
        if (@order) {
                my $total = sum @order;
        }
        if (@order) {
                my $total = sum @order;
-               printf '%s total', $total;
+               printf '%s total', color(1) . $total . color(0);
                printf ' in %d values', scalar @values;
                printf ' in %d values', scalar @values;
-               printf ' (%s min, %*.*f avg, %s max)',
-                       $order[-1], 0, 2, $total / @order, $order[0];
+               printf(' (%s min, %s avg, %s max)',
+                       color(31) . $order[-1] . color(0),
+                       color(36) . (sprintf '%*.*f', 0, 2, $total / @order) . color(0),
+                       color(32) . $order[0] . color(0),
+               );
        }
        say '';
 }
        }
        say '';
 }
@@ -216,6 +248,12 @@ Visualizes relative sizes of values read from input (file(s) or STDIN).
 Contents are concatenated similar to I<cat>,
 but numbers are reformatted and a bar graph is appended to each line.
 
 Contents are concatenated similar to I<cat>,
 but numbers are reformatted and a bar graph is appended to each line.
 
+Don't worry, barcat does not drink and divide.
+It can has various options for input and output (re)formatting,
+but remains limited to one-dimensional charts.
+For more complex graphing needs
+you'll need a larger animal like I<gnuplot>.
+
 =head1 OPTIONS
 
 =over
 =head1 OPTIONS
 
 =over
@@ -304,7 +342,7 @@ Total statistics after all data.
 
 =item -u, --unmodified
 
 
 =item -u, --unmodified
 
-Do not strip leading whitespace.
+Do not reformat values, keeping leading whitespace.
 Keep original value alignment, which may be significant in some programs.
 
 =item --value-length=<size>
 Keep original value alignment, which may be significant in some programs.
 
 =item --value-length=<size>
@@ -316,6 +354,19 @@ Reserved space for numbers.
 Override the maximum number of columns to use.
 Appended graphics will extend to fill up the entire screen.
 
 Override the maximum number of columns to use.
 Appended graphics will extend to fill up the entire screen.
 
+=item -h, --usage
+
+Overview of available options.
+
+=item --help
+
+Full documentation
+rendered by perldoc.
+
+=item --version
+
+Version information.
+
 =back
 
 =head1 EXAMPLES
 =back
 
 =head1 EXAMPLES
@@ -398,7 +449,7 @@ Activity of the last days (substitute date C<-v-{}d> on BSD):
 
     ( git log --pretty=%ci --since=30day | cut -b-10
       seq 0 30 | xargs -i date +%F -d-{}day ) |
 
     ( git log --pretty=%ci --since=30day | cut -b-10
       seq 0 30 | xargs -i date +%F -d-{}day ) |
-    sort | uniq -c | awk '$1--' | graph
+    sort | uniq -c | awk '$1--' | graph --spark
 
 =head1 AUTHOR
 
 
 =head1 AUTHOR