0 | module Text.Markdown.String
 1 |
 2 | import Data.Nat
 3 | import Text.Lexer
 4 | import Text.Quantity
 5 |
 6 | %default total
 7 |
 8 | export
 9 | blankLine : Lexer
10 | blankLine = newline <+> some (manyThen newline space)
11 |
12 | export
13 | headingSym : Lexer
14 | headingSym = some (is '#')
15 |
16 | ||| A horizontal rule.
17 | |||
18 | ||| The horizontal rule is reprenseted by three or more consecutive '*', '-', or
19 | ||| '_' characters.
20 | |||
21 | ||| The current implementation allows for the horizontal rule to be directly
22 | ||| following the above block, without a blank line, for example:
23 | |||
24 | ||| ```markdown
25 | ||| Hello world!
26 | ||| ---
27 | ||| ```
28 | |||
29 | ||| However, ideally, there should be a blank line before:
30 | |||
31 | ||| ```markdown
32 | ||| Hello
33 | |||
34 | ||| ---
35 | ||| ```
36 | |||
37 | ||| Space characters are tolerated after the horizontal rule.
38 | export
39 | horizontalRules : Lexer
40 | horizontalRules =
41 |   let
42 |     separator = (blankLine <|> newline)
43 |   in
44 |       separator
45 |   <+> (atLeast3 '*' <|> atLeast3 '-' <|> atLeast3 '_')
46 |   <+> manyUntil newline space
47 |   <+> separator
48 |   where
49 |     atLeast3 : Char -> Lexer
50 |     atLeast3 c = is c <+> is c <+> some (is c)
51 |
52 | export
53 | imageSym : Lexer
54 | imageSym = is '!'
55 |
56 | export
57 | italicsSym : Lexer
58 | italicsSym = is '_'
59 |
60 | export
61 | boldSym : Lexer
62 | boldSym = count (exactly 2) (is '*')
63 |
64 | export
65 | link : Lexer
66 | link =
67 |       surround (is '[') (is ']') any
68 |   <+> surround (is '(') (is ')') any
69 |
70 | ||| Note: we currently don't allow attributes
71 | ||| To do so, we might need to move this from the lexer into the parser
72 | export
73 | htmlOpenTag : Lexer
74 | htmlOpenTag = surround (is '<') (is '>') alphaNum
75 |
76 | export
77 | htmlCloseTag : Lexer
78 | htmlCloseTag = surround (exact "</") (is '>') alphaNum
79 |
80 | export
81 | pre : Lexer
82 | pre = quote (is '`') (non newline)
83 |
84 | export
85 | codeFence : Lexer
86 | codeFence = quote (exact "```") any
87 |
88 | -- Grab the next non-newline character (even if it's special, like a *),
89 | -- and then consume non-special characters until we find another special marker.
90 | export
91 | text : Lexer
92 | text = (isNot '\n') <+> manyUntil (oneOf "_*\n<>#[]()`") any
93 |