Browse Source

Markdown.pl: support tables

Add support for basic tables.

Nested tables are not supported although tables themselves can
appear within lists and blockquotes and do work properly there.

The commonly used table syntax is recognized including the
left/right/center alignment indicators.

Inline markup within each column also works just fine.

Signed-off-by: Kyle J. McKay <mackyle@gmail.com>
master
Kyle J. McKay 7 years ago
parent
commit
2b798a8841
  1. 105
      Markdown.pl
  2. 20
      basics.md
  3. 61
      syntax.md

105
Markdown.pl

@ -111,7 +111,7 @@ BEGIN {
# Table of hash values for escaped characters:
my %g_escape_table;
BEGIN {
foreach my $char (split //, "\\\`*_~{}[]()>#+-.!") {
foreach my $char (split //, "\\\`*_~{}[]()>#+-.!|") {
$g_escape_table{$char} = block_id($char,1);
}
}
@ -696,6 +696,8 @@ sub _RunBlockGamut {
$text = _DoBlockQuotes($text);
$text = _DoTables($text);
# We already ran _HashHTMLBlocks() before, in Markdown(), but that
# was to escape raw HTML in the original Markdown source. This time,
# we're escaping the markup we've just created, so that we don't wrap
@ -1798,6 +1800,98 @@ sub _DoBlockQuotes {
}
my ($LEAD, $TRAIL, $LEADBAR, $LEADSP, $COLPL, $SEP);
BEGIN {
$LEAD = qr/(?>[ ]*(?:\|[ ]*)?)/o;
$TRAIL = qr/\|[ ]*/o;
$LEADBAR = qr/(?>[ ]*\|[ ]*)/o;
$LEADSP = qr/(?>[ ]*)/o;
$COLPL = qr/(?:[^\n|\\]|\\[^\n])+/o;
$SEP = qr/[ ]*:?-+:?[ ]*/o;
}
sub _DoTables {
my $text = shift;
$text =~ s{
( # Wrap whole thing to avoid $&
(?: (?<=\n\n) | \A\n? ) # Preceded by blank line or beginning of string
^( # Header line
$LEADBAR \| [^\n]* |
$LEADBAR $COLPL [^\n]* |
$LEADSP $COLPL \| [^\n]*
)\n
( # Separator line
$LEADBAR $SEP (?: \| $SEP )* (?: \| [ ]*)? |
$SEP (?: \| $SEP )+ (?: \| [ ]*)? |
$SEP \| [ ]*
)\n
((?: # Rows (0+)
$LEADBAR \| [^\n]* \n |
$LEADBAR $COLPL [^\n]* \n |
$LEADSP $COLPL \| [^\n]* \n
)*)
)
} {
my ($w, $h, $s, $rows) = ($1, $2, $3, $4);
my @heads = _SplitTableRow($h);
my @seps = _SplitTableRow($s);
if (@heads == @seps) {
my @align = map {
if (/^:-+:$/) {" align=\"center\""}
elsif (/^:/) {" align=\"left\""}
elsif (/:$/) {" align=\"right\""}
else {""}
} @seps;
my $headers = _MakeTableRow("th", \@align, @heads);
my $tab ="\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"2\" class=\"$opt{style_prefix}table\">\n" .
" <tr class=\"$opt{style_prefix}row-hdr\">" . _MakeTableRow("th", \@align, @heads) . "</tr>\n";
my $cnt = 0;
my @classes = ("class=\"$opt{style_prefix}row-even\"", "class=\"$opt{style_prefix}row-odd\"");
$tab .= " <tr " . $classes[++$cnt % 2] . ">" . _MakeTableRow("td", \@align, _SplitTableRow($_)) . "</tr>\n"
foreach split(/\n/, $rows);
$tab .= "</table>\n\n";
} else {
$w;
}
}egmx;
return $text;
}
sub _SplitTableRow {
my $row = shift;
$row =~ s/^$LEAD//;
$row =~ s/$TRAIL$//;
$row =~ s!\\\\!$g_escape_table{'\\'}!go; # Must process escaped backslashes first.
$row =~ s!\\\|!$g_escape_table{'|'}!go; # Then do \|
my @elems = map {
s!$g_escape_table{'|'}!|!go;
s!$g_escape_table{'\\'}!\\!go;
s/^[ ]+//;
s/[ ]+$//;
$_;
} split(/[ ]*\|[ ]*/, $row, -1);
@elems or push(@elems, "");
return @elems;
}
sub _MakeTableRow {
my $etype = shift;
my $align = shift;
my $row = "";
for (my $i = 0; $i < @$align; ++$i) {
my $data = $_[$i];
defined($data) or $data = "";
$row .= "<" . $etype . $$align[$i] . ">" .
_RunSpanGamut($data) . "</" . $etype . ">";
}
return $row;
}
sub _FormParagraphs {
#
# Params:
@ -2151,6 +2245,15 @@ div.%(base)code-bt > pre > code, div.%(base)code > pre > code {
border-bottom: thin dotted;
}
table.%(base)table {
margin-bottom: 0.5em;
}
table.%(base)table, table.%(base)table th, table.%(base)table td {
border-collapse: collapse;
border-spacing: 0;
border: thin solid;
}
ol.%(base)ol {
counter-reset: %(base)item;
}

20
basics.md

@ -198,6 +198,26 @@ Output:
</ul>
~~~~~~
Tables
~~~~~~
Markdown supports simple tables like so:
| Item | Price | Description |
| ---- | -----:| ----------- |
| Nut | $1.29 | Delicious |
| Bean | $0.37 | Fiber |
Output:
<table>
<tr><th>Item</th><th align="right">Price</th><th>Description</th></tr>
<tr><td>Nut</td><td align="right">$1.29</td><td>Delicious</td></tr>
<tr><td>Bean</td><td align="right">$0.37</td><td>Fiber</td></tr>
</table>
~~~~~
Links
~~~~~

61
syntax.md

@ -17,6 +17,7 @@ Markdown: Syntax
* [Headers]
* [Blockquotes]
* [Lists]
* [Tables]
* [Style Sheet]
* [Code Blocks]
* [Horizontal Rules]
@ -554,6 +555,65 @@ immediately followed by another line that looks like a list item (either
of the same kind or of a sublist).
~~~~~~
Tables
~~~~~~
Markdown supports simple tables like so:
| Item | Price | Description |
| ---- | -----:| ----------- |
| Nut | $1.29 | Delicious |
| Bean | $0.37 | Fiber |
Output:
<table>
<tr><th>Item</th><th align="right">Price</th><th>Description</th></tr>
<tr><td>Nut</td><td align="right">$1.29</td><td>Delicious</td></tr>
<tr><td>Bean</td><td align="right">$0.37</td><td>Fiber</td></tr>
</table>
The leading and trailing `|` on each line are optional unless there is only
a single column in which case at least one `|` is always required -- two if
the single column contains only whitespace.
Leading and trailing whitespace are always trimmed from each column's value
before using it.
To include a literal `|` (veritical bar) character in a column's value, precede
it with a `\` (backslash). To include a literal `\` use `\\` (double them).
The number of columns in the separator row must match exactly the number of
columns in the header row in order for the table to be recognized.
Each separator in the separator line must be one or more `-` (dash) characters
optionally with a `:` (colon) on either or both ends. With no colons the
column alignment will be the default. With a colon only on the left the
alignment will be `left`. With a colon only on the right the alignment will
be `right`. And finally, with a colon on both ends the alignment will be
`center`. The alignment will be applied to the column in both header and body
rows.
Body rows that contain fewer columns than the header row have empty columns
added. Body rows that contain more columns than the header row have the
extra columns dropped.
The vertical bars do not need to be lined up, sloppy tables work just fine.
The above example could be rewritten like so:
Item|Price|Description
-|-:|-
Nut|$1.29|Delicious
Bean|$0.37|Fiber
Inline markup is recognized just fine within each column:
|Example
|:-
|~~Strikeout~~ `code` _etc._
~~~~~~~~~~~
Style Sheet
~~~~~~~~~~~
@ -1091,3 +1151,4 @@ Markdown provides backslash escapes for the following characters:
- minus sign (hyphen)
. dot
! exclamation mark
| vertical bar (escape only needed/recognized in tables)

Loading…
Cancel
Save