-- set-table-col-widths.lua -- -- Pandoc filter which sets the widths of columns to explicit -- percentages of the available width according to values given -- in an attribute `table-column-widths` or `table-col-widths` of -- an enclosing div. -- for example -- -- ````markdown -- ::: {table-col-widths="20 20 40"} -- -- |This|That|Description -- |----|----|----------- -- |Foo |Bar |Foo and bar -- -- ::: -- ```` -- -- will make the first two colums 20% wide and the third -- column 40% wide, taking up a total of 80% of the available -- width. -- -- If the attribute contains more widths than there are -- columns in an enclosed table the list of new widths will be -- truncated to fit, ignoring excess items. If on the other -- hand the attribute contains fewer widths than there are -- columns in an enclosed table the list of new widths will be -- extended to fit **by appending copies of the last item!** -- -- Note that any substrings in the attribute value which are not -- sequences of digits will be ignored except as separators. -- In particular something like "20.5" will count as two column -- widths of 20% and 5% respectively! -- If you want to make your attribute values more human -- friendly you can include commas, spaces and per cent signs -- like `20%, 20%, 40%`. The filter still only "sees" the -- three substrings `20`, `20` and `40` and something "crazy" -- like `-20:20 -- !40` would be -- entirely equivalent! -- -- Note that a percentage of zero has a special meaning: -- it makes the width of the corresponding column "automatic" -- so that it will fit the content of the row with the -- widest content for that column. -- -- If no sequences of digits are found in the attribute value -- all column widths are set to zero — i.e. automatic —, so that -- a human-friendly way of making all column widths -- automatic is to set the attribute value to the string -- `auto`, although `foo` or `Ni` or `""` will have the same -- effect! -- -- By default the enclosing div will be "removed", i.e. replaced -- with its possibly altered content. To avoid this set a class `.keep-div` on the div! local function copy_table (t) local c = {} for k,v in pairs(t) do c[k] = v end return c end local function gen_set_widths (wanted) local function set_widths (table) local old = table.widths local new = copy_table(wanted) if #new > #old then -- If there are more wanted widths than columns -- then truncate the list of new widths local start = #old+1 for i=#new, start, -1 do new[i] = nil end elseif #old > #new then -- If there are fewer wanted widths than columns then -- extend the list of new widths with copies of the last -- new width specified local last = new[#new] local start = #new+1 for i=start, #old do new[i] = last end end table.widths = new return table end return { Table = set_widths } end -- "Parse" a string of wanted widths by extracting all -- sequences of digits with string.gmatch, meaning that -- any sequences of non-digits are ignored except as separators. -- These are taken to be percentages of the total width -- available, so are divided by 100 to get the floats Pandoc wants local function extract_widths (str) wd = {} for w in str:gmatch('%d+') do wd[#wd+1] = tonumber(w, 10) / 100 end -- If no widths were found default to automatic width for all columns! if #wd == 0 then wd[1] = 0.0 end return wd end function Div (div) local wd_string = div.attributes['table-column-widths'] or div.attributes['table-col-widths'] if not wd_string then return nil end new_widths = extract_widths(wd_string) filter = gen_set_widths(new_widths) new_div = pandoc.walk_block(div, filter) if div.classes:includes('keep-div') then return new_div else return new_div.content end end