Skip to content

Commit

Permalink
Updated table syntax to allow table lines without leading pipe charac…
Browse files Browse the repository at this point in the history
…ters

This allows kramdown to correctly parse PHP Markdown Extra tables.
  • Loading branch information
gettalong committed Sep 24, 2010
1 parent fb3b6e5 commit 5354385
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 19 deletions.
2 changes: 2 additions & 0 deletions doc/news/release_0_11_0.page
Expand Up @@ -43,6 +43,8 @@ has changed and developers may therefore need to update their extensions!
all converters
- Colons are now allowed in ID names for ALDs and IALs
- Tables and math blocks now have to start and end on block boundaries
- The table syntax was relaxed to allow table lines that don't start with a pipe character (to be
more compatible with PHP Markdown Extra tables)
- HTML elements `<b>` and `<i>` are now converted to `<strong>` and `<em>` when using
HTML-to-native conversion

Expand Down
34 changes: 24 additions & 10 deletions doc/syntax.page
Expand Up @@ -657,13 +657,19 @@ Sometimes one wants to include simple tabular data in a kramdown document for wh
full-blown HTML table is just too much. kramdown supports this with a simple syntax for ASCII
tables.

Tables can be created with or without a leading pipe character: If the first line of a table
contains a pipe character at the start of the line (optionally indented up to three spaces), then
all leading pipe characters (i.e. pipe characters that are only preceded by whitespace) are ignored
on all table lines. Otherwise they are not ignored and count when dividing a table line into table
cells.

There are four different line types that can be used in a table:

* *Table rows* define the content of a table.

A table row is started with a pipe character, optionally indented up to three spaces, and then the
text of the first table cell. Subsequent table cells consist of a pipe character followed by the
cell text. One may optionally use a pipe character at the the end of a table row line.
A table row is any line that contains at least one pipe character and is not identified as any
other type of table line! The table row is divided into indivdual table cells by pipe characters.
An optional trailing pipe character is ignored.

Header rows, footer rows and normal rows are all done using these table rows. Table cells can only
contain a single line of text, no multiline text is supported. The text of a table cell is parsed
Expand All @@ -675,13 +681,14 @@ There are four different line types that can be used in a table:
| First cell|Second cell|Third cell
| First | Second | Third |

First | Second | | Fourth |

* *Separator lines* are used to split the table body into multiple body parts.

A separator line is started with a pipe or plus character, optionally indented up to three spaces,
followed by an optional space, an optional colon, a dash and then any number and combination of
pipes, dashes, pluses, colons and spaces. The pipe and plus characters can be used to visually
separate columns although this is not needed. Multiple separator lines after another are treated
as one separator line.
A separator line is any line that contains only pipes, dashes, pluses, colons and spaces and which
contains at least one dash and one pipe character. The pipe and plus characters can be used to
visually separate columns although this is not needed. Multiple separator lines after another are
treated as one separator line.

Here are some example separator lines:

Expand All @@ -690,6 +697,7 @@ There are four different line types that can be used in a table:
|---------|
|-
| :-----: |
-|-

* The first separator line after at least one table row is treated specially, namely as *header
separator line*. It is used to demarcate header rows from normal table rows and/or to set column
Expand All @@ -710,6 +718,7 @@ There are four different line types that can be used in a table:
|---+---+---|
+ :-: |:------| ---:|
| :-: :- -: -
:-: | :-

* A *footer separator line* is used to demarcate footer rows from normal table rows. All table rows
below the footer separator line are considered to be footer rows.
Expand Down Expand Up @@ -739,11 +748,16 @@ Given the above components, a table is specified by
* optionally followed by a footer separator line and zero, one or more table rows and
* an optional trailing separator line.

Also note that tables have to start and end on [block boundaries](#block-boundaries)!
Also note

* that the first line of a table must not have more than three spaces of indentation before the
first none space character,
* that each line of a table needs to have at least one not escaped pipe character so that kramdown
recognizes it as a line belonging to the table and
* that tables have to start and end on [block boundaries](#block-boundaries)!

> The table syntax differs from the one used in [PHP Markdown Extra] as follows:
>
> * kramdown tables have to begin with a pipe character, this is optional in [PHP Markdown Extra].
> * kramdown tables do not need to have a table header.
> * kramdown tables can be structured using separator lines.
> * kramdown tables can contain a table footer.
Expand Down
8 changes: 5 additions & 3 deletions lib/kramdown/converter/kramdown.rb
Expand Up @@ -91,9 +91,11 @@ def convert_text(el, opts)

def convert_p(el, opts)
w = @doc.options[:line_width] - opts[:indent].to_s.to_i
inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").gsub(/\A(?:([#|])|(\d+)\.|([+-]\s|[=-]+\s*?$))/) do
$1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\."
end
first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
first.gsub!(/^(?:(#)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\."}
first.gsub!(/\|/, '\\|')
second.gsub!(/^([=-]+\s*?)$/, "\\\1") if second
[first, second, *rest].compact.join("\n") + "\n"
end


Expand Down
12 changes: 8 additions & 4 deletions lib/kramdown/parser/kramdown/table.rb
Expand Up @@ -26,18 +26,20 @@ module Kramdown
module Parser
class Kramdown

TABLE_SEP_LINE = /^#{OPT_SPACE}(?:\||\+)([ ]?:?-[+|: -]*)[ \t]*\n/
TABLE_SEP_LINE = /^([+|: -]*?-[+|: -]*?)[ \t]*\n/
TABLE_HSEP_ALIGN = /[ ]?(:?)-+(:?)[ ]?/
TABLE_FSEP_LINE = /^#{OPT_SPACE}(\||\+)[ ]?:?=[+|: =]*[ \t]*\n/
TABLE_ROW_LINE = /^#{OPT_SPACE}\|(.*?)[ \t]*\n/
TABLE_START = /^#{OPT_SPACE}\|(?:-|(?!=))/
TABLE_FSEP_LINE = /^[+|: =]*?=[+|: =]*?[ \t]*\n/
TABLE_ROW_LINE = /^(.*?)[ \t]*\n/
TABLE_LINE = /(?:\||.*?[^\\\n]\|).*?\n/
TABLE_START = /^#{OPT_SPACE}(?=\S)#{TABLE_LINE}/

# Parse the table at the current location.
def parse_table
return false if !after_block_boundary?

orig_pos = @src.pos
table = new_block_el(:table, nil, nil, :alignment => [])
leading_pipe = (@src.check(TABLE_LINE) =~ /^\s*\|/)
@src.scan(TABLE_SEP_LINE)

rows = []
Expand All @@ -53,6 +55,7 @@ def parse_table
end

while !@src.eos?
break if !@src.check(TABLE_LINE)
if @src.scan(TABLE_SEP_LINE) && !rows.empty?
if table.options[:alignment].empty? && !has_footer
add_container.call(:thead, false)
Expand All @@ -78,6 +81,7 @@ def parse_table
i += 1
end
end
cells.shift if leading_pipe && cells.first.strip.empty?
cells.pop if cells.last.strip.empty?
cells.each do |cell_text|
tcell = Element.new(:td)
Expand Down
2 changes: 1 addition & 1 deletion test/testcases/block/14_table/header.text
Expand Up @@ -26,7 +26,7 @@ With leading sep line
Multiple bodies

| cell1 | cell2
+ :-:
+ :-: |
| cell3 | cell4
|----|||
| cell5 | cell6
2 changes: 1 addition & 1 deletion test/testcases/block/14_table/no_table.text
@@ -1,3 +1,3 @@
No table

\| Some | thing | here
\| Some \| thing \| here
58 changes: 58 additions & 0 deletions test/testcases/block/14_table/simple.html
Expand Up @@ -79,3 +79,61 @@
</tr>
</tbody>
</table>

<p>not starting with a bar</p>

<table>
<tbody>
<tr>
<td>simple</td>
<td>table</td>
</tr>
</tbody>
</table>

<table>
<thead>
<tr>
<th>head1</th>
<th>head2</th>
</tr>
</thead>
<tbody>
<tr>
<td>cell1</td>
<td>cell2</td>
</tr>
</tbody>
</table>

<table>
<thead>
<tr>
<th>head1</th>
<th>head2</th>
</tr>
</thead>
<tbody>
<tr>
<td>&nbsp;</td>
<td>cell2</td>
</tr>
</tbody>
</table>

<table>
<tbody>
<tr>
<td>a</td>
<td>b</td>
</tr>
<tr>
<td>c</td>
<td>d</td>
</tr>
<tr>
<td>e</td>
<td>f</td>
</tr>
</tbody>
</table>
16 changes: 16 additions & 0 deletions test/testcases/block/14_table/simple.text
Expand Up @@ -20,3 +20,19 @@ Escaped pipe characters

| table | with | ial
{:.cls}

not starting with a bar

simple | table

head1 | head2
------|------
cell1 | cell2

head1 | head2
-------|------
| cell2

| a | b |
c | d
| e | f |

0 comments on commit 5354385

Please sign in to comment.