Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way in pandoc to include a filename on top of code blocks?

I'm working on a document in markdown (using pandoc for generating the final document) and would like to have code blocks showing excerpts from files. I would like to have the name of the file on top of the code block, something like this:

enter image description here

I have searched through pandoc's documentation but couldn't find anything.

like image 972
lindelof Avatar asked Sep 06 '25 15:09

lindelof


2 Answers

One method would be to use attributes and custom CSS, like so:

<style>
div.sourceCode::before {
    content: attr(data-filename);
    display: block;
    background-color: #cfeadd;
    font-family: monospace;
}
</style>

``` {.python filename="ch1/test_one.py"}
def test_passing():
    assert (1, 2, 3) == (1, 2, 3)
```

This allows to specify the filename as a code block attribute, and uses CSS to render the attribute as a header.

rendered HTML


An alternative approach is via a pandoc filter; I usually suggest using Lua filters. This would also allow to include the file directly, so one could just write

``` {.python filename="ch1/test_one.py"}
```

and a filter would handle the content inclusion. It should be only a few lines of Lua.

like image 141
tarleb Avatar answered Sep 11 '25 00:09

tarleb


While it can be done in CSS, the best way is to inject a Lua filter between the parsing and writing process.

Lua filters are thoroughly documented here. They are basically Lua modules that override AST hooks with your own custom behaviour. For example, to add a file name before each code block one may proceed by first adding a custom attribute to the markdown block:

``` {.python filename="ch1/test_one.py"}
    def test_passing():
        assert (1, 2, 3) == (1, 2, 3)
```

Attributes are a markdown extension supported by Pandoc.

Then, you need to overwrite the CodeBlock hook inside a Lua filter, which is basically just file (say, filters.lua) returning a table with the required fields. The elem parameter is an AST element which will contain the attribute we just added as the elem.attr.attributes.filename field.

---@diagnostic disable-next-line: undefined-global
local pandoc = pandoc

return {
    {
        CodeBlock = function(elem)
            if (elem.attr.attributes.filename \~= nil) then
                return pandoc.Div {
                    pandoc.Div( -- Add a div element to wrap the code block
                        { pandoc.Plain { pandoc.Str(v) } }, -- Inject a text element with the filename before that
                    ),
                    elem,
                }
            end
            return elem
        end,
     }
}

Finally you can generate the output with a command line line pandoc --lua-filter ./filters.lua --from markdown+backtick_code_blocks+fenced_code_attributes -s -o index.html content.md, where:

  • --lua-filter ./filters.lua specifies the filter file to use

  • from markdown+backtick_code_blocks+fenced_code_attributes adds the relevant extensions to make this work

  • I've assumed content.md to be the markdown file and converted it to html just as an example

The final result without stile is barren but works as expected and generates something like this:

enter image description here

like image 44
Maldus Avatar answered Sep 11 '25 02:09

Maldus