vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

vcard.lua

(2594B)


      1 -- Copyright (c) 2015-2025 Piotr Orzechowski [drzewo.org]. See LICENSE.
      2 -- vCard 2.1, 3.0 and 4.0 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('vcard')
      9 
     10 -- Whitespace.
     11 lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
     12 
     13 -- Begin vCard, end vCard.
     14 lex:add_rule('begin_sequence', token(lexer.KEYWORD, 'BEGIN') * token(lexer.OPERATOR, ':') *
     15 	token(lexer.COMMENT, 'VCARD'))
     16 lex:add_rule('end_sequence', token(lexer.KEYWORD, 'END') * token(lexer.OPERATOR, ':') *
     17 	token(lexer.COMMENT, 'VCARD'))
     18 
     19 -- vCard version (in v3.0 and v4.0 must appear immediately after BEGIN:VCARD).
     20 lex:add_rule('version_sequence', token(lexer.KEYWORD, 'VERSION') * token(lexer.OPERATOR, ':') *
     21 	token(lexer.CONSTANT, lexer.digit^1 * ('.' * lexer.digit^1)^-1))
     22 
     23 -- Required properties.
     24 local required_property = token(lexer.KEYWORD, word_match({
     25 	'BEGIN', 'END', 'FN', 'VERSION', --
     26 	'N' -- Not required in v4.0.
     27 }, true)) * #P(':')
     28 lex:add_rule('required_property', required_property)
     29 
     30 -- Supported properties.
     31 local supported_property = token(lexer.TYPE, word_match({
     32 	'ADR', 'BDAY', 'CATEGORIES', 'EMAIL', 'END', 'GEO', 'KEY', 'LOGO', 'NOTE', 'ORG', 'PHOTO', 'REV',
     33 	'ROLE', 'SOUND', 'SOURCE', 'TEL', 'TITLE', 'TZ', 'UID', 'URL',
     34 	-- Supported in v4.0 only.
     35 	'ANNIVERSARY', 'CALADRURI', 'CALURI', 'CLIENTPIDMAP', 'FBURL', 'GENDER', 'KIND', 'LANG', 'MEMBER',
     36 	'RELATED', 'XML',
     37 	-- Not supported in v4.0.
     38 	'AGENT', 'LABEL', 'MAILER', 'PROFILE', 'SORT-STRING',
     39 	-- Supported in v3.0 only.
     40 	'CLASS', 'NAME',
     41 	-- Not supported in v2.1.
     42 	'IMPP', 'NICKNAME', 'PRODID'
     43 }, true)) * #S(':;')
     44 lex:add_rule('supported_property', supported_property)
     45 
     46 -- Group and property.
     47 local identifier = lexer.alpha^1 * lexer.digit^0 * ('-' * lexer.alnum^1)^0
     48 local property = required_property + supported_property +
     49 	lexer.token(lexer.TYPE, S('xX') * '-' * identifier) * #S(':;')
     50 lex:add_rule('group_sequence', token(lexer.CONSTANT, lexer.starts_line(identifier)) *
     51 	token(lexer.OPERATOR, '.') * property)
     52 
     53 -- Extension.
     54 lex:add_rule('extension',
     55 	token(lexer.TYPE, lexer.starts_line(S('xX') * '-' * identifier * #S(':;'))))
     56 
     57 -- Parameter.
     58 local parameter = (token(lexer.IDENTIFIER, lexer.starts_line(identifier)) +
     59 	token(lexer.STRING, identifier)) * #S(':=')
     60 lex:add_rule('parameter', parameter)
     61 
     62 -- Operators.
     63 lex:add_rule('operator', token(lexer.OPERATOR, S('.:;=')))
     64 
     65 -- Data.
     66 lex:add_rule('data', token(lexer.IDENTIFIER, lexer.any))
     67 
     68 -- Fold points.
     69 lex:add_fold_point(lexer.KEYWORD, 'BEGIN', 'END')
     70 
     71 return lex