Format tables as HTML, not as ASCII pseudographic
parent
3e36282959
commit
d34758d028
|
@ -130,11 +130,6 @@ sub REQUIRED_MODULES {
|
||||||
module => 'Text::Wrap',
|
module => 'Text::Wrap',
|
||||||
version => '2013.0426',
|
version => '2013.0426',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
package => 'Text-TabularDisplay',
|
|
||||||
module => 'Text::TabularDisplay',
|
|
||||||
feature => 'Table formatting inside bug comments',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
package => 'LWP-MediaTypes',
|
package => 'LWP-MediaTypes',
|
||||||
module => 'LWP::MediaTypes',
|
module => 'LWP::MediaTypes',
|
||||||
|
|
|
@ -171,13 +171,17 @@ sub makeTables
|
||||||
{
|
{
|
||||||
if (scalar($line =~ s/(\t+|│+)/$1/gso) > 0)
|
if (scalar($line =~ s/(\t+|│+)/$1/gso) > 0)
|
||||||
{
|
{
|
||||||
$line =~ s/^\s*│\s*//;
|
$line =~ /[─┌┐└┘├┴┬┤┼]+/gso; # legacy ascii tables
|
||||||
$table->add(split /\t+|\s*│+\s*/, $line);
|
$line =~ s/^\s*│\s*//s;
|
||||||
|
$line =~ s/\s*│\s*$//s;
|
||||||
|
$line = [ split /\t+\s*|\s*│+\s*/, $line ];
|
||||||
|
$line = '<tr><td>'.join('</td><td>', @$line).'</td></tr>';
|
||||||
|
$table .= "\n".$line;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$wrappedcomment .= "\0\1".$table->render."\0\1";
|
$wrappedcomment .= "<table class='bz_fmt_table'>$table</table>\n";
|
||||||
$table = undef;
|
$table = undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,21 +189,19 @@ sub makeTables
|
||||||
if ($n > 1 && length($line) < MAX_TABLE_COLS)
|
if ($n > 1 && length($line) < MAX_TABLE_COLS)
|
||||||
{
|
{
|
||||||
# Table
|
# Table
|
||||||
$line =~ s/^\s*│\s*//;
|
$line =~ /[─┌┐└┘├┴┬┤┼]+/gso; # legacy ascii tables
|
||||||
$line =~ s/\s*│\s*$//;
|
$line =~ s/^\s*│\s*//s;
|
||||||
$table = Text::TabularDisplay::Utf8->new;
|
$line =~ s/\s*│\s*$//s;
|
||||||
$table->add(split /\t+|\s*│+\s*/, $line);
|
$line = [ split /\t+\s*|\s*│+\s*/, $line ];
|
||||||
|
$table = "<tr><td>".join('</td><td>', @$line)."</td></tr>\n";
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
unless ($line =~ /^[│─┌┐└┘├┴┬┤┼].*[│─┌┐└┘├┴┬┤┼]$/iso)
|
$line =~ s/\t/ /gso;
|
||||||
{
|
|
||||||
$line =~ s/\t/ /gso;
|
|
||||||
}
|
|
||||||
$wrappedcomment .= $line . "\n";
|
$wrappedcomment .= $line . "\n";
|
||||||
}
|
}
|
||||||
if ($table)
|
if ($table)
|
||||||
{
|
{
|
||||||
$wrappedcomment .= "\0\1".$table->render."\0\1";
|
$wrappedcomment .= "<table class='bz_fmt_table'>$table</table>\n";
|
||||||
}
|
}
|
||||||
return $wrappedcomment;
|
return $wrappedcomment;
|
||||||
}
|
}
|
||||||
|
@ -215,8 +217,6 @@ sub quoteUrls
|
||||||
my ($text, $bug, $comment) = (@_);
|
my ($text, $bug, $comment) = (@_);
|
||||||
return $text unless $text;
|
return $text unless $text;
|
||||||
|
|
||||||
$text = makeTables($text);
|
|
||||||
|
|
||||||
# We use /g for speed, but uris can have other things inside them
|
# We use /g for speed, but uris can have other things inside them
|
||||||
# (http://foo/bug#3 for example). Filtering that out filters valid
|
# (http://foo/bug#3 for example). Filtering that out filters valid
|
||||||
# bug refs out, so we have to do replacements.
|
# bug refs out, so we have to do replacements.
|
||||||
|
@ -345,6 +345,9 @@ sub quoteUrls
|
||||||
# Replace nowrap markers (\1\0\1)
|
# Replace nowrap markers (\1\0\1)
|
||||||
$text =~ s/\x01\x00\x01(.*?)\x01\x00\x01/<div style="white-space: nowrap">$1<\/div>/gso;
|
$text =~ s/\x01\x00\x01(.*?)\x01\x00\x01/<div style="white-space: nowrap">$1<\/div>/gso;
|
||||||
|
|
||||||
|
# Replace tables
|
||||||
|
$text = makeTables($text);
|
||||||
|
|
||||||
# Color quoted text
|
# Color quoted text
|
||||||
$text = makeCitations($text);
|
$text = makeCitations($text);
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,6 @@ use List::Util qw(first);
|
||||||
use Scalar::Util qw(tainted blessed);
|
use Scalar::Util qw(tainted blessed);
|
||||||
use Template::Filters;
|
use Template::Filters;
|
||||||
use Text::Wrap;
|
use Text::Wrap;
|
||||||
use Text::TabularDisplay::Utf8;
|
|
||||||
use JSON;
|
use JSON;
|
||||||
|
|
||||||
use Data::Dumper qw(Dumper);
|
use Data::Dumper qw(Dumper);
|
||||||
|
@ -457,17 +456,18 @@ sub wrap_comment # makeParagraphs
|
||||||
my $tmp;
|
my $tmp;
|
||||||
my $text = '';
|
my $text = '';
|
||||||
my $block_tags = '(?:div|h[1-6]|center|ol|ul|li)';
|
my $block_tags = '(?:div|h[1-6]|center|ol|ul|li)';
|
||||||
|
my $table_tags = '(?:table|tbody|thead|tr|td|th)';
|
||||||
while ($input ne '')
|
while ($input ne '')
|
||||||
{
|
{
|
||||||
# Convert double line breaks to new paragraphs
|
# Convert double line breaks to new paragraphs
|
||||||
if ($input =~ m!\n\s*\n|(</?$block_tags[^<>]*>)!so)
|
if ($input =~ m!\n\s*\n|(</?$table_tags[^<>]*>)|(</?$block_tags[^<>]*>)!so)
|
||||||
{
|
{
|
||||||
@m = (substr($input, 0, $-[0]), $1);
|
@m = (substr($input, 0, $-[0]), $1||$2, $1);
|
||||||
$input = substr($input, $+[0]);
|
$input = substr($input, $+[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@m = ($input, '');
|
@m = ($input, '', '');
|
||||||
$input = '';
|
$input = '';
|
||||||
}
|
}
|
||||||
if ($m[0] ne '')
|
if ($m[0] ne '')
|
||||||
|
@ -476,7 +476,7 @@ sub wrap_comment # makeParagraphs
|
||||||
$m[0] =~ s/^\s*\n//s;
|
$m[0] =~ s/^\s*\n//s;
|
||||||
$m[0] =~ s/^([ \t]+)/$tmp = $1; s!\t! !g; $tmp/emog;
|
$m[0] =~ s/^([ \t]+)/$tmp = $1; s!\t! !g; $tmp/emog;
|
||||||
$m[0] =~ s/(<[^<>]*>)|( +)/$1 || ' '.(' ' x (length($2)-1))/ge;
|
$m[0] =~ s/(<[^<>]*>)|( +)/$1 || ' '.(' ' x (length($2)-1))/ge;
|
||||||
if (!$p && $m[0] ne '')
|
if (!$p && $m[0] ne '' && !$m[2])
|
||||||
{
|
{
|
||||||
$text .= '<p>';
|
$text .= '<p>';
|
||||||
$p = 1;
|
$p = 1;
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
package Text::TabularDisplay::Utf8;
|
|
||||||
|
|
||||||
use utf8;
|
|
||||||
use strict;
|
|
||||||
use base 'Text::TabularDisplay';
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# render([$start, $end])
|
|
||||||
#
|
|
||||||
# Returns the data formatted as a table. By default, all rows are
|
|
||||||
# returned; if $start or $end are specified, then only those indexes
|
|
||||||
# are returned. Those are the start and end indexes!
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
sub render {
|
|
||||||
my $self = shift;
|
|
||||||
my $start = shift || 0;
|
|
||||||
my $end = shift || $#{ $self->{ _DATA } };
|
|
||||||
my $size = $self->{ _SIZE };
|
|
||||||
my (@columns, $datum, @text);
|
|
||||||
|
|
||||||
push @text, '┌' . join("┬", map( { "─" x ($_ + 2) } @{ $self->{ _LENGTHS } })) . '┐';
|
|
||||||
|
|
||||||
if (@columns = $self->columns) {
|
|
||||||
push @text, _format_line(\@columns, $self->{ _LENGTHS });
|
|
||||||
push @text, '├' . join("┼", map( { "─" x ($_ + 2) } @{ $self->{ _LENGTHS } })) . '┤';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (my $i = $start; $i <= $end; $i++) {
|
|
||||||
$datum = $self->{ _DATA }->[$i];
|
|
||||||
last unless defined $datum;
|
|
||||||
|
|
||||||
# Pad the array if there are more elements in @columns
|
|
||||||
push @$datum, ""
|
|
||||||
until (@$datum == $size);
|
|
||||||
push @text, _format_line($datum, $self->{ _LENGTHS });
|
|
||||||
}
|
|
||||||
|
|
||||||
push @text, '└' . join("┴", map( { "─" x ($_ + 2) } @{ $self->{ _LENGTHS } })) . '┘';
|
|
||||||
return join "\n", @text;
|
|
||||||
}
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# _column_length($str)
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
sub _column_length
|
|
||||||
{
|
|
||||||
my ($str) = @_;
|
|
||||||
|
|
||||||
my $len = 0;
|
|
||||||
for (split "\n", $str) {
|
|
||||||
$len = length
|
|
||||||
if $len < length;
|
|
||||||
}
|
|
||||||
# why the /hell/ this length is tainted?..
|
|
||||||
if (${^TAINT})
|
|
||||||
{
|
|
||||||
($len) = $len =~ /(\d+)/so;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $len;
|
|
||||||
}
|
|
||||||
|
|
||||||
undef &Text::TabularDisplay::_column_length;
|
|
||||||
*Text::TabularDisplay::_column_length = \&_column_length;
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
# _format_line(\@columns, \@lengths)
|
|
||||||
#
|
|
||||||
# Returns a formatted line out of @columns; the size of $column[$i]
|
|
||||||
# is determined by $length[$i].
|
|
||||||
# -------------------------------------------------------------------
|
|
||||||
sub _format_line {
|
|
||||||
my ($columns, $lengths) = @_;
|
|
||||||
|
|
||||||
my $height = 0;
|
|
||||||
my @col_lines;
|
|
||||||
for (@$columns) {
|
|
||||||
my @lines = split "\n";
|
|
||||||
$height = scalar @lines
|
|
||||||
if $height < @lines;
|
|
||||||
push @col_lines, \@lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
my @lines;
|
|
||||||
for my $h (0 .. $height - 1 ) {
|
|
||||||
my @line;
|
|
||||||
for (my $i = 0; $i <= $#$columns; $i++) {
|
|
||||||
my $val = defined($col_lines[$i][$h]) ? $col_lines[$i][$h] : '';
|
|
||||||
push @line, sprintf " %-" . $lengths->[$i] . "s ", $val;
|
|
||||||
}
|
|
||||||
push @lines, join '│', "", @line, "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return join "\n", @lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
||||||
__END__
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Text::TabularDisplay::Utf8 - Display text in formatted table output using UTF-8 pseudographics
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
use Text::TabularDisplay::Utf8;
|
|
||||||
|
|
||||||
my $table = Text::TabularDisplay::Utf8->new(@columns);
|
|
||||||
$table->add(@row)
|
|
||||||
while (@row = $sth->fetchrow);
|
|
||||||
print $table->render;
|
|
||||||
|
|
||||||
┌────┬──────────────┐
|
|
||||||
│ id │ name │
|
|
||||||
├────┼──────────────┤
|
|
||||||
│ 1 │ Tom │
|
|
||||||
│ 2 │ Dick │
|
|
||||||
│ 3 │ Barry │
|
|
||||||
│ │ (aka Bazza) │
|
|
||||||
│ 4 │ Harry │
|
|
||||||
└────┴──────────────┘
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
The program interface is fully compatible with C<Text::TabularDisplay> -
|
|
||||||
see its perldoc for more information.
|
|
|
@ -26,6 +26,9 @@
|
||||||
.bz_comment .attachment_image { max-width: 50em; margin: 10px 0px 0px 0px; }
|
.bz_comment .attachment_image { max-width: 50em; margin: 10px 0px 0px 0px; }
|
||||||
|
|
||||||
.bz_comment_text.bz_fullscreen_comment { min-width: 50em; width: 100%; word-wrap: break-word; }
|
.bz_comment_text.bz_fullscreen_comment { min-width: 50em; width: 100%; word-wrap: break-word; }
|
||||||
|
#commentpreviewhtml .bz_comment_text.bz_fullscreen_comment { min-width: 40em; }
|
||||||
|
|
||||||
|
.bz_comment .bz_fmt_table td, .bz_comment .bz_fmt_table th { border: 1px solid gray; padding: 5px; }
|
||||||
|
|
||||||
#comments > table, .bz_section_additional_comments > table { table-layout: fixed; }
|
#comments > table, .bz_section_additional_comments > table { table-layout: fixed; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue