* Rewriting table filters
@ 2020-08-17 13:36 BPJ
[not found] ` <e47081d5-e61c-6b57-e747-65e22085f976-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
0 siblings, 1 reply; 3+ messages in thread
From: BPJ @ 2020-08-17 13:36 UTC (permalink / raw)
To: pandoc-discuss-/JYPxA39Uh5TLH3MbocFFw
[-- Attachment #1: Type: text/plain, Size: 2729 bytes --]
I would be grateful if someone who knows and understands the new table
model could comment on or assess how hard it might be to rewrite the two
attached filters which modify and create tables, and which I rely quite
heavily on. The more simple of them is written directly in Lua, the
other one is written in MoonScript and compiled into Lua code, for which
see below!
The — considerably — simpler of the two allows fine control over the
widths of table columns according to a “list” of percentages given in an
attribute of an enclosing div.
The other filter — considerably more complex already — which turns a
list of lists into a table or a table into a list of lists (similar in
the method it uses to specify column widths and column alignments) for
which I fear that a version for the new table model would be crazy
complex.
This second filter is written in MoonScript <http://moonscript.org>, a
terser scripting language which compiles source-to-source into Lua. The
Lua code produced by the MoonScript compiler is included for reference,
but it is far from elegant/idiomatic Lua code and not meant for humans
to read/work on. The filter is complex enough as is, so I don’t feel
like rewriting it in idiomatic Lua just for expository purposes! If you
know a bunch of scripting languages — in particular (not incidentally!)
CoffeeScript — MoonScript code isn’t hard to follow. The intro at
<https://learnxinyminutes.com/docs/moonscript/> might be helpful.
However it can be hard to see what this filter does just from looking at
the code, so I have included a Markdown file with description and
examples.
I originally wrote the list—table filter for a document where there is a
long table where each row has a very narrow left column containing a
symbol — but not so narrow in the source since the symbol is wrapped in
a span with both an id (unique among about a hundred ids) and a class —,
and two wider cells, which may contain several paragraphs and lists with
various spans with attributes, describing the use of each symbol in two
different contexts. I did try to write that table as a grid table but
soon had to give up. Writing a list of lists with three items in each
second-level list made for a much more unconstrained writing process.
--
You received this message because you are subscribed to the Google Groups "pandoc-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pandoc-discuss+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To view this discussion on the web visit https://groups.google.com/d/msgid/pandoc-discuss/e47081d5-e61c-6b57-e747-65e22085f976%40gmail.com.
[-- Attachment #2: set-table-col-widths.lua --]
[-- Type: text/x-lua, Size: 3905 bytes --]
-- 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
[-- Attachment #3: README.md --]
[-- Type: text/markdown, Size: 5568 bytes --]
# list-table
This Pandoc filter allows to convert lists of lists (bullet lists and/or
ordered lists) into tables. This makes it easier to type long tables and
tables with "complicated" content because you don't need to
draw any ASCII art.
The filter can also convert tables to lists of lists,
allowing full roundtripping.
## Usage
Obviously it would be dysfunctional if all lists of lists
were converted to tables. Hence you must tell the filter
that you want to convert a given list of list to a table by
wrapping the list in a div with the class `lol2table` (short
for "list-of-lists-to-table":
````pandoc
:::lol2table
* - foo
- bar
- baz
* - + tic
+ pic
- + tac
+ pac
:::
````
When running this through pandoc with the filter enabled and
with markdown as output format it is replaced with this:
````pandoc
+---------+---------+-----+
| foo | bar | baz |
+=========+=========+=====+
| - tic | - tac | |
| - pic | - pac | |
+---------+---------+-----+
````
Note how each item in the top level list becomes a table
row and each item in the second level list becomes a table
cell, while third level list remain lists. Note also that
the filter handles the situation where there are only two
items in the second second-level list: if any rows are shorter
than the longest row they are padded with empty cells
towards the end.
### Headerless tables
To turn a list of lists into a headerless table just include
the class `no-header` (or `noheader`) on the wrapping div:
````pandoc
::: {.lol2table}
Table with header
1. 1. foo
2. bar
3. baz
2. 1. tic
2. tac
3. toc
:::
::: {.lol2table .no-header}
Table without header
1. 1. foo
2. bar
3. baz
2. 1. tic
2. tac
3. toc
:::
````
````pandoc
foo bar baz
----- ----- -----
tic tac toc
: Table with header
----- ----- -----
foo bar baz
tic tac toc
----- ----- -----
: Table without header
````
### Captions
The previous example also shows how to set a caption on the
table: just include a paragraph with the caption text inside
the div.
### Custom alignments and custom column widths
To specify the alignment of the table columns set an
attribute `align` on the div. Its value should be a comma
separated "list" (and I mean *comma* separated, not
comma-and-whitespace!) of any of the letters `d l c r`
(for `AlignDefault`, `AlignLeft`, `AlignCenter`, `AlignRight`
respectively):
````pandoc
::: {.lol2table align="l,c,r"}
* - foo
- bar
- baz
* - + tic
+ pic
- + tac
+ pac
:::
````
````pandoc
+---------+---------+-----+
| foo | bar | baz |
+:========+:=======:+====:+
| - tic | - tac | |
| - pic | - pac | |
+---------+---------+-----+
````
Likewise to specify the relative width of columns include an
attribute `widths` on the div. Its value should be
a comma-separated (again really *comma* separated!) "list" of
integers between 0 and 100, where each integer is the
percentage of the available total width which should be the
width of the respective column:
````pandoc
::: {.lol2table widths="20,40,10"}
* - foo
- bar
- baz
* - + tic
+ pic
- + tac
+ pac
:::
````
````pandoc
+-------------+---------------------------+------+
| foo | bar | baz |
+=============+===========================+======+
| - tic | - tac | |
| - pic | - pac | |
+-------------+---------------------------+------+
````
Naturally you can combine the two:
````pandoc
::: {.lol2table align="l,c,r" widths="20,40,10"}
* - foo
- bar
- baz
* - tic
- tac
:::
````
````pandoc
---------------------------------------------------
foo bar baz
-------------- ---------------------------- -------
tic tac
---------------------------------------------------
````
If you specify more alignments or widths than there are
columns the extra alignments/widths will be ignored.
If you specify fewer alignments than there are columns the
list of alignments is padded to the right length with copies
of the rightmost alignment actually specified.
If you specify fewer widths than there are columns the list
of widths is padded to the right length with zeroes.
This should cause Pandoc to distribute the remaining width
between them.
## Roundtripping
To convert a table into a list of lists you wrap it in a div
with the class `table2lol`:
````pandoc
:::table2lol
|foo|bar|baz
|---|---|---
|tic|tac|toc
:::
````
````pandoc
0. 1. foo
2. bar
3. baz
1. 1. tic
2. tac
3. toc
````
Note that the resulting lists always are numbered lists and
that if there was a header row the numbering of the
top-level list starts at zero.
### Keeping the div
If you include a class `keep-div` (or `keepdiv`) on the div
the result will also be wrapped in a div, designed to make
roundtripping easier:
````pandoc
::: {#alpha .lol2table .keep-div}
1. 1. foo
2. bar
3. baz
2. 1. tic
2. tac
3. toc
:::
::: {#beta .table2lol .keep-div}
foo bar baz
----- ----- -----
tic tac toc
:::
````
::: {#alpha .maybe-table2lol .keep-div}
foo bar baz
----- ----- -----
tic tac toc
:::
::: {#beta .maybe-lol2table .keep-div align="l,l,l" widths="0,0,0"}
0. 1. foo
2. bar
3. baz
1. 1. tic
2. tac
3. toc
:::
[-- Attachment #4: list-table.lua --]
[-- Type: text/x-lua, Size: 9135 bytes --]
local concat, insert, pack, remove
do
local _obj_0 = table
concat, insert, pack, remove = _obj_0.concat, _obj_0.insert, _obj_0.pack, _obj_0.remove
end
local floor
floor = math.floor
local assertion
assertion = function(msg, val)
return assert(val, msg)
end
local contains_any
contains_any = function(...)
local wanted
do
local _tbl_0 = { }
local _list_0 = pack(...)
for _index_0 = 1, #_list_0 do
local w = _list_0[_index_0]
_tbl_0[w] = true
end
wanted = _tbl_0
end
return function(list)
local _exp_0 = type(list)
if 'table' == _exp_0 then
for _index_0 = 1, #list do
local v = list[_index_0]
if wanted[v] then
return true
end
end
else
return nil
end
return false
end
end
local is_elem
is_elem = function(x, ...)
local _exp_0 = type(x)
if 'table' == _exp_0 then
local tag = x.tag
local _exp_1 = type(tag)
if 'string' == _exp_1 then
local tags = pack(...)
if #tags > 0 then
for _index_0 = 1, #tags do
local t = tags[_index_0]
if t == tag then
return tag
end
end
return nil
end
return true
end
return false
end
end
local get_div_id
get_div_id = function(cls, div, div_count)
if div_count == nil then
div_count = ""
end
local div_id = div.identifier or ""
if "" == div_id then
div_id = div_count
end
return tostring(cls) .. " div #" .. tostring(div_id)
end
local letter2align = {
d = 'AlignDefault',
l = 'AlignLeft',
c = 'AlignCenter',
r = 'AlignRight'
}
local align2letter
do
local _tbl_0 = { }
for k, v in pairs(letter2align) do
_tbl_0[v] = k
end
align2letter = _tbl_0
end
local contains_no_header = contains_any('no-header', 'noheader')
local contains_keep_div = contains_any('keep-div', 'keepdiv')
local lol2table
do
local div_count = 0
lol2table = function(div)
div_count = div_count + 1
local div_id = get_div_id('lol2table', div, div_count)
local lol, caption = nil, nil
local _list_0 = div.content
for _index_0 = 1, #_list_0 do
local _continue_0 = false
repeat
local item = _list_0[_index_0]
if not (is_elem(item)) then
_continue_0 = true
break
end
local _exp_0 = item.tag
if 'BulletList' == _exp_0 or 'OrderedList' == _exp_0 then
if lol then
error("Expected only one list in " .. tostring(div_id), 2)
end
lol = item
elseif 'Para' == _exp_0 or 'Plain' == _exp_0 then
if caption then
error("Expected only one caption paragraph in " .. tostring(div_id), 2)
end
caption = item.content
else
error("Didn't expect " .. tostring(item.tag) .. " in " .. tostring(div_id), 2)
end
_continue_0 = true
until true
if not _continue_0 then
break
end
end
if not (lol) then
return nil
end
caption = caption or { }
if not (is_elem(lol, 'BulletList', 'OrderedList')) then
return nil
end
local header = not (contains_no_header(div.classes))
local rows = { }
local col_count = 0
local _list_1 = lol.content
for _index_0 = 1, #_list_1 do
local item = _list_1[_index_0]
assertion("Expected list in " .. tostring(div_id) .. " to be list of lists", #item == 1 and is_elem(item[1], 'BulletList', 'OrderedList'))
local row = item[1].content
if #row > col_count then
col_count = #row
end
rows[#rows + 1] = row
end
for _index_0 = 1, #rows do
local row = rows[_index_0]
while #row < col_count do
row[#row + 1] = { }
end
end
local headers
if header then
headers = remove(rows, 1)
else
headers = { }
end
local aligns = { }
local align = (div.attributes.align or ""):lower()
if "" == align then
align = 'd'
end
for a in align:gmatch('[^,]+') do
aligns[#aligns + 1] = assertion("Unknown column alignment in " .. tostring(div_id) .. ": '" .. tostring(a) .. "'", letter2align[a])
if #aligns == col_count then
break
end
end
while #aligns < col_count do
aligns[#aligns + 1] = aligns[#aligns]
end
local widths = { }
local width = div.attributes.widths or ""
if "" == width then
width = '0'
end
for w in width:gmatch('[^,]+') do
assertion("Expected column width in " .. tostring(div_id) .. " to be percentage, not '" .. tostring(w) .. "'", w:match('^[01]?%d?%d$'))
widths[#widths + 1] = tonumber(w, 10) / 100
if #widths == col_count then
break
end
end
while #widths < col_count do
widths[#widths + 1] = 0
end
local ok, res = pcall(pandoc.Table, caption, aligns, widths, headers, rows)
assert(ok, "Error converting list to table in " .. tostring(div_id) .. ": " .. tostring(res))
if contains_keep_div(div.classes) then
local attr = div.attr
local _list_2 = {
'align',
'widths'
}
for _index_0 = 1, #_list_2 do
local key = _list_2[_index_0]
attr.attributes[key] = nil
end
do
local _accum_0 = { }
local _len_0 = 1
local _list_3 = div.classes
for _index_0 = 1, #_list_3 do
local c = _list_3[_index_0]
if 'lol2table' ~= c then
_accum_0[_len_0] = c
_len_0 = _len_0 + 1
end
end
attr.classes = _accum_0
end
insert(attr.classes, 1, 'maybe-table2lol')
return pandoc.Div({
res
}, attr)
end
return res
end
end
local table2lol
do
local no_class = {
table2lol = true,
['no-header'] = true,
noheader = true
}
local div_count = 0
table2lol = function(div)
div_count = div_count + 1
if #div.content == 0 then
return nil
end
local div_id = get_div_id('table2lol', div, div_count)
assertion("Expected " .. tostring(div_id) .. " to contain only a table", #div.content == 1 and is_elem(div.content[1], 'Table'))
local tab = div.content[1]
local caption, headers, rows = tab.caption, tab.headers, tab.rows
local header = false
for _index_0 = 1, #headers do
local h = headers[_index_0]
if #h > 0 then
header = true
end
end
local lol
do
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #rows do
local row = rows[_index_0]
_accum_0[_len_0] = {
pandoc.OrderedList(row)
}
_len_0 = _len_0 + 1
end
lol = _accum_0
end
local list_attr = pandoc.ListAttributes()
if header then
insert(lol, 1, {
pandoc.OrderedList(headers)
})
list_attr.start = 0
end
lol = pandoc.OrderedList(lol, list_attr)
if contains_keep_div(div.classes) then
local cols = {
align = (function()
local _accum_0 = { }
local _len_0 = 1
local _list_0 = tab.aligns
for _index_0 = 1, #_list_0 do
local a = _list_0[_index_0]
_accum_0[_len_0] = align2letter[a]
_len_0 = _len_0 + 1
end
return _accum_0
end)(),
widths = (function()
local _accum_0 = { }
local _len_0 = 1
local _list_0 = tab.widths
for _index_0 = 1, #_list_0 do
local w = _list_0[_index_0]
_accum_0[_len_0] = floor(w * 100)
_len_0 = _len_0 + 1
end
return _accum_0
end)()
}
local classes
do
local _accum_0 = { }
local _len_0 = 1
local _list_0 = div.classes
for _index_0 = 1, #_list_0 do
local c = _list_0[_index_0]
if not no_class[c] then
_accum_0[_len_0] = c
_len_0 = _len_0 + 1
end
end
classes = _accum_0
end
if #caption > 0 then
caption = pandoc.Para(caption)
else
caption = pandoc.Null()
end
if not (header) then
insert(classes, 1, 'no-header')
end
insert(classes, 1, 'maybe-lol2table')
local attr = div.attr
attr.classes = classes
for key, list in pairs(cols) do
attr.attributes[key] = concat(list, ",")
end
return pandoc.Div({
lol,
caption
}, attr)
end
return lol
end
end
do
local div_count = 0
return {
{
Div = function(self)
div_count = div_count + 1
local is_lol2table = self.classes:includes('lol2table')
local is_table2lol = self.classes:includes('table2lol')
if is_lol2table and is_table2lol then
local div_id = get_div_id("", self, div_count)
error("Expected" .. tostring(div_id) .. " to have class .lol2table or class .table2lol, not both")
elseif is_lol2table then
return lol2table(self)
elseif is_table2lol then
return table2lol(self)
end
return nil
end
}
}
end
[-- Attachment #5: list-table.moon --]
[-- Type: text/plain, Size: 9192 bytes --]
import concat, insert, pack, remove from table
import floor from math
assertion = (msg, val) -> assert val, msg
-- contains_any(val1 [, val2, ...])
-- returns a closure such that closure(x) returns
-- * nil if x is not a table
-- * true if x is an array and contains a value
-- which is equal to one of val1, ...
-- * false otherwise
contains_any = (...) ->
wanted = {w, true for w in *pack ...}
return (list) ->
switch type list
when 'table'
for v in *list
if wanted[v]
return true
else
return nil
return false
-- is_elem(val, tag1 [, tag2, ...])
-- returns
-- * false if x is not a table
-- * false if x.tag is not a string
-- * x.tag if x.tag equals one of tag1, ...
-- * nil otherwise
-- is_elem(x)
-- returns
-- * false if x is not a table
-- * false if x.tag is not a string
-- * true otherwise
is_elem = (x, ...) ->
switch type x
when 'table'
tag = x.tag
switch type tag
when 'string'
tags = pack ...
if #tags > 0
for t in *tags
if t == tag
return tag
return nil
return true
return false
-- get_div_id(cls, div [, div_count])
--
-- Takes the following arguments:
--
-- 1. A string. May be a class name, something else which
-- migh serve as a "div type", or an empty string.
--
-- 2. An actual Pandoc Div object.
--
-- 3. An optional number, assumed to be the number of divs of
-- the same "type" already seen, including the current
-- one.
--
-- Returns a string of the form `<cls> div #<id>`, where
-- `<id>` is either the id attribute of `div`, or if
-- that is empty the `div_count`.
get_div_id = (cls, div, div_count="") ->
div_id = div.identifier or ""
div_id = div_count if "" == div_id
return "#{cls} div ##{div_id}"
-- Map one-letter abbreviations to full alignment type names.
letter2align = {
d: 'AlignDefault'
l: 'AlignLeft'
c: 'AlignCenter'
r: 'AlignRight'
}
-- Map full alignment type names to one-letter abbreviations.
align2letter = {v,k for k,v in pairs letter2align}
-- Functions to look for variants of the 'magic' classes.
contains_no_header = contains_any 'no-header', 'noheader'
contains_keep_div = contains_any 'keep-div', 'keepdiv'
-- Function to convert a list of lists to a table
lol2table = do
-- Keep track of how many lol2table divs we have seen.
div_count = 0
-- The function receives the enclosing div as argument
(div) ->
-- Increment the count
div_count += 1
-- Get a moniker for this div
div_id = get_div_id 'lol2table', div, div_count
-- Now look up the LoL and the caption paragraph if any.
-- Start by declaring the variables
lol, caption = nil, nil
-- Now loop through the children of the div:
for item in *div.content
continue unless is_elem item -- can't happen!
-- See what kind of element we got
switch item.tag
when 'BulletList', 'OrderedList'
-- Complain if we already saw a list
if lol
error "Expected only one list in #{div_id}", 2
lol = item
when 'Para', 'Plain'
-- Complain if we already saw a paragraph
if caption
error "Expected only one caption paragraph in #{div_id}", 2
caption = item.content
else
-- Complain if we see something other than a list or para
error "Didn't expect #{item.tag} in #{div_id}", 2
-- Abort if we didn't see any list
return nil unless lol
-- The caption defaults to an empty list
caption or= {}
-- This can't really happen, so why is this check there?
unless is_elem lol, 'BulletList', 'OrderedList'
return nil
-- Do we want a table with a header?
header = not( contains_no_header div.classes )
-- Init the array of rows
rows = {}
-- Init the column count
col_count = 0
-- Loop through the list items
for item in *lol.content
-- Check that the item contains a list and nothing else
assertion "Expected list in #{div_id} to be list of lists",
#item == 1 and is_elem item[1], 'BulletList', 'OrderedList'
-- The items of the inner list are the next table row
row = item[1].content
-- If this row is longer than any seen before
-- we update the column count
if #row > col_count
col_count = #row
rows[#rows+1] = row
-- Make sure all rows are the same length by adding empty
-- cells until they are the same length as the longest row
for row in *rows
while #row < col_count
row[#row+1] = {}
-- If we want a header use the first row,
-- else set the headers to an empty list
headers = if header
remove rows, 1
else
{}
-- Init the list of aligns
aligns = {}
-- Get the align attribute if any and coerce it to lowercase
align = (div.attributes.align or "")\lower!
-- If the align attr is empty it defaults to a single d
align = 'd' if "" == align
-- Now step through the comma-separated "items"
for a in align\gmatch '[^,]+'
-- Check that we have a valid "align-letter" and
-- append its expansion to the list of aligns
aligns[#aligns+1] = assertion "Unknown column alignment in #{div_id}: '#{a}'",
letter2align[a]
-- Don't look any further if we got the right number of aligns
if #aligns == col_count
break
-- If we got too few aligns pad out with copies of the last
while #aligns < col_count
aligns[#aligns+1] = aligns[#aligns]
-- Now do the same with widths
widths = {}
width = div.attributes.widths or ""
-- Widths default to automatic widths
width = '0' if "" == width
for w in width\gmatch '[^,]+'
-- A width is a percentage of the available total width,
-- tableso an integer with up to three digits
assertion "Expected column width in #{div_id} to be percentage, not '#{w}'",
w\match '^[01]?%d?%d$'
-- Convert it to a float and append it to the
-- list of widths
widths[#widths+1] = tonumber(w, 10) / 100
if #widths == col_count
break
while #widths < col_count
-- Pad with auto widths if we got too few widths
widths[#widths+1] = 0
-- See if we can create a table
ok, res = pcall pandoc.Table, caption, aligns, widths, headers, rows
-- and give a nice error message if we fail
assert ok, "Error converting list to table in #{div_id}: #{res}"
-- Do we want to keep the div?
if contains_keep_div div.classes
-- Reuse the attrs of the old div as far as possible!
attr = div.attr
-- Remove any old align/widths attrs since they may
-- become inaccurate if the table is altered.
for key in *{'align', 'widths'}
attr.attributes[key] = nil
-- Remove the lol2table class which certainly is
-- wrong now
attr.classes = [c for c in *div.classes when 'lol2table' != c]
-- but make it easy for the user to revert to a LoL
-- should they want to!
insert attr.classes, 1, 'maybe-table2lol'
-- Return a div with the table and the attributes
return pandoc.Div {res}, attr
-- Else don't keep the div, just return the table!
return res
table2lol = do
no_class = table2lol: true, 'no-header': true, noheader: true
div_count = 0
(div) ->
div_count += 1
return nil if #div.content == 0
div_id = get_div_id 'table2lol', div, div_count
assertion "Expected #{div_id} to contain only a table",
#div.content == 1 and is_elem div.content[1], 'Table'
tab = div.content[1]
caption, headers, rows = tab.caption, tab.headers, tab.rows
header = false
for h in *headers
header = true if #h > 0
lol = [ {pandoc.OrderedList(row)} for row in *rows ]
list_attr = pandoc.ListAttributes!
if header
insert lol, 1, {pandoc.OrderedList(headers)}
list_attr.start = 0
lol = pandoc.OrderedList lol, list_attr
if contains_keep_div div.classes
cols = {
align: [align2letter[a] for a in *tab.aligns]
widths: [floor(w * 100) for w in *tab.widths]
}
classes = [ c for c in *div.classes when not no_class[c] ]
caption = if #caption > 0
pandoc.Para caption
else
pandoc.Null!
unless header
insert classes, 1, 'no-header'
insert classes, 1, 'maybe-lol2table'
attr = div.attr
attr.classes = classes
for key, list in pairs cols
attr.attributes[key] = concat list, ","
return pandoc.Div {lol, caption}, attr
return lol
return do
div_count = 0
{
{
Div: =>
div_count += 1
is_lol2table = @classes\includes 'lol2table'
is_table2lol = @classes\includes 'table2lol'
if is_lol2table and is_table2lol
div_id = get_div_id "", @, div_count
error "Expected#{div_id} to have class .lol2table or class .table2lol, not both"
elseif is_lol2table
return lol2table @
elseif is_table2lol
return table2lol @
return nil
}
}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Rewriting table filters
[not found] ` <e47081d5-e61c-6b57-e747-65e22085f976-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2020-08-18 0:09 ` EBkysko
[not found] ` <702aad33-76ea-4766-9bc9-4c2127b938c1o-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org>
0 siblings, 1 reply; 3+ messages in thread
From: EBkysko @ 2020-08-18 0:09 UTC (permalink / raw)
To: pandoc-discuss
[-- Attachment #1.1: Type: text/plain, Size: 874 bytes --]
See the pull request from AW/tarleb : *Lua filters: allow using SimpleTable
instead of Table #6575 <https://github.com/jgm/pandoc/pull/6575>* which
would give a way to adapt to the previous table scheme, when it is
available.
So if your scripts works with the previous format, they would still work
with the new.
In the meantime, you might *look here at my own attempt at a shim
<https://groups.google.com/d/msg/pandoc-discuss/E1k7Wf9VGwQ/GsiUHhG3BQAJ>*.
--
You received this message because you are subscribed to the Google Groups "pandoc-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pandoc-discuss+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To view this discussion on the web visit https://groups.google.com/d/msgid/pandoc-discuss/702aad33-76ea-4766-9bc9-4c2127b938c1o%40googlegroups.com.
[-- Attachment #1.2: Type: text/html, Size: 1301 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Rewriting table filters
[not found] ` <702aad33-76ea-4766-9bc9-4c2127b938c1o-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org>
@ 2020-08-18 0:10 ` EBkysko
0 siblings, 0 replies; 3+ messages in thread
From: EBkysko @ 2020-08-18 0:10 UTC (permalink / raw)
To: pandoc-discuss
[-- Attachment #1.1: Type: text/plain, Size: 21 bytes --]
edit, typo: AW -> AK
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-08-18 0:10 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-17 13:36 Rewriting table filters BPJ
[not found] ` <e47081d5-e61c-6b57-e747-65e22085f976-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2020-08-18 0:09 ` EBkysko
[not found] ` <702aad33-76ea-4766-9bc9-4c2127b938c1o-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org>
2020-08-18 0:10 ` EBkysko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).