summaryrefslogtreecommitdiffstats
path: root/src/MdBlocks/Parser.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/MdBlocks/Parser.hs')
-rw-r--r--src/MdBlocks/Parser.hs95
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