/ Markdown.hs - generates markdown from a lit file

Markdown is a module which transforms the main data structure for a parsed lit file into markdown. The main motivation for markdown as a supported document is to enable users to render lit files with existing Markdown engines. Most notably, converted lit files can be automatically viewed on Github. Although lit files can be functional markdown, this module labels code blocks by language and allows the original lit file to use a preferred indentation. Markdown primarily transforms code blocks.

An overview of the file:

<< * >>=
<< define html module >>
<< import modules >>
<< generate markdown document from chunks >>
<< helper functions >>

Markdown only exports generate akin to Code and Html, the other output modules.

<< define html module >>=
{-# LANGUAGE OverloadedStrings #-}
module Markdown ( generate ) where

Markdown performs little processing and as a result has light dependencies. In Markdown, getLang is used to to label code blocks with a language.

<< import modules >>=
import qualified Data.Text as T

import Types
import Highlight (getLang)

generate is the interface for the module. lit generates the [Chunk] with Parse.hs before calling generate to make the markdown file from a lit file. generate returns the union of all the transformed markdown Chunks.

<< generate markdown document from chunks >>=
generate :: String -> [Chunk] -> T.Text
generate name chunks = 
    let 
        lang = getLang name
        toMarkDown = chunkToMarkdown lang
    in
        T.concat $ map toMarkDown chunks

An overview of the helper functions used to generate a markdown document.

<< helper functions >>=
<< frequently used operator for appending text >>
<< transorm a chunk to markdown >>
<< transform a part of a chunk to markdown >>

Due to the verbosity of using T.append as an infix operator for T.Text, the following operator appends text like the list append operator ++

<< frequently used operator for appending text >>=
(<++>) :: T.Text -> T.Text -> T.Text
(<++>) = T.append

chunkToMarkdown only processes code portions, since Prose is already assumed to be markdown. Code blocks are wrapped in triple backticks and labeled with the inferred language of the code from the file extension.

<< transorm a chunk to markdown >>=
chunkToMarkdown lang chunk =
    case chunk of
    Prose text  -> text
    Def _ name parts -> 
        let 
            lang' = T.pack lang
            header = "<< " <++> (T.strip name) <++> " >>="
            mdParts = T.concat $ map (partToText lang) parts
        in 
            "```" <++> lang'   <++> 
            "\n"  <++> header  <++> 
            "\n"  <++> mdParts <++> "```\n"

A Chunk contains a [Part] where each Part is either a line of code or a macro reference. In this module a [Part] is rendered as a code block. Each line of code is valid, but each reference needs to be classified as a macro, with the macro syntax << ... >>.

<< transform a part of a chunk to markdown >>=
partToText :: String -> Part -> T.Text
partToText lang part =
    case part of
    Code txt -> txt
    Ref txt indent -> (indent <++> "<< " <++> (T.strip txt) <++> " >>\n")