-- 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