App-sdview
view release on metacpan or search on metacpan
lib/App/sdview/Output/Formatted.pm view on Meta::CPAN
=head1 NAME
C<App::sdview::Output::Formatted> - base class for generating formatted output from L<App::sdview>
=head1 DESCRIPTION
This module is the base class used by both L<App::sdview::Output::Plain> and
L<App::sdview::Output::Terminal>. It shouldn't be used directly.
=cut
field $_TERMWIDTH;
field $_nextblank;
method output ( @paragraphs )
{
$self->setup_output();
$_TERMWIDTH = $self->width;
foreach my $para ( @paragraphs ) {
my $code = $self->can( "output_" . ( $para->type =~ s/-/_/gr ) )
or die "TODO: Unhandled paragraph type " . $para->type;
$self->$code( $para );
}
}
# Most paragraphs are handled in a uniform way
*output_head1 = \&_output_para;
*output_head2 = \&_output_para;
*output_head3 = \&_output_para;
*output_head4 = \&_output_para;
*output_plain = \&_output_para;
*output_verbatim = \&_output_para;
*output_item = \&_output_para;
method _output_para ( $para,
:$margin //= 0,
:$leader = undef,
:$indent //= 0,
) {
my %typestyle = App::sdview::Style->para_style( $para->type )->%*;
$self->say() if $_nextblank;
my $text = App::sdview::Style->convert_str( $para->text );
$typestyle{$_} and $text->apply_tag( 0, -1, $_ => $typestyle{$_} )
for qw( fg bg bold under italic monospace );
$_nextblank = !!$typestyle{blank_after};
my @lines = $text->split( qr/\n/ );
@lines or @lines = ( String::Tagged->new ) if defined $leader;
# If there's a background set, then space-pad every line to the same width
# so it looks neater on the terminal
# https://rt.cpan.org/Ticket/Display.html?id=140536
if( defined $typestyle{bg} ) {
my $width = max map { length $_ } @lines;
$_ .= " " x ( $width - length $_ ) for @lines;
}
$margin += ( $typestyle{margin} // 0 );
foreach my $line ( @lines ) {
length $line or defined $leader or
( $self->say() ), next;
my $width = $_TERMWIDTH - $margin - $indent;
while( length $line or defined $leader ) {
my $part;
if( length($line) > $width ) {
if( substr($line, 0, $width) =~ m/(\s+)\S*$/ ) {
my $partlen = $-[1];
my $chopat = $+[1];
$part = $line->substr( 0, $partlen );
$line->set_substr( 0, $chopat, "" );
}
else {
die "ARGH: notsure how to trim this one\n";
}
}
else {
$part = $line;
$line = "";
}
my $prefix = " "x$margin;;
if( defined $leader ) {
my %leaderstyle = App::sdview::Style->para_style( "leader" )->%*;
$leaderstyle{$_} and $leader->apply_tag( 0, -1, $_ => $leaderstyle{$_} )
for qw( fg bg bold under italic monospace );
if( length($leader) + 1 <= $indent ) {
# If the leader will fit on the same line with at least one space
$prefix .= $leader . " "x($indent - length $leader);
}
else {
# Spill the leader onto its own line
$self->say( $prefix, $leader );
$prefix .= " "x$indent if length $part;
}
undef $leader;
}
else {
$prefix .= " "x$indent;
}
$self->say( $prefix, $part );
}
}
( run in 1.033 second using v1.01-cache-2.11-cpan-39bf76dae61 )