ui: add support for blink style attribute
[vis.git] / lexers / yaml.lua
blobb88d5a0b714e0caebefd21d7920a265221628eae
1 -- Copyright 2006-2016 Mitchell mitchell.att.foicica.com. See LICENSE.
2 -- YAML LPeg lexer.
3 -- It does not keep track of indentation perfectly.
5 local l = require('lexer')
6 local token, word_match = l.token, l.word_match
7 local P, R, S = lpeg.P, lpeg.R, lpeg.S
9 local M = {_NAME = 'yaml'}
11 -- Whitespace.
12 local indent = #l.starts_line(S(' \t')) *
13 (token(l.WHITESPACE, ' ') + token('indent_error', '\t'))^1
14 local ws = token(l.WHITESPACE, S(' \t')^1 + l.newline^1)
16 -- Comments.
17 local comment = token(l.COMMENT, '#' * l.nonnewline^0)
19 -- Strings.
20 local string = token(l.STRING, l.delimited_range("'") + l.delimited_range('"'))
22 -- Numbers.
23 local integer = l.dec_num + l.hex_num + '0' * S('oO') * R('07')^1
24 local special_num = '.' * word_match({'inf', 'nan'}, nil, true)
25 local number = token(l.NUMBER, special_num + l.float + integer)
27 -- Timestamps.
28 local ts = token('timestamp', l.digit * l.digit * l.digit * l.digit * -- year
29 '-' * l.digit * l.digit^-1 * -- month
30 '-' * l.digit * l.digit^-1 * -- day
31 ((S(' \t')^1 + S('tT'))^-1 * -- separator
32 l.digit * l.digit^-1 * -- hour
33 ':' * l.digit * l.digit * -- minute
34 ':' * l.digit * l.digit * -- second
35 ('.' * l.digit^0)^-1 * -- fraction
36 ('Z' + -- timezone
37 S(' \t')^0 * S('-+') * l.digit * l.digit^-1 *
38 (':' * l.digit * l.digit)^-1)^-1)^-1)
40 -- Constants.
41 local constant = token(l.CONSTANT,
42 word_match({'null', 'true', 'false'}, nil, true))
44 -- Types.
45 local type = token(l.TYPE, '!!' * word_match({
46 -- Collection types.
47 'map', 'omap', 'pairs', 'set', 'seq',
48 -- Scalar types.
49 'binary', 'bool', 'float', 'int', 'merge', 'null', 'str', 'timestamp',
50 'value', 'yaml'
51 }, nil, true) + '!' * l.delimited_range('<>'))
53 -- Document boundaries.
54 local doc_bounds = token('document', l.starts_line(P('---') + '...'))
56 -- Directives
57 local directive = token('directive', l.starts_line('%') * l.nonnewline^1)
59 local word = (l.alpha + '-' * -l.space) * (l.alnum + '-')^0
61 -- Keys and literals.
62 local colon = S(' \t')^0 * ':' * (l.space + -1)
63 local key = token(l.KEYWORD,
64 #word * (l.nonnewline - colon)^1 * #colon *
65 P(function(input, index)
66 local line = input:sub(1, index - 1):match('[^\r\n]+$')
67 return not line:find('[%w-]+:') and index
68 end))
69 local value = #word * (l.nonnewline - l.space^0 * S(',]}'))^1
70 local block = S('|>') * S('+-')^-1 * (l.newline + -1) * function(input, index)
71 local rest = input:sub(index)
72 local level = #rest:match('^( *)')
73 for pos, indent, line in rest:gmatch('() *()([^\r\n]+)') do
74 if indent - pos < level and line ~= ' ' or level == 0 and pos > 1 then
75 return index + pos - 1
76 end
77 end
78 return #input + 1
79 end
80 local literal = token('literal', value + block)
82 -- Indicators.
83 local anchor = token(l.LABEL, '&' * word)
84 local alias = token(l.VARIABLE, '*' * word)
85 local tag = token('tag', '!' * word * P('!')^-1)
86 local reserved = token(l.ERROR, S('@`') * word)
87 local indicator_chars = token(l.OPERATOR, S('-?:,[]{}!'))
89 M._rules = {
90 {'indent', indent},
91 {'whitespace', ws},
92 {'comment', comment},
93 {'doc_bounds', doc_bounds},
94 {'key', key},
95 {'literal', literal},
96 {'timestamp', ts},
97 {'number', number},
98 {'constant', constant},
99 {'type', type},
100 {'indicator', tag + indicator_chars + alias + anchor + reserved},
101 {'directive', directive},
104 M._tokenstyles = {
105 indent_error = 'back:%(color.red)',
106 document = l.STYLE_CONSTANT,
107 literal = l.STYLE_DEFAULT,
108 timestamp = l.STYLE_NUMBER,
109 tag = l.STYLE_CLASS,
110 directive = l.STYLE_PREPROCESSOR,
113 M._FOLDBYINDENTATION = true
115 return M