62 lines
1.8 KiB
Lua
Executable File
62 lines
1.8 KiB
Lua
Executable File
-- column-fit.lua (robust, 2025-06-05)
|
||
-- Auto-sizes every table so columns get a width proportional to the
|
||
-- longest word/line they contain. Works on Pandoc 2.17 → 3.x.
|
||
|
||
local stringify = (require 'pandoc.utils').stringify
|
||
local hasRCW = type(pandoc.RelativeColumnWidth) == "function"
|
||
|
||
-- UTF-8 code-point length (pure Lua)
|
||
local function ulen(s)
|
||
local _, n = s:gsub('[\0-\127\194-\244][\128-\191]*', '')
|
||
return n
|
||
end
|
||
|
||
-- ensure arrays are long enough ----------------------------------------
|
||
local function ensure(tbl, i, v)
|
||
if not tbl[i] then tbl[i] = v end
|
||
end
|
||
|
||
-- walk every cell ------------------------------------------------------
|
||
local function each_cell(t, fn)
|
||
local function rows(block)
|
||
if block then
|
||
for _, row in ipairs(block) do
|
||
for c, cell in ipairs(row.cells) do fn(cell, c) end
|
||
end
|
||
end
|
||
end
|
||
rows(t.head.rows)
|
||
for _, body in ipairs(t.bodies) do rows(body.body) end
|
||
rows(t.foot.rows)
|
||
end
|
||
|
||
function Table(t)
|
||
local max = {} -- longest token per col
|
||
|
||
-- pass 1 – measure --------------------------------------------------
|
||
each_cell(t, function (cell, col)
|
||
ensure(max, col, 0)
|
||
ensure(t.colspecs, col, {pandoc.AlignDefault, 0})
|
||
|
||
local txt = stringify(cell.contents or cell)
|
||
for line in txt:gmatch('[^\n]+') do
|
||
for word in line:gmatch('%S+') do
|
||
local len = ulen(word)
|
||
if len > max[col] then max[col] = len end
|
||
end
|
||
end
|
||
end)
|
||
|
||
local total = 0
|
||
for _, v in ipairs(max) do total = total + v end
|
||
if total == 0 then return nil end -- empty table
|
||
|
||
-- pass 2 – write widths back ----------------------------------------
|
||
for c, spec in ipairs(t.colspecs) do
|
||
local rel = max[c] / total
|
||
spec[2] = hasRCW and pandoc.RelativeColumnWidth(rel) or rel
|
||
end
|
||
return t
|
||
end
|
||
|