inliterate-0.1.0: lib/Inliterate.hs
{-# LANGUAGE OverloadedStrings, StandaloneDeriving, CPP #-}
module Inliterate where
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TL
import Data.Text (Text)
import Data.List (isPrefixOf)
import qualified Data.Text.IO as T
import Cheapskate
import Cheapskate.Html
import Text.Read (readMaybe)
import Data.Foldable (toList)
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Data.Sequence as Seq
import Text.Blaze.Html.Renderer.Text (renderHtml)
import Lucid
import Data.Monoid ((<>))
#if MIN_VERSION_haskell_src_exts(1,18,0)
import Language.Haskell.Exts hiding (Do)
#else
import Language.Haskell.Exts.Annotated hiding (Do)
#endif
import Inliterate.Inspect
import Inliterate.Import
dumpDoc :: FilePath -> IO ()
dumpDoc fp = do
t <- T.readFile fp
let md = markdown def t
print md
mapM_ print $ codeBlocks md
parseCodeInfo :: Text -> Set CodeType
parseCodeInfo = Set.fromList . map parse1 . T.words where
parse1 t = case readMaybe $ T.unpack $ T.toTitle t of
Just ct -> ct
Nothing -> error $ "unknown code type: "++T.unpack t
genHaskell :: Doc -> Text
genHaskell doc =
let cbs = codeBlocks doc
toplns = map snd $ filter ((Top `Set.member`) . fst) cbs
mparsedTop = parseFileContents $ T.unpack $ T.unlines toplns
newTop = case mparsedTop of
ParseFailed l s -> error $ "parse failure: "++s++" at "++show l
ParseOk m -> T.pack $ prettyPrint $ addTheImport m
inDoBody (cb, _) = Do `Set.member` cb
printDoBody (_,t) = T.lines $ chomp t
-- asks = map snd $ filter ((Eval `Set.member`) . fst) cbs
-- printAsk t = ["ask $ " `T.append` chomp t]
doBody = concatMap printDoBody (filter inDoBody cbs) ++
concatMap printBlock (getBlocks doc) ++
["return ()"]
hdr = unlines $ map (T.unpack . codeBlockBody) $ filter isHtmlHeader $ getBlocks doc
in T.unlines $ [newTop, "main = Inliterate.Import.wrapMain "<>T.pack (show hdr)<>" $ do"] ++ map (" " `T.append`) doBody
addTheImport :: Module SrcSpanInfo -> Module SrcSpanInfo
addTheImport (Module l v1 v2 v6 decls) = Module l v1 v2 (m:v6) decls
where m = ImportDecl {importAnn = l,
importModule = ModuleName l "Inliterate.Import",
importQualified = True,
importSrc = False,
importSafe = False,
importPkg = Nothing,
importAs = Just (ModuleName l "Inliterate.Import"),
importSpecs = Nothing}
printBlock :: Block -> [Text]
printBlock blk@(CodeBlock (CodeAttr "haskell" ci) t)
| Eval `Set.member` ct = printAsk ct t
| Hide `Set.member` ct = []
| otherwise = printAnyBlock blk
where ct = parseCodeInfo ci
printBlock blk = if isHtmlHeader blk then [] else printAnyBlock blk
isHtmlHeader (CodeBlock (CodeAttr "html_header" ci) t) = True
isHtmlHeader _ = False
codeBlockBody (CodeBlock (CodeAttr "html_header" ci) t) = t
printAsk :: Set CodeType -> Text -> [Text]
printAsk cts t
= let showCts = map (T.pack . ("Inliterate.Import."++) . show) (Set.toList cts)
in [T.concat ["Inliterate.Import.askInliterate ", escape $ chomp t, " ",
"[",T.intercalate "," showCts, "]" , " (", chomp t, ")"]]
printAnyBlock :: Block -> [Text]
printAnyBlock blk =
map (("putStrLn " `T.append`) . escape)
$ T.lines
$ TL.toStrict
$ renderHtml
$ renderBlocks def (Seq.singleton blk)
escape :: Text -> Text
escape = T.pack . show . T.unpack
chomp :: Text -> Text
chomp = T.dropWhile (=='\n') . T.strip . T.dropWhileEnd (=='\n')
getBlocks :: Doc -> [Block]
getBlocks (Doc _ sblocks) = removeOptionsGhc $ toList sblocks
codeBlocks :: Doc -> [(Set CodeType, Text)]
codeBlocks d =
[(parseCodeInfo ci, body)
| CodeBlock (CodeAttr "haskell" ci) body
<- getBlocks d]
removeOptionsGhc :: [Block] -> [Block]
removeOptionsGhc allBlks@(Para inls:blks)
| [Str "{",Str "-",Str "#",Space,Str "OPTIONS",Str "_",Str "GHC"] `isPrefixOf` toList inls
= removeOptionsGhc blks
| [Str "{",Str "-",Str "#",Space,Str "LANGUAGE"] `isPrefixOf` toList inls
= removeOptionsGhc blks
| otherwise = allBlks
removeOptionsGhc blks = blks
deriving instance Eq Inline
-- get extra headers