1

I use pandoc for generating a PDF file via lualatex from a markdown file. The document class scrartcl defines the command \publishers{}, which is employed in \maketitle. I would like to write a lua filter that extracts the value from a meta data field and adds the command to the preamble.

The markdown file looks like this:

---
title:      My very important document
author:     It's me
publishers: This is what I would like to add
...

# Introduction

And so on and on ...

This is my filter so far

if FORMAT:match 'latex' then
  function Meta(meta)
    -- How to check for a KOMA-Script document class?
    if meta.publishers then
      local publishers = pandoc.utils.stringify(meta.publishers)
      local latex_cmd = '\\publishers{' .. publishers .. '}'
      local raw_inline = pandoc.RawInline('latex', latex_cmd)
      -- How to add the command to the preamble?      
    end
  end
end

Here are my questions:

  1. How can I check for a KOMA-Script document class in the filter?
  2. How can I add the command to the document preamble? Do I need a custom writer for this?
3
  • Why don't you just use a custom template instead of trying to modify the existing template on the fly with filters? Commented May 27, 2022 at 12:28
  • Using a custom template would be an easy solution indeed. The default template, however, might change in future pandoc versions. Therefore, I try to avoid writing custom templates.
    – Matthias
    Commented May 27, 2022 at 12:45
  • 1
    You can have a look here as to how to modify KOMA vars with pandoc filters: github.com/pandoc/lua-filters/blob/master/scrlttr2/scrlttr2.lua Commented May 27, 2022 at 13:08

1 Answer 1

1

Here's a filter that'd add the \publishers command to the header-includes metadata field, which is then inserted in the document preamble.

function Meta (meta)
  if meta.publishers then
    local publishers = pandoc.utils.stringify(meta.publishers)
    meta["header-includes"] = {
      pandoc.RawBlock('latex', '\\publishers{' .. publishers .. '}')
    }
  end
  return meta
end

The document class is expected to be passed via the documentclass value, either in the metadata, or via a variable. There are some subtleties to metadata and variables, but in general, checking meta.documentclass should work. However, a better approach might be to define the \publishers command if it doesn't exist, e.g., by changing the filter to

    meta["header-includes"] = {
      pandoc.RawBlock('latex', '\\providecommand{\\publishers}[1]{}'),
      pandoc.RawBlock('latex', '\\publishers{' .. publishers .. '}')
    }

This will ensure that there won't be an error if a non-KOMA class is used, but the \publishers command will have no effect then.


There may be issues when trying to use the filter while also adding other content to include in the header, e.g. by calling pandoc with the -H/--include-in-header option. In that case you'll have to use a custom Lua writer to make it work. It's a bit less convenient though, because pandoc cannot infer the default template, so its path must be given explicitly:

local type = pandoc.utils.type

-- Convert a metadata value to Blocks
local to_blocks
to_blocks = function (x)
  if type(x) == 'Blocks' then
    return x
  elseif type(x) == 'Inlines' or type(x) == 'string' then
    return {pandoc.Plain(x)}
  elseif type(x) == 'List' then
    local accum = pandoc.List{}
    for i, b in ipairs(x:map(to_blocks)) do
      accum:extend(b)
    end
    return accum
  end
  return pandoc.Blocks{}
end

function Writer (doc, opts)
  local header_includes = opts.variables['header-includes'] or ''
  header_includes =
    pandoc.write(
      pandoc.Pandoc(to_blocks(doc.meta['header-includes'])),
      'latex'
    ) .. '\n' .. header_includes
  local latex = pandoc.write(doc, 'latex', opts)
  return latex
end

Use with

    pandoc -t mywriter.lua \
        -o out.pdf \
        --pdf-engine=xelatex \
        --template=data/default.latex

The path data/default.latex points to pandoc's default LaTeX template.

5
  • It looks right, but it does not work as expected. The command does not show up in the LaTeX document. The filter, however, is definitely executed.
    – Matthias
    Commented May 27, 2022 at 20:34
  • 1
    @Matthias Are you using other options that would affect the content of header-includes, something like -H or -V header-includes=x?
    – tarleb
    Commented May 27, 2022 at 22:01
  • 1
    Yes, you are right. I have header-includes and include-in-header in a defaults YAML file. When I remove them, the filter works.
    – Matthias
    Commented May 28, 2022 at 1:24
  • 1
    @Matthias I've amended my answer to include a custom writer that will work even if you set include-in-header. It's not quite as convenient, but as you are already using a defaults file, it shouldn't matter much.
    – tarleb
    Commented May 28, 2022 at 10:36
  • @tarleb a simpler way to include a header file that's compatible with this method is to use: pandoc.RawBlock('latex', '\\publishers{' .. publishers .. '}'), pandoc.RawBlock('latex', '\\input{header.tex}')
    – Compholio
    Commented Aug 17, 2023 at 19:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .