Search code examples
luapandoc

Place content between headers in LaTeX environments using a lua filter


Consider this markdown file:

#

This is text below a h1 header

##

This is text below a h2 header

#

This is text below a h1 header

##

This is text below a h2 header

I wonder if it would be possible to grab content below a h1 header and put it in a latex environment A and content below a h2 header in environment B using a lua filter.

Something like this:

function Header(el)
  local beginEnv, endEnv

  if ( el.level == 1 ) then
    beginEnv = "\\begin{A}"
    endEnv = "\\end{A}"
  elseif ( el.level == 2 ) then
    beginEnv = "\\begin{B}"
    endEnv = "\\end{B}"
  end

  -- grab all of the content below the respective header
  -- in the case of the h1 header it should be: "This is text below a h1 header"
  -- in the case of the h2 header it should be: "This is text below a h2 header"
  local contentBelowHeader = ???

  table.insert( contentBelowHeader, 1, pandoc.RawBlock("latex", beginEnv .. "\n" ))
  table.insert( contentBelowHeader, pandoc.RawBlock("latex", "\n" .. endEnv ))

  return el
end

The output should be something like (tex file):

...

\begin{A}
  This is text below a h1 header
\end{A}

\begin{B}
  This is text below a h2 header
\end{B}

\begin{A}
  This is text below a h1 header
\end{A}

\begin{B}
  This is text below a h2 header
\end{B}

...

Solution

  • One solution is to traverse the whole document and insert the \begin{...} and \end{...}.

    function latex(str)
      return pandoc.RawInline('latex', str)
    end
    
    function Pandoc(doc)
      local blocks = {}
      local pending_end_env = nil
    
      for i, el in pairs(doc.blocks) do
        if el.t == "Header" then
          if el.level == 1 then
            -- Insert end of last environment if needed
            if pending_end_env then
              table.insert(blocks, latex(pending_end_env))
            end
            -- Insert begin of new environment
            table.insert(blocks, latex('\\begin{A}'))
            -- Store the end of new environment for later use
            pending_end_env = '\\end{A}'
          elseif el.level == 2 then
            -- Same as the el.level == 1 case above
            if pending_end_env then
              table.insert(blocks, latex(pending_end_env))
            end
            table.insert(blocks, latex('\\begin{B}'))
            pending_end_env = '\\end{B}'
          end
        else
          -- Keep all non-header elements as-is
          table.insert(blocks, el)
        end
      end
    
      -- Close the last environment
      if pending_end_env then
        table.insert(blocks, latex(pending_end_env))
      end
    
      return pandoc.Pandoc(blocks, doc.meta)
    end
    

    With this filter, pandoc produces the following tex file from the example markdown in the question.

    \begin{A}
    
    This is text below a h1 header
    
    \end{A}
    
    \begin{B}
    
    This is text below a h2 header
    
    \end{B}
    
    \begin{A}
    
    This is text below a h1 header
    
    \end{A}
    
    \begin{B}
    
    This is text below a h2 header
    
    \end{B}