diff options
Diffstat (limited to 'src/MdBlocks/Parser.hs')
| -rw-r--r-- | src/MdBlocks/Parser.hs | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/MdBlocks/Parser.hs b/src/MdBlocks/Parser.hs new file mode 100644 index 0000000..f2f184d --- /dev/null +++ b/src/MdBlocks/Parser.hs @@ -0,0 +1,95 @@ +{-# LANGUAGE OverloadedStrings #-} + +module MdBlocks.Parser where + +import Data.Text (Text) +import qualified Data.Text as T + +import MdBlocks.Metadata +import MdBlocks.Types + +parseFile :: FilePath -> Text -> [Block] +parseFile fp txt = + numberBlocks $ + parseFenced fp ls + ++ parseIndented fp ls + where + ls = zip [1..] (T.lines txt) + +numberBlocks :: [Block] -> [Block] +numberBlocks = + zipWith (\n b -> b { blockNumber = n }) [1..] + +parseFenced :: FilePath -> [(Int,Text)] -> [Block] +parseFenced fp = + go False 0 "" [] + where + go _ _ _ acc [] = reverse acc + + go False _ _ acc ((ln,t):xs) + | "```" `T.isPrefixOf` T.stripStart t = + go True ln t acc xs + | otherwise = + go False 0 "" acc xs + + go True start hdr acc ((ln,t):xs) + | "```" `T.isPrefixOf` T.stripStart t = + let body = + T.unlines $ + map snd $ + takeWhile + (\(_,x) -> + not ("```" + `T.isPrefixOf` + T.stripStart x)) + ((ln,t):xs) + in go False 0 "" (mk start ln hdr body:acc) xs + + | otherwise = + go True start hdr acc xs + + mk s e hdr body = + let meta = + parseMetadataLine $ + "@" <> T.drop 3 (T.strip hdr) + in Block fp 0 Fenced meta s e body + +parseIndented :: FilePath -> [(Int,Text)] -> [Block] +parseIndented fp = + go + where + go [] = [] + + go ((ln,t):xs) + | isIndented t = + let (blk,rest) = span (isIndented . snd) xs + chunk = + T.unlines $ + map (T.drop 4 . snd) + ((ln,t):blk) + + meta = + case T.lines chunk of + [] -> emptyMetadata + (x:_) + | "@" `T.isPrefixOf` x -> + parseMetadataLine x + | otherwise -> + emptyMetadata + + code = + case T.lines chunk of + [] -> "" + (x:rs) + | "@" `T.isPrefixOf` x -> + T.unlines rs + | otherwise -> + chunk + in Block fp 0 Indented meta ln (fst $ last (blk++[(ln,t)])) code + : go rest + + | otherwise = + go xs + + isIndented t = + " " `T.isPrefixOf` t |
