Skip to content

Commit 3e5c72d

Browse files
Add filter list-table (#202)
Allows the use of RST-like list tables in markdown.
1 parent 914e5aa commit 3e5c72d

File tree

5 files changed

+207
-0
lines changed

5 files changed

+207
-0
lines changed

list-table/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
DIFF ?= diff --strip-trailing-cr -u
2+
PANDOC ?= pandoc
3+
4+
test: sample.md expected.html list-table.lua
5+
@$(PANDOC) --lua-filter list-table.lua --to=html $< \
6+
| $(DIFF) expected.html -
7+
8+
.PHONY: test

list-table/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# list-table
2+
3+
reStructuredText has so-called [list tables], which are not
4+
only easy-to-write but also produce clean diffs since you
5+
don't need to re-align all the whitespace when one cell width
6+
changes. This filter lets you use RST-inspired list tables in
7+
markdown. Any div with the first class `list-table` is
8+
converted, for example the following Markdown:
9+
10+
```
11+
:::list-table
12+
* - Heading row 1, column 1
13+
- Heading row 1, column 2
14+
- Heading row 1, column 3
15+
16+
* - Row 1, column 1
17+
-
18+
- Row 1, column 3
19+
20+
* - Row 2, column 1
21+
- Row 2, column 2
22+
:::
23+
```
24+
25+
results in the following table:
26+
27+
| Heading row 1, column 1 | Heading row 1, column 2 | Heading row 1, column 3 |
28+
|-------------------------|-------------------------|-------------------------|
29+
| Row 1, column 1 | | Row 1, column 3 |
30+
| Row 2, column 1 | Row 2, column 2 | |
31+
32+
Three additional features are supported:
33+
34+
* If the div starts with a paragraph its content is used as the table caption.
35+
36+
* With the `align` attribute you can configure column alignment. When given
37+
the value must specify an alignment character (`d`, `l`, `r`, or `c` for
38+
default, left, right or center respectively) for each column. The characters
39+
must be separated by commas.
40+
41+
* With the `widths` attribute you can configure column widths via
42+
comma-separated numbers. The column widths will be relative to the numbers
43+
e.g. for `1,3` the second column will be three times as wide as the first.
44+
45+
For a demonstration of these features see [sample.md](sample.md).
46+
47+
[list tables]: https://docutils.sourceforge.io/docs/ref/rst/directives.html#list-table

list-table/expected.html

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<table>
2+
<caption></caption>
3+
<thead>
4+
<tr class="header">
5+
<th>Heading row 1, column 1</th>
6+
<th>Heading row 1, column 2</th>
7+
<th>Heading row 1, column 3</th>
8+
</tr>
9+
</thead>
10+
<tbody>
11+
<tr class="odd">
12+
<td>Row 1, column 1</td>
13+
<td></td>
14+
<td>Row 1, column 3</td>
15+
</tr>
16+
<tr class="even">
17+
<td>Row 2, column 1</td>
18+
<td>Row 2, column 2</td>
19+
<td></td>
20+
</tr>
21+
</tbody>
22+
</table>
23+
<table id="some-id" class="some-class">
24+
<caption>Here be some caption.</caption>
25+
<colgroup>
26+
<col style="width: 16%" />
27+
<col style="width: 33%" />
28+
<col style="width: 50%" />
29+
</colgroup>
30+
<thead>
31+
<tr class="header">
32+
<th style="text-align: left;">Heading row 1, column 1</th>
33+
<th style="text-align: center;">Heading row 1, column 2</th>
34+
<th style="text-align: right;">Heading row 1, column 3</th>
35+
</tr>
36+
</thead>
37+
<tbody>
38+
<tr class="odd">
39+
<td style="text-align: left;">Row 1, column 1</td>
40+
<td style="text-align: center;"></td>
41+
<td style="text-align: right;">Row 1, column 3</td>
42+
</tr>
43+
<tr class="even">
44+
<td style="text-align: left;">Row 2, column 1</td>
45+
<td style="text-align: center;">Row 2, column 2</td>
46+
<td style="text-align: right;"></td>
47+
</tr>
48+
</tbody>
49+
</table>

list-table/list-table.lua

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
-- lua filter for RST-like list-tables in Markdown.
2+
-- Copyright (C) 2021 Martin Fischer, released under MIT license
3+
4+
if PANDOC_VERSION and PANDOC_VERSION.must_be_at_least then
5+
PANDOC_VERSION:must_be_at_least("2.11")
6+
else
7+
error("pandoc version >=2.11 is required")
8+
end
9+
10+
local function process(div)
11+
if div.attr.classes[1] ~= "list-table" then return nil end
12+
table.remove(div.attr.classes, 1)
13+
14+
local caption = {}
15+
16+
if div.content[1].t == "Para" then
17+
caption = table.remove(div.content, 1).content
18+
end
19+
20+
assert(div.content[1].t == "BulletList",
21+
"expected bullet list, found " .. div.content[1].t)
22+
local list = div.content[1]
23+
24+
local rows = {}
25+
26+
for i = 1, #list.content do
27+
assert(#list.content[i] == 1, "expected item to contain only one block")
28+
assert(list.content[i][1].t == "BulletList",
29+
"expected bullet list, found " .. list.content[i][1].t)
30+
table.insert(rows, list.content[i][1].content)
31+
end
32+
33+
local aligns = {}
34+
local widths = {}
35+
36+
local headers = table.remove(rows, 1)
37+
38+
if div.attr.attributes.align then
39+
local alignments = {
40+
d = 'AlignDefault',
41+
l = 'AlignLeft',
42+
r = 'AlignRight',
43+
c = 'AlignCenter'
44+
}
45+
for a in div.attr.attributes.align:gmatch('[^,]') do
46+
assert(alignments[a] ~= nil,
47+
"unknown column alignment " .. tostring(a))
48+
table.insert(aligns, alignments[a])
49+
end
50+
div.attr.attributes.align = nil
51+
else
52+
for i = 1, #headers do table.insert(aligns, pandoc.AlignDefault) end
53+
end
54+
55+
if div.attr.attributes.widths then
56+
local total = 0
57+
for w in div.attr.attributes.widths:gmatch('[^,]') do
58+
table.insert(widths, tonumber(w))
59+
total = total + tonumber(w)
60+
end
61+
for i = 1, #headers do widths[i] = widths[i] / total end
62+
div.attr.attributes.widths = nil
63+
else
64+
for i = 1, #headers do
65+
table.insert(widths, 0) -- let pandoc determine col widths
66+
end
67+
end
68+
69+
local table = pandoc.utils.from_simple_table(
70+
pandoc.SimpleTable(caption, aligns, widths, headers, rows))
71+
table.attr = div.attr
72+
return {table}
73+
end
74+
75+
return {{Div = process}}

list-table/sample.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
:::list-table
2+
* - Heading row 1, column 1
3+
- Heading row 1, column 2
4+
- Heading row 1, column 3
5+
6+
* - Row 1, column 1
7+
-
8+
- Row 1, column 3
9+
10+
* - Row 2, column 1
11+
- Row 2, column 2
12+
:::
13+
14+
:::{.list-table align=l,c,r widths=1,2,3 #some-id .some-class}
15+
Here be some caption.
16+
17+
* - Heading row 1, column 1
18+
- Heading row 1, column 2
19+
- Heading row 1, column 3
20+
21+
* - Row 1, column 1
22+
-
23+
- Row 1, column 3
24+
25+
* - Row 2, column 1
26+
- Row 2, column 2
27+
:::
28+

0 commit comments

Comments
 (0)