vis: implement :set cursorline
[vis.git] / lexers / markdown.lua
blob9ab15687ea0e08d16fc7730aa9dd0739cb73f945
1 -- Copyright 2006-2015 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'}
10 -- Whitespace.
11 local ws = token(l.WHITESPACE, l.space^1)
13 -- Block elements.
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',
25 index)
26 return (e or #input) + 1
27 end))
29 local blockcode = token('code', l.starts_line(P(' ')^4 + P('\t')) * -P('<') *
30 l.nonnewline^0)
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
37 return nil
38 end
39 return (input:find('\n', index) or #input) + 1
40 end))
42 -- Span elements.
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 *
48 (S(' \t')^1 *
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 * '.')) *
67 S(' \t'))
69 M._rules = {
70 {'header', header},
71 {'blockquote', blockquote},
72 {'blockcode', blockcode},
73 {'hr', hr},
74 {'list', list},
75 {'whitespace', ws},
76 {'link_label', link_label},
77 {'escape', escape},
78 {'link', link},
79 {'strong', strong},
80 {'em', em},
81 {'code', code},
84 local font_size = 10
85 local hstyle = 'fore:$(color.red)'
86 M._tokenstyles = {
87 h6 = hstyle,
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 = 'back:$(color.black),eolfilled',
95 link = 'underlined',
96 link_url = 'underlined',
97 link_label = l.STYLE_LABEL,
98 strong = 'bold',
99 em = 'italics',
100 list = l.STYLE_CONSTANT,
103 -- Embedded HTML.
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)
109 return M