blob: f2f184d7076678681147fd20d2c67317a62cb73b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
|