vis
a vi-like editor based on Plan 9's structural regular expressions
git clone https://9o.is/git/vis.git
rc.lua
(1556B)
1 -- Copyright 2017-2025 Michael Forney. See LICENSE.
2 -- rc LPeg lexer.
3
4 local lexer = require('lexer')
5 local token, word_match = lexer.token, lexer.word_match
6 local P, S = lpeg.P, lpeg.S
7
8 local lex = lexer.new('rc')
9
10 -- Whitespace.
11 lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
12
13 -- Keywords.
14 lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
15 'for', 'in', 'while', 'if', 'not', 'switch', 'case', 'fn', 'builtin', 'cd', 'eval', 'exec',
16 'exit', 'flag', 'rfork', 'shift', 'ulimit', 'umask', 'wait', 'whatis', '.', '~'
17 }))
18
19 -- Identifiers.
20 lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
21
22 -- Strings.
23 local str = lexer.range("'", false, false)
24 local heredoc = '<<' * P(function(input, index)
25 local s, e, _, delimiter = input:find('[ \t]*(["\']?)([%w!"%%+,-./:?@_~]+)%1', index)
26 if s == index and delimiter then
27 delimiter = delimiter:gsub('[%%+-.?]', '%%%1')
28 e = select(2, input:find('[\n\r]' .. delimiter .. '[\n\r]', e))
29 return e and e + 1 or #input + 1
30 end
31 end)
32 lex:add_rule('string', token(lexer.STRING, str + heredoc))
33
34 -- Comments.
35 lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
36
37 -- Numbers.
38 lex:add_rule('number', token(lexer.NUMBER, lexer.number))
39
40 -- Variables.
41 lex:add_rule('variable',
42 token(lexer.VARIABLE, '$' * S('"#')^-1 * ('*' + lexer.digit^1 + lexer.word)))
43
44 -- Operators.
45 lex:add_rule('operator', token(lexer.OPERATOR, S('@`=!<>*&^|;?()[]{}') + '\\\n'))
46
47 -- Fold points.
48 lex:add_fold_point(lexer.OPERATOR, '{', '}')
49
50 lexer.property['scintillua.comment'] = '#'
51
52 return lex