App-ansicolumn
view release on metacpan or search on metacpan
lib/App/ansicolumn.pm view on Meta::CPAN
sub set_vertical {
my $obj = shift;
my $dp = shift;
$obj->border_height = do {
sum map { length > 0 }
map { $obj->get_border($_) }
qw(top bottom);
};
$obj->height ||= div(int @$dp, $obj->panes) + $obj->border_height;
die "Not enough height.\n" if $obj->effective_height <= 0;
return $obj;
}
sub page_out {
my $obj = shift;
my $name = shift;
my $column_out = $obj->_column_out;
for ($obj->current_page = 0; @_; $obj->current_page++) {
my @columns = grep { @$_ } do {
if ($obj->fillrows) {
xpose map { [ splice @_, 0, $obj->panes ] } 1 .. $obj->effective_height;
} else {
map { [ splice @_, 0, $obj->effective_height ] } 1 .. $obj->panes;
}
};
$column_out->({ names => [($name) x scalar @columns] }, @columns);
}
return $obj;
}
sub color_border {
my $obj = shift;
$obj->color('BORDER', $obj->get_border(@_));
}
sub _parse_labels {
my $hash = shift;
return 0 unless %$hash;
my %result;
while (my($key, $s) = each %$hash) {
next unless defined $s and $s ne '';
my $offset;
if ($s =~ s/@(\d+)$//) {
$offset = $1 + 0;
}
$s =~ s/%n/%1\$d/g;
$s =~ s/%p/%2\$d/g;
$s =~ s/%f/%3\$s/g;
$s =~ s/%F/%4\$s/g;
$result{lc $key} = [ $offset, $s ];
}
%result ? \%result : 0;
}
# Overlay labels onto a border line string.
# $fs/$fe: fill region start/end.
# $ml/$mr: border margin accessible via @0.
# $n/$p: pane number / page number for sprintf expansion.
# $file: filename (path as given) - used as %3$s (basename) and %4$s (path as given).
sub _overlay_labels {
my($obj, $str, $fs, $fe, $ml, $mr, $n, $p, $file, $left, $center, $right) = @_;
use File::Basename qw(basename);
use Text::ANSI::Fold::Util qw(ansi_substr);
my $base = defined $file ? basename($file) : '';
for my $item (
[ $left, sub { $fs - $ml + ($_[0] // $ml) } ],
[ $right, sub { $fe + $mr - ($_[0] // $mr) - $_[1] } ],
[ $center, sub { $fs + int(($fe - $fs - $_[1]) / 2) } ],
) {
my($spec, $pos_fn) = @$item;
next unless $spec;
my $fmt = $spec->[1];
next unless defined $fmt && $fmt ne '';
my $text = $fmt =~ /%/ ? sprintf($fmt, $n, $p, $base, $file // '') : $fmt;
my $lw = ansi_width($text);
my $label = $obj->color('BORDER_LABEL', $text);
$str = ansi_substr($str, $pos_fn->($spec->[0], $lw), $lw, $label);
}
$str;
}
sub _column_out {
my $obj = shift;
my %bd = map { $_ => $obj->get_border($_) } qw(top bottom);
my $bl = $obj->{_bl} //= _parse_labels($obj->label);
my $pbl = $obj->{_pbl} //= _parse_labels($obj->page_label);
# pre-build pane label closures per pane index
my(@pane_top, @pane_bottom, @page_top, @page_bottom);
my($bw_l, $bw_c, $bw_r);
if ($bl || $pbl) {
$bw_l = ansi_width($obj->get_border('left', 0));
$bw_c = ansi_width($obj->get_border('center', 0));
$bw_r = ansi_width($obj->get_border('right', 0));
my $span = $obj->{span};
for my $set ([ \@pane_top, \@page_top, qw(nw n ne) ],
[ \@pane_bottom, \@page_bottom, qw(sw s se) ]) {
my($pane_list, $page_list, @keys) = @$set;
if ($bl) {
my @g = map { $bl->{$_} } @keys;
if (grep { $_ } @g) {
my $fp = $bw_l;
for my $i (0 .. $obj->panes - 1) {
my($fs, $fe) = ($fp, $fp + $span);
push @$pane_list, sub {
$obj->_overlay_labels($_[0], $fs, $fe, $bw_l, $bw_r,
$_[1] + $i + 1, $_[2], $_[3], @g);
};
$fp += $span + $bw_c;
}
}
}
if ($pbl) {
my @g = map { $pbl->{$_} } @keys;
if (grep { $_ } @g) {
push @$page_list, sub {
my $w = ansi_width($_[0]);
$obj->_overlay_labels($_[0], 1, $w - 1, 1, 1,
$_[1] + 1, $_[2], $_[3], @g);
};
}
}
}
}
my $has_labels = @pane_top || @pane_bottom || @page_top || @page_bottom;
# pre-build border strings for 3 positions (top=0, middle=1, bottom=2)
my %border;
for my $pos (0, 1, 2) {
$border{$pos} = {
left => $obj->color_border('left', $pos),
center => $obj->color_border('center', $pos),
right => $obj->color_border('right', $pos),
};
}
my $print_border = sub {
my($side, $pos, $span, $npanes, $n0, $p, $names,
$pane_labels, $page_labels) = @_;
return unless $bd{$side};
my $bd = $border{$pos};
my $line = join '',
$bd->{left},
join($bd->{center},
map { $obj->color('BORDER', $bd{$side} x $_) } @$span),
$bd->{right};
if (@$pane_labels) {
my $i = 0;
for (@{$pane_labels}[0 .. $npanes - 1]) {
$line = $_->($line, $n0, $p, $names->[$i++] // '');
}
}
$line = $_->($line, $n0, $p, $names->[0] // '') for @$page_labels;
print $line, "\n";
};
sub {
my $opt = ref $_[0] eq 'HASH' ? shift : {};
my @span = $opt->{span} ? @{$opt->{span}} : (($obj->{span}) x @_);
my $page = $obj->current_page // 0;
my $npanes = scalar @_;
my($n0, $p) = $has_labels
? ($page * ($obj->panes // 1), $page + 1) : ();
my $names = $opt->{names} // [];
$print_border->('top', 0, \@span, $npanes, $n0, $p, $names,
\@pane_top, \@page_top);
# content rows
my $max = max map $#{$_}, @_;
for my $i (0 .. $max) {
my $pos = !$bd{top} && $i == 0 ? 0
: !$bd{bottom} && $i == $max ? 2
: 1;
my $bd = $border{$pos};
my @span = @span;
( run in 2.004 seconds using v1.01-cache-2.11-cpan-7fcb06a456a )