Skip to content

Commit 6e4d7da

Browse files
committed
lua filter to convert complex tables to list tables
1 parent fedd1ae commit 6e4d7da

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
-- Lua filter to convert Pandoc grid tables to list-table format
2+
-- This produces output that can be processed by list-table.lua
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+
-- Convert alignment enum to character code
11+
local function alignment_to_char(align)
12+
local align_str = tostring(align)
13+
if align_str == 'AlignLeft' then return 'l'
14+
elseif align_str == 'AlignRight' then return 'r'
15+
elseif align_str == 'AlignCenter' then return 'c'
16+
else return 'd' end
17+
end
18+
19+
-- Convert a cell to a list of blocks with optional attribute span prepended
20+
local function cell_to_blocks(cell)
21+
-- Extract cell properties using Lua API
22+
local contents = cell.contents
23+
local align = cell.alignment
24+
local rowspan = cell.row_span
25+
local colspan = cell.col_span
26+
local attr = cell.attr
27+
28+
-- Clone the blocks to avoid modifying the original
29+
local blocks = pandoc.Blocks({})
30+
for _, block in ipairs(contents) do
31+
table.insert(blocks, block:clone())
32+
end
33+
34+
-- If we have non-default cell attributes, prepend an empty span
35+
local align_str = tostring(align)
36+
if rowspan ~= 1 or colspan ~= 1 or align_str ~= 'AlignDefault' then
37+
local span_attr = pandoc.Attr('', {}, {})
38+
if colspan ~= 1 then
39+
span_attr.attributes.colspan = tostring(colspan)
40+
end
41+
if rowspan ~= 1 then
42+
span_attr.attributes.rowspan = tostring(rowspan)
43+
end
44+
if align_str ~= 'AlignDefault' then
45+
span_attr.attributes.align = alignment_to_char(align)
46+
end
47+
48+
local empty_span = pandoc.Span({}, span_attr)
49+
50+
-- Insert the empty span at the beginning of the first block's content
51+
if #blocks > 0 and blocks[1].content then
52+
table.insert(blocks[1].content, 1, empty_span)
53+
else
54+
-- If there's no content, create a paragraph with just the span
55+
blocks = pandoc.Blocks({pandoc.Para({empty_span})})
56+
end
57+
end
58+
59+
-- Ensure we have at least one block
60+
if #blocks == 0 then
61+
blocks = pandoc.Blocks({pandoc.Para({})})
62+
end
63+
64+
return blocks
65+
end
66+
67+
-- Convert a Pandoc Table to a list-table Div
68+
local function table_to_list_table(tbl)
69+
-- Extract table components using Lua API
70+
local attr = tbl.attr
71+
local caption = tbl.caption
72+
local colspecs = tbl.colspecs
73+
local thead = tbl.head
74+
local tbodies = tbl.bodies
75+
local tfoot = tbl.foot
76+
77+
-- Build div attributes, starting from table attributes
78+
local div_attr = pandoc.Attr(attr.identifier, {'list-table'}, {})
79+
80+
-- Copy table classes
81+
for _, class in ipairs(attr.classes) do
82+
table.insert(div_attr.classes, class)
83+
end
84+
85+
-- Copy table attributes
86+
for k, v in pairs(attr.attributes) do
87+
div_attr.attributes[k] = v
88+
end
89+
90+
-- Count header rows from thead
91+
local thead_rows = thead.rows
92+
local header_row_count = #thead_rows
93+
if header_row_count > 0 then
94+
div_attr.attributes['header-rows'] = tostring(header_row_count)
95+
end
96+
97+
-- Extract alignments and widths from colspecs
98+
local aligns = {}
99+
local widths = {}
100+
local has_non_default_widths = false
101+
102+
for i, colspec in ipairs(colspecs) do
103+
-- ColSpec is a pair: [1] = alignment, [2] = width
104+
local align = colspec[1]
105+
local width = colspec[2]
106+
107+
table.insert(aligns, alignment_to_char(align))
108+
109+
-- Width is a number (0.0-1.0) or ColWidthDefault
110+
if type(width) == "number" and width > 0 then
111+
table.insert(widths, tostring(width))
112+
has_non_default_widths = true
113+
else
114+
-- ColWidthDefault or 0
115+
table.insert(widths, "1")
116+
end
117+
end
118+
119+
-- Only add aligns if there are non-default alignments
120+
local has_non_default_aligns = false
121+
for _, a in ipairs(aligns) do
122+
if a ~= 'd' then
123+
has_non_default_aligns = true
124+
break
125+
end
126+
end
127+
128+
if has_non_default_aligns then
129+
div_attr.attributes.aligns = table.concat(aligns, ',')
130+
end
131+
132+
if has_non_default_widths then
133+
div_attr.attributes.widths = table.concat(widths, ',')
134+
end
135+
136+
-- Build div content
137+
local content = {}
138+
139+
-- Add caption if present
140+
if caption and caption.long and #caption.long > 0 then
141+
for _, block in ipairs(caption.long) do
142+
table.insert(content, block)
143+
end
144+
end
145+
146+
-- Build list of rows (each row is a list item containing a bullet list of cells)
147+
local row_items = {}
148+
149+
-- Add header rows
150+
for _, row in ipairs(thead_rows) do
151+
local cells = row.cells
152+
local cell_blocks_list = {}
153+
for _, cell in ipairs(cells) do
154+
table.insert(cell_blocks_list, cell_to_blocks(cell))
155+
end
156+
-- Each row item contains a single bullet list of cells
157+
table.insert(row_items, {pandoc.BulletList(cell_blocks_list)})
158+
end
159+
160+
-- Add body rows from all table bodies
161+
for _, tbody in ipairs(tbodies) do
162+
for _, row in ipairs(tbody.body) do
163+
local cells = row.cells
164+
local cell_blocks_list = {}
165+
for _, cell in ipairs(cells) do
166+
table.insert(cell_blocks_list, cell_to_blocks(cell))
167+
end
168+
-- Each row item contains a single bullet list of cells
169+
table.insert(row_items, {pandoc.BulletList(cell_blocks_list)})
170+
end
171+
end
172+
173+
-- Add footer rows if any
174+
for _, row in ipairs(tfoot.rows) do
175+
local cells = row.cells
176+
local cell_blocks_list = {}
177+
for _, cell in ipairs(cells) do
178+
table.insert(cell_blocks_list, cell_to_blocks(cell))
179+
end
180+
table.insert(row_items, {pandoc.BulletList(cell_blocks_list)})
181+
end
182+
183+
-- Create the outer bullet list (list of rows)
184+
table.insert(content, pandoc.BulletList(row_items))
185+
186+
return pandoc.Div(content, div_attr)
187+
end
188+
189+
return {{Table = table_to_list_table}}

0 commit comments

Comments
 (0)