luamarkdownpandocbbcode

Custom Pandoc Writer/Filter: Output BulletList as BBCode


I'd like to convert this markdown list (list.md):

- Europe
    - Germany
        - Berlin
        - Hamburg

To the following output (BBCode):

[list]
  [*]Europe
  [list]
    [*]Germany
    [list]
      [*]Berlin
      [*]Hamburg
    [/list]
  [/list]
[/list]

And wrote this script (list.lua):

function processBulletList (bl)
    inner = bl:walk {
        BulletList = processBulletList,
        Plain = function (p) return string.format('\n[*]%s', pandoc.utils.stringify(p)) end,
    }
    return pandoc.RawBlock('markdown', string.format('[list]\n%s\n[/list]', inner))
end

function Writer (doc, opts)
    local filter = {
        BulletList = processBulletList
    }
    return pandoc.write(doc:walk(filter))
end

I run pandoc as follows:

$ pandoc list.md -t list.lua -o list.txt

Which results in list.txt:

[list]
BulletList [[Plain [SoftBreak,Str "[*]Europe"],RawBlock (Format "markdown") "[list]\nBulletList [[Plain [SoftBreak,Str \"[*]Germany\"],RawBlock (Format \"markdown\") \"[list]\\nBulletList [[Plain [SoftBreak,Str \\\"[*]Berlin\\\"]],[Plain [SoftBreak,Str \\\"[*]Hamburg\\\"]]]\\n[/list]\"]]\n[/list]"]]
[/list]

This contains everything that is needed, but I have two major issues:

  1. The tree is not converted to plain text.
  2. There is a lot of escaping with \.

I guess the two problems are related. However, I have no clue what's going on. It looks like walk does not traverse the tree as I'd like it to.

Can anybody tell me what I got wrong?


Solution

  • I figured out that my resulting list was processed again. So I decided to work around that in the Plain clause upon walking the tree. I also only return strings now as plain text instead of wrapping it in pandoc elements again:

    function map(xs, f)
        local ys = {}
        for i,x in pairs(xs) do
            ys[i] = f(x)
        end
        return ys
    end
    
    function startswith(str, sub)
        return string.sub(str, 1, string.len(sub)) == sub
    end
    
    function processBulletList (bl)
        inner = bl:walk {
            BulletList = function (bl) processBulletList(bl.content) end,
            Plain = function (p)
                str = pandoc.utils.stringify(p)
                if startswith(str, '[list]') then
                    return p
                else
                    return string.format('[*] %s', str)
                end
            end,
        }
        return string.format('[list]%s[/list]', pandoc.utils.stringify(inner))
    end
    
    function Writer (doc, opts)
        local filter = {
            BulletList = processBulletList
        }
        return pandoc.write(doc:walk(filter), 'plain')
    end
    

    The output looks as follows:

    [list][*] Europe[list][*] Germany[list][*] Berlin[*]
    Hamburg[/list][/list][/list]