-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathdocx-table-styles.lua
More file actions
155 lines (128 loc) · 3.62 KB
/
Copy pathdocx-table-styles.lua
File metadata and controls
155 lines (128 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
--- Route DOCX table styles for Quarto output.
---
--- Quarto often renders labeled floats (`#fig-*`, `#tbl-*`) with table wrappers.
--- We map wrapper/container tables -> `FigureTable` (no border),
--- and real data tables -> `Table` (three-line style).
--- Unlabeled figures (normal image path without `#fig-*`) are not affected.
--- Only table `custom-style` is changed.
--- Cannot use as a Quarto format filter since it needs to run after crossref labeling.
--- Copyright: © 2026–Present Tom Ben
--- License: MIT License
local STYLE_WRAPPER = "FigureTable"
local STYLE_DATA = "Table"
local function has_id_prefix(attr, prefix)
local id = attr and attr.identifier
if not id then
return false
end
return id:sub(1, #prefix + 1) == (prefix .. "-")
end
local function first_row(tbl)
if not tbl.bodies or #tbl.bodies == 0 then
return nil
end
local body = tbl.bodies[1]
if not body.body or #body.body == 0 then
return nil
end
return body.body[1]
end
local function first_cell(tbl)
local row = first_row(tbl)
if not row or not row.cells or #row.cells == 0 then
return nil
end
return row.cells[1], row
end
local function block_has_div_id_prefix(block, prefix)
if block.t ~= "Div" then
return false
end
if has_id_prefix(block.attr, prefix) then
return true
end
for _, child in ipairs(block.content or {}) do
if block_has_div_id_prefix(child, prefix) then
return true
end
end
return false
end
local function cell_has_div_prefix(cell, prefix)
for _, block in ipairs(cell.contents or {}) do
if block_has_div_id_prefix(block, prefix) then
return true
end
end
return false
end
-- Return wrapper type for labeled crossref tables: "fig", "tbl", or nil.
local function crossref_wrapper_kind(tbl)
local cell, row = first_cell(tbl)
if not cell then
return nil
end
-- Keep this strict to avoid matching real data tables.
if not row or not row.cells or #row.cells ~= 1 then
return nil
end
if cell_has_div_prefix(cell, "fig") then
return "fig"
end
if cell_has_div_prefix(cell, "tbl") then
return "tbl"
end
return nil
end
local function set_table_style(tbl, style_name)
tbl.attr = tbl.attr or pandoc.Attr("", {}, {})
tbl.attr.attributes = tbl.attr.attributes or {}
tbl.attr.attributes["custom-style"] = style_name
return tbl
end
local function set_all_col_align(tbl, align)
if not tbl.colspecs then
return tbl
end
for i, cs in ipairs(tbl.colspecs) do
cs[1] = align
tbl.colspecs[i] = cs
end
return tbl
end
function Table(tbl)
if not FORMAT:match("docx") then
return nil
end
-- Respect style decisions that may already be set by another pass.
if tbl.attr and tbl.attr.attributes and tbl.attr.attributes["custom-style"] then
return tbl
end
-- Wrapper for labeled figures: keep centered figure layout.
local wrapper_kind = crossref_wrapper_kind(tbl)
if wrapper_kind == "fig" then
set_all_col_align(tbl, pandoc.AlignCenter)
return set_table_style(tbl, STYLE_WRAPPER)
end
-- Wrapper for labeled tables: keep table body at default (not forced center).
if wrapper_kind == "tbl" then
set_all_col_align(tbl, pandoc.AlignDefault)
return set_table_style(tbl, STYLE_WRAPPER)
end
-- Default: real data table.
return set_table_style(tbl, STYLE_DATA)
end
function Div(div)
if not FORMAT:match("docx") then
return nil
end
-- Figure layouts (e.g. layout-ncol) may put tables inside `Div(id="fig-*")`.
if has_id_prefix(div.attr, "fig") then
return div:walk({
Table = function(tbl)
return set_table_style(tbl, STYLE_WRAPPER)
end
})
end
return nil
end