1 -- Copyright 2006-2017 Mitchell mitchell.att.foicica.com. See LICENSE.
2 -- Markdown LPeg lexer.
4 local l
= require('lexer')
5 local token
, word_match
= l
.token
, l
.word_match
6 local P
, R
, S
= lpeg
.P
, lpeg
.R
, lpeg
.S
8 local M
= {_NAME
= 'markdown'}
11 local ws
= token(l
.WHITESPACE
, l
.space^
1)
14 local header
= token('h6', l
.starts_line('######') * l
.nonnewline^
0) +
15 token('h5', l
.starts_line('#####') * l
.nonnewline^
0) +
16 token('h4', l
.starts_line('####') * l
.nonnewline^
0) +
17 token('h3', l
.starts_line('###') * l
.nonnewline^
0) +
18 token('h2', l
.starts_line('##') * l
.nonnewline^
0) +
19 token('h1', l
.starts_line('#') * l
.nonnewline^
0)
21 local blockquote
= token(l
.STRING
,
22 lpeg
.Cmt(l
.starts_line(S(' \t')^
0 * '>'),
23 function(input
, index
)
24 local _
, e
= input
:find('\n[ \t]*\r?\n',
26 return (e
or #input
) + 1
29 local blockcode
= token('code', l
.starts_line(P(' ')^
4 + P('\t')) * -P('<') *
32 local hr
= token('hr', lpeg
.Cmt(l
.starts_line(S(' \t')^
0 * lpeg
.C(S('*-_'))),
33 function(input
, index
, c
)
34 local line
= input
:match('[^\n]*', index
)
35 line
= line
:gsub('[ \t]', '')
36 if line
:find('[^'..c
..']') or #line
< 2 then
39 return (input
:find('\n', index
) or #input
) + 1
43 local dq_str
= token(l
.STRING
, l
.delimited_range('"', false, true))
44 local sq_str
= token(l
.STRING
, l
.delimited_range("'", false, true))
45 local paren_str
= token(l
.STRING
, l
.delimited_range('()'))
46 local link
= token('link', P('!')^
-1 * l
.delimited_range('[]') *
47 (P('(') * (l
.any
- S(') \t'))^
0 *
49 l
.delimited_range('"', false, true))^
-1 * ')' +
50 S(' \t')^
0 * l
.delimited_range('[]')) +
51 P('http://') * (l
.any
- l
.space
)^
1)
52 local link_label
= token('link_label', l
.delimited_range('[]') * ':') * ws
*
53 token('link_url', (l
.any
- l
.space
)^
1) *
54 (ws
* (dq_str
+ sq_str
+ paren_str
))^
-1
56 local strong
= token('strong', (P('**') * (l
.any
- '**')^
0 * P('**')^
-1) +
57 (P('__') * (l
.any
- '__')^
0 * P('__')^
-1))
58 local em
= token('em',
59 l
.delimited_range('*', true) + l
.delimited_range('_', true))
60 local code
= token('code', (P('``') * (l
.any
- '``')^
0 * P('``')^
-1) +
61 l
.delimited_range('`', true, true))
63 local escape
= token(l
.DEFAULT
, P('\\') * 1)
65 local list
= token('list',
66 l
.starts_line(S(' \t')^
0 * (S('*+-') + R('09')^
1 * '.')) *
71 {'blockquote', blockquote
},
72 {'blockcode', blockcode
},
76 {'link_label', link_label
},
85 local hstyle
= 'fore:red'
88 h5
= hstyle
..',size:'..(font_size
+ 1),
89 h4
= hstyle
..',size:'..(font_size
+ 2),
90 h3
= hstyle
..',size:'..(font_size
+ 3),
91 h2
= hstyle
..',size:'..(font_size
+ 4),
92 h1
= hstyle
..',size:'..(font_size
+ 5),
93 code
= l
.STYLE_EMBEDDED
..',eolfilled',
94 hr
= l
.STYLE_DEFAULT
..',bold',
96 link_url
= 'underlined',
97 link_label
= l
.STYLE_LABEL
,
100 list
= l
.STYLE_CONSTANT
,
104 local html
= l
.load('html')
105 local start_rule
= token('tag', l
.starts_line(S(' \t')^
0 * '<'))
106 local end_rule
= token(l
.DEFAULT
, P('\n')) -- TODO: l.WHITESPACE causes errors
107 l
.embed_lexer(M
, html
, start_rule
, end_rule
)