| 
 | 1 | +-- Lua filter to convert Pandoc grid tables to list-table format  | 
 | 2 | +-- This produces output that can be processed by list-table.lua  | 
 | 3 | + | 
 | 4 | +if PANDOC_VERSION and PANDOC_VERSION.must_be_at_least then  | 
 | 5 | +    PANDOC_VERSION:must_be_at_least("2.11")  | 
 | 6 | +else  | 
 | 7 | +    error("pandoc version >=2.11 is required")  | 
 | 8 | +end  | 
 | 9 | + | 
 | 10 | +-- Convert alignment enum to character code  | 
 | 11 | +local function alignment_to_char(align)  | 
 | 12 | +    local align_str = tostring(align)  | 
 | 13 | +    if align_str == 'AlignLeft' then return 'l'  | 
 | 14 | +    elseif align_str == 'AlignRight' then return 'r'  | 
 | 15 | +    elseif align_str == 'AlignCenter' then return 'c'  | 
 | 16 | +    else return 'd' end  | 
 | 17 | +end  | 
 | 18 | + | 
 | 19 | +-- Convert a cell to a list of blocks with optional attribute span prepended  | 
 | 20 | +local function cell_to_blocks(cell)  | 
 | 21 | +    -- Extract cell properties using Lua API  | 
 | 22 | +    local contents = cell.contents  | 
 | 23 | +    local align = cell.alignment  | 
 | 24 | +    local rowspan = cell.row_span  | 
 | 25 | +    local colspan = cell.col_span  | 
 | 26 | +    local attr = cell.attr  | 
 | 27 | + | 
 | 28 | +    -- Clone the blocks to avoid modifying the original  | 
 | 29 | +    local blocks = pandoc.Blocks({})  | 
 | 30 | +    for _, block in ipairs(contents) do  | 
 | 31 | +        table.insert(blocks, block:clone())  | 
 | 32 | +    end  | 
 | 33 | + | 
 | 34 | +    -- If we have non-default cell attributes, prepend an empty span  | 
 | 35 | +    local align_str = tostring(align)  | 
 | 36 | +    if rowspan ~= 1 or colspan ~= 1 or align_str ~= 'AlignDefault' then  | 
 | 37 | +        local span_attr = pandoc.Attr('', {}, {})  | 
 | 38 | +        if colspan ~= 1 then  | 
 | 39 | +            span_attr.attributes.colspan = tostring(colspan)  | 
 | 40 | +        end  | 
 | 41 | +        if rowspan ~= 1 then  | 
 | 42 | +            span_attr.attributes.rowspan = tostring(rowspan)  | 
 | 43 | +        end  | 
 | 44 | +        if align_str ~= 'AlignDefault' then  | 
 | 45 | +            span_attr.attributes.align = alignment_to_char(align)  | 
 | 46 | +        end  | 
 | 47 | + | 
 | 48 | +        local empty_span = pandoc.Span({}, span_attr)  | 
 | 49 | + | 
 | 50 | +        -- Insert the empty span at the beginning of the first block's content  | 
 | 51 | +        if #blocks > 0 and blocks[1].content then  | 
 | 52 | +            table.insert(blocks[1].content, 1, empty_span)  | 
 | 53 | +        else  | 
 | 54 | +            -- If there's no content, create a paragraph with just the span  | 
 | 55 | +            blocks = pandoc.Blocks({pandoc.Para({empty_span})})  | 
 | 56 | +        end  | 
 | 57 | +    end  | 
 | 58 | + | 
 | 59 | +    -- Ensure we have at least one block  | 
 | 60 | +    if #blocks == 0 then  | 
 | 61 | +        blocks = pandoc.Blocks({pandoc.Para({})})  | 
 | 62 | +    end  | 
 | 63 | + | 
 | 64 | +    return blocks  | 
 | 65 | +end  | 
 | 66 | + | 
 | 67 | +-- Convert a Pandoc Table to a list-table Div  | 
 | 68 | +local function table_to_list_table(tbl)  | 
 | 69 | +    -- Extract table components using Lua API  | 
 | 70 | +    local attr = tbl.attr  | 
 | 71 | +    local caption = tbl.caption  | 
 | 72 | +    local colspecs = tbl.colspecs  | 
 | 73 | +    local thead = tbl.head  | 
 | 74 | +    local tbodies = tbl.bodies  | 
 | 75 | +    local tfoot = tbl.foot  | 
 | 76 | + | 
 | 77 | +    -- Build div attributes, starting from table attributes  | 
 | 78 | +    local div_attr = pandoc.Attr(attr.identifier, {'list-table'}, {})  | 
 | 79 | + | 
 | 80 | +    -- Copy table classes  | 
 | 81 | +    for _, class in ipairs(attr.classes) do  | 
 | 82 | +        table.insert(div_attr.classes, class)  | 
 | 83 | +    end  | 
 | 84 | + | 
 | 85 | +    -- Copy table attributes  | 
 | 86 | +    for k, v in pairs(attr.attributes) do  | 
 | 87 | +        div_attr.attributes[k] = v  | 
 | 88 | +    end  | 
 | 89 | + | 
 | 90 | +    -- Count header rows from thead  | 
 | 91 | +    local thead_rows = thead.rows  | 
 | 92 | +    local header_row_count = #thead_rows  | 
 | 93 | +    if header_row_count > 0 then  | 
 | 94 | +        div_attr.attributes['header-rows'] = tostring(header_row_count)  | 
 | 95 | +    end  | 
 | 96 | + | 
 | 97 | +    -- Extract alignments and widths from colspecs  | 
 | 98 | +    local aligns = {}  | 
 | 99 | +    local widths = {}  | 
 | 100 | +    local has_non_default_widths = false  | 
 | 101 | + | 
 | 102 | +    for i, colspec in ipairs(colspecs) do  | 
 | 103 | +        -- ColSpec is a pair: [1] = alignment, [2] = width  | 
 | 104 | +        local align = colspec[1]  | 
 | 105 | +        local width = colspec[2]  | 
 | 106 | + | 
 | 107 | +        table.insert(aligns, alignment_to_char(align))  | 
 | 108 | + | 
 | 109 | +        -- Width is a number (0.0-1.0) or ColWidthDefault  | 
 | 110 | +        if type(width) == "number" and width > 0 then  | 
 | 111 | +            table.insert(widths, tostring(width))  | 
 | 112 | +            has_non_default_widths = true  | 
 | 113 | +        else  | 
 | 114 | +            -- ColWidthDefault or 0  | 
 | 115 | +            table.insert(widths, "1")  | 
 | 116 | +        end  | 
 | 117 | +    end  | 
 | 118 | + | 
 | 119 | +    -- Only add aligns if there are non-default alignments  | 
 | 120 | +    local has_non_default_aligns = false  | 
 | 121 | +    for _, a in ipairs(aligns) do  | 
 | 122 | +        if a ~= 'd' then  | 
 | 123 | +            has_non_default_aligns = true  | 
 | 124 | +            break  | 
 | 125 | +        end  | 
 | 126 | +    end  | 
 | 127 | + | 
 | 128 | +    if has_non_default_aligns then  | 
 | 129 | +        div_attr.attributes.aligns = table.concat(aligns, ',')  | 
 | 130 | +    end  | 
 | 131 | + | 
 | 132 | +    if has_non_default_widths then  | 
 | 133 | +        div_attr.attributes.widths = table.concat(widths, ',')  | 
 | 134 | +    end  | 
 | 135 | + | 
 | 136 | +    -- Build div content  | 
 | 137 | +    local content = {}  | 
 | 138 | + | 
 | 139 | +    -- Add caption if present  | 
 | 140 | +    if caption and caption.long and #caption.long > 0 then  | 
 | 141 | +        for _, block in ipairs(caption.long) do  | 
 | 142 | +            table.insert(content, block)  | 
 | 143 | +        end  | 
 | 144 | +    end  | 
 | 145 | + | 
 | 146 | +    -- Build list of rows (each row is a list item containing a bullet list of cells)  | 
 | 147 | +    local row_items = {}  | 
 | 148 | + | 
 | 149 | +    -- Add header rows  | 
 | 150 | +    for _, row in ipairs(thead_rows) do  | 
 | 151 | +        local cells = row.cells  | 
 | 152 | +        local cell_blocks_list = {}  | 
 | 153 | +        for _, cell in ipairs(cells) do  | 
 | 154 | +            table.insert(cell_blocks_list, cell_to_blocks(cell))  | 
 | 155 | +        end  | 
 | 156 | +        -- Each row item contains a single bullet list of cells  | 
 | 157 | +        table.insert(row_items, {pandoc.BulletList(cell_blocks_list)})  | 
 | 158 | +    end  | 
 | 159 | + | 
 | 160 | +    -- Add body rows from all table bodies  | 
 | 161 | +    for _, tbody in ipairs(tbodies) do  | 
 | 162 | +        for _, row in ipairs(tbody.body) do  | 
 | 163 | +            local cells = row.cells  | 
 | 164 | +            local cell_blocks_list = {}  | 
 | 165 | +            for _, cell in ipairs(cells) do  | 
 | 166 | +                table.insert(cell_blocks_list, cell_to_blocks(cell))  | 
 | 167 | +            end  | 
 | 168 | +            -- Each row item contains a single bullet list of cells  | 
 | 169 | +            table.insert(row_items, {pandoc.BulletList(cell_blocks_list)})  | 
 | 170 | +        end  | 
 | 171 | +    end  | 
 | 172 | + | 
 | 173 | +    -- Add footer rows if any  | 
 | 174 | +    for _, row in ipairs(tfoot.rows) do  | 
 | 175 | +        local cells = row.cells  | 
 | 176 | +        local cell_blocks_list = {}  | 
 | 177 | +        for _, cell in ipairs(cells) do  | 
 | 178 | +            table.insert(cell_blocks_list, cell_to_blocks(cell))  | 
 | 179 | +        end  | 
 | 180 | +        table.insert(row_items, {pandoc.BulletList(cell_blocks_list)})  | 
 | 181 | +    end  | 
 | 182 | + | 
 | 183 | +    -- Create the outer bullet list (list of rows)  | 
 | 184 | +    table.insert(content, pandoc.BulletList(row_items))  | 
 | 185 | + | 
 | 186 | +    return pandoc.Div(content, div_attr)  | 
 | 187 | +end  | 
 | 188 | + | 
 | 189 | +return {{Table = table_to_list_table}}  | 
0 commit comments