git.shiar.nl
/
barcat.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
strip pipe arguments from test options
[barcat.git]
/
barcat
diff --git
a/barcat
b/barcat
index 0d843c13e177580776d2b81e4556f38961c0b4e7..d4a8274f6c9af8015332215138b8d46c3158a30d 100755
(executable)
--- a/
barcat
+++ b/
barcat
@@
-4,8
+4,9
@@
use warnings;
use utf8;
use List::Util qw( min max sum );
use open qw( :std :utf8 );
use utf8;
use List::Util qw( min max sum );
use open qw( :std :utf8 );
+use re '/msx';
-our $VERSION = '1.0
6
';
+our $VERSION = '1.0
7
';
use Getopt::Long '2.33', qw( :config gnu_getopt );
my %opt;
use Getopt::Long '2.33', qw( :config gnu_getopt );
my %opt;
@@
-15,15
+16,15
@@
GetOptions(\%opt,
'field|f=s' => sub {
eval {
local $_ = $_[1];
'field|f=s' => sub {
eval {
local $_ = $_[1];
- $opt{anchor} = /
^[0-9]+$
/ ? qr/(?:\S*\h+){$_}\K/ : qr/$_/;
- } or die $@ =~ s/(?:
at .+)?$
/ for option $_[0]/r;
+ $opt{anchor} = /
\A[0-9]+\z
/ ? qr/(?:\S*\h+){$_}\K/ : qr/$_/;
+ } or die $@ =~ s/(?:
\ at\ \N+)?\Z
/ for option $_[0]/r;
},
'human-readable|H!',
'interval|t:i',
'trim|length|l=s' => sub {
my ($optname, $optval) = @_;
$optval =~ s/%$// and $opt{trimpct}++;
},
'human-readable|H!',
'interval|t:i',
'trim|length|l=s' => sub {
my ($optname, $optval) = @_;
$optval =~ s/%$// and $opt{trimpct}++;
- $optval =~ m/
^-?[0-9]+$
/ or die(
+ $optval =~ m/
\A-?[0-9]+\z
/ or die(
"Value \"$optval\" invalid for option $optname",
" (number or percentage expected)\n"
);
"Value \"$optval\" invalid for option $optname",
" (number or percentage expected)\n"
);
@@
-38,7
+39,7
@@
GetOptions(\%opt,
my ($optname, $optval) = @_;
$optval ||= 0;
($opt{hidemin}, $opt{hidemax}) =
my ($optname, $optval) = @_;
$optval ||= 0;
($opt{hidemin}, $opt{hidemax}) =
- $optval =~ m/\A (?: ([0-9]+)? - )? ([0-9]+)? \z/
x
or die(
+ $optval =~ m/\A (?: ([0-9]+)? - )? ([0-9]+)? \z/ or die(
"Value \"$optval\" invalid for option limit",
" (range expected)\n"
);
"Value \"$optval\" invalid for option limit",
" (range expected)\n"
);
@@
-77,12
+78,12
@@
GetOptions(\%opt,
exit;
},
'usage|h' => sub {
exit;
},
'usage|h' => sub {
- local $/
;
+ local $/
= undef; # slurp
my $pod = readline *DATA;
my $pod = readline *DATA;
- $pod =~ s/^=over\K/ 25/
m
; # indent options list
- $pod =~ s/^=item
\N*\n\n\N*\n\K(?:(?:^=over.*?^=back\n)?(?!=)\N*\n)*/\n/ms
g;
+ $pod =~ s/^=over\K/ 25/; # indent options list
+ $pod =~ s/^=item
\ \N*\n\n\N*\n\K (?:(?:^=over.*?^=back\n)?(?!=)\N*\n)*/\n/
g;
$pod =~ s/[.,](?=\n)//g; # trailing punctuation
$pod =~ s/[.,](?=\n)//g; # trailing punctuation
- $pod =~ s/^=item
\K(?=--)/____/gm
; # align long options
+ $pod =~ s/^=item
\ \K(?=--)/____/g
; # align long options
# abbreviate <variable> indicators
$pod =~ s/\Q>.../s>/g;
$pod =~ s/<(?:number|count|seconds)>/N/g;
# abbreviate <variable> indicators
$pod =~ s/\Q>.../s>/g;
$pod =~ s/<(?:number|count|seconds)>/N/g;
@@
-99,7
+100,7
@@
GetOptions(\%opt,
$parser->parse_string_document($pod);
$contents =~ s/\n(?=\n\h)//msg; # strip space between items
$parser->parse_string_document($pod);
$contents =~ s/\n(?=\n\h)//msg; # strip space between items
- $contents =~ s/^
\K____/ /gm
; # nbsp substitute
+ $contents =~ s/^
\ \ \K____/ /g
; # nbsp substitute
print $contents;
exit;
},
print $contents;
exit;
},
@@
-123,7
+124,7
@@
$opt{'signal-stat'} //= exists $SIG{INFO} ? 'INFO' : 'QUIT';
$opt{markers} //= '=avg >31.73v <68.27v +50v |0';
$opt{palette} //= $opt{color} && [31, 90, 32];
$opt{hidemin} = ($opt{hidemin} || 1) - 1;
$opt{markers} //= '=avg >31.73v <68.27v +50v |0';
$opt{palette} //= $opt{color} && [31, 90, 32];
$opt{hidemin} = ($opt{hidemin} || 1) - 1;
-$opt{input} =
@ARGV && $ARGV[0] =~ m/\A[-0-9]/
? \@ARGV : undef
+$opt{input} =
(@ARGV && $ARGV[0] =~ m/\A[-0-9]/)
? \@ARGV : undef
and undef $opt{interval};
my (@lines, @values, @order);
and undef $opt{interval};
my (@lines, @values, @order);
@@
-146,20
+147,22
@@
if (defined $opt{interval}) {
}
my $valmatch = qr<
}
my $valmatch = qr<
- $opt{anchor} ( \h* -? [0-9]*
\.
? [0-9]+ (?: e[+-]?[0-9]+ )? |)
+ $opt{anchor} ( \h* -? [0-9]*
[.]
? [0-9]+ (?: e[+-]?[0-9]+ )? |)
>x;
while (defined ($_ = $opt{input} ? shift @{ $opt{input} } : readline)) {
s/\r?\n\z//;
>x;
while (defined ($_ = $opt{input} ? shift @{ $opt{input} } : readline)) {
s/\r?\n\z//;
- s/^\h*// unless $opt{unmodified};
- push @values, s/$valmatch/\n/ && $1;
- push @order, $1 if length $1;
- if (defined $opt{trim} and defined $1) {
+ s/\A\h*// unless $opt{unmodified};
+ my $valnum = s/$valmatch/\n/ && $1;
+ push @values, $valnum;
+ push @order, $valnum if length $valnum;
+ if (defined $opt{trim} and defined $valnum) {
my $trimpos = abs $opt{trim};
my $trimpos = abs $opt{trim};
- $trimpos -= length $
1
if $opt{unmodified};
+ $trimpos -= length $
valnum
if $opt{unmodified};
if ($trimpos <= 1) {
$_ = substr $_, 0, 2;
}
elsif (length > $trimpos) {
if ($trimpos <= 1) {
$_ = substr $_, 0, 2;
}
elsif (length > $trimpos) {
+ # cut and replace (intentional lvalue for speed, contrary to PBP)
substr($_, $trimpos - 1) = '…';
}
}
substr($_, $trimpos - 1) = '…';
}
}
@@
-182,8
+185,8
@@
sub color {
sub sival {
my $unit = int(log(abs $_[0] || 1) / log(10) - 3*($_[0] < 1) + 1e-15);
sub sival {
my $unit = int(log(abs $_[0] || 1) / log(10) - 3*($_[0] < 1) + 1e-15);
- my $float = $_[0] !~ /
^0*[-0-9]{1,3}$
/;
- sprintf('%3.*f%1s',
+ my $float = $_[0] !~ /
\A0*[-0-9]{1,3}\z
/;
+
return
sprintf('%3.*f%1s',
$float && ($unit % 3) == ($unit < 0), # tenths
$_[0] / 1000 ** int($unit/3), # number
$#{$opt{units}} * 1.5 < abs $unit ? "e$unit" : $opt{units}->[$unit/3]
$float && ($unit % 3) == ($unit < 0), # tenths
$_[0] / 1000 ** int($unit/3), # number
$#{$opt{units}} * 1.5 < abs $unit ? "e$unit" : $opt{units}->[$unit/3]
@@
-193,9
+196,8
@@
sub sival {
sub show_lines {
state $nr = $opt{hidemin};
sub show_lines {
state $nr = $opt{hidemin};
-@lines and @lines > $nr or return;
@lines or return;
@lines or return;
-@lines > $nr or return
unless $opt{hidemin}
;
+@lines > $nr or return;
@order = sort { $b <=> $a } @order unless tied @order;
my $maxval = $opt{maxval} // (
@order = sort { $b <=> $a } @order unless tied @order;
my $maxval = $opt{maxval} // (
@@
-208,7
+210,7
@@
my $lenval = $opt{'value-length'} // max map { length } @order;
my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
max map { length $values[$_] && length $lines[$_] }
0 .. min $#lines, $opt{hidemax} || (); # left padding
my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
max map { length $values[$_] && length $lines[$_] }
0 .. min $#lines, $opt{hidemax} || (); # left padding
-my $size = $range &&
+my $size =
defined $opt{width} &&
$range &&
($opt{width} - $lenval - $len) / $range; # bar multiplication
my @barmark;
($opt{width} - $lenval - $len) / $range; # bar multiplication
my @barmark;
@@
-220,13
+222,22
@@
if ($opt{markers} and $size > 0) {
return sum(@order) / @order;
}
elsif ($func =~ /\A([0-9.]+)v\z/) {
return sum(@order) / @order;
}
elsif ($func =~ /\A([0-9.]+)v\z/) {
+ die "Invalid marker $char: percentile $1 out of bounds\n" if $1 > 100;
my $index = $#order * $1 / 100;
return ($order[$index] + $order[$index + .5]) / 2;
}
my $index = $#order * $1 / 100;
return ($order[$index] + $order[$index + .5]) / 2;
}
- els
e
{
+ els
if ($func =~ /\A-?[0-9.]+\z/)
{
return $func;
}
return $func;
}
- } - $minval;
+ else {
+ die "Unknown marker $char: $func\n";
+ }
+ };
+ defined $pos or do {
+ warn $@ if $@;
+ next;
+ };
+ $pos -= $minval;
$pos >= 0 or next;
color(36) for $barmark[$pos * $size] = $char;
}
$pos >= 0 or next;
color(36) for $barmark[$pos * $size] = $char;
}
@@
-245,8
+256,6
@@
if ($opt{markers} and $size > 0) {
}
}
}
}
-@lines > $nr or return if $opt{hidemin};
-
say(
color(31), sprintf('%*s', $lenval, $minval),
color(90), '-', color(36), '+',
say(
color(31), sprintf('%*s', $lenval, $minval),
color(90), '-', color(36), '+',
@@
-267,7
+276,7
@@
while ($nr <= $#lines) {
if ($opt{spark}) {
say '' if $opt{width} and $nr and $nr % $opt{width} == 0;
print color($color), $opt{spark}->[
if ($opt{spark}) {
say '' if $opt{width} and $nr and $nr % $opt{width} == 0;
print color($color), $opt{spark}->[
- !$val ? 0 : # blank
+ !$val
|| !$#{$opt{spark}}
? 0 : # blank
$val == $order[0] ? -1 : # max
$val == $order[-1] ? 1 : # min
$#{$opt{spark}} < 3 ? 1 :
$val == $order[0] ? -1 : # max
$val == $order[-1] ? 1 : # min
$#{$opt{spark}} < 3 ? 1 :
@@
-291,6
+300,7
@@
continue {
}
say $opt{palette} ? color(0) : '' if $opt{spark};
}
say $opt{palette} ? color(0) : '' if $opt{spark};
+ return $nr;
}
sub show_stat {
}
sub show_stat {
@@
-311,6
+321,7
@@
sub show_stat {
);
}
say '';
);
}
say '';
+ return 1;
}
sub show_exit {
}
sub show_exit {
@@
-451,6
+462,11
@@
or alternatively I<1;30> for bright black.
In case of additional colors,
the last is used for values equal to the maximum, the first for minima.
If unspecified, these are green and red respectively (I<31 90 32>).
In case of additional colors,
the last is used for values equal to the maximum, the first for minima.
If unspecified, these are green and red respectively (I<31 90 32>).
+Multiple intermediate colors will be distributed
+relative to the size of values.
+
+Predefined color schemes are named I<whites> and I<fire>,
+or I<greys> and I<fire256> for 256-color variants.
=item --spark[=<characters>]
=item --spark[=<characters>]
@@
-534,14
+550,18
@@
Any kind of database query with counts, preserving returned alignment:
echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
psql -t | barcat -u
echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
psql -t | barcat -u
+In PostgreSQL from within the client:
+
+ postgres=> SELECT sin(generate_series(0, 3, .1)) \g |barcat
+
Earthquakes worldwide magnitude 1+ in the last 24 hours:
Earthquakes worldwide magnitude 1+ in the last 24 hours:
- https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_day.csv |
- column -tns, |
graph
-f4 -u -l80%
+
curl
https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_day.csv |
+ column -tns, |
barcat
-f4 -u -l80%
External datasets, like movies per year:
External datasets, like movies per year:
- curl https://github.com/prust/wikipedia-movie-data/raw/master/movies.json |
+ curl https://github.com/prust/wikipedia-movie-data/raw/master/movies.json
-L
|
perl -054 -nlE 'say if s/^"year"://' | uniq -c | barcat
But please get I<jq> to process JSON
perl -054 -nlE 'say if s/^"year"://' | uniq -c | barcat
But please get I<jq> to process JSON
@@
-549,7
+569,7
@@
and replace the manual selection by C<< jq '.[].year' >>.
Pokémon height comparison:
Pokémon height comparison:
- curl https://github.com/Biuni/PokemonGO-Pokedex/raw/master/pokedex.json |
+ curl https://github.com/Biuni/PokemonGO-Pokedex/raw/master/pokedex.json
-L
|
jq -r '.pokemon[] | [.height,.num,.name] | join(" ")' | barcat
USD/EUR exchange rate from CSV provided by the ECB:
jq -r '.pokemon[] | [.height,.num,.name] | join(" ")' | barcat
USD/EUR exchange rate from CSV provided by the ECB:
@@
-560,7
+580,7
@@
USD/EUR exchange rate from CSV provided by the ECB:
Total population history in XML from the World Bank:
Total population history in XML from the World Bank:
- curl http://api.worldbank.org/v2/country/1W/indicator/SP.POP.TOTL |
+ curl http://api.worldbank.org/v2/country/1W/indicator/SP.POP.TOTL
-L
|
xmllint --xpath '//*[local-name()="date" or local-name()="value"]' - |
sed -r 's,</wb:value>,\n,g; s,(<[^>]+>)+, ,g' | barcat -f1 -H
xmllint --xpath '//*[local-name()="date" or local-name()="value"]' - |
sed -r 's,</wb:value>,\n,g; s,(<[^>]+>)+, ,g' | barcat -f1 -H
@@
-580,7
+600,7
@@
Activity graph 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
--spark
+ sort | uniq -c | awk '$1--' |
barcat
--spark
=head1 AUTHOR
=head1 AUTHOR