After sleeping on it, I figured it out. It was right there in the documentation, it just didn’t click with me that that is what I needed.
Using map_with_ast we can use the accumulator to conditionally match on a specific text node. The part that the accumulator was used to match in this was is that part that flew over my head when first reading it.
So I’ve ended up with this:
"""
```sql
<span class="k">SELECT</span> * <span class="k">FROM</span> table
```
"""
markdown
|> Earmark.as_ast!()
|> Earmark.Transform.map_ast_with(false, fn
{"code", [{"class", "sql"}], _, meta}, _ ->
{{"code", [{"class", "sql"}], nil, meta}, true}
html, true ->
{:ok, html} = Floki.parse_fragment(html)
html =
Floki.traverse_and_update(html, fn
{tag, args, children} -> {tag, args, children, %{}}
end)
{html, false}
node, _ ->
{node, false}
end)
|> Earmark.transform(options())
Which works! The Floki.traverse_and_update/2 call is necessary to convert from Floki’s tuple representation to Earmark’s.
The only thing left is that the spans are put on their own lines which is causing the formatting to be all wonky, though that is expected and will have to figure something else out there.


















