pandoc-markdown-ghci-filter =========================== A `Pandoc` filter that identifies code blocks(`Haskell`) in Pandoc supported formats, executes the code in GHCI and embeds the results in the returned output by updating the AST provided by `Pandoc`. Quick Overview ============== Often a markdown(or any `pandoc` supported document) for any `Haskell` related documentation or a technical blog post involves `code` blocks. The `code` block could include `definitions` and also a demonstration of output with an `interactive` prompt. For, example, take this `code` block: ``` {.haskell code-filter="Off"} -- README.md -- definition increment:: Integer -> Integer increment x = x + 1 -- interactive prompt to demonstrate the working of definitions so far >> increment 41 ``` It would be nice if this `code` block was automatically evaluated and `output` of `increment 41` is automatically recorded below `>> increment 41`, as follows: ``` {.haskell} -- README.md -- definition increment:: Integer -> Integer increment x = x + 1 -- interactive prompt to demonstrate the working of definitions so far >> increment 41 42 ``` Notice, that the `42` is automatically populated by this filter while transforming the original document. To transform the document, we need to run the document through the `pandoc` filter, as follows: ``` {.shell} -- set up pandoc_filter to the executable of this program (see Installation) pandoc -s -t json README.md | pandoc_filter | pandoc -f json -t markdown ``` To read more about how `filter` work, visit the [this](https://pandoc.org/filters.html) page. Installation ============ Requirements ------------ - [Stack](https://docs.haskellstack.org/en/stable/README/) ### From Source ``` {.shell} git clone https://github.com/gdevanla/pandoc-markdown-ghci-filter.git cd pandoc-markdown-ghci-filter stack build ``` ### From Stackage/Hackage ``` {.shell} stack build pandoc-markdown-ghci-filter # executable only available to local stack environment or stack install pandoc-markdown-ghci-filter # if you want to across all stack environments ``` Running the filter ================== ``` {.shell} pandoc -s -t json test.md | pandoc-markdown-ghci-filter-exe | pandoc -f json -t markdown ``` Usage Notes/Caveats =================== 1. All interactive statements (prefixed with `>>`) need to be preceded by `\n` to let the filter respect original new line spacing. If this is not followed, `\n` may be truncated. 2. The program internally wraps all commands inside the GHCi multi-line construct `:{..:}`. Therefore, the code segments should not have multi-line constructs as part of code blocks. 3. If you want the filter to ignore a certain `code` block, you can turn-off the filter by setting the `code` block attribute as follows ``` {.markdown} {.haskell code_filter="Off"} -- do not run this code through GHCi >> putStrLn "This line will not be expanded by the filter" ``` Note, the default value is "On" Limitations/Open Issues ======================= 1. Attaching different formattting properties to `output`. 2. As explained in `Usage Notes`, all `interactive` statements should be preceded by an empty line, for the filter to maintain the `\n` characters as given by the input. More examples ============= Sample Markdown Before Transformation ------------------------------------- Sample markdown as fed into filter through `pandoc`. Example 1 --------- ``` {.haskell code-filter="Off"} import Data.Text >> putStrLn "This string should show up in the output" ``` Example 2 --------- ``` {.haskell code-filter="Off"} addOne:: Integer -> Integer addOne x = x + 1 >> addOne 13 multBy2:: Integer -> Integer multBy2 x = x * 2 >> (addOne 10) + (multBy2 20) ``` Example 3 --------- Any errors that occur while executing statements in the `code` block are also rendered. ``` {.haskell code-filter="Off"} wrongFuncDefinition:: Integer -> Integer wrongFuncDefintion = x + 1 >> functionNotInScope 10 ``` Markdown after transformation ----------------------------- Example 1 --------- ``` {.haskell code-filter="On"} import Data.Text >> putStrLn "This string should show up in the output" This string should show up in the output ``` Example 2 --------- ``` {.haskell code-filter="On"} addOne:: Integer -> Integer addOne x = x + 1 >> addOne 13 14 multBy2:: Integer -> Integer multBy2 x = x * 2 >> (addOne 10) + (multBy2 20) 51 ``` Example 3 --------- Any errors that occur while executing statements in the `code` block are also rendered. ``` {.haskell code-filter="On"} wrongFuncDefinition:: Integer -> Integer wrongFuncDefintion = x + 1 :16:1: error: The type signature for ‘wrongFuncDefinition’ lacks an accompanying binding >> functionNotInScope 10 :29:2: error: Variable not in scope: functionNotInScope :: Integer -> t ``` *Fun Fact:* This document was generated using this same tool it describes. This [README-pre-process.md](https://github.com/gdevanla/pandoc-markdown-ghci-filter/blob/master/README-pre-process.md) was used to generate this document. Here is the command that was used: ``` {.shell} pandoc -s -t json README-pre-process.md | stack runhaskell app/Main.hs | pandoc -f json -t markdown > README.md ```