Pandoc filter to allow embedding arbitary HTML in latex documents I wrote a Pandoc filter that allows me to embed arbitrary HTML snippets in LaTeX documents, which are then printed out as-is when the document is converted to HTML. It is slightly more generic than it needs to be right now, in case I want to embed other types of things in the future.

It can be used like:

\begin{verbatim}
    %%% html
    &lt;iframe width="560" height="315" src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
\end{verbatim}


In particular, I think the chain of &gt;&gt;= in convertCode could be improved some how, possibly using Applicatives. runReader basically does nothing except rearrange its arguments and call a thing.

import Data.Char ( isSpace )
import Data.List ( dropWhileEnd )
import Data.Maybe ( fromMaybe )

import Text.Pandoc.JSON ( Block(CodeBlock, RawBlock), Format(Format), toJSONFilter )

main = toJSONFilter convertCodeBlocks

type Reader = String -&gt; Maybe [Block]

convertCodeBlocks :: Block -&gt; [Block]
convertCodeBlocks b = case b of
    (CodeBlock _ code) -&gt; fromMaybe [b] $ convertCode code
    _                  -&gt; [b]

-- Given a string of code, try to convert it into something nicer
convertCode :: String -&gt; Maybe [Block]
convertCode code =
    codeBlockType codeHead &gt;&gt;= codeBlockReader &gt;&gt;= runReader codeTail
  where (codeHead, codeTail) = splitWhen (== '\n') $ strip code

-- Get the reader name from the magic header
codeBlockType :: String -&gt; Maybe String
codeBlockType line = if percent == "%%% "
    then Just $ strip typeName
    else Nothing
  where (percent, typeName) = splitAt 4 $ strip line

-- All the known readers and their name from the magic header
codeBlockReader :: String -&gt; Maybe Reader
codeBlockReader "html" = Just rawHtml
codeBlockReader _      = Nothing

-- Make a raw HTML block from some string
rawHtml html = Just [RawBlock (Format "html") html]

-- A mostly useless function, only here because I can't make Applicatives work
runReader :: String -&gt; Reader -&gt; Maybe [Block]
runReader code reader = reader code

-- Strip whitespace from the start and end of a string
strip = dropWhileEnd isSpace . dropWhile isSpace

-- Split an array at a predicate, returning (before, after)
splitWhen :: (a -&gt; Bool) -&gt; [a] -&gt; ([a], [a])
splitWhen pred [] = ([], [])
splitWhen pred (x:xs) = if pred x
    then ([], xs)
    else let (before, after) = splitWhen pred xs in (x:before, after)


I initially implemented something for this as a modification to Pandoc itself (See this PR on Github), but the maintainer suggested a filter instead.
I think it's clearer to just merge all those functions into one since you only really care about one case:

convertCode :: String -&gt; Maybe [Block]
convertCode code =
  case strip codeHead of
    ('%':'%':'%':' ':typeName) -&gt; matchType $ strip typeName
    _                          -&gt; Nothing
 where
   (codeHead, codeTail) = splitWhen (== '\n') $ strip code

   matchType "html" = Just [RawBlock (Format "html") codeTail]
   matchType _      = Nothing


Does this do the same thing? I cant test it without too much effort on my part.