Skip to content

Instantly share code, notes, and snippets.

@mcepl
Last active November 30, 2022 10:27
Show Gist options
  • Save mcepl/47f3da40a3903b82d03377b066c44b12 to your computer and use it in GitHub Desktop.
Save mcepl/47f3da40a3903b82d03377b066c44b12 to your computer and use it in GitHub Desktop.
Diff between default branch of scintillua lexers and master branch of vis
diff -uNr /home/matej/repos/tmp/scintillua/lexers/actionscript.lua lexers/actionscript.lua
--- /home/matej/repos/tmp/scintillua/lexers/actionscript.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/actionscript.lua 2022-11-29 23:51:43.326328927 +0100
@@ -53,8 +53,7 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
lex:add_fold_point(lexer.STRING, '<![CDATA[', ']]>')
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/ada.lua lexers/ada.lua
--- /home/matej/repos/tmp/scintillua/lexers/ada.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/ada.lua 2022-11-29 23:51:43.326328927 +0100
@@ -11,23 +11,28 @@
lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', token(lexer.KEYWORD, word_match({
- 'abort', 'abs', 'abstract', 'accept', 'access', 'aliased', 'all', 'and', 'array', 'at', 'begin',
- 'body', 'case', 'constant', 'declare', 'delay', 'delta', 'digits', 'do', 'else', 'elsif', 'end',
- 'entry', 'exception', 'exit', 'for', 'function', 'generic', 'goto', 'if', 'in', 'interface', 'is',
- 'limited', 'loop', 'mod', 'new', 'not', 'null', 'of', 'or', 'others', 'out', 'overriding',
- 'package', 'parallel', 'pragma', 'private', 'procedure', 'protected', 'raise', 'range', 'record',
- 'rem', 'renames', 'requeue', 'return', 'reverse', 'select', 'separate', 'some', 'subtype',
- 'synchronized', 'tagged', 'task', 'terminate', 'then', 'type', 'until', 'use', 'when', 'while',
- 'with', 'xor', --
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'abort', 'abs', 'accept', 'all', 'and', 'begin', 'body', 'case', 'declare', 'delay', 'do', 'else',
+ 'elsif', 'end', 'entry', 'exception', 'exit', 'for', 'generic', 'goto', 'if', 'in', 'is', 'loop',
+ 'mod', 'new', 'not', 'null', 'or', 'others', 'out', 'protected', 'raise', 'record', 'rem',
+ 'renames', 'requeue', 'reverse', 'select', 'separate', 'subtype', 'task', 'terminate', 'then',
+ 'type', 'until', 'when', 'while', 'xor',
+ -- Preprocessor.
+ 'package', 'pragma', 'use', 'with',
+ -- Function.
+ 'function', 'procedure', 'return',
+ -- Storage class.
+ 'abstract', 'access', 'aliased', 'array', 'at', 'constant', 'delta', 'digits', 'interface',
+ 'limited', 'of', 'private', 'range', 'tagged', 'synchronized',
+ -- Boolean.
'true', 'false'
-}, true)))
+}))
-- Types.
-lex:add_rule('type', token(lexer.TYPE, word_match({
+lex:add_rule('type', token(lexer.TYPE, word_match{
'boolean', 'character', 'count', 'duration', 'float', 'integer', 'long_float', 'long_integer',
'priority', 'short_float', 'short_integer', 'string'
-}, true)))
+}))
-- Identifiers.
lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
@@ -39,11 +44,11 @@
lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('--')))
-- Numbers.
-lex:add_rule('number', token(lexer.NUMBER, lexer.number_('_')))
+local integer = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local float = integer^1 * ('.' * integer^0)^-1 * S('eE') * S('+-')^-1 * integer
+lex:add_rule('number', token(lexer.NUMBER, S('+-')^-1 * (float + integer)))
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S(':;=<>&+-*/.()')))
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/ansi_c.lua lexers/ansi_c.lua
--- /home/matej/repos/tmp/scintillua/lexers/ansi_c.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/ansi_c.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,57 +1,90 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- C LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
-
-local lex = lexer.new(...)
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
+
+local lex = lexer.new('ansi_c')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'auto', 'break', 'case', 'const', 'continue', 'default', 'do', 'else', 'enum', 'extern', 'for',
+ 'goto', 'if', 'inline', 'register', 'restrict', 'return', 'sizeof', 'static', 'switch', 'typedef',
+ 'volatile', 'while',
+ -- C99.
+ 'false', 'true',
+ -- C11.
+ '_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn', '_Static_assert', '_Thread_local',
+ -- Compiler.
+ 'asm', '__asm', '__asm__', '__restrict__', '__inline', '__inline__', '__attribute__', '__declspec'
+}))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
-
--- Functions.
-local builtin_func = -(B('.') + B('->')) *
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = (B('.') + B('->')) * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + method + func) * #(lexer.space^0 * '('))
+lex:add_rule('type', token(lexer.TYPE, word_match{
+ 'bool', 'char', 'double', 'float', 'int', 'long', 'short', 'signed', 'struct', 'union',
+ 'unsigned', 'void', '_Bool', '_Complex', '_Imaginary',
+ -- Stdlib types.
+ 'ptrdiff_t', 'size_t', 'max_align_t', 'wchar_t', 'intptr_t', 'uintptr_t', 'intmax_t', 'uintmax_t'
+} + P('u')^-1 * 'int' * (P('_least') + '_fast')^-1 * lexer.digit^1 * '_t'))
-- Constants.
-lex:add_rule('constants', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
+lex:add_rule('constants', token(lexer.CONSTANT, word_match{
+ 'NULL',
+ -- Preprocessor.
+ '__DATE__', '__FILE__', '__LINE__', '__TIME__', '__func__',
+ -- errno.h.
+ 'E2BIG', 'EACCES', 'EADDRINUSE', 'EADDRNOTAVAIL', 'EAFNOSUPPORT', 'EAGAIN', 'EALREADY', 'EBADF',
+ 'EBADMSG', 'EBUSY', 'ECANCELED', 'ECHILD', 'ECONNABORTED', 'ECONNREFUSED', 'ECONNRESET',
+ 'EDEADLK', 'EDESTADDRREQ', 'EDOM', 'EDQUOT', 'EEXIST', 'EFAULT', 'EFBIG', 'EHOSTUNREACH', 'EIDRM',
+ 'EILSEQ', 'EINPROGRESS', 'EINTR', 'EINVAL', 'EIO', 'EISCONN', 'EISDIR', 'ELOOP', 'EMFILE',
+ 'EMLINK', 'EMSGSIZE', 'EMULTIHOP', 'ENAMETOOLONG', 'ENETDOWN', 'ENETRESET', 'ENETUNREACH',
+ 'ENFILE', 'ENOBUFS', 'ENODATA', 'ENODEV', 'ENOENT', 'ENOEXEC', 'ENOLCK', 'ENOLINK', 'ENOMEM',
+ 'ENOMSG', 'ENOPROTOOPT', 'ENOSPC', 'ENOSR', 'ENOSTR', 'ENOSYS', 'ENOTCONN', 'ENOTDIR',
+ 'ENOTEMPTY', 'ENOTRECOVERABLE', 'ENOTSOCK', 'ENOTSUP', 'ENOTTY', 'ENXIO', 'EOPNOTSUPP',
+ 'EOVERFLOW', 'EOWNERDEAD', 'EPERM', 'EPIPE', 'EPROTO', 'EPROTONOSUPPORT', 'EPROTOTYPE', 'ERANGE',
+ 'EROFS', 'ESPIPE', 'ESRCH', 'ESTALE', 'ETIME', 'ETIMEDOUT', 'ETXTBSY', 'EWOULDBLOCK', 'EXDEV',
+ -- stdint.h.
+ 'PTRDIFF_MIN', 'PTRDIFF_MAX', 'SIZE_MAX', 'SIG_ATOMIC_MIN', 'SIG_ATOMIC_MAX', 'WINT_MIN',
+ 'WINT_MAX', 'WCHAR_MIN', 'WCHAR_MAX'
+} + P('U')^-1 * 'INT' * ((P('_LEAST') + '_FAST')^-1 * lexer.digit^1 + 'PTR' + 'MAX') *
+ (P('_MIN') + '_MAX')))
-- Labels.
-lex:add_rule('label', lex:tag(lexer.LABEL, lexer.starts_line(lexer.word * ':')))
+lex:add_rule('label', token(lexer.LABEL, lexer.starts_line(lexer.word * ':')))
-- Strings.
-local sq_str = lexer.range("'", true)
-local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, P('L')^-1 * (sq_str + dq_str)))
+local sq_str = P('L')^-1 * lexer.range("'", true)
+local dq_str = P('L')^-1 * lexer.range('"', true)
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
local line_comment = lexer.to_eol('//', true)
local block_comment = lexer.range('/*', '*/') +
lexer.range('#if' * S(' \t')^0 * '0' * lexer.space, '#endif')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Numbers.
-local integer = lexer.integer * lexer.word_match('u l ll ul ull lu llu', true)^-1
+local integer = lexer.integer * word_match('u l ll ul ull lu llu', true)^-1
local float = lexer.float * P('f')^-1
-lex:add_rule('number', lex:tag(lexer.NUMBER, float + integer))
+lex:add_rule('number', token(lexer.NUMBER, float + integer))
-- Preprocessor.
-local include = lex:tag(lexer.PREPROCESSOR, '#' * S('\t ')^0 * 'include') *
- (lex:get_rule('whitespace') * lex:tag(lexer.STRING, lexer.range('<', '>', true)))^-1
-local preproc = lex:tag(lexer.PREPROCESSOR, '#' * S('\t ')^0 * lex:word_match(lexer.PREPROCESSOR))
+local include = token(lexer.PREPROCESSOR, '#' * S('\t ')^0 * 'include') *
+ (ws * token(lexer.STRING, lexer.range('<', '>', true)))^-1
+local preproc = token(lexer.PREPROCESSOR, '#' * S('\t ')^0 *
+ word_match('define elif else endif if ifdef ifndef line pragma undef'))
lex:add_rule('preprocessor', include + preproc)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.PREPROCESSOR, '#if', '#endif')
@@ -59,140 +92,6 @@
lex:add_fold_point(lexer.PREPROCESSOR, '#ifndef', '#endif')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'auto', 'break', 'case', 'const', 'continue', 'default', 'do', 'else', 'enum', 'extern', 'for',
- 'goto', 'if', 'inline', 'register', 'restrict', 'return', 'sizeof', 'static', 'switch', 'typedef',
- 'volatile', 'while', --
- 'false', 'true', -- C99
- 'alignas', 'alignof', '_Atomic', '_Generic', 'noreturn', '_Static_assert', 'thread_local', -- C11
- -- Compiler.
- 'asm', '__asm', '__asm__', '__restrict__', '__inline', '__inline__', '__attribute__', '__declspec'
-})
-
-lex:set_word_list(lexer.TYPE, {
- 'bool', 'char', 'double', 'float', 'int', 'long', 'short', 'signed', 'struct', 'union',
- 'unsigned', 'void', --
- 'complex', 'imaginary', '_Complex', '_Imaginary', -- complex.h C99
- 'lconv', -- locale.h
- 'div_t', -- math.h
- 'va_list', -- stdarg.h
- 'bool', '_Bool', -- stdbool.h C99
- -- stddef.h.
- 'size_t', 'ptrdiff_t', --
- 'max_align_t', -- C11
- -- stdint.h.
- 'int8_t', 'int16_t', 'int32_t', 'int64_t', 'int_fast8_t', 'int_fast16_t', 'int_fast32_t',
- 'int_fast64_t', 'int_least8_t', 'int_least16_t', 'int_least32_t', 'int_least64_t', 'intmax_t',
- 'intptr_t', 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'uint_fast8_t', 'uint_fast16_t',
- 'uint_fast32_t', 'uint_fast64_t', 'uint_least8_t', 'uint_least16_t', 'uint_least32_t',
- 'uint_least64_t', 'uintmax_t', 'uintptr_t', --
- 'FILE', 'fpos_t', -- stdio.h
- 'div_t', 'ldiv_t', -- stdlib.h
- -- time.h.
- 'tm', 'time_t', 'clock_t', --
- 'timespec' -- C11
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'assert', -- assert.h
- -- complex.h.
- 'CMPLX', 'creal', 'cimag', 'cabs', 'carg', 'conj', 'cproj',
- -- C99
- 'cexp', 'cpow', 'csin', 'ccos', 'ctan', 'casin', 'cacos', 'catan', 'csinh', 'ccosh', 'ctanh',
- 'casinh', 'cacosh', 'catanh',
- -- ctype.h.
- 'isalnum', 'isalpha', 'islower', 'isupper', 'isdigit', 'isxdigit', 'iscntrl', 'isgraph',
- 'isspace', 'isprint', 'ispunct', 'tolower', 'toupper', --
- 'isblank', -- C99
- -- inttypes.h.
- 'INT8_C', 'INT16_C', 'INT32_C', 'INT64_C', 'INTMAX_C', 'UINT8_C', 'UINT16_C', 'UINT32_C',
- 'UINT64_C', 'UINTMAX_C', --
- 'setlocale', 'localeconv', -- locale.h
- -- math.h.
- 'abs', 'div', 'fabs', 'fmod', 'exp', 'log', 'log10', 'pow', 'sqrt', 'sin', 'cos', 'tan', 'asin',
- 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'ceil', 'floor', 'frexp', 'ldexp', 'modf',
- -- C99.
- 'remainder', 'remquo', 'fma', 'fmax', 'fmin', 'fdim', 'nan', 'exp2', 'expm1', 'log2', 'log1p',
- 'cbrt', 'hypot', 'asinh', 'acosh', 'atanh', 'erf', 'erfc', 'tgamma', 'lgamma', 'trunc', 'round',
- 'nearbyint', 'rint', 'scalbn', 'ilogb', 'logb', 'nextafter', 'nexttoward', 'copysign', 'isfinite',
- 'isinf', 'isnan', 'isnormal', 'signbit', 'isgreater', 'isgreaterequal', 'isless', 'islessequal',
- 'islessgreater', 'isunordered', --
- 'strtoimax', 'strtoumax', -- inttypes.h C99
- 'signal', 'raise', -- signal.h
- 'setjmp', 'longjmp', -- setjmp.h
- 'va_start', 'va_arg', 'va_end', -- stdarg.h
- -- stdio.h.
- 'fopen', 'freopen', 'fclose', 'fflush', 'setbuf', 'setvbuf', 'fwide', 'fread', 'fwrite', 'fgetc',
- 'getc', 'fgets', 'fputc', 'putc', 'getchar', 'gets', 'putchar', 'puts', 'ungetc', 'scanf',
- 'fscanf', 'sscanf', 'printf', 'fprintf', 'sprintf', 'vprintf', 'vfprintf', 'vsprintf', 'ftell',
- 'fgetpos', 'fseek', 'fsetpos', 'rewind', 'clearerr', 'feof', 'ferror', 'perror', 'remove',
- 'rename', 'tmpfile', 'tmpnam',
- -- stdlib.h.
- 'abort', 'exit', 'atexit', 'system', 'getenv', 'malloc', 'calloc', 'realloc', 'free', 'atof',
- 'atoi', 'atol', 'strtol', 'strtoul', 'strtod', 'mblen', 'mbsinit', 'mbrlen', 'qsort', 'bsearch',
- 'rand', 'srand', --
- 'quick_exit', '_Exit', 'at_quick_exit', 'aligned_alloc', -- C11
- -- string.h.
- 'strcpy', 'strncpy', 'strcat', 'strncat', 'strxfrm', 'strlen', 'strcmp', 'strncmp', 'strcoll',
- 'strchr', 'strrchr', 'strspn', 'strcspn', 'strpbrk', 'strstr', 'strtok', 'memchr', 'memcmp',
- 'memset', 'memcpy', 'memmove', 'strerror',
- -- time.h.
- 'difftime', 'time', 'clock', 'asctime', 'ctime', 'gmtime', 'localtime', 'mktime', --
- 'timespec_get' -- C11
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'NULL', --
- '__DATE__', '__FILE__', '__LINE__', '__TIME__', '__func__', -- preprocessor
- -- errno.h.
- 'errno', --
- 'E2BIG', 'EACCES', 'EADDRINUSE', 'EADDRNOTAVAIL', 'EAFNOSUPPORT', 'EAGAIN', 'EALREADY', 'EBADF',
- 'EBADMSG', 'EBUSY', 'ECANCELED', 'ECHILD', 'ECONNABORTED', 'ECONNREFUSED', 'ECONNRESET',
- 'EDEADLK', 'EDESTADDRREQ', 'EDOM', 'EDQUOT', 'EEXIST', 'EFAULT', 'EFBIG', 'EHOSTUNREACH', 'EIDRM',
- 'EILSEQ', 'EINPROGRESS', 'EINTR', 'EINVAL', 'EIO', 'EISCONN', 'EISDIR', 'ELOOP', 'EMFILE',
- 'EMLINK', 'EMSGSIZE', 'EMULTIHOP', 'ENAMETOOLONG', 'ENETDOWN', 'ENETRESET', 'ENETUNREACH',
- 'ENFILE', 'ENOBUFS', 'ENODATA', 'ENODEV', 'ENOENT', 'ENOEXEC', 'ENOLCK', 'ENOLINK', 'ENOMEM',
- 'ENOMSG', 'ENOPROTOOPT', 'ENOSPC', 'ENOSR', 'ENOSTR', 'ENOSYS', 'ENOTCONN', 'ENOTDIR',
- 'ENOTEMPTY', 'ENOTRECOVERABLE', 'ENOTSOCK', 'ENOTSUP', 'ENOTTY', 'ENXIO', 'EOPNOTSUPP',
- 'EOVERFLOW', 'EOWNERDEAD', 'EPERM', 'EPIPE', 'EPROTO', 'EPROTONOSUPPORT', 'EPROTOTYPE', 'ERANGE',
- 'EROFS', 'ESPIPE', 'ESRCH', 'ESTALE', 'ETIME', 'ETIMEDOUT', 'ETXTBSY', 'EWOULDBLOCK', 'EXDEV',
- -- float.h.
- 'FLT_MIN', 'DBL_MIN', 'LDBL_MIN', 'FLT_MAX', 'DBL_MAX', 'LDBL_MAX',
- -- limits.h.
- 'CHAR_BIT', 'MB_LEN_MAX', 'CHAR_MIN', 'CHAR_MAX', 'SCHAR_MIN', 'SHRT_MIN', 'INT_MIN', 'LONG_MIN',
- 'SCHAR_MAX', 'SHRT_MAX', 'INT_MAX', 'LONG_MAX', 'UCHAR_MAX', 'USHRT_MAX', 'UINT_MAX', 'ULONG_MAX',
- -- C99.
- 'LLONG_MIN', 'ULLONG_MAX', 'PTRDIFF_MIN', 'PTRDIFF_MAX', 'SIZE_MAX', 'SIG_ATOMIC_MIN',
- 'SIG_ATOMIC_MAX', 'WINT_MIN', 'WINT_MAX', 'WCHAR_MIN', 'WCHAR_MAX', --
- 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME', -- locale.h
- -- math.h.
- 'HUGE_VAL', --
- 'INFINITY', 'NAN', -- C99
- -- stdint.h.
- 'INT8_MIN', 'INT16_MIN', 'INT32_MIN', 'INT64_MIN', 'INT_FAST8_MIN', 'INT_FAST16_MIN',
- 'INT_FAST32_MIN', 'INT_FAST64_MIN', 'INT_LEAST8_MIN', 'INT_LEAST16_MIN', 'INT_LEAST32_MIN',
- 'INT_LEAST64_MIN', 'INTPTR_MIN', 'INTMAX_MIN', 'INT8_MAX', 'INT16_MAX', 'INT32_MAX', 'INT64_MAX',
- 'INT_FAST8_MAX', 'INT_FAST16_MAX', 'INT_FAST32_MAX', 'INT_FAST64_MAX', 'INT_LEAST8_MAX',
- 'INT_LEAST16_MAX', 'INT_LEAST32_MAX', 'INT_LEAST64_MAX', 'INTPTR_MAX', 'INTMAX_MAX', 'UINT8_MAX',
- 'UINT16_MAX', 'UINT32_MAX', 'UINT64_MAX', 'UINT_FAST8_MAX', 'UINT_FAST16_MAX', 'UINT_FAST32_MAX',
- 'UINT_FAST64_MAX', 'UINT_LEAST8_MAX', 'UINT_LEAST16_MAX', 'UINT_LEAST32_MAX', 'UINT_LEAST64_MAX',
- 'UINTPTR_MAX', 'UINTMAX_MAX',
- -- stdio.h
- 'stdin', 'stdout', 'stderr', 'EOF', 'FOPEN_MAX', 'FILENAME_MAX', 'BUFSIZ', '_IOFBF', '_IOLBF',
- '_IONBF', 'SEEK_SET', 'SEEK_CUR', 'SEEK_END', 'TMP_MAX', --
- 'EXIT_SUCCESS', 'EXIT_FAILURE', 'RAND_MAX', -- stdlib.h
- -- signal.h.
- 'SIG_DFL', 'SIG_IGN', 'SIG_ERR', 'SIGABRT', 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', --
- 'CLOCKS_PER_SEC' -- time.h.
-})
-
-lex:set_word_list(lexer.PREPROCESSOR, {
- 'define', 'defined', 'elif', 'else', 'endif', 'error', 'if', 'ifdef', 'ifndef', 'line', 'pragma',
- 'undef'
-})
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/antlr.lua lexers/antlr.lua
--- /home/matej/repos/tmp/scintillua/lexers/antlr.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/antlr.lua 2022-11-29 23:51:43.326328927 +0100
@@ -51,7 +51,6 @@
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/apdl.lua lexers/apdl.lua
--- /home/matej/repos/tmp/scintillua/lexers/apdl.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/apdl.lua 2022-11-29 23:51:43.326328927 +0100
@@ -73,7 +73,6 @@
lex:add_fold_point(lexer.KEYWORD, '*if', '*endif')
lex:add_fold_point(lexer.KEYWORD, '*do', '*enddo')
lex:add_fold_point(lexer.KEYWORD, '*dowhile', '*enddo')
-
-lexer.property['scintillua.comment'] = '!'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('!'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/apl.lua lexers/apl.lua
--- /home/matej/repos/tmp/scintillua/lexers/apl.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/apl.lua 2022-11-29 23:51:43.326328927 +0100
@@ -52,6 +52,4 @@
-- Nabla.
lex:add_rule('nabla', token(lexer.PREPROCESSOR, P('∇') + '⍫'))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/applescript.lua lexers/applescript.lua
--- /home/matej/repos/tmp/scintillua/lexers/applescript.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/applescript.lua 2022-11-29 23:51:43.326328927 +0100
@@ -66,6 +66,4 @@
-- Fold points.
lex:add_fold_point(lexer.COMMENT, '(*', '*)')
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/asm.lua lexers/asm.lua
--- /home/matej/repos/tmp/scintillua/lexers/asm.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/asm.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,65 +1,17 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- NASM Assembly LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('asm')
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
--- Instructions.
-lex:add_rule('instruction',
- lex:tag(lexer.FUNCTION_BUILTIN .. '.instruction', lex:word_match('instruction')))
-
--- Registers.
-lex:add_rule('register', lex:tag(lexer.CONSTANT_BUILTIN .. '.register', lex:word_match('register')))
-
--- Types.
-local sizes = lex:word_match('size')
-local wrt_types = '..' * lex:word_match(lexer.TYPE .. '.wrt')
-lex:add_rule('type', lex:tag(lexer.TYPE, sizes + wrt_types))
-
--- Constants.
-local word = (lexer.alpha + S('$._?')) * (lexer.alnum + S('$._?#@~'))^0
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN,
- lex:word_match(lexer.CONSTANT_BUILTIN) + '$' * P('$')^-1 * -word))
-
--- Labels.
-lex:add_rule('label', lex:tag(lexer.LABEL, word * ':'))
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, word))
-
--- Strings.
-local sq_str = lexer.range("'", true)
-local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
-
--- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol(';')))
-
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number * S('hqb')^-1))
-
--- Preprocessor.
-local pp_word = lex:word_match(lexer.PREPROCESSOR)
-local pp_symbol = '??' + S('!$+?') + '%' * -lexer.space + lexer.digit^1
-lex:add_rule('preproc', lex:tag(lexer.PREPROCESSOR, '%' * (pp_word + pp_symbol)))
-
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>!=^&|~:,()[]')))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
--- Fold points.
-lex:add_fold_point(lexer.PREPROCESSOR, '%if', '%endif')
-lex:add_fold_point(lexer.PREPROCESSOR, '%macro', '%endmacro')
-lex:add_fold_point(lexer.PREPROCESSOR, '%rep', '%endrep')
-lex:add_fold_point(lexer.PREPROCESSOR, '%while', '%endwhile')
-lex:add_fold_point(lexer.KEYWORD, 'struc', 'endstruc')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
+-- Keywords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
-- Preprocessor macros.
'struc', 'endstruc', 'istruc', 'at', 'iend', 'align', 'alignb', 'sectalign', '.nolist',
-- Preprocessor Packages.
@@ -77,11 +29,12 @@
-- Operators.
'abs', 'rel', 'seg', 'wrt', 'strict', '__utf16__', '__utf16be__', '__utf16le__', '__utf32__',
'__utf32be__', '__utf32le__'
-})
+}))
+-- Instructions.
-- awk '{print $1}'|uniq|tr '[:upper:]' '[:lower:]'|
-- lua -e "for l in io.lines() do print(\"'\"..l..\"',\") end"|fmt -w 98
-lex:set_word_list('instruction', {
+lex:add_rule('instruction', token('instruction', word_match{
-- Special Instructions.
'db', 'dd', 'do', 'dq', 'dt', 'dw', 'dy', 'resb', 'resd', 'reso', 'resq', 'rest', 'resw', 'resy',
-- Conventional Instructions.
@@ -351,9 +304,11 @@
'hint_nop49', 'hint_nop50', 'hint_nop51', 'hint_nop52', 'hint_nop53', 'hint_nop54', 'hint_nop55',
'hint_nop56', 'hint_nop57', 'hint_nop58', 'hint_nop59', 'hint_nop60', 'hint_nop61', 'hint_nop62',
'hint_nop63'
-})
+}))
+lex:add_style('instruction', lexer.styles['function'])
-lex:set_word_list('register', {
+-- Registers.
+lex:add_rule('register', token('register', word_match{
-- 32-bit registers.
'ah', 'al', 'ax', 'bh', 'bl', 'bp', 'bx', 'ch', 'cl', 'cx', 'dh', 'di', 'dl', 'dx', 'eax', 'ebx',
'ebx', 'ecx', 'edi', 'edx', 'esi', 'esp', 'fs', 'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6',
@@ -366,21 +321,45 @@
'r15w', 'rax', 'rbp', 'rbx', 'rcx', 'rdi', 'rdx', 'rsi', 'rsp', 'sil', 'xmm8', 'xmm9', 'xmm10',
'xmm11', 'xmm12', 'xmm13', 'xmm14', 'xmm15', 'ymm8', 'ymm9', 'ymm10', 'ymm11', 'ymm12', 'ymm13',
'ymm14', 'ymm15'
-})
-
-lex:set_word_list('size', {
- 'byte', 'word', 'dword', 'qword', 'tword', 'oword', 'yword', --
- 'a16', 'a32', 'a64', 'o16', 'o32', 'o64' -- instructions
-})
+}))
+lex:add_style('register', lexer.styles.constant)
-lex:set_word_list(lexer.TYPE .. '.wrt', 'start gotpc gotoff gottpoff got plt sym tlsie')
+-- Types.
+local sizes = word_match{
+ 'byte', 'word', 'dword', 'qword', 'tword', 'oword', 'yword',
+ -- Instructions.
+ 'a16', 'a32', 'a64', 'o16', 'o32', 'o64'
+}
+local wrt_types = '..' * word_match('start gotpc gotoff gottpoff got plt sym tlsie')
+lex:add_rule('type', token(lexer.TYPE, sizes + wrt_types))
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
+-- Constants.
+local word = (lexer.alpha + S('$._?')) * (lexer.alnum + S('$._?#@~'))^0
+local constants = word_match{
'__float128h__', '__float128l__', '__float16__', '__float32__', '__float64__', '__float8__',
'__float80e__', '__float80m__', '__Infinity__', '__NaN__', '__QNaN__', '__SNaN__'
-})
+}
+lex:add_rule('constant', token(lexer.CONSTANT, constants + '$' * P('$')^-1 * -word))
+
+-- Labels.
+lex:add_rule('label', token(lexer.LABEL, word * ':'))
+
+-- Identifiers.
+lex:add_rule('identifier', token(lexer.IDENTIFIER, word))
-lex:set_word_list(lexer.PREPROCESSOR, {
+-- Strings.
+local sq_str = lexer.range("'", true)
+local dq_str = lexer.range('"', true)
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
+
+-- Comments.
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol(';')))
+
+-- Numbers.
+lex:add_rule('number', token(lexer.NUMBER, lexer.number * S('hqb')^-1))
+
+-- Preprocessor.
+local pp_word = word_match{
'arg', 'assign', 'clear', 'define', 'defstr', 'deftok', 'depend', 'elif', 'elifctx', 'elifdef',
'elifempty', 'elifenv', 'elifid', 'elifidn', 'elifidni', 'elifmacro', 'elifn', 'elifnctx',
'elifndef', 'elifnempty', 'elifnenv', 'elifnid', 'elifnidn', 'elifnidni', 'elifnmacro',
@@ -392,8 +371,19 @@
'include', 'ixdefine', 'line', 'local', 'macro', 'pathsearch', 'pop', 'push', 'rep', 'repl',
'rmacro', 'rotate', 'stacksize', 'strcat', 'strlen', 'substr', 'undef', 'unmacro', 'use',
'warning', 'while', 'xdefine'
-})
+}
+local pp_symbol = '??' + S('!$+?') + '%' * -lexer.space + lexer.digit^1
+lex:add_rule('preproc', token(lexer.PREPROCESSOR, '%' * (pp_word + pp_symbol)))
-lexer.property['scintillua.comment'] = ';'
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|~:,()[]')))
+
+-- Fold points.
+lex:add_fold_point(lexer.PREPROCESSOR, '%if', '%endif')
+lex:add_fold_point(lexer.PREPROCESSOR, '%macro', '%endmacro')
+lex:add_fold_point(lexer.PREPROCESSOR, '%rep', '%endrep')
+lex:add_fold_point(lexer.PREPROCESSOR, '%while', '%endwhile')
+lex:add_fold_point(lexer.KEYWORD, 'struc', 'endstruc')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines(';'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/asp.lua lexers/asp.lua
--- /home/matej/repos/tmp/scintillua/lexers/asp.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/asp.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,31 +1,31 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- ASP LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
local html = lexer.load('html')
-local lex = lexer.new(..., {inherit = html}) -- proxy for HTML
+local lex = lexer.new('asp', {inherit = html}) -- proxy for HTML
-- Embedded VB.
local vb = lexer.load('vb')
-local vb_start_rule = lex:tag(lexer.PREPROCESSOR, '<%' * P('=')^-1)
-local vb_end_rule = lex:tag(lexer.PREPROCESSOR, '%>')
+local vb_start_rule = token('asp_tag', '<%' * P('=')^-1)
+local vb_end_rule = token('asp_tag', '%>')
lex:embed(vb, vb_start_rule, vb_end_rule)
+lex:add_style('asp_tag', lexer.styles.embedded)
-- Embedded VBScript.
local vbs = lexer.load('vb', 'vbscript')
-local script_element = lexer.word_match('script', true)
-local vbs_start_rule = #('<' * script_element * (P(function(input, index)
+local script_element = word_match('script', true)
+local vbs_start_rule = #(P('<') * script_element * (P(function(input, index)
if input:find('^%s+language%s*=%s*(["\'])vbscript%1', index) or
- input:find('^%s+type%s*=%s*(["\'])text/vbscript%1', index) then return true end
+ input:find('^%s+type%s*=%s*(["\'])text/vbscript%1', index) then return index end
end) + '>')) * html.embed_start_tag -- <script language="vbscript">
-local vbs_end_rule = #('</' * script_element * '>') * html.embed_end_tag -- </script>
+local vbs_end_rule = #('</' * script_element * lexer.space^0 * '>') * html.embed_end_tag -- </script>
lex:embed(vbs, vbs_start_rule, vbs_end_rule)
-- Fold points.
-lex:add_fold_point(lexer.PREPROCESSOR, '<%', '%>')
-
-lexer.property['scintillua.comment'] = '<!--|-->'
+lex:add_fold_point('asp_tag', '<%', '%>')
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/autohotkey.lua lexers/autohotkey.lua
--- /home/matej/repos/tmp/scintillua/lexers/autohotkey.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/autohotkey.lua 1970-01-01 01:00:00.000000000 +0100
@@ -1,160 +0,0 @@
--- Copyright 2022 Mitchell. See LICENSE.
--- AutoHotkey LPeg lexer.
--- Contributed by Snoopy.
-
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
-
-local lex = lexer.new(...)
-
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD, true)))
-
--- Variables.
-lex:add_rule('variable',
- lex:tag(lexer.VARIABLE_BUILTIN, 'A_' * lex:word_match(lexer.VARIABLE_BUILTIN, true)))
-
--- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, S('fF') * lexer.digit * (lexer.digit)^-1 +
- lex:word_match(lexer.CONSTANT_BUILTIN, true)))
-
--- Functions.
-local builtin_func = -B('.') *
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN, true))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + method + func) * #(lexer.space^0 * '('))
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-
--- Comments.
-local line_comment = lexer.to_eol(';')
-local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
-
--- Preprocessor.
-lex:add_rule('preprocessor',
- lex:tag(lexer.PREPROCESSOR, '#' * lex:word_match(lexer.PREPROCESSOR, true)))
-
--- Strings.
-local dq_str = lexer.range('"', true, false)
-local sq_str = lexer.range("'", true, false)
-lex:add_rule('string', lex:tag(lexer.STRING, dq_str + sq_str))
-
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
-
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('~+-^*/&<>=?:()[]{}')))
-
-lex:set_word_list(lexer.KEYWORD, {
- 'as', 'and', 'contains', 'false', 'in', 'is', 'IsSet', 'not', 'or', 'super', 'true', 'unset',
- 'Break', 'Catch', 'Continue', 'Else', 'Finally', 'For', 'Global', 'Goto', 'If', 'Local', 'Loop',
- 'Return', 'Static', 'Throw', 'Try', 'Until', 'While'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'Abs', 'AutoTrim', 'Asc', 'ASin', 'ACos', 'ATan', 'BlockInput', 'Ceil', 'Chr', 'Click',
- 'ClipWait', 'ComObjActive', 'ComObjArray', 'ComObjConnect', 'ComObjCreate', 'ComObject',
- 'ComObjEnwrap', 'ComObjUnwrap', 'ComObjError', 'ComObjFlags', 'ComObjGet', 'ComObjMissing',
- 'ComObjParameter', 'ComObjQuery', 'ComObjType', 'ComObjValue', 'Control', 'ControlClick',
- 'ControlFocus', 'ControlGet', 'ControlGetFocus', 'ControlGetPos', 'ControlGetText', 'ControlMove',
- 'ControlSend', 'ControlSendRaw', 'ControlSetText', 'CoordMode', 'Cos', 'Critical',
- 'DetectHiddenText', 'DetectHiddenWindows', 'DllCall', 'Drive', 'DriveGet', 'DriveSpaceFree',
- 'Edit', 'Else', 'EnvAdd', 'EnvDiv', 'EnvGet', 'EnvMult', 'EnvSet', 'EnvSub', 'EnvUpdate',
- 'Exception', 'Exit', 'ExitApp', 'Exp', 'FileAppend', 'FileCopy', 'FileCopyDir', 'FileCreateDir',
- 'FileCreateShortcut', 'FileDelete', 'FileEncoding', 'FileExist', 'FileInstall', 'FileGetAttrib',
- 'FileGetShortcut', 'FileGetSize', 'FileGetTime', 'FileGetVersion', 'FileMove', 'FileMoveDir',
- 'FileOpen', 'FileRead', 'FileReadLine', 'FileRecycle', 'FileRecycleEmpty', 'FileRemoveDir',
- 'FileSelectFile', 'FileSelectFolder', 'FileSetAttrib', 'FileSetTime', 'Floor', 'Format',
- 'FormatTime', 'Func', 'GetKeyName', 'GetKeyVK', 'GetKeySC', 'GetKeyState', 'GetKeyState', 'Gosub',
- 'GroupActivate', 'GroupAdd', 'GroupClose', 'GroupDeactivate', 'Gui', 'GuiControl',
- 'GuiControlGet', 'Hotkey', 'Hotstring', 'IfEqual', 'IfNotEqual', 'IfExist', 'IfNotExist',
- 'IfGreater', 'IfGreaterOrEqual', 'IfInString', 'IfNotInString', 'IfLess', 'IfLessOrEqual',
- 'IfMsgBox', 'IfWinActive', 'IfWinNotActive', 'IfWinExist', 'IfWinNotExist', 'IL_Create', 'IL_Add',
- 'IL_Destroy', 'ImageSearch', 'IniDelete', 'IniRead', 'IniWrite', 'Input', 'InputBox', 'InputHook',
- 'InStr', 'IsByRef', 'IsFunc', 'IsLabel', 'IsObject', 'IsSet', 'KeyHistory', 'KeyWait',
- 'ListHotkeys', 'ListLines', 'ListVars', 'LoadPicture', 'Log', 'Ln', 'LV_Add', 'LV_Delete',
- 'LV_DeleteCol', 'LV_GetCount', 'LV_GetNext', 'LV_GetText', 'LV_Insert', 'LV_InsertCol',
- 'LV_Modify', 'LV_ModifyCol', 'LV_SetImageList', 'Max', 'Menu', 'MenuGetHandle', 'MenuGetName',
- 'Min', 'Mod', 'MouseClick', 'MouseClickDrag', 'MouseGetPos', 'MouseMove', 'MsgBox', 'NumGet',
- 'NumPut', 'ObjAddRef', 'ObjRelease', 'ObjBindMethod', 'ObjClone', 'ObjCount', 'ObjDelete',
- 'ObjGetAddress', 'ObjGetCapacity', 'ObjHasKey', 'ObjInsert', 'ObjInsertAt', 'ObjLength',
- 'ObjMaxIndex', 'ObjMinIndex', 'ObjNewEnum', 'ObjPop', 'ObjPush', 'ObjRemove', 'ObjRemoveAt',
- 'ObjSetCapacity', 'ObjGetBase', 'ObjRawGet', 'ObjRawSet', 'ObjSetBase', 'OnClipboardChange',
- 'OnError', 'OnExit', 'OnExit', 'OnMessage', 'Ord', 'OutputDebug', 'Pause', 'PixelGetColor',
- 'PixelSearch', 'PostMessage', 'Process', 'Progress', 'Random', 'RegExMatch', 'RegExReplace',
- 'RegDelete', 'RegRead', 'RegWrite', 'RegisterCallback', 'Reload', 'Round', 'Run', 'RunAs',
- 'RunWait', 'SB_SetIcon', 'SB_SetParts', 'SB_SetText', 'Send', 'SendRaw', 'SendInput', 'SendPlay',
- 'SendEvent', 'SendLevel', 'SendMessage', 'SendMode', 'SetBatchLines', 'SetCapsLockState',
- 'SetControlDelay', 'SetDefaultMouseSpeed', 'SetEnv', 'SetFormat', 'SetKeyDelay', 'SetMouseDelay',
- 'SetNumLockState', 'SetScrollLockState', 'SetRegView', 'SetStoreCapsLockMode', 'SetTimer',
- 'SetTitleMatchMode', 'SetWinDelay', 'SetWorkingDir', 'Shutdown', 'Sin', 'Sleep', 'Sort',
- 'SoundBeep', 'SoundGet', 'SoundGetWaveVolume', 'SoundPlay', 'SoundSet', 'SoundSetWaveVolume',
- 'SplashImage', 'SplashTextOn', 'SplashTextOff', 'SplitPath', 'Sqrt', 'StatusBarGetText',
- 'StatusBarWait', 'StrGet', 'StringCaseSense', 'StringGetPos', 'StringLeft', 'StringLen',
- 'StringLower', 'StringMid', 'StringReplace', 'StringRight', 'StringSplit', 'StringTrimLeft',
- 'StringTrimRight', 'StringUpper', 'StrLen', 'StrPut', 'StrReplace', 'StrSplit', 'SubStr',
- 'Suspend', 'Switch', 'SysGet', 'Tan', 'Thread', 'ToolTip', 'Transform', 'TrayTip', 'Trim',
- 'LTrim', 'RTrim', 'TV_Add', 'TV_Delete', 'TV_Get', 'TV_GetChild', 'TV_GetCount', 'TV_GetNext',
- 'TV_GetParent', 'TV_GetPrev', 'TV_GetSelection', 'TV_GetText', 'TV_Modify', 'TV_SetImageList',
- 'UrlDownloadToFile', 'VarSetCapacity', 'WinActivate', 'WinActivateBottom', 'WinActive',
- 'WinClose', 'WinExist', 'WinGetActiveStats', 'WinGetActiveTitle', 'WinGetClass', 'WinGet',
- 'WinGetPos', 'WinGetText', 'WinGetTitle', 'WinHide', 'WinKill', 'WinMaximize',
- 'WinMenuSelectItem', 'WinMinimize', 'WinMinimizeAll', 'WinMinimizeAllUndo', 'WinMove',
- 'WinRestore', 'WinSet', 'WinSetTitle', 'WinShow', 'WinWait', 'WinWaitActive', 'WinWaitNotActive',
- 'WinWaitClose'
-})
-
-lex:set_word_list(lexer.PREPROCESSOR, {
- 'ClipboardTimeout', 'CommentFlag', 'Delimiter', 'DerefChar', 'ErrorStdOut', 'EscapeChar',
- 'HotkeyInterval', 'HotkeyModifierTimeout', 'Hotstring', 'If', 'IfTimeout', 'IfWinActive',
- 'IfWinNotActive', 'IfWinExist', 'IfWinNotExist', 'Include', 'IncludeAgain', 'InputLevel',
- 'InstallKeybdHook', 'InstallMouseHook', 'KeyHistory', 'LTrim', 'MaxHotkeysPerInterval', 'MaxMem',
- 'MaxThreads', 'MaxThreadsBuffer', 'MaxThreadsPerHotkey', 'MenuMaskKey', 'NoEnv', 'NoTrayIcon',
- 'Persistent', 'Requires', 'SingleInstance', 'UseHook', 'Warn', 'WinActivateForce'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'LButton', 'RButton', 'MButton', 'Advanced Buttons', 'XButton1', 'XButton2', 'Wheel', 'WheelDown',
- 'WheelUp', 'WheelLeft', 'WheelRight', 'CapsLock', 'Space', 'Tab', 'Enter', 'Return', 'Esc',
- 'Escape', 'BS', 'Backspace', 'ScrollLock', 'Del', 'Delete', 'Ins', 'Insert', 'Home', 'End',
- 'PgUp', 'PgDn', 'Up', 'Down', 'Left', 'Right', 'Numpad0', 'NumpadIns', 'Numpad1', 'NumpadEnd',
- 'Numpad2', 'NumpadDown', 'Numpad3', 'NumpadPgDn', 'Numpad4', 'NumpadLeft', 'Numpad5',
- 'NumpadClear', 'Numpad6', 'NumpadRight', 'Numpad7', 'NumpadHome', 'Numpad8', 'NumpadUp',
- 'Numpad9', 'NumpadPgUp', 'NumpadDot', 'NumpadDel', 'NumLock', 'NumpadDiv', 'NumpadMult',
- 'NumpadAdd', 'NumpadSub', 'NumpadEnter', 'LWin', 'RWin', 'Ctrl', 'Control', 'Alt', 'Shift',
- 'LCtrl', 'LControl', 'RCtrl', 'RControl', 'LShift', 'RShift', 'LAlt', 'RAlt', 'Browser_Back',
- 'Browser_Forward', 'Browser_Refresh', 'Browser_Stop', 'Browser_Search', 'Browser_Favorites',
- 'Browser_Home', 'Volume_Mute', 'Volume_Down', 'Volume_Up', 'Media_Next', 'Media_Prev',
- 'Media_Stop', 'Media_Play_Pause', 'Launch_Mail', 'Launch_Media', 'Launch_App1', 'Launch_App2',
- 'AppsKey', 'PrintScreen', 'CtrlBreak', 'Pause', 'Break', 'Help'
-})
-
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- 'Space', 'Tab', 'Args', 'WorkingDir', 'InitialWorkingDir', 'ScriptDir', 'ScriptName',
- 'ScriptFullPath', 'ScriptHwnd', 'LineNumber', 'LineFile', 'ThisFunc', 'ThisLabel', 'AhkVersion',
- 'AhkPath', 'IsUnicode', 'IsCompiled', 'ExitReason', 'Year', 'MM', 'DD', 'MMMM', 'MMM', 'DDDD',
- 'DDD', 'WDay', 'YDay', 'YWeek', 'Hour', 'Min', 'Sec', 'MSec', 'Now', 'NowUTC', 'TickCount',
- 'IsSuspended', 'IsPaused', 'IsCritical', 'BatchLines', 'ListLines', 'TitleMatchMode',
- 'TitleMatchModeSpeed', 'DetectHiddenWindows', 'DetectHiddenText', 'AutoTrim', 'StringCaseSense',
- 'FileEncoding', 'FormatInteger', 'FormatFloat', 'SendMode', 'SendLevel', 'StoreCapsLockMode',
- 'KeyDelay', 'KeyDuration', 'KeyDelayPlay', 'KeyDurationPlay', 'WinDelay', 'ControlDelay',
- 'MouseDelay', 'MouseDelayPlay', 'DefaultMouseSpeed', 'CoordModeToolTip', 'CoordModePixel',
- 'CoordModeMouse', 'CoordModeCaret', 'CoordModeMenu', 'RegView', 'IconHidden', 'IconTip',
- 'IconFile', 'IconNumber', 'TimeIdle', 'TimeIdlePhysical', 'TimeIdleKeyboard', 'TimeIdleMouse',
- 'DefaultGui', 'DefaultListView', 'DefaultTreeView', 'Gui', 'GuiControl', 'GuiWidth', 'GuiHeight',
- 'GuiX', 'GuiY', 'GuiEvent', 'GuiControlEvent', 'EventInfo', 'ThisMenuItem', 'ThisMenu',
- 'ThisMenuItemPos', 'ThisHotkey', 'PriorHotkey', 'PriorKey', 'TimeSinceThisHotkey',
- 'TimeSincePriorHotkey', 'EndChar', 'ComSpec', 'Temp', 'OSType', 'OSVersion', 'Is64bitOS',
- 'PtrSize', 'Language', 'ComputerName', 'UserName', 'WinDir', 'ProgramFiles', 'AppData',
- 'AppDataCommon', 'Desktop', 'DesktopCommon', 'StartMenu', 'StartMenuCommon', 'Programs',
- 'ProgramsCommon', 'Startup', 'StartupCommon', 'MyDocuments', 'IsAdmin', 'ScreenWidth',
- 'ScreenHeight', 'ScreenDPI', 'Cursor', 'CaretX', 'CaretY', 'Clipboard', 'LastError', 'Index',
- 'LoopFileName', 'LoopRegName', 'LoopReadLine', 'LoopField'
-})
-
-lexer.property['scintillua.comment'] = ';'
-
-return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/autoit.lua lexers/autoit.lua
--- /home/matej/repos/tmp/scintillua/lexers/autoit.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/autoit.lua 2022-11-29 23:51:43.326328927 +0100
@@ -2,60 +2,26 @@
-- AutoIt LPeg lexer.
-- Contributed by Jeff Stone.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('autoit')
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD, true)))
-
--- Functions.
-local builtin_func = -B('.') *
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN, true))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + method + func) * #(lexer.space^0 * '('))
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-
--- Comments.
-local line_comment = lexer.to_eol(';')
-local block_comment = lexer.range('#comments-start', '#comments-end') + lexer.range('#cs', '#ce')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
--- Preprocessor.
-lex:add_rule('preprocessor',
- lex:tag(lexer.PREPROCESSOR, '#' * lex:word_match(lexer.PREPROCESSOR, true)))
-
--- Strings.
-local dq_str = lexer.range('"', true, false)
-local sq_str = lexer.range("'", true, false)
-local inc = lexer.range('<', '>', true, false, true)
-lex:add_rule('string', lex:tag(lexer.STRING, dq_str + sq_str + inc))
-
--- Macros.
-lex:add_rule('macro', lex:tag(lexer.CONSTANT_BUILTIN, '@' * (lexer.alnum + '_')^1))
-
--- Variables.
-lex:add_rule('variable', lex:tag(lexer.VARIABLE, '$' * (lexer.alnum + '_')^1))
-
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
-
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-^*/&<>=?:()[]')))
-
-lex:set_word_list(lexer.KEYWORD, {
+-- Keywords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match({
'False', 'True', 'And', 'Or', 'Not', 'ContinueCase', 'ContinueLoop', 'Default', 'Dim', 'Global',
'Local', 'Const', 'Do', 'Until', 'Enum', 'Exit', 'ExitLoop', 'For', 'To', 'Step', 'Next', 'In',
'Func', 'Return', 'EndFunc', 'If', 'Then', 'ElseIf', 'Else', 'EndIf', 'Null', 'ReDim', 'Select',
'Case', 'EndSelect', 'Static', 'Switch', 'EndSwitch', 'Volatile', 'While', 'WEnd', 'With',
'EndWith'
-})
+}, true)))
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Functions.
+lex:add_rule('function', token(lexer.FUNCTION, word_match({
'Abs', 'ACos', 'AdlibRegister', 'AdlibUnRegister', 'Asc', 'AscW', 'ASin', 'Assign', 'ATan',
'AutoItSetOption', 'AutoItWinGetTitle', 'AutoItWinSetTitle', 'Beep', 'Binary', 'BinaryLen',
'BinaryMid', 'BinaryToString', 'BitAND', 'BitNOT', 'BitOR', 'BitRotate', 'BitShift', 'BitXOR',
@@ -125,13 +91,39 @@
'WinGetState', 'WinGetText', 'WinGetTitle', 'WinKill', 'WinList', 'WinMenuSelectItem',
'WinMinimizeAll', 'WinMinimizeAllUndo', 'WinMove', 'WinSetOnTop', 'WinSetState', 'WinSetTitle',
'WinSetTrans', 'WinWait', 'WinWaitActive', 'WinWaitClose', 'WinWaitNotActive'
-})
+}, true)))
-lex:set_word_list(lexer.PREPROCESSOR, {
+-- Identifiers.
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
+
+-- Comments.
+local line_comment = lexer.to_eol(';')
+local block_comment = lexer.range('#comments-start', '#comments-end') + lexer.range('#cs', '#ce')
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
+
+-- Preprocessor.
+lex:add_rule('preprocessor', token(lexer.PREPROCESSOR, '#' * word_match({
'include-once', 'include', 'pragma', 'forceref', 'RequireAdmin', 'NoTrayIcon',
'OnAutoItStartRegister'
-})
+}, true)))
+
+-- Strings.
+local dq_str = lexer.range('"', true, false)
+local sq_str = lexer.range("'", true, false)
+local inc = lexer.range('<', '>', true, false, true)
+lex:add_rule('string', token(lexer.STRING, dq_str + sq_str + inc))
+
+-- Macros.
+lex:add_rule('macro', token('macro', '@' * (lexer.alnum + '_')^1))
+lex:add_style('macro', lexer.styles.preprocessor)
-lexer.property['scintillua.comment'] = ';'
+-- Variables.
+lex:add_rule('variable', token(lexer.VARIABLE, '$' * (lexer.alnum + '_')^1))
+
+-- Numbers.
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
+
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-^*/&<>=?:()[]')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/awk.lua lexers/awk.lua
--- /home/matej/repos/tmp/scintillua/lexers/awk.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/awk.lua 2022-11-29 23:51:43.326328927 +0100
@@ -2,10 +2,11 @@
-- AWK LPeg lexer.
-- Modified by Wolfgang Seeberg 2012, 2013.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('awk')
local LEFTBRACKET = '['
local RIGHTBRACKET = ']'
@@ -214,82 +215,70 @@
return false
end
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
+
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, '#' * P(scanComment)))
+lex:add_rule('comment', token(lexer.COMMENT, '#' * P(scanComment)))
-- Strings.
-lex:add_rule('string', lex:tag(lexer.STRING, DQUOTE * P(scanString)))
+lex:add_rule('string', token(lexer.STRING, DQUOTE * P(scanString)))
-- No leading sign because it might be binary.
local float = ((lexer.digit^1 * ('.' * lexer.digit^0)^-1) + ('.' * lexer.digit^1)) *
(S('eE') * S('+-')^-1 * lexer.digit^1)^-1
-- Fields. E.g. $1, $a, $(x), $a(x), $a[x], $"1", $$a, etc.
-lex:add_rule('field', lex:tag(lexer.VARIABLE .. '.field', '$' * S('$+-')^0 *
+lex:add_rule('field', token('field', '$' * S('$+-')^0 *
(float + lexer.word^0 * '(' * P(scanFieldDelimiters) + lexer.word^1 *
('[' * P(scanFieldDelimiters))^-1 + '"' * P(scanString) + '/' * P(eatRegex) * '/')))
+lex:add_style('field', lexer.styles.label)
-- Regular expressions.
-- Slash delimited regular expressions are preceded by most operators or the keywords 'print'
-- and 'case', possibly on a preceding line. They can contain unescaped slashes and brackets
-- in brackets. Some escape sequences like '\S', '\s' have special meanings with Gawk. Tokens
-- that contain them are displayed differently.
-lex:add_rule('gawkRegex', lex:tag(lexer.REGEX .. '.gawk', SLASH * P(scanGawkRegex)))
-lex:add_rule('regex', lex:tag(lexer.REGEX, SLASH * P(scanRegex)))
+lex:add_rule('gawkRegex', token('gawkRegex', SLASH * P(scanGawkRegex)))
+lex:add_style('gawkRegex', lexer.styles.preprocessor .. {underlined = true})
+lex:add_rule('regex', token(lexer.REGEX, SLASH * P(scanRegex)))
-- Operators.
-lex:add_rule('gawkOperator', lex:tag(lexer.OPERATOR .. '.gawk', P("|&") + "@" + "**=" + "**"))
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('!%&()*+,-/:;<=>?[\\]^{|}~')))
+lex:add_rule('gawkOperator', token('gawkOperator', P("|&") + "@" + "**=" + "**"))
+lex:add_style('gawkOperator', lexer.styles.operator .. {underlined = true})
+lex:add_rule('operator', token(lexer.OPERATOR, S('!%&()*+,-/:;<=>?[\\]^{|}~')))
-- Numbers.
-lex:add_rule('gawkNumber', lex:tag(lexer.NUMBER .. '.gawk', lexer.hex_num + lexer.oct_num))
-lex:add_rule('number', lex:tag(lexer.NUMBER, float))
+lex:add_rule('gawkNumber', token('gawkNumber', lexer.hex_num + lexer.oct_num))
+lex:add_style('gawkNumber', lexer.styles.number .. {underlined = true})
+lex:add_rule('number', token(lexer.NUMBER, float))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
-lex:add_rule('builtInVariable',
- lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'BEGIN', 'END', 'atan2', 'break', 'close', 'continue', 'cos', 'delete', 'do', 'else', 'exit',
+ 'exp', 'fflush', 'for', 'function', 'getline', 'gsub', 'if', 'in', 'index', 'int', 'length',
+ 'log', 'match', 'next', 'nextfile', 'print', 'printf', 'rand', 'return', 'sin', 'split',
+ 'sprintf', 'sqrt', 'srand', 'sub', 'substr', 'system', 'tolower', 'toupper', 'while'
+}))
+
+lex:add_rule('builtInVariable', token('builtInVariable', word_match(
+ 'ARGC ARGV CONVFMT ENVIRON FILENAME FNR FS NF NR OFMT OFS ORS RLENGTH RS RSTART SUBSEP')))
+lex:add_style('builtInVariable', lexer.styles.constant)
-lex:add_rule('gawkBuiltInVariable', lex:tag(lexer.VARIABLE_BUILTIN .. '.gawk',
- lex:word_match(lexer.VARIABLE_BUILTIN .. '.gawk')))
+lex:add_rule('gawkBuiltInVariable', token('gawkBuiltInVariable', word_match{
+ 'ARGIND', 'BINMODE', 'ERRNO', 'FIELDWIDTHS', 'FPAT', 'FUNCTAB', 'IGNORECASE', 'LINT', 'PREC',
+ 'PROCINFO', 'ROUNDMODE', 'RT', 'SYMTAB', 'TEXTDOMAIN'
+}))
+lex:add_style('gawkBuiltInVariable', lexer.styles.constant .. {underlined = true})
-- Functions.
-local builtin_func = lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-lex:add_rule('function', (builtin_func + func) * #P('('))
+lex:add_rule('function', token(lexer.FUNCTION, lexer.word * #P('(')))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'BEGIN', 'END', 'break', 'continue', 'do', 'else', 'for', 'if', 'in', 'while', --
- 'delete', -- array
- 'print', 'printf', 'getline', 'close', 'fflush', 'system', -- I/O
- 'function', 'return', -- functions
- 'next', 'nextfile', 'exit' -- program execution
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'gsub', 'index', 'length', 'match', 'split', 'sprintf', 'sub', 'substr', 'tolower', 'toupper', -- string
- 'mktime', 'strftime', 'systime', -- time
- 'atan2', 'cos', 'exp', 'int', 'log', 'rand', 'sin', 'sqrt', 'srand' -- arithmetic
-})
-
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- 'ARGC', 'ARGV', 'CONVFMT', 'ENVIRON', 'FILENAME', 'FNR', 'FS', 'NF', 'NR', 'OFMT', 'OFS', 'ORS',
- 'RLENGTH', 'RS', 'RSTART', 'SUBSEP'
-})
-
-lex:set_word_list(lexer.VARIABLE_BUILTIN .. '.gawk', {
- 'ARGIND', 'BINMODE', 'ERRNO', 'FIELDWIDTHS', 'FPAT', 'FUNCTAB', 'IGNORECASE', 'LINT', 'PREC',
- 'PROCINFO', 'ROUNDMODE', 'RT', 'SYMTAB', 'TEXTDOMAIN'
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/bash.lua lexers/bash.lua
--- /home/matej/repos/tmp/scintillua/lexers/bash.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/bash.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,131 +1,58 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Shell LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('bash')
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
--- Builtins.
-lex:add_rule('builtin', lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
--- Variable assignment.
-local assign = lex:tag(lexer.VARIABLE, lexer.word) * lex:tag(lexer.OPERATOR, '=')
-lex:add_rule('assign', lexer.starts_line(assign, true))
+-- Keywords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'if', 'then', 'elif', 'else', 'fi', 'case', 'in', 'esac', 'while', 'for', 'do', 'done',
+ 'continue', 'local', 'return', 'select',
+ -- Operators.
+ '-a', '-b', '-c', '-d', '-e', '-f', '-g', '-h', '-k', '-p', '-r', '-s', '-t', '-u', '-w', '-x',
+ '-O', '-G', '-L', '-S', '-N', '-nt', '-ot', '-ef', '-o', '-z', '-n', '-eq', '-ne', '-lt', '-le',
+ '-gt', '-ge'
+}))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local sq_str = lexer.range("'", false, false)
local dq_str = lexer.range('"')
+local ex_str = lexer.range('`')
local heredoc = '<<' * P(function(input, index)
- local _, e, minus, _, delimiter = input:find('^(%-?)%s*(["\']?)([%w_]+)%2[^\n]*[\n\r\f;]+', index)
- if not delimiter then return nil end
- -- If the starting delimiter of a here-doc begins with "-", then spaces are allowed to come
- -- before the closing delimiter.
- _, e =
- input:find((minus == '' and '[\n\r\f]+' or '[\n\r\f]+[ \t]*') .. delimiter .. '%f[^%w_]', e)
+ local _, e, _, delimiter = input:find('^%-?(["\']?)([%a_][%w_]*)%1[\n\r\f;]+', index)
+ if not delimiter then return end
+ _, e = input:find('[\n\r\f]+' .. delimiter, e)
return e and e + 1 or #input + 1
end)
-local ex_str = P('`')
-lex:add_rule('string',
- lex:tag(lexer.STRING, sq_str + dq_str + heredoc) + lex:tag(lexer.EMBEDDED, ex_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str + ex_str + heredoc))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Variables.
-local builtin_var = lex:tag(lexer.OPERATOR, '$') * lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(
- lexer.VARIABLE_BUILTIN) + S('!#?*@$-') + lexer.digit^1)
-local var_ref = lex:tag(lexer.OPERATOR, '$' * ('{' * S('!#')^-1)^-1) *
- lex:tag(lexer.VARIABLE, lexer.word)
-lex:add_rule('variable', builtin_var + var_ref)
+lex:add_rule('variable', token(lexer.VARIABLE, '$' *
+ (S('!#?*@$') + lexer.digit^1 + lexer.word + lexer.range('{', '}', true, false, true))))
-- Operators.
-local op = S('!<>&|;$()[]{}') + lpeg.B(lexer.space) * S('.:') * #lexer.space
-
-local function in_expr(constructs)
- return P(function(input, index)
- local line = input:sub(1, index):match('[^\r\n]*$')
- for k, v in pairs(constructs) do
- local s = line:find(k, 1, true)
- if not s then goto continue end
- local e = line:find(v, 1, true)
- if not e or e < s then return true end
- ::continue::
- end
- return nil
- end)
-end
-
-local file_op = '-' * (S('abcdefghkprstuwxGLNOS') + 'ef' + 'nt' + 'ot')
-local shell_op = '-o'
-local var_op = '-' * S('vR')
-local string_op = '-' * S('zn') + S('!=')^-1 * '=' + S('<>')
-local num_op = '-' * lexer.word_match('eq ne lt le gt ge')
-local in_cond_expr = in_expr{[' [[ '] = ' ]]', [' [ '] = ' ]'}
-local conditional_op = (num_op + file_op + shell_op + var_op + string_op) * #lexer.space *
- in_cond_expr
-
-local in_arith_expr = in_expr{['(('] = '))'}
-local arith_op = (S('+!~*/%<>=&^|?:,') + '--' + '-' * #S(' \t')) * in_arith_expr
-
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, op + conditional_op + arith_op))
+lex:add_rule('operator', token(lexer.OPERATOR, S('=!<>+-/*^&|~.,:;?()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.KEYWORD, 'if', 'fi')
lex:add_fold_point(lexer.KEYWORD, 'case', 'esac')
lex:add_fold_point(lexer.KEYWORD, 'do', 'done')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'if', 'then', 'elif', 'else', 'fi', 'time', 'for', 'in', 'until', 'while', 'do', 'done', 'case',
- 'esac', 'coproc', 'select', 'function'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- -- Shell built-ins.
- 'break', 'cd', 'continue', 'eval', 'exec', 'exit', 'export', 'getopts', 'hash', 'pwd', 'readonly',
- 'return', 'shift', 'test', 'times', 'trap', 'umask', 'unset',
- -- Bash built-ins.
- 'alias', 'bind', 'builtin', 'caller', 'command', 'declare', 'echo', 'enable', 'help', 'let',
- 'local', 'logout', 'mapfile', 'printf', 'read', 'readarray', 'source', 'type', 'typeset',
- 'ulimit', 'unalias', --
- 'set', 'shopt', -- shell behavior
- 'dirs', 'popd', 'pushd', -- directory stack
- 'bg', 'fg', 'jobs', 'kill', 'wait', 'disown', 'suspend', -- job control
- 'fc', 'history' -- history
-})
-
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- -- Shell built-ins.
- 'CDPATH', 'HOME', 'IFS', 'MAIL', 'MAILPATH', 'OPTARG', 'OPTIND', 'PATH', 'PS1', 'PS2',
- -- Bash built-ins.
- 'BASH', 'BASHOPTS', 'BASHPID', 'BASH_ALIASES', 'BASH_ARGC', 'BASH_ARGV', 'BASH_ARGV0',
- 'BASH_CMDS', 'BASH_COMMAND', 'BASH_COMPAT', 'BASH_ENV', 'BASH_EXECUTION_STRING', 'BASH_LINENO',
- 'BASH_LOADABLES_PATH', 'BASH_REMATCH', 'BASH_SOURCE', 'BASH_SUBSHELL', 'BASH_VERSINFO',
- 'BASH_VERSION', 'BASH_XTRACEFD', 'CHILD_MAX', 'COLUMNS', 'COMP_CWORD', 'COMP_LINE', 'COMP_POINT',
- 'COMP_TYPE', 'COMP_KEY', 'COMP_WORDBREAKS', 'COMP_WORDS', 'COMP_REPLY', 'COPROC', 'DIRSTACK',
- 'EMACS', 'ENV', 'EPOCHREALTIME', 'EPOCHSECONDS', 'EUID', 'EXECIGNORE', 'FCEDIT', 'FIGNORE',
- 'FUNCNAME', 'FUNCNEST', 'GLOBIGNORE', 'GROUPS', 'histchars', 'HISTCMD', 'HISTCONTROL', 'HISTFILE',
- 'HISTFILESIZE', 'HISTIGNORE', 'HISTSIZE', 'HISTTIMEFORMAT', 'HOSTFILE', 'HOSTNAME', 'HOSTTYPE',
- 'IGNOREEOF', 'INPUTRC', 'INSIDE_EMACS', 'LANG', 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES',
- 'LC_NUMERIC', 'LC_TIME', 'LINENO', 'LINES', 'MACHTYPE', 'MAILCHECK', 'MAPFILE', 'OLDPWD',
- 'OPTERR', 'OSTYPE', 'PIPESTATUS', 'POSIXLY_CORRECT', 'PPID', 'PROMPT_COMMAND', 'PROMPT_DIRTRIM',
- 'PSO', 'PS3', 'PS4', 'PWD', 'RANDOM', 'READLINE_LINE', 'READLINE_MARK', 'READLINE_POINT', 'REPLY',
- 'SECONDS', 'SHELL', 'SHELLOPTS', 'SHLVL', 'SRANDOM', 'TIMEFORMAT', 'TMOUT', 'TMPDIR', 'UID',
- -- Job control.
- 'auto_resume'
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/batch.lua lexers/batch.lua
--- /home/matej/repos/tmp/scintillua/lexers/batch.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/batch.lua 2022-11-29 23:51:43.326328927 +0100
@@ -50,6 +50,4 @@
-- Fold points.
lex:add_fold_point(lexer.KEYWORD, 'setlocal', 'endlocal')
-lexer.property['scintillua.comment'] = 'REM '
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/bibtex.lua lexers/bibtex.lua
--- /home/matej/repos/tmp/scintillua/lexers/bibtex.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/bibtex.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,48 +1,46 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Bibtex LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('bibtex')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
-- Fields.
-lex:add_rule('field', lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN, true)))
+lex:add_rule('field', token('field', word_match{
+ 'author', 'title', 'journal', 'year', 'volume', 'number', 'pages', 'month', 'note', 'key',
+ 'publisher', 'editor', 'series', 'address', 'edition', 'howpublished', 'booktitle',
+ 'organization', 'chapter', 'school', 'institution', 'type', 'isbn', 'issn', 'affiliation',
+ 'issue', 'keyword', 'url'
+}))
+lex:add_style('field', lexer.styles.constant)
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local dq_str = lexer.range('"')
local br_str = lexer.range('{', '}', false, false, true)
-lex:add_rule('string', lex:tag(lexer.STRING, dq_str + br_str))
+lex:add_rule('string', token(lexer.STRING, dq_str + br_str))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S(',=')))
+lex:add_rule('operator', token(lexer.OPERATOR, S(',=')))
-- Embedded in Latex.
local latex = lexer.load('latex')
-- Embedded Bibtex.
-local entry = lex:tag(lexer.PREPROCESSOR, '@' * lex:word_match('entry', true))
-local bibtex_start_rule = entry * lex:get_rule('whitespace')^0 * lex:tag(lexer.OPERATOR, '{')
-local bibtex_end_rule = lex:tag(lexer.OPERATOR, '}')
-latex:embed(lex, bibtex_start_rule, bibtex_end_rule)
-
--- Word lists.
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- 'author', 'title', 'journal', 'year', 'volume', 'number', 'pages', 'month', 'note', 'key',
- 'publisher', 'editor', 'series', 'address', 'edition', 'howpublished', 'booktitle',
- 'organization', 'chapter', 'school', 'institution', 'type', 'isbn', 'issn', 'affiliation',
- 'issue', 'keyword', 'url'
-})
-
-lex:set_word_list('entry', {
- 'string', --
+local entry = token('entry', '@' * word_match({
'book', 'article', 'booklet', 'conference', 'inbook', 'incollection', 'inproceedings', 'manual',
'mastersthesis', 'lambda', 'misc', 'phdthesis', 'proceedings', 'techreport', 'unpublished'
-})
-
-lexer.property['scintillua.comment'] = '%'
+}, true))
+lex:add_style('entry', lexer.styles.preprocessor)
+local bibtex_start_rule = entry * ws^0 * token(lexer.OPERATOR, '{')
+local bibtex_end_rule = token(lexer.OPERATOR, '}')
+latex:embed(lex, bibtex_start_rule, bibtex_end_rule)
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/boo.lua lexers/boo.lua
--- /home/matej/repos/tmp/scintillua/lexers/boo.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/boo.lua 2022-11-29 23:51:43.326328927 +0100
@@ -46,7 +46,7 @@
local dq_str = lexer.range('"', true)
local tq_str = lexer.range('"""')
local string = token(lexer.STRING, tq_str + sq_str + dq_str)
-local regex_str = lexer.after_set('!%^&*([{-=+|:;,?<>~', lexer.range('/', true))
+local regex_str = #P('/') * lexer.last_char_includes('!%^&*([{-=+|:;,?<>~') * lexer.range('/', true)
local regex = token(lexer.REGEX, regex_str)
lex:add_rule('string', string + regex)
@@ -61,6 +61,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('!%^&*()[]{}-=+/|:;.,?<>~`')))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/caml.lua lexers/caml.lua
--- /home/matej/repos/tmp/scintillua/lexers/caml.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/caml.lua 2022-11-29 23:51:43.326328927 +0100
@@ -60,6 +60,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('=<>+-*/.,:;~!#%^&|?[](){}')))
-lexer.property['scintillua.comment'] = '(*|*)'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/clojure.lua lexers/clojure.lua
--- /home/matej/repos/tmp/scintillua/lexers/clojure.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/clojure.lua 2022-11-29 23:51:43.326328927 +0100
@@ -139,10 +139,9 @@
-- Fold points.
lex:add_fold_point(lexer.COMMENT, '#_(', ')')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines(';'))
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-lexer.property['scintillua.comment'] = ';'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/cmake.lua lexers/cmake.lua
--- /home/matej/repos/tmp/scintillua/lexers/cmake.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/cmake.lua 2022-11-29 23:51:43.326328927 +0100
@@ -127,7 +127,6 @@
lex:add_fold_point(lexer.FUNCTION, 'MACRO', 'ENDMACRO')
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/coffeescript.lua lexers/coffeescript.lua
--- /home/matej/repos/tmp/scintillua/lexers/coffeescript.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/coffeescript.lua 2022-11-29 23:51:43.326328927 +0100
@@ -2,16 +2,16 @@
-- CoffeeScript LPeg lexer.
local lexer = require('lexer')
-local word_match = lexer.word_match
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
local lex = lexer.new('coffeescript', {fold_by_indentation = true})
-- Whitespace.
-lex:add_rule('whitespace', lex:tag(lexer.WHITESPACE, lexer.space^1))
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, word_match{
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
'all', 'and', 'bind', 'break', 'by', 'case', 'catch', 'class', 'const', 'continue', 'default',
'delete', 'do', 'each', 'else', 'enum', 'export', 'extends', 'false', 'finally', 'for',
'function', 'if', 'import', 'in', 'instanceof', 'is', 'isnt', 'let', 'loop', 'native', 'new',
@@ -21,30 +21,29 @@
-- Fields: object properties and methods.
lex:add_rule('field',
- lex:tag(lexer.FUNCTION, '.' * (S('_$') + lexer.alpha) * (S('_$') + lexer.alnum)^0))
+ token(lexer.FUNCTION, '.' * (S('_$') + lexer.alpha) * (S('_$') + lexer.alnum)^0))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local sq_str = lexer.range("'")
local dq_str = lexer.range('"')
-local string = lex:tag(lexer.STRING, sq_str + dq_str)
-local regex_str = lexer.after_set('+-*%<>!=^&|?~:;,([{', lexer.range('/', true) * S('igm')^0)
-local regex = lex:tag(lexer.REGEX, regex_str)
+local string = token(lexer.STRING, sq_str + dq_str)
+local regex_str =
+ #P('/') * lexer.last_char_includes('+-*%<>!=^&|?~:;,([{') * lexer.range('/', true) * S('igm')^0
+local regex = token(lexer.REGEX, regex_str)
lex:add_rule('string', string + regex)
-- Comments.
local block_comment = lexer.range('###')
local line_comment = lexer.to_eol('#', true)
-lex:add_rule('comment', lex:tag(lexer.COMMENT, block_comment + line_comment))
+lex:add_rule('comment', token(lexer.COMMENT, block_comment + line_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;,.()[]{}')))
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;,.()[]{}')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/context.lua lexers/context.lua
--- /home/matej/repos/tmp/scintillua/lexers/context.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/context.lua 2022-11-29 23:51:43.326328927 +0100
@@ -42,6 +42,7 @@
lex:add_fold_point('environment', '\\start', '\\stop')
lex:add_fold_point('environment', '\\begin', '\\end')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('%'))
-- Embedded Lua.
local luatex = lexer.load('lua')
@@ -49,6 +50,4 @@
local luatex_end_rule = #P('\\stopluacode') * environment
lex:embed(luatex, luatex_start_rule, luatex_end_rule)
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/cpp.lua lexers/cpp.lua
--- /home/matej/repos/tmp/scintillua/lexers/cpp.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/cpp.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,64 +1,68 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- C++ LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
-
-local lex = lexer.new(...)
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
+
+local lex = lexer.new('cpp')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'asm', 'auto', 'break', 'case', 'catch', 'class', 'const', 'const_cast', 'continue', 'default',
+ 'delete', 'do', 'dynamic_cast', 'else', 'explicit', 'export', 'extern', 'false', 'for', 'friend',
+ 'goto', 'if', 'inline', 'mutable', 'namespace', 'new', 'operator', 'private', 'protected',
+ 'public', 'register', 'reinterpret_cast', 'return', 'sizeof', 'static', 'static_cast', 'switch',
+ 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'using', 'virtual',
+ 'volatile', 'while',
+ -- Operators.
+ 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq',
+ -- C++11.
+ 'alignas', 'alignof', 'constexpr', 'decltype', 'final', 'noexcept', 'override', 'static_assert',
+ 'thread_local'
+}))
-- Types.
-local basic_type = lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE))
-local stl_type = lex:tag(lexer.TYPE .. '.stl', 'std::' * lex:word_match(lexer.TYPE .. '.stl'))
-lex:add_rule('type', basic_type + stl_type * -P('::'))
-
--- Functions.
-local non_member = -(B('.') + B('->') + B('::'))
-local builtin_func = lex:tag(lexer.FUNCTION_BUILTIN,
- P('std::')^-1 * lex:word_match(lexer.FUNCTION_BUILTIN))
-local stl_func = lex:tag(lexer.FUNCTION_BUILTIN .. '.stl',
- 'std::' * lex:word_match(lexer.FUNCTION_BUILTIN .. '.stl'))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = (B('.') + B('->')) * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function',
- (non_member * (stl_func + builtin_func) + method + func) * #(lexer.space^0 * '('))
-
--- Constants.
-local const =
- lex:tag(lexer.CONSTANT_BUILTIN, P('std::')^-1 * lex:word_match(lexer.CONSTANT_BUILTIN))
-local stl_const = lex:tag(lexer.CONSTANT_BUILTIN .. '.stl',
- 'std::' * lex:word_match(lexer.CONSTANT_BUILTIN .. '.stl'))
-lex:add_rule('constants', stl_const + const)
+lex:add_rule('type', token(lexer.TYPE, word_match{
+ 'bool', 'char', 'double', 'enum', 'float', 'int', 'long', 'short', 'signed', 'struct', 'union',
+ 'unsigned', 'void', 'wchar_t',
+ -- C++11.
+ 'char16_t', 'char32_t', 'nullptr'
+}))
-- Strings.
-local sq_str = lexer.range("'", true)
-local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, ('u8' + S('LuU'))^-1 * (sq_str + dq_str)))
+local sq_str = P('L')^-1 * lexer.range("'", true)
+local dq_str = P('L')^-1 * lexer.range('"', true)
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
local line_comment = lexer.to_eol('//', true)
local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number_("'")))
+local dec = lexer.digit^1 * ("'" * lexer.digit^1)^0
+local hex = '0' * S('xX') * lexer.xdigit^1 * ("'" * lexer.xdigit^1)^0
+local bin = '0' * S('bB') * S('01')^1 * ("'" * S('01')^1)^0 * -lexer.xdigit
+local integer = S('+-')^-1 * (hex + bin + dec)
+lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Preprocessor.
-local include = lex:tag(lexer.PREPROCESSOR, '#' * S('\t ')^0 * 'include') *
- (lex:get_rule('whitespace') * lex:tag(lexer.STRING, lexer.range('<', '>', true)))^-1
-local preproc = lex:tag(lexer.PREPROCESSOR, '#' * S('\t ')^0 * lex:word_match(lexer.PREPROCESSOR))
+local include = token(lexer.PREPROCESSOR, '#' * S('\t ')^0 * 'include') *
+ (ws * token(lexer.STRING, lexer.range('<', '>', true)))^-1
+local preproc = token(lexer.PREPROCESSOR, '#' * S('\t ')^0 *
+ word_match('define elif else endif error if ifdef ifndef import line pragma undef using warning'))
lex:add_rule('preprocessor', include + preproc)
--- Attributes.
-lex:add_rule('attribute', lex:tag(lexer.ATTRIBUTE, '[[' * lex:word_match(lexer.ATTRIBUTE) * ']]'))
-
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;,.()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;,.()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.PREPROCESSOR, 'if', 'endif')
@@ -66,222 +70,6 @@
lex:add_fold_point(lexer.PREPROCESSOR, 'ifndef', 'endif')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'asm', 'auto', 'break', 'case', 'catch', 'class', 'const', 'const_cast', 'continue', 'default',
- 'delete', 'do', 'dynamic_cast', 'else', 'explicit', 'export', 'extern', 'false', 'for', 'friend',
- 'goto', 'if', 'inline', 'mutable', 'namespace', 'new', 'operator', 'private', 'protected',
- 'public', 'register', 'reinterpret_cast', 'return', 'sizeof', 'static', 'static_cast', 'switch',
- 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'using', 'virtual',
- 'volatile', 'while',
- -- Operators.
- 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq',
- -- C++11.
- 'alignas', 'alignof', 'constexpr', 'decltype', 'final', 'noexcept', 'nullptr', 'override',
- 'static_assert', 'thread_local', --
- 'consteval', 'constinit', 'co_await', 'co_return', 'co_yield', 'requires' -- C++20
-})
-
-lex:set_word_list(lexer.TYPE, {
- 'bool', 'char', 'double', 'enum', 'float', 'int', 'long', 'short', 'signed', 'struct', 'union',
- 'unsigned', 'void', 'wchar_t', --
- 'char16_t', 'char32_t', -- C++11
- 'char8_t', -- C++20
- -- <cstddef>
- 'size_t', 'ptrdiff_t', 'max_align_t', --
- 'byte', -- C++17
- -- <cstdint>
- 'int8_t', 'int16_t', 'int32_t', 'int64_t', 'int_fast8_t', 'int_fast16_t', 'int_fast32_t',
- 'int_fast64_t', 'int_least8_t', 'int_least16_t', 'int_least32_t', 'int_least64_t', 'intmax_t',
- 'intptr_t', 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'uint_fast8_t', 'uint_fast16_t',
- 'uint_fast32_t', 'uint_fast64_t', 'uint_least8_t', 'uint_least16_t', 'uint_least32_t',
- 'uint_least64_t', 'uintmax_t', 'uintptr_t'
-})
-
-lex:set_word_list(lexer.TYPE .. '.stl', {
- 'any', 'bad_any_cast', -- <any> C++17
- 'array', -- <array> C++11
- 'atomic', -- <atomic> C++11
- 'barrier', -- <barrier> C++20
- 'bitset', -- <bitset>
- -- <concepts> C++20
- 'same_as', 'derived_from', 'convertible_to', 'common_reference_with', 'common_with', 'integral',
- 'signed_integral', 'unsigned_integral', 'floating_point', 'assignable_from', 'swappable',
- 'swappable_with', 'destructible', 'constructible_from', 'default_initializable',
- 'move_constructible', 'copy_constructible', 'equality_comparable', 'equality_comparable_with',
- 'movable', 'copyable', 'semiregular', 'regular', 'invocable', 'regular_invocable', 'predicate',
- 'relation', 'equivalence_relation', 'strict_weak_order', --
- 'complex', -- <complex>
- 'deque', -- <deque>
- 'exception', 'bad_exception', -- <exception>
- 'forward_list', -- <forward_list> C++11
- 'function', 'hash', -- <functional> C++11
- -- <future> C++11
- 'promise', 'packaged_task', 'future', 'shared_future', 'launch', 'future_status', 'future_error',
- 'future_errc', --
- 'initializer_list', -- <initializer_list>
- 'istream', 'iostream', -- <istream>
- -- <iterator>
- 'reverse_iterator', 'back_insert_iterator', 'front_insert_iterator', 'insert_iterator',
- 'istream_iterator', 'ostream_iterator', 'istreambuf_iterator', 'ostreambuf_iterator', --
- 'move_iterator', -- C++11
- 'latch', -- <latch> C++20
- 'list', -- <list>
- -- <map>
- 'map', 'multimap', --
- 'unordered_set', 'unordered_map', 'unordered_multiset', 'unordered_multimap', -- C++11
- 'unique_ptr', 'shared_ptr', 'weak_ptr', -- <memory> C++11
- -- <mutex> C++11
- 'mutex', 'timed_mutex', 'recursive_mutex', 'recursive_timed_mutex', 'lock_guard', 'unique_lock', --
- 'scoped_lock', -- C++17
- 'optional', 'bad_optional_access', -- <optional> C++17
- 'ostream', -- <ostream>
- 'queue', 'priority_queue', -- <queue>
- -- <random> C++11
- 'linear_congruential_engine', 'mersenne_twister_engine', 'subtract_with_carry_engine',
- 'discard_block_engine', 'independent_bits_engine', 'shuffle_order_engine', 'random_device',
- 'uniform_int_distribution', 'uniform_real_distribution', 'bernoulli_distribution',
- 'binomial_distribution', 'negative_binomial_distribution', 'geometric_distribution',
- 'poisson_distribution', 'exponential_distribution', 'gamma_distribution', 'weibull_distribution',
- 'extreme_value_distribution', 'normal_distribution', 'lognormal_distribution',
- 'chi_squared_distribution', 'cauchy_distribution', 'fisher_f_distribution',
- 'student_t_distribution', 'discrete_distibution', 'piecewise_constant_distribution',
- 'piecewise_linear_distribution', 'seed_seq', --
- 'ratio', -- <ratio> C++11
- -- <regex> C++11
- 'regex', 'csub_match', 'ssub_match', 'cmatch', 'smatch', 'cregex_iterator', 'sregex_iterator',
- 'cregex_token_iterator', 'sregex_token_iterator', 'regex_error', 'regex_traits', --
- 'counting_semaphore', 'binary_semaphore', -- <semaphore> C++20
- 'set', 'multiset', -- <set>
- 'span', -- <span> C++20
- 'stringbuf', 'istringstream', 'ostringstream', 'stringstream', -- <stringstream>
- 'stack', -- <stack>
- -- <stdexcept>
- 'logic_error', 'invalid_argument', 'domain_error', 'length_error', 'out_of_range',
- 'runtime_error', 'range_error', 'overflow_error', 'underflow_error', --
- 'streambuf', -- <streambuf>
- -- <string>
- 'string', --
- 'u16string', 'u32string', -- C++11
- 'u8string', -- C++20
- -- <string_view> C++17
- 'string_view', 'u16string_view', 'u32string_view', --
- 'u8string_view', -- C++20
- 'syncbuf', 'osyncstream', -- <syncstream> C++20
- 'thread', -- <thread> C++11
- 'tuple', 'tuple_size', 'tuple_element', -- <tuple> C++11
- 'pair', -- <utility>
- 'variant', 'monostate', 'bad_variant_access', 'variant_size', 'variant_alternative', -- <variant> C++17
- 'vector' -- <vector>
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'assert', -- <cassert>
- -- <cctype>
- 'isalnum', 'isalpha', 'islower', 'isupper', 'isdigit', 'isxdigit', 'iscntrl', 'isgraph',
- 'isspace', 'isprint', 'ispunct', 'tolower', 'toupper', --
- 'isblank', -- C++11
- 'va_start', 'va_arg', 'va_end', -- <cstdarg>
- -- <cmath>
- 'abs', 'fmod', 'exp', 'log', 'log10', 'pow', 'sqrt', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
- 'atan2', 'sinh', 'cosh', 'tanh', 'ceil', 'floor', 'frexp', 'ldexp', 'modf',
- -- C++11.
- 'remainder', 'remquo', 'exp2', 'expm1', 'log2', 'log1p', 'cbrt', 'hypot', 'asinh', 'acosh',
- 'atanh', 'erf', 'erfc', 'tgamma', 'lgamma', 'trunc', 'round', 'nearbyint', 'rint', 'scalbn',
- 'ilogb', 'logb', 'nextafter', 'copysign', 'isfinite', 'isinf', 'isnan', 'isnormal', 'signbit',
- 'isgreater', 'isgreaterequal', 'isless', 'islessequal', 'islessgreater', 'isunordered', --
- -- C++17.
- 'assoc_laguerre', 'assoc_legendre', 'beta', 'comp_ellint_1', 'comp_ellint_2', 'comp_ellint_3',
- 'cyl_bessel_i', 'cyl_bessel_j', 'cyl_bessel_k', 'cyl_neumann', 'ellint_1', 'ellint_2', 'ellint_3',
- 'expint', 'lhermite', 'lgendre', 'laguerre', 'riemann_zeta', 'sph_bessel', 'sph_legendre',
- 'sph_neumann', --
- 'lerp', -- C++20
- -- <cstring>
- 'strcpy', 'strncpy', 'strcat', 'strncat', 'strxfrm', 'strlen', 'strcmp', 'strncmp', 'strcoll',
- 'strchr', 'strrchr', 'strspn', 'strcspn', 'strpbrk', 'strstr', 'strtok', 'memchr', 'memcmp',
- 'memset', 'memcpy', 'memmove', 'strerror'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN .. '.stl', {
- -- <algorithm>
- 'for_each', 'count', 'count_if', 'mismatch', 'find', 'find_if', 'find_end', 'find_first_of',
- 'adjacent_find', 'search', 'search_n', 'copy', 'copy_backward', 'fill', 'fill_n', 'transform',
- 'generate', 'generate_n', 'remove', 'remove_if', 'remove_copy', 'remove_copy_if', 'replace',
- 'replace_if', 'replace_copy', 'replace_copy_if', 'swap', 'swap_ranges', 'iter_swap', 'reverse',
- 'reverse_copy', 'rotate', 'rotate_copy', 'unique_copy', 'partition', 'stable_partition', 'sort',
- 'partial_sort', 'partial_sort_copy', 'stable_sort', 'nth_element', 'lower_bound', 'upper_bound',
- 'binary_search', 'equal_range', 'merge', 'inplace_merge', 'includes', 'set_difference',
- 'set_intersection', 'set_symmetric_difference', 'set_union', 'make_heap', 'push_heap', 'pop_heap',
- 'sort_heap', 'max', 'max_element', 'min', 'min_element', 'equal', 'lexicographical_compare',
- 'next_permutation', 'prev_permutation', --
- -- C++11.
- 'all_of', 'any_of', 'none_of', 'find_if_not', 'copy_if', 'copy_n', 'move', 'move_backward',
- 'shuffle', 'is_partitioned', 'partition_copy', 'partition_point', 'is_sorted', 'is_sorted_until',
- 'is_heap', 'is_heap_until', 'minmax', 'minmax_element', 'is_permutation', --
- 'for_each_n', 'random_shuffle', 'sample', 'clamp', -- C++17
- 'shift_left', 'shift_right', 'lexicographical_compare_three_way', -- C++20
- 'make_any', 'any_cast', -- <any> C++17
- -- <bit> C++20
- 'bit_cast', 'byteswap', 'has_single_bit', 'bit_ceil', 'bit_floor', 'bit_width', 'rotl', 'rotr',
- 'countl_zero', 'countl_one', 'countl_zero', 'countr_one', 'popcount', --
- 'from_chars', 'to_chars', -- <charconv> C++17
- -- <format> C++20
- 'format', 'format_to', 'format_to_n', 'formatted_size', 'vformat', 'vformat_to',
- 'visit_format_arg', 'make_format_args', --
- 'async', 'future_category', -- <future> C++11
- -- <iterator>
- 'front_inserter', 'back_inserter', 'inserter', --
- 'make_move_iterator', -- C++11
- 'make_reverse_iterator', -- C++14
- -- <memory>
- 'make_shared', 'allocate_shared', 'static_pointer_cast', 'dynamic_pointer_cast',
- 'const_pointer_cast', --
- 'make_unique', -- C++14
- 'reinterpret_pointer_cast', -- C++17
- 'try_lock', 'lock', 'call_once', -- <mutex> C++11
- -- <numeric>
- 'accumulate', 'inner_product', 'adjacent_difference', 'partial_sum', --
- 'iota', -- C++11
- 'reduce', 'transform_reduce', 'inclusive_scan', 'exclusive_scan', 'gcd', 'lcm', -- C++17
- 'midpoint', -- C++20
- 'make_optional', -- <optional> C++17
- 'generate_canonical', -- <random> C++11
- 'regex_match', 'regex_search', 'regex_replace', -- <regex> C++11
- 'as_bytes', 'as_writable_bytes', -- <span> C++20
- -- <tuple> C++11
- 'make_tuple', 'tie', 'forward_as_tuple', 'tuple_cat', --
- 'apply', 'make_from_tuple', -- C++17
- -- <utility>
- 'swap', 'make_pair', 'get', --
- 'forward', 'move', 'move_if_noexcept', 'declval', -- C++11
- 'exchange', -- C++14
- 'as_const', -- C++17
- -- C++20.
- 'cmp_equal', 'cmp_not_equal', 'cmp_less', 'cmp_greater', 'cmp_less_equal', 'cmp_greater_equal',
- 'in_range', --
- 'visit', 'holds_alternative', 'get_if' -- <variant> C++17
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN .. '.stl', {
- 'cin', 'cout', 'cerr', 'clog', -- <iostream>
- 'endl', 'ends', 'flush', -- <ostream>
- 'nullopt' -- <optional> C++17
-})
-
-lex:set_word_list(lexer.PREPROCESSOR, {
- 'define', 'defined', 'elif', 'else', 'endif', 'error', 'if', 'ifdef', 'ifndef', 'import', 'line',
- 'pragma', 'undef', 'using', 'warning', --
- 'export', 'include', 'module' -- C++20
-})
-
-lex:set_word_list(lexer.ATTRIBUTE, {
- 'carries_dependency', 'noreturn', -- C++11
- 'deprecated', -- C++14
- 'fallthrough', 'maybe_unused', 'nodiscard', -- C++17
- 'likely', 'no_unique_address', 'unlikely' -- C++20
-})
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/crystal.lua lexers/crystal.lua
--- /home/matej/repos/tmp/scintillua/lexers/crystal.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/crystal.lua 2022-11-29 23:51:43.330328988 +0100
@@ -49,13 +49,18 @@
end)
local string = token(lexer.STRING, (sq_str + dq_str + heredoc + cmd_str) * S('f')^-1)
-- TODO: regex_str fails with `obj.method /patt/` syntax.
-local regex_str = lexer.after_set('!%^&*([{-=+|:;,?<>~', lexer.range('/', true) * S('iomx')^0)
+local regex_str =
+ #P('/') * lexer.last_char_includes('!%^&*([{-=+|:;,?<>~') * lexer.range('/', true) * S('iomx')^0
local regex = token(lexer.REGEX, regex_str)
lex:add_rule('string', string + regex)
-- Numbers.
-local numeric_literal = '?' * (lexer.any - lexer.space) * -word_char -- TODO: meta, control, etc.
-lex:add_rule('number', token(lexer.NUMBER, lexer.number_('_') * S('ri')^-1 + numeric_literal))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0 * S('ri')^-1
+local bin = '0b' * S('01')^1 * ('_' * S('01')^1)^0
+local integer = S('+-')^-1 * (bin + lexer.hex_num + lexer.oct_num + dec)
+-- TODO: meta, control, etc. for numeric_literal.
+local numeric_literal = '?' * (lexer.any - lexer.space) * -word_char
+lex:add_rule('number', token(lexer.NUMBER, lexer.float * S('ri')^-1 + integer + numeric_literal))
-- Variables.
local global_var = '$' *
@@ -66,7 +71,7 @@
-- Symbols.
lex:add_rule('symbol', token('symbol', ':' * P(function(input, index)
- if input:sub(index - 2, index - 2) ~= ':' then return true end
+ if input:sub(index - 2, index - 2) ~= ':' then return index end
end) * (word_char^1 + sq_str + dq_str)))
lex:add_style('symbol', lexer.styles.constant)
@@ -92,7 +97,6 @@
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/csharp.lua lexers/csharp.lua
--- /home/matej/repos/tmp/scintillua/lexers/csharp.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/csharp.lua 2022-11-29 23:51:43.330328988 +0100
@@ -59,7 +59,6 @@
lex:add_fold_point(lexer.PREPROCESSOR, 'region', 'endregion')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/css.lua lexers/css.lua
--- /home/matej/repos/tmp/scintillua/lexers/css.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/css.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,78 +1,17 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- CSS LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {no_user_word_lists = true})
+local lex = lexer.new('css')
--- Tags.
-local sel_prefix = B(S('#.'))
-local sel_suffix = lexer.space^0 * S('!>+.,:[{')
-lex:add_rule('tag', -sel_prefix * lex:tag(lexer.TAG, lex:word_match(lexer.TAG) * #sel_suffix))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Properties.
-lex:add_rule('property', lex:tag('property', lex:word_match('property')) * #P(':'))
-
--- Values.
-lex:add_rule('value',
- -sel_prefix * lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match('value')) * -sel_suffix)
-
--- Functions.
-lex:add_rule('function', lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)))
-
--- Colors.
-local color_name = lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match('color'))
-local xdigit = lexer.xdigit
-local color_value = lex:tag(lexer.NUMBER,
- '#' * xdigit * xdigit * xdigit * (xdigit * xdigit * xdigit)^-1)
-lex:add_rule('color', color_name + color_value)
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.alpha * (lexer.alnum + S('_-'))^0))
-
--- Pseudo classes and pseudo elements.
-lex:add_rule('pseudoclass', ':' * lex:tag('pseudoclass', lex:word_match('pseudoclass')))
-lex:add_rule('pseudoelement', '::' * lex:tag('pseudoelement', lex:word_match('pseudoelement')))
-
--- Strings.
-local sq_str = lexer.range("'")
-local dq_str = lexer.range('"')
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
-
--- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.range('/*', '*/')))
-
--- Numbers.
-local unit = lex:word_match('unit') + '%'
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number * unit^-1))
-
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('~!#*>+=|.,:;()[]{}')))
-
--- At rule.
-lex:add_rule('at_rule', lex:tag(lexer.PREPROCESSOR, '@' * lex:word_match('at_rule')))
-
--- Fold points.
-lex:add_fold_point(lexer.OPERATOR, '{', '}')
-lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
--- Word lists.
-lex:set_word_list(lexer.TAG, {
- 'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'blockquote', 'body',
- 'button', 'canvas', 'caption', 'cite', 'code', 'colgroup', 'content', 'data', 'datalist', 'dd',
- 'decorator', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'element', 'em', 'fieldset',
- 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header',
- 'html', 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'menu',
- 'menuitem', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p',
- 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'shadow',
- 'small', 'spacer', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td',
- 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'u', 'ul', 'var', 'video', --
- 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta',
- 'param', 'source', 'track', 'wbr'
-})
-
-lex:set_word_list('property', {
+lex:add_rule('property', token('property', word_match{
-- CSS 1.
'color', 'background-color', 'background-image', 'background-repeat', 'background-attachment',
'background-position', 'background', 'font-family', 'font-style', 'font-variant', 'font-weight',
@@ -103,9 +42,11 @@
'align-content', 'align-items', 'align-self', 'justify-content', 'order', 'border-radius',
'transition', 'transform', 'box-shadow', 'filter', 'opacity', 'resize', 'word-break', 'word-wrap',
'box-sizing', 'animation', 'text-overflow'
-})
+}))
+lex:add_style('property', lexer.styles.keyword)
-lex:set_word_list('value', {
+-- Values.
+lex:add_rule('value', token('value', word_match{
-- CSS 1.
'auto', 'none', 'normal', 'italic', 'oblique', 'small-caps', 'bold', 'bolder', 'lighter',
'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'larger', 'smaller',
@@ -141,9 +82,11 @@
'female', 'child', 'x-low', 'low', 'high', 'x-high', 'code', 'digits', 'continous',
-- CSS 3.
'flex', 'row', 'column', 'ellipsis', 'inline-block'
-})
+}))
+lex:add_style('value', lexer.styles.constant)
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Functions.
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
'attr', 'blackness', 'blend', 'blenda', 'blur', 'brightness', 'calc', 'circle', 'color-mod',
'contrast', 'counter', 'cubic-bezier', 'device-cmyk', 'drop-shadow', 'ellipse', 'gray',
'grayscale', 'hsl', 'hsla', 'hue', 'hue-rotate', 'hwb', 'image', 'inset', 'invert', 'lightness',
@@ -152,9 +95,11 @@
'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'saturate', 'saturation', 'scale', 'scale3d',
'scaleX', 'scaleY', 'scaleZ', 'sepia', 'shade', 'skewX', 'skewY', 'steps', 'tint', 'toggle',
'translate', 'translate3d', 'translateX', 'translateY', 'translateZ', 'url', 'whiteness', 'var'
-})
+}))
-lex:set_word_list('color', {
+-- Colors.
+local xdigit = lexer.xdigit
+lex:add_rule('color', token('color', word_match{
'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black',
'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan',
@@ -176,24 +121,48 @@
'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray', 'slategrey',
'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'transparent',
'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen'
-})
+} + '#' * xdigit * xdigit * xdigit * (xdigit * xdigit * xdigit)^-1))
+lex:add_style('color', lexer.styles.number)
-lex:set_word_list('pseudoclass', {
+-- Identifiers.
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.alpha * (lexer.alnum + S('_-'))^0))
+
+-- Pseudo classes and pseudo elements.
+lex:add_rule('pseudoclass', ':' * token('pseudoclass', word_match{
'active', 'checked', 'disabled', 'empty', 'enabled', 'first-child', 'first-of-type', 'focus',
'hover', 'in-range', 'invalid', 'lang', 'last-child', 'last-of-type', 'link', 'not', 'nth-child',
'nth-last-child', 'nth-last-of-type', 'nth-of-type', 'only-of-type', 'only-child', 'optional',
'out-of-range', 'read-only', 'read-write', 'required', 'root', 'target', 'valid', 'visited'
-})
+}))
+lex:add_style('pseudoclass', lexer.styles.constant)
+lex:add_rule('pseudoelement', '::' *
+ token('pseudoelement', word_match('after before first-letter first-line selection')))
+lex:add_style('pseudoelement', lexer.styles.constant)
-lex:set_word_list('pseudoelement', 'after before first-letter first-line selection')
+-- Strings.
+local sq_str = lexer.range("'")
+local dq_str = lexer.range('"')
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
+
+-- Comments.
+lex:add_rule('comment', token(lexer.COMMENT, lexer.range('/*', '*/')))
+
+-- Numbers.
+local unit = token('unit', word_match(
+ 'ch cm deg dpcm dpi dppx em ex grad Hz in kHz mm ms pc pt px q rad rem s turn vh vmax vmin vw'))
+lex:add_style('unit', lexer.styles.number)
+lex:add_rule('number', token(lexer.NUMBER, lexer.dec_num) * unit^-1)
-lex:set_word_list('unit', {
- 'ch', 'cm', 'deg', 'dpcm', 'dpi', 'dppx', 'em', 'ex', 'grad', 'Hz', 'in', 'kHz', 'mm', 'ms', 'pc',
- 'pt', 'px', 'q', 'rad', 'rem', 's', 'turn', 'vh', 'vmax', 'vmin', 'vw'
-})
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, S('~!#*>+=|.,:;()[]{}')))
-lex:set_word_list('at_rule', 'charset font-face media page import namespace keyframes')
+-- At rule.
+lex:add_rule('at_rule', token('at_rule', '@' *
+ word_match('charset font-face media page import namespace keyframes')))
+lex:add_style('at_rule', lexer.styles.preprocessor)
-lexer.property['scintillua.comment'] = '/*|*/'
+-- Fold points.
+lex:add_fold_point(lexer.OPERATOR, '{', '}')
+lex:add_fold_point(lexer.COMMENT, '/*', '*/')
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/cuda.lua lexers/cuda.lua
--- /home/matej/repos/tmp/scintillua/lexers/cuda.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/cuda.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,21 +1,29 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- CUDA LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {inherit = lexer.load('cpp')})
+local lex = lexer.new('cuda', {inherit = lexer.load('cpp')})
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, '__global__ __host__ __device__ __constant__ __shared__', true)
+-- Whitespace
+lex:modify_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-lex:set_word_list(lexer.TYPE, {
+-- Keywords.
+local keyword = token(lexer.KEYWORD,
+ word_match('__global__ __host__ __device__ __constant__ __shared__'))
+lex:modify_rule('keyword', keyword + lex:get_rule('keyword'))
+
+-- Types.
+lex:modify_rule('type', token(lexer.TYPE, word_match{
'uint', 'int1', 'uint1', 'int2', 'uint2', 'int3', 'uint3', 'int4', 'uint4', 'float1', 'float2',
'float3', 'float4', 'char1', 'char2', 'char3', 'char4', 'uchar1', 'uchar2', 'uchar3', 'uchar4',
'short1', 'short2', 'short3', 'short4', 'dim1', 'dim2', 'dim3', 'dim4'
-}, true)
+}) + lex:get_rule('type') +
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Functions.
+token(lexer.FUNCTION, word_match{
-- Atom.
'atomicAdd', 'atomicAnd', 'atomicCAS', 'atomicDec', 'atomicExch', 'atomicInc', 'atomicMax',
'atomicMin', 'atomicOr', 'atomicSub', 'atomicXor', --
@@ -53,10 +61,9 @@
'cudaMemcpyToSymbol', 'cudaMemset', 'cudaMemset2D', 'cudaMemset3D', 'cudaSetDevice',
'cudaSetupArgument', 'cudaStreamCreate', 'cudaStreamDestroy', 'cudaStreamQuery',
'cudaStreamSynchronize', 'cudaThreadExit', 'cudaThreadSynchronize', 'cudaUnbindTexture'
-}, true)
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, 'gridDim blockIdx blockDim threadIdx', true)
+}) +
-lexer.property['scintillua.comment'] = '//'
+-- Variables.
+token(lexer.VARIABLE, word_match('gridDim blockIdx blockDim threadIdx')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/dart.lua lexers/dart.lua
--- /home/matej/repos/tmp/scintillua/lexers/dart.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/dart.lua 2022-11-29 23:51:43.330328988 +0100
@@ -45,12 +45,12 @@
lex:add_rule('operator', token(lexer.OPERATOR, S('#?=!<>+-*$/%&|^~.,;()[]{}')))
-- Annotations.
-lex:add_rule('annotation', token(lexer.ANNOTATION, '@' * lexer.word^1))
+lex:add_rule('annotation', token('annotation', '@' * lexer.word^1))
+lex:add_style('annotation', lexer.styles.preprocessor)
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/desktop.lua lexers/desktop.lua
--- /home/matej/repos/tmp/scintillua/lexers/desktop.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/desktop.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,49 +1,53 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Desktop Entry LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('desktop')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keys.
-lex:add_rule('key', lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN)))
+lex:add_rule('key', token('key', word_match{
+ 'Type', 'Version', 'Name', 'GenericName', 'NoDisplay', 'Comment', 'Icon', 'Hidden', 'OnlyShowIn',
+ 'NotShowIn', 'TryExec', 'Exec', 'Exec', 'Path', 'Terminal', 'MimeType', 'Categories',
+ 'StartupNotify', 'StartupWMClass', 'URL'
+}))
+lex:add_style('key', lexer.styles.keyword)
-- Values.
-lex:add_rule('value', lex:tag(lexer.CONSTANT_BUILTIN, lexer.word_match('true false')))
+lex:add_rule('value', token('value', word_match('true false')))
+lex:add_style('value', lexer.styles.constant)
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.alpha * (lexer.alnum + S('_-'))^0))
+lex:add_rule('identifier', lexer.token(lexer.IDENTIFIER, lexer.alpha * (lexer.alnum + S('_-'))^0))
-- Group headers.
local bracketed = lexer.range('[', ']')
-lex:add_rule('header', lexer.starts_line(lex:tag(lexer.HEADING, bracketed)))
+lex:add_rule('header', lexer.starts_line(token('header', bracketed)))
+lex:add_style('header', lexer.styles.label)
-- Locales.
-lex:add_rule('locale', lex:tag(lexer.TYPE, bracketed))
+lex:add_rule('locale', token('locale', bracketed))
+lex:add_style('locale', lexer.styles.class)
-- Strings.
-lex:add_rule('string', lex:tag(lexer.STRING, lexer.range('"')))
+lex:add_rule('string', token(lexer.STRING, lexer.range('"')))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Field codes.
-lex:add_rule('code', lex:tag(lexer.CONSTANT_BUILTIN, '%' * S('fFuUdDnNickvm')))
+lex:add_rule('code', lexer.token('code', '%' * S('fFuUdDnNickvm')))
+lex:add_style('code', lexer.styles.variable)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('=')))
-
--- Word lists.
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- 'Type', 'Version', 'Name', 'GenericName', 'NoDisplay', 'Comment', 'Icon', 'Hidden', 'OnlyShowIn',
- 'NotShowIn', 'TryExec', 'Exec', 'Exec', 'Path', 'Terminal', 'MimeType', 'Categories',
- 'StartupNotify', 'StartupWMClass', 'URL'
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('operator', token(lexer.OPERATOR, S('=')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/diff.lua lexers/diff.lua
--- /home/matej/repos/tmp/scintillua/lexers/diff.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/diff.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,25 +1,29 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Diff LPeg lexer.
-local lexer = lexer
-local to_eol, starts_line = lexer.to_eol, lexer.starts_line
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {lex_by_line = true})
+local lex = lexer.new('diff', {lex_by_line = true})
--- Text, file headers, and separators.
-lex:add_rule('index', lex:tag(lexer.COMMENT, to_eol(starts_line('Index: '))))
-lex:add_rule('header', lex:tag(lexer.HEADING, to_eol(starts_line(P('*** ') + '--- ' + '+++ '))))
-lex:add_rule('separator', lex:tag(lexer.COMMENT, to_eol(starts_line(P('---') + '****' + '='))))
+-- Text, separators, and file headers.
+lex:add_rule('index', token(lexer.COMMENT, 'Index: ' * lexer.any^0 * -1))
+lex:add_rule('separator', token(lexer.COMMENT, ('---' + P('*')^4 + P('=')^1) * lexer.space^0 * -1))
+lex:add_rule('header', token('header', (P('*** ') + '--- ' + '+++ ') * lexer.any^1))
+lex:add_style('header', lexer.styles.comment)
-- Location.
-lex:add_rule('location', lex:tag(lexer.NUMBER, to_eol(starts_line('@@' + lexer.dec_num + '****'))))
+lex:add_rule('location', token(lexer.NUMBER, ('@@' + lexer.dec_num + '****') * lexer.any^1))
-- Additions, deletions, and changes.
-lex:add_rule('addition', lex:tag('addition', to_eol(starts_line(S('>+')))))
-lex:add_rule('deletion', lex:tag('deletion', to_eol(starts_line(S('<-')))))
-lex:add_rule('change', lex:tag('change', to_eol(starts_line('!'))))
+lex:add_rule('addition', token('addition', S('>+') * lexer.any^0))
+lex:add_style('addition', {fore = lexer.colors.green})
+lex:add_rule('deletion', token('deletion', S('<-') * lexer.any^0))
+lex:add_style('deletion', {fore = lexer.colors.red})
+lex:add_rule('change', token('change', '!' * lexer.any^0))
+lex:add_style('change', {fore = lexer.colors.yellow})
-lex:add_rule('any_line', lex:tag(lexer.DEFAULT, lexer.to_eol()))
+lex:add_rule('any_line', token(lexer.DEFAULT, lexer.any^1))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/django.lua lexers/django.lua
--- /home/matej/repos/tmp/scintillua/lexers/django.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/django.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,63 +1,55 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Django LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('django')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'as', 'block', 'blocktrans', 'by', 'endblock', 'endblocktrans', 'comment', 'endcomment', 'cycle',
+ 'date', 'debug', 'else', 'extends', 'filter', 'endfilter', 'firstof', 'for', 'endfor', 'if',
+ 'endif', 'ifchanged', 'endifchanged', 'ifnotequal', 'endifnotequal', 'in', 'load', 'not', 'now',
+ 'or', 'parsed', 'regroup', 'ssi', 'trans', 'with', 'widthratio'
+}))
-- Functions.
-lex:add_rule('function',
- lpeg.B('|') * lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)))
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
+ 'add', 'addslashes', 'capfirst', 'center', 'cut', 'date', 'default', 'dictsort',
+ 'dictsortreversed', 'divisibleby', 'escape', 'filesizeformat', 'first', 'fix_ampersands',
+ 'floatformat', 'get_digit', 'join', 'length', 'length_is', 'linebreaks', 'linebreaksbr',
+ 'linenumbers', 'ljust', 'lower', 'make_list', 'phone2numeric', 'pluralize', 'pprint', 'random',
+ 'removetags', 'rjust', 'slice', 'slugify', 'stringformat', 'striptags', 'time', 'timesince',
+ 'title', 'truncatewords', 'unordered_list', 'upper', 'urlencode', 'urlize', 'urlizetrunc',
+ 'wordcount', 'wordwrap', 'yesno'
+}))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
-lex:add_rule('string', lex:tag(lexer.STRING, lexer.range('"', false, false)))
+lex:add_rule('string', token(lexer.STRING, lexer.range('"', false, false)))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S(':,.|')))
+lex:add_rule('operator', token(lexer.OPERATOR, S(':,.|')))
-- Embed Django in HTML.
local html = lexer.load('html')
-html:add_rule('django_comment', lex:tag(lexer.COMMENT, lexer.range('{#', '#}', true)))
-local django_start_rule = lex:tag(lexer.PREPROCESSOR, '{' * S('{%'))
-local django_end_rule = lex:tag(lexer.PREPROCESSOR, S('%}') * '}')
+local html_comment = lexer.range('<!--', '-->')
+local django_comment = lexer.range('{#', '#}', true)
+html:modify_rule('comment', token(lexer.COMMENT, html_comment + django_comment))
+local django_start_rule = token('django_tag', '{' * S('{%'))
+local django_end_rule = token('django_tag', S('%}') * '}')
html:embed(lex, django_start_rule, django_end_rule)
+lex:add_style('django_tag', lexer.styles.embedded)
-- Fold points.
-lex:add_fold_point(lexer.PREPROCESSOR, '{{', '}}')
-lex:add_fold_point(lexer.PREPROCESSOR, '{%', '%}')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'autoescape', 'endautoescape', 'block', 'endblock', 'comment', 'endcomment', 'csrf_token',
- 'cycle', 'as', 'debug', 'extends', 'filter', 'endfilter', 'firstof', 'for', 'in', 'endfor',
- 'empty', 'if', 'elif', 'else', 'endif', 'and', 'or', 'not', 'is', 'ifchanged', 'endifchanged',
- 'include', 'load', 'lorem', 'now', 'regroup', 'resetcycle', 'spaceless', 'endspaceless',
- 'templatetag', 'url', 'verbatim', 'endverbatim', 'widthratio', 'with', 'endwith', --
- 'blocktranslate', 'endblocktranslate', 'translate', 'language', 'get_available_languages',
- 'get_current_language', 'get_current_language_bidi', 'get_language_info',
- 'get_language_info_list', --
- 'get_static_prefix', 'get_media_prefix'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'add', 'addslashes', 'capfirst', 'center', 'cut', 'date', 'default', 'default_if_none',
- 'dictsort', 'dictsortreversed', 'divisibleby', 'escape', 'escapejs', 'filesizeformat', 'first',
- 'floatformat', 'force_escape', 'get_digit', 'iriencode', 'join', 'json_script', 'last', 'length',
- 'length_is', 'linebreaks', 'linebreaksbr', 'linenumbers', 'ljust', 'lower', 'make_list',
- 'phone2numeric', 'pluralize', 'pprint', 'random', 'rjust', 'safe', 'safeseq', 'slice', 'slugify',
- 'stringformat', 'striptags', 'time', 'timesince', 'timeuntil', 'title', 'truncatechars_html',
- 'truncatewords', 'truncatewords_html', 'unordered_list', 'upper', 'urlencode', 'urlize',
- 'urlizetrunc', 'wordcount', 'wordwrap', 'yesno', --
- 'language_name', 'language_name_local', 'language_bidi', 'language_name_translated'
-})
-
-lexer.property['scintillua.comment'] = '{#|#}'
+lex:add_fold_point('django_tag', '{{', '}}')
+lex:add_fold_point('django_tag', '{%', '%}')
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/dmd.lua lexers/dmd.lua
--- /home/matej/repos/tmp/scintillua/lexers/dmd.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/dmd.lua 2022-11-29 23:51:43.330328988 +0100
@@ -2,47 +2,98 @@
-- D LPeg lexer.
-- Heavily modified by Brian Schott (@Hackerpilot on Github).
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('dmd')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Class names.
-local ws = lex:get_rule('whitespace')
lex:add_rule('class',
- lex:tag(lexer.TYPE, P('class') + 'struct') * ws^-1 * lex:tag(lexer.CLASS, lexer.word))
+ token(lexer.TYPE, P('class') + 'struct') * ws^-1 * token(lexer.CLASS, lexer.word))
-- Versions.
-local open_paren = lex:tag(lexer.OPERATOR, '(')
-lex:add_rule('version', lex:tag(lexer.KEYWORD, 'version') * ws^-1 * open_paren * ws^-1 *
- lex:tag(lexer.CONSTANT_BUILTIN .. '.version', lex:word_match('version')))
+local version = word_match{
+ 'AArch64', 'AIX', 'all', 'Alpha', 'Alpha_HardFloat', 'Alpha_SoftFloat', 'Android', 'ARM',
+ 'ARM_HardFloat', 'ARM_SoftFloat', 'ARM_SoftFP', 'ARM_Thumb', 'assert', 'BigEndian', 'BSD',
+ 'Cygwin', 'D_Coverage', 'D_Ddoc', 'D_HardFloat', 'DigitalMars', 'D_InlineAsm_X86',
+ 'D_InlineAsm_X86_64', 'D_LP64', 'D_NoBoundsChecks', 'D_PIC', 'DragonFlyBSD', 'D_SIMD',
+ 'D_SoftFloat', 'D_Version2', 'D_X32', 'FreeBSD', 'GNU', 'Haiku', 'HPPA', 'HPPA64', 'Hurd', 'IA64',
+ 'LDC', 'linux', 'LittleEndian', 'MIPS32', 'MIPS64', 'MIPS_EABI', 'MIPS_HardFloat', 'MIPS_N32',
+ 'MIPS_N64', 'MIPS_O32', 'MIPS_O64', 'MIPS_SoftFloat', 'NetBSD', 'none', 'OpenBSD', 'OSX', 'Posix',
+ 'PPC', 'PPC64', 'PPC_HardFloat', 'PPC_SoftFloat', 'S390', 'S390X', 'SDC', 'SH', 'SH64', 'SkyOS',
+ 'Solaris', 'SPARC', 'SPARC64', 'SPARC_HardFloat', 'SPARC_SoftFloat', 'SPARC_V8Plus', 'SysV3',
+ 'SysV4', 'unittest', 'Win32', 'Win64', 'Windows', 'X86', 'X86_64'
+}
+local open_paren = token(lexer.OPERATOR, '(')
+lex:add_rule('version', token(lexer.KEYWORD, 'version') * ws^-1 * open_paren * ws^-1 *
+ token('versions', version))
+lex:add_style('versions', lexer.styles.constant)
-- Scopes.
-lex:add_rule('scope', lex:tag(lexer.KEYWORD, 'scope') * ws^-1 * open_paren * ws^-1 *
- lex:tag(lexer.CONSTANT_BUILTIN .. '.scope', lexer.word_match('exit success failure')))
+local scope = word_match('exit success failure')
+lex:add_rule('scope',
+ token(lexer.KEYWORD, 'scope') * ws^-1 * open_paren * ws^-1 * token('scopes', scope))
+lex:add_style('scopes', lexer.styles.constant)
-- Traits.
-lex:add_rule('trait', lex:tag(lexer.KEYWORD, '__traits') * ws^-1 * open_paren * ws^-1 *
- lex:tag(lexer.VARIABLE_BUILTIN .. '.traits', lex:word_match('trait')))
+local trait = word_match{
+ 'allMembers', 'classInstanceSize', 'compiles', 'derivedMembers', 'getAttributes', 'getMember',
+ 'getOverloads', 'getProtection', 'getUnitTests', 'getVirtualFunctions', 'getVirtualIndex',
+ 'getVirtualMethods', 'hasMember', 'identifier', 'isAbstractClass', 'isAbstractFunction',
+ 'isArithmetic', 'isAssociativeArray', 'isFinalClass', 'isFinalFunction', 'isFloating',
+ 'isIntegral', 'isLazy', 'isNested', 'isOut', 'isOverrideFunction', 'isPOD', 'isRef', 'isSame',
+ 'isScalar', 'isStaticArray', 'isStaticFunction', 'isUnsigned', 'isVirtualFunction',
+ 'isVirtualMethod', 'parent'
+}
+lex:add_rule('trait',
+ token(lexer.KEYWORD, '__traits') * ws^-1 * open_paren * ws^-1 * token('traits', trait))
+lex:add_style('traits', {fore = lexer.colors.yellow})
-- Function names.
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = lpeg.B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (method + func) * #(ws^-1 * ('!' * lexer.word^-1 * ws^-1)^-1 * '('))
+lex:add_rule('function',
+ token(lexer.FUNCTION, lexer.word) * #(ws^-1 * ('!' * lexer.word^-1 * ws^-1)^-1 * '('))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'abstract', 'align', 'asm', 'assert', 'auto', 'body', 'break', 'case', 'cast', 'catch', 'const',
+ 'continue', 'debug', 'default', 'delete', 'deprecated', 'do', 'else', 'extern', 'export', 'false',
+ 'final', 'finally', 'for', 'foreach', 'foreach_reverse', 'goto', 'if', 'import', 'immutable',
+ 'in', 'inout', 'invariant', 'is', 'lazy', 'macro', 'mixin', 'new', 'nothrow', 'null', 'out',
+ 'override', 'pragma', 'private', 'protected', 'public', 'pure', 'ref', 'return', 'scope',
+ 'shared', 'static', 'super', 'switch', 'synchronized', 'this', 'throwtrue', 'try', 'typeid',
+ 'typeof', 'unittest', 'version', 'virtual', 'volatile', 'while', 'with', '__gshared', '__thread',
+ '__traits', '__vector', '__parameters'
+}))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
+local type = token(lexer.TYPE, word_match{
+ 'alias', 'bool', 'byte', 'cdouble', 'cent', 'cfloat', 'char', 'class', 'creal', 'dchar',
+ 'delegate', 'double', 'enum', 'float', 'function', 'idouble', 'ifloat', 'int', 'interface',
+ 'ireal', 'long', 'module', 'package', 'ptrdiff_t', 'real', 'short', 'size_t', 'struct',
+ 'template', 'typedef', 'ubyte', 'ucent', 'uint', 'ulong', 'union', 'ushort', 'void', 'wchar',
+ 'string', 'wstring', 'dstring', 'hash_t', 'equals_t'
+})
+lex:add_rule('type', type)
-- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
+lex:add_rule('constant', token(lexer.CONSTANT, word_match{
+ '__FILE__', '__LINE__', '__DATE__', '__EOF__', '__TIME__', '__TIMESTAMP__', '__VENDOR__',
+ '__VERSION__', '__FUNCTION__', '__PRETTY_FUNCTION__', '__MODULE__'
+}))
-- Properties.
-local dot = lex:tag(lexer.OPERATOR, '.')
-lex:add_rule('property', lpeg.B(lexer.alnum + ')') * dot *
- lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match('property')))
+local dot = token(lexer.OPERATOR, '.')
+lex:add_rule('property', lpeg.B(lexer.alnum + ')') * dot * token(lexer.VARIABLE, word_match{
+ 'alignof', 'dig', 'dup', 'epsilon', 'idup', 'im', 'init', 'infinity', 'keys', 'length',
+ 'mangleof', 'mant_dig', 'max', 'max_10_exp', 'max_exp', 'min', 'min_normal', 'min_10_exp',
+ 'min_exp', 'nan', 'offsetof', 'ptr', 're', 'rehash', 'reverse', 'sizeof', 'sort', 'stringof',
+ 'tupleof', 'values'
+}))
-- Strings.
local sq_str = lexer.range("'", true) * S('cwd')^-1
@@ -55,87 +106,37 @@
for left, right in pairs{['['] = ']', ['('] = ')', ['{'] = '}', ['<'] = '>'} do
str = str + lexer.range('q"' .. left, right .. '"', false, false, true) * S('cwd')^-1
end
-lex:add_rule('string', lex:tag(lexer.STRING, str))
+lex:add_rule('string', token(lexer.STRING, str))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
local line_comment = lexer.to_eol('//', true)
local block_comment = lexer.range('/*', '*/')
local nested_comment = lexer.range('/+', '+/', false, false, true)
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment + nested_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment + nested_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number_('_') * S('uULdDfFi')^-1))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local hex_num = lexer.hex_num * ('_' * lexer.xdigit^1)^0
+local bin_num = '0' * S('bB') * S('01_')^1 * -lexer.xdigit
+local oct_num = '0' * S('01234567_')^1
+local integer = S('+-')^-1 * (hex_num + oct_num + bin_num + dec)
+lex:add_rule('number', token(lexer.NUMBER, (lexer.float + integer) * S('uULdDfFi')^-1))
-- Preprocessor.
-lex:add_rule('annotation', lex:tag(lexer.ANNOTATION, '@' * lexer.word^1))
-lex:add_rule('preprocessor', lex:tag(lexer.PREPROCESSOR, lexer.to_eol('#')))
+lex:add_rule('annotation', token('annotation', '@' * lexer.word^1))
+lex:add_style('annotation', lexer.styles.preprocessor)
+lex:add_rule('preprocessor', token(lexer.PREPROCESSOR, lexer.to_eol('#')))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('?=!<>+-*$/%&|^~.,;:()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('?=!<>+-*$/%&|^~.,;:()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
lex:add_fold_point(lexer.COMMENT, '/+', '+/')
-
--- Word lists.
-lex:set_word_list('version', {
- 'AArch64', 'AIX', 'all', 'Alpha', 'Alpha_HardFloat', 'Alpha_SoftFloat', 'Android', 'ARM',
- 'ARM_HardFloat', 'ARM_SoftFloat', 'ARM_SoftFP', 'ARM_Thumb', 'assert', 'BigEndian', 'BSD',
- 'Cygwin', 'D_Coverage', 'D_Ddoc', 'D_HardFloat', 'DigitalMars', 'D_InlineAsm_X86',
- 'D_InlineAsm_X86_64', 'D_LP64', 'D_NoBoundsChecks', 'D_PIC', 'DragonFlyBSD', 'D_SIMD',
- 'D_SoftFloat', 'D_Version2', 'D_X32', 'FreeBSD', 'GNU', 'Haiku', 'HPPA', 'HPPA64', 'Hurd', 'IA64',
- 'LDC', 'linux', 'LittleEndian', 'MIPS32', 'MIPS64', 'MIPS_EABI', 'MIPS_HardFloat', 'MIPS_N32',
- 'MIPS_N64', 'MIPS_O32', 'MIPS_O64', 'MIPS_SoftFloat', 'NetBSD', 'none', 'OpenBSD', 'OSX', 'Posix',
- 'PPC', 'PPC64', 'PPC_HardFloat', 'PPC_SoftFloat', 'S390', 'S390X', 'SDC', 'SH', 'SH64', 'SkyOS',
- 'Solaris', 'SPARC', 'SPARC64', 'SPARC_HardFloat', 'SPARC_SoftFloat', 'SPARC_V8Plus', 'SysV3',
- 'SysV4', 'unittest', 'Win32', 'Win64', 'Windows', 'X86', 'X86_64'
-})
-
-lex:set_word_list('trait', {
- 'allMembers', 'classInstanceSize', 'compiles', 'derivedMembers', 'getAttributes', 'getMember',
- 'getOverloads', 'getProtection', 'getUnitTests', 'getVirtualFunctions', 'getVirtualIndex',
- 'getVirtualMethods', 'hasMember', 'identifier', 'isAbstractClass', 'isAbstractFunction',
- 'isArithmetic', 'isAssociativeArray', 'isFinalClass', 'isFinalFunction', 'isFloating',
- 'isIntegral', 'isLazy', 'isNested', 'isOut', 'isOverrideFunction', 'isPOD', 'isRef', 'isSame',
- 'isScalar', 'isStaticArray', 'isStaticFunction', 'isUnsigned', 'isVirtualFunction',
- 'isVirtualMethod', 'parent'
-})
-
-lex:set_word_list(lexer.KEYWORD, {
- 'abstract', 'align', 'asm', 'assert', 'auto', 'body', 'break', 'case', 'cast', 'catch', 'const',
- 'continue', 'debug', 'default', 'delete', 'deprecated', 'do', 'else', 'extern', 'export', 'false',
- 'final', 'finally', 'for', 'foreach', 'foreach_reverse', 'goto', 'if', 'import', 'immutable',
- 'in', 'inout', 'invariant', 'is', 'lazy', 'macro', 'mixin', 'new', 'nothrow', 'null', 'out',
- 'override', 'pragma', 'private', 'protected', 'public', 'pure', 'ref', 'return', 'scope',
- 'shared', 'static', 'super', 'switch', 'synchronized', 'this', 'throwtrue', 'try', 'typeid',
- 'typeof', 'unittest', 'version', 'virtual', 'volatile', 'while', 'with', '__gshared', '__thread',
- '__traits', '__vector', '__parameters'
-})
-
-lex:set_word_list(lexer.TYPE, {
- 'alias', 'bool', 'byte', 'cdouble', 'cent', 'cfloat', 'char', 'class', 'creal', 'dchar',
- 'delegate', 'double', 'enum', 'float', 'function', 'idouble', 'ifloat', 'int', 'interface',
- 'ireal', 'long', 'module', 'package', 'ptrdiff_t', 'real', 'short', 'size_t', 'struct',
- 'template', 'typedef', 'ubyte', 'ucent', 'uint', 'ulong', 'union', 'ushort', 'void', 'wchar',
- 'string', 'wstring', 'dstring', 'hash_t', 'equals_t'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- '__FILE__', '__LINE__', '__DATE__', '__EOF__', '__TIME__', '__TIMESTAMP__', '__VENDOR__',
- '__VERSION__', '__FUNCTION__', '__PRETTY_FUNCTION__', '__MODULE__'
-})
-
-lex:set_word_list('property', {
- 'alignof', 'dig', 'dup', 'epsilon', 'idup', 'im', 'init', 'infinity', 'keys', 'length',
- 'mangleof', 'mant_dig', 'max', 'max_10_exp', 'max_exp', 'min', 'min_normal', 'min_10_exp',
- 'min_exp', 'nan', 'offsetof', 'ptr', 're', 'rehash', 'reverse', 'sizeof', 'sort', 'stringof',
- 'tupleof', 'values'
-})
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/dockerfile.lua lexers/dockerfile.lua
--- /home/matej/repos/tmp/scintillua/lexers/dockerfile.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/dockerfile.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,47 +1,40 @@
-- Copyright 2016-2022 Alejandro Baez (https://keybase.io/baez). See LICENSE.
-- Dockerfile LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {fold_by_indentation = true})
+local lex = lexer.new('dockerfile', {fold_by_indentation = true})
+
+-- Whitespace
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-local keyword = lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD))
-lex:add_rule('keyword', keyword)
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'ADD', 'ARG', 'CMD', 'COPY', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'FROM', 'LABEL', 'MAINTAINER',
+ 'ONBUILD', 'RUN', 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'
+}))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Variable.
lex:add_rule('variable',
--B('\\') * lex:tag(lexer.OPERATOR, '$' * P('{')^-1) * lex:tag(lexer.VARIABLE, lexer.word))
+ token(lexer.VARIABLE, S('$')^1 * (P('{')^1 * lexer.word * P('}')^1 + lexer.word)))
-- Strings.
local sq_str = lexer.range("'", false, false)
local dq_str = lexer.range('"')
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('\\[],=:{}')))
-
-local bash = lexer.load('bash')
-local start_rule = #P('RUN') * keyword * bash:get_rule('whitespace')
-local end_rule = -B('\\') * #lexer.newline * lex:get_rule('whitespace')
-lex:embed(bash, start_rule, end_rule)
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'ADD', 'ARG', 'CMD', 'COPY', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'FROM', 'LABEL', 'MAINTAINER',
- 'ONBUILD', 'RUN', 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('operator', token(lexer.OPERATOR, S('\\[],=:{}')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/dot.lua lexers/dot.lua
--- /home/matej/repos/tmp/scintillua/lexers/dot.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/dot.lua 2022-11-29 23:51:43.330328988 +0100
@@ -51,7 +51,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/dsv.lua lexers/dsv.lua
--- /home/matej/repos/tmp/scintillua/lexers/dsv.lua 1970-01-01 01:00:00.000000000 +0100
+++ lexers/dsv.lua 2022-11-29 23:51:43.330328988 +0100
@@ -0,0 +1,12 @@
+-- Copyright 2016 Christian Hesse
+-- delimiter separated values LPeg lexer.
+
+local lexer = require('lexer')
+local token = lexer.token
+local S = lpeg.S
+
+local lex = lexer.new('dsv')
+
+lex:add_rule('operator', token(lexer.OPERATOR, S(',;:|')))
+
+return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/eiffel.lua lexers/eiffel.lua
--- /home/matej/repos/tmp/scintillua/lexers/eiffel.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/eiffel.lua 2022-11-29 23:51:43.330328988 +0100
@@ -53,7 +53,6 @@
lex:add_fold_point(lexer.KEYWORD, 'once', 'end')
lex:add_fold_point(lexer.KEYWORD, 'class',
function(text, pos, line, s) return line:find('deferred%s+class') and 0 or 1 end)
-
-lexer.property['scintillua.comment'] = '--'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('--'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/elixir.lua lexers/elixir.lua
--- /home/matej/repos/tmp/scintillua/lexers/elixir.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/elixir.lua 2022-11-29 23:51:43.330328988 +0100
@@ -94,6 +94,4 @@
lex:add_rule('number',
B(1 - (lexer.alpha + '_')) * S('+-')^-1 * token(lexer.NUMBER, float + integer))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/elm.lua lexers/elm.lua
--- /home/matej/repos/tmp/scintillua/lexers/elm.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/elm.lua 2022-11-29 23:51:43.330328988 +0100
@@ -40,6 +40,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, op))
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/erlang.lua lexers/erlang.lua
--- /home/matej/repos/tmp/scintillua/lexers/erlang.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/erlang.lua 2022-11-29 23:51:43.330328988 +0100
@@ -49,11 +49,12 @@
lex:add_rule('variable', token(lexer.VARIABLE, P('_')^0 * lexer.upper * ('_' + lexer.alnum)^0))
-- Directives.
-lex:add_rule('directive', token(lexer.PREPROCESSOR, '-' * word_match{
+lex:add_rule('directive', token('directive', '-' * word_match{
'author', 'behaviour', 'behavior', 'compile', 'copyright', 'define', 'doc', 'else', 'endif',
'export', 'file', 'ifdef', 'ifndef', 'import', 'include', 'include_lib', 'module', 'record',
'spec', 'type', 'undef'
}))
+lex:add_style('directive', lexer.styles.preprocessor)
-- Strings.
local sq_str = lexer.range("'", true)
@@ -84,7 +85,6 @@
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '%'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('%'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/fantom.lua lexers/fantom.lua
--- /home/matej/repos/tmp/scintillua/lexers/fantom.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/fantom.lua 2022-11-29 23:51:43.330328988 +0100
@@ -73,12 +73,12 @@
lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;.()[]{}#')))
-- Annotations.
-lex:add_rule('facet', token(lexer.ANNOTATION, '@' * lexer.word))
+lex:add_rule('facet', token('facet', '@' * lexer.word))
+lex:add_style('facet', lexer.styles.preprocessor)
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/faust.lua lexers/faust.lua
--- /home/matej/repos/tmp/scintillua/lexers/faust.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/faust.lua 2022-11-29 23:51:43.330328988 +0100
@@ -41,6 +41,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}@#$`\\\'')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/fennel.lua lexers/fennel.lua
--- /home/matej/repos/tmp/scintillua/lexers/fennel.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/fennel.lua 2022-11-29 23:51:43.330328988 +0100
@@ -36,10 +36,8 @@
lex:modify_rule('comment', token(lexer.COMMENT, lexer.to_eol(';')))
-- Ignore these rules.
--- lex:modify_rule('longstring', P(false))
+lex:modify_rule('longstring', P(false))
lex:modify_rule('label', P(false))
lex:modify_rule('operator', P(false))
-lexer.property['scintillua.comment'] = ';'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/fish.lua lexers/fish.lua
--- /home/matej/repos/tmp/scintillua/lexers/fish.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/fish.lua 2022-11-29 23:51:43.330328988 +0100
@@ -34,7 +34,8 @@
lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Shebang.
-lex:add_rule('shebang', token(lexer.COMMENT, lexer.to_eol('#!/')))
+lex:add_rule('shebang', token('shebang', lexer.to_eol('#!/')))
+lex:add_style('shebang', lexer.styles.label)
-- Comments.
lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
@@ -53,6 +54,4 @@
lex:add_fold_point(lexer.KEYWORD, 'switch', 'end')
lex:add_fold_point(lexer.KEYWORD, 'while', 'end')
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/forth.lua lexers/forth.lua
--- /home/matej/repos/tmp/scintillua/lexers/forth.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/forth.lua 2022-11-29 23:51:43.330328988 +0100
@@ -53,6 +53,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S(':;<>+*-/[]#')))
-lexer.property['scintillua.comment'] = '\\'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/fortran.lua lexers/fortran.lua
--- /home/matej/repos/tmp/scintillua/lexers/fortran.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/fortran.lua 2022-11-29 23:51:43.330328988 +0100
@@ -82,6 +82,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('<>=&+-/*,()')))
-lexer.property['scintillua.comment'] = '!'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/fsharp.lua lexers/fsharp.lua
--- /home/matej/repos/tmp/scintillua/lexers/fsharp.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/fsharp.lua 2022-11-29 23:51:43.330328988 +0100
@@ -54,6 +54,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('=<>+-*/^.,:;~!@#%^&|?[](){}')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/fstab.lua lexers/fstab.lua
--- /home/matej/repos/tmp/scintillua/lexers/fstab.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/fstab.lua 2022-11-29 23:51:43.330328988 +0100
@@ -106,7 +106,9 @@
-- Numbers.
local uuid = lexer.xdigit^8 * ('-' * lexer.xdigit^4)^-3 * '-' * lexer.xdigit^12
-local integer = S('+-')^-1 * (lexer.hex_num + lexer.oct_num_('_') + lexer.dec_num_('_'))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local oct_num = '0' * S('01234567_')^1
+local integer = S('+-')^-1 * (lexer.hex_num + oct_num + dec)
lex:add_rule('number', token(lexer.NUMBER, uuid + lexer.float + integer))
-- Identifiers.
@@ -121,6 +123,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('=,')))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gap.lua lexers/gap.lua
--- /home/matej/repos/tmp/scintillua/lexers/gap.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gap.lua 2022-11-29 23:51:43.330328988 +0100
@@ -39,7 +39,6 @@
lex:add_fold_point(lexer.KEYWORD, 'do', 'od')
lex:add_fold_point(lexer.KEYWORD, 'if', 'fi')
lex:add_fold_point(lexer.KEYWORD, 'repeat', 'until')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gemini.lua lexers/gemini.lua
--- /home/matej/repos/tmp/scintillua/lexers/gemini.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gemini.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,23 +1,42 @@
--- Copyright 2020-2022 Haelwenn (lanodan) Monnier <contact+gemini.lua@hacktivis.me>. See LICENSE.
+
+-- Copyright 2006-2017 Mitchell mitchell.att.foicica.com. See LICENSE.
+-- Markdown LPeg lexer.
+-- Copyright 2020 Haelwenn (lanodan) Monnier <contact+gemini.lua@hacktivis.me>
-- Gemini / Gemtext LPeg lexer.
-- See https://gemini.circumlunar.space/docs/specification.html
-local lexer = lexer
-local P, S = lpeg.P, lpeg.S
-
-local lex = lexer.new(...)
-
-local header = lex:tag(lexer.HEADING .. '.h3', lexer.to_eol(lexer.starts_line('###'))) +
- lex:tag(lexer.HEADING .. '.h2', lexer.to_eol(lexer.starts_line('##'))) +
- lex:tag(lexer.HEADING .. '.h1', lexer.to_eol(lexer.starts_line('#')))
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, R, S = lpeg.P, lpeg.R, lpeg.S
+
+local lex = lexer.new('gemini')
+
+local header = token('h3', lexer.starts_line('###') * lexer.nonnewline^0) +
+ token('h2', lexer.starts_line('##') * lexer.nonnewline^0) +
+ token('h1', lexer.starts_line('#') * lexer.nonnewline^0)
lex:add_rule('header', header)
-
-lex:add_rule('list', lex:tag(lexer.LIST, lexer.to_eol(lexer.starts_line('*'))))
-
-lex:add_rule('blockquote', lex:tag(lexer.STRING, lexer.to_eol(lexer.starts_line('>'))))
-
-lex:add_rule('pre', lex:tag(lexer.CODE, lexer.to_eol(lexer.range('```', false, true))))
-
-lex:add_rule('link', lex:tag(lexer.LINK, lexer.to_eol(lexer.starts_line('=>'))))
+lex:add_style('h1', {fore = lexer.colors.red, size = 15})
+lex:add_style('h2', {fore = lexer.colors.red, size = 14})
+lex:add_style('h3', {fore = lexer.colors.red, size = 13})
+
+local list = token('list', lexer.starts_line('*') * lexer.nonnewline^0)
+lex:add_rule('list', list)
+lex:add_style('list', lexer.styles.constant)
+
+local blockquote = token(lexer.STRING, lexer.starts_line('>') * lexer.nonnewline^0)
+lex:add_rule('blockquote', blockquote)
+
+-- Should only match ``` at start of line
+local pre = token('pre', lexer.range('```', false, true))
+lex:add_rule('pre', pre)
+lex:add_style('pre', lexer.styles.embedded .. {eolfilled = true})
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, S(' \t')^1 + S('\v\r\n')^1)
+lex:add_rule('whitespace', ws)
+
+local link = token('link', lexer.starts_line('=>') * lexer.nonnewline^0)
+lex:add_rule('link', link)
+lex:add_style('link', {underlined=true})
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gettext.lua lexers/gettext.lua
--- /home/matej/repos/tmp/scintillua/lexers/gettext.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gettext.lua 2022-11-29 23:51:43.330328988 +0100
@@ -26,6 +26,4 @@
-- Comments.
lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#' * S(': .~'))))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gherkin.lua lexers/gherkin.lua
--- /home/matej/repos/tmp/scintillua/lexers/gherkin.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gherkin.lua 2022-11-29 23:51:43.330328988 +0100
@@ -26,14 +26,15 @@
-- lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Tags.
-lex:add_rule('tag', token(lexer.LABEL, '@' * lexer.word^0))
+lex:add_rule('tag', token('tag', '@' * lexer.word^0))
+lex:add_style('tag', lexer.styles.label)
-- Placeholders.
-lex:add_rule('placeholder', token(lexer.VARIABLE, lexer.range('<', '>', false, false, true)))
+lex:add_rule('placeholder', token('placeholder', lexer.range('<', '>', false, false, true)))
+lex:add_style('placeholder', lexer.styles.variable)
-- Examples.
-lex:add_rule('example', token(lexer.DEFAULT, lexer.to_eol('|')))
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('example', token('example', lexer.to_eol('|')))
+lex:add_style('example', lexer.styles.number)
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/git-rebase.lua lexers/git-rebase.lua
--- /home/matej/repos/tmp/scintillua/lexers/git-rebase.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/git-rebase.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,28 +1,20 @@
--- Copyright 2017-2022 Marc André Tanner. See LICENSE.
+-- Copyright 2017-2021 Marc André Tanner
-- git-rebase(1) LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, R = lpeg.P, lpeg.R
-local lex = lexer.new(..., {lex_by_line = true})
+local lex = lexer.new('git-rebase', {lex_by_line = true})
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol(lexer.starts_line('#'))))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.starts_line('#') * lexer.nonnewline^0))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lexer.starts_line(lex:word_match(lexer.KEYWORD))))
-
--- Commit SHA1.
-local function patn(pat, min, max)
- return -pat^(max + 1) * pat^min
-end
-
-lex:add_rule('commit', lex:tag(lexer.NUMBER, patn(R('09', 'af'), 7, 40)))
-
-lex:add_rule('message', lex:tag('message', lexer.to_eol()))
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, [[
+local keywords = lexer.starts_line(word_match[[
p pick
r reword
e edit
@@ -35,5 +27,15 @@
t reset
m merge
]])
+lex:add_rule('keyword', token(lexer.KEYWORD, keywords))
+
+-- Commit SHA1.
+local function patn(pat, min, max)
+ return -pat^(max + 1) * pat^min
+end
+
+lex:add_rule('commit', token(lexer.NUMBER, patn(R('09', 'af'), 7, 40)))
+
+lex:add_rule('message', token(lexer.STRING, lexer.nonnewline^1))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gleam.lua lexers/gleam.lua
--- /home/matej/repos/tmp/scintillua/lexers/gleam.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gleam.lua 2022-11-29 23:51:43.330328988 +0100
@@ -88,16 +88,17 @@
lex:add_rule('error', err_tok)
-- Fold points.
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '(', ')')
-- Embedded Bit Strings.
-- Mimic lexer.load() by creating a bitstring-specific whitespace style.
-local bitstring = lexer.new(lex._name .. '_bitstring')
-local bitstring_ws = token(bitstring._name .. '_whitespace', lexer.space^1)
+local bitstring = lexer.new(lex._NAME .. '_bitstring')
+local bitstring_ws = token(bitstring._NAME .. '_whitespace', lexer.space^1)
bitstring:add_rule('whitespace', bitstring_ws)
-bitstring:add_style(bitstring._name .. '_whitespace', lexer.styles.whitespace)
+bitstring:add_style(bitstring._NAME .. '_whitespace', lexer.styles.whitespace)
bitstring:add_rule('type', typ_tok)
bitstring:add_rule('module', mod_tok(bitstring_ws))
bitstring:add_rule('keyword', key_tok + token(KEY, word_match{
@@ -115,6 +116,4 @@
bitstring:add_rule('error', err_tok)
lex:embed(bitstring, token(OP, '<<'), token(OP, '>>'))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/glsl.lua lexers/glsl.lua
--- /home/matej/repos/tmp/scintillua/lexers/glsl.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/glsl.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,49 +1,39 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- GLSL LPeg lexer.
-local lexer = lexer
-local P, S = lpeg.P, lpeg.S
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S, R = lpeg.P, lpeg.S, lpeg.R
+
+local lex = lexer.new('glsl', {inherit = lexer.load('cpp')})
+
+-- Whitespace.
+lex:modify_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
+
+-- Keywords.
+lex:modify_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'attribute', 'const', 'in', 'inout', 'out', 'uniform', 'varying', 'invariant', 'centroid', 'flat',
+ 'smooth', 'noperspective', 'layout', 'patch', 'sample', 'subroutine', 'lowp', 'mediump', 'highp',
+ 'precision',
+ -- Macros.
+ '__VERSION__', '__LINE__', '__FILE__'
+}) + lex:get_rule('keyword'))
+
+-- Types.
+-- LuaFormatter off
+lex:modify_rule('type', token(lexer.TYPE,
+ S('bdiu')^-1 * 'vec' * R('24') +
+ P('d')^-1 * 'mat' * R('24') * ('x' * R('24')^-1) +
+ S('iu')^-1 * 'sampler' * R('13') * 'D' +
+ 'sampler' * R('12') * 'D' * P('Array')^-1 * 'Shadow' +
+ (S('iu')^-1 * 'sampler' * (R('12') * 'DArray' +
+ word_match('Cube 2DRect Buffer 2DMS 2DMSArray 2DMSCubeArray'))) +
+ word_match('samplerCubeShadow sampler2DRectShadow samplerCubeArrayShadow')) +
+-- LuaFormatter on
+ lex:get_rule('type') +
-local lex = lexer.new(..., {inherit = lexer.load('ansi_c')})
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'attribute', 'const', 'uniform', 'varying', 'buffer', 'shared', 'coherent', 'volatile',
- 'restrict', 'readonly', 'writeonly', 'layout', 'centroid', 'flat', 'smooth', 'noperspective',
- 'patch', 'sample', 'break', 'continue', 'do', 'for', 'while', 'switch', 'case', 'default', 'if',
- 'else', 'subroutine', 'in', 'inout', 'out', 'true', 'false', 'invariant', 'precise', 'discard',
- 'return', 'lowp', 'mediump', 'highp', 'precision', 'struct', --
- -- Reserved.
- 'common', 'partition', 'active', 'asm', 'class', 'union', 'enum', 'typedef', 'template', 'this',
- 'resource', 'goto', 'inline', 'noinline', 'public', 'static', 'extern', 'external', 'interface',
- 'superp', 'input', 'output', 'filter', 'sizeof', 'cast', 'namespace', 'using'
-})
-
-lex:set_word_list(lexer.TYPE, {
- 'atomic_uint', 'float', 'double', 'int', 'void', 'bool', 'mat2', 'mat3', 'mat4', 'dmat2', 'dmat3',
- 'dmat4', 'mat2x2', 'mat2x3', 'mat2x4', 'dmat2x2', 'dmat2x3', 'dmat2x4', 'mat3x2', 'mat3x3',
- 'mat3x4', 'dmat3x2', 'dmat3x3', 'dmat3x4', 'mat4x2', 'mat4x3', 'mat4x4', 'dmat4x2', 'dmat4x3',
- 'dmat4x4', 'vec2', 'vec3', 'vec4', 'ivec2', 'ivec3', 'ivec4', 'bvec2', 'bvec3', 'bvec4', 'dvec2',
- 'dvec3', 'dvec4', 'uint', 'uvec2', 'uvec3', 'uvec4', 'sampler1D', 'sampler2D', 'sampler3D',
- 'samplerCube', 'sampler1DShadow', 'sampler2DShadow', 'samplerCubeShadow', 'sampler1DArray',
- 'sampler2DArray', 'sampler1DArrayShadow', 'sampler2DArrayShadow', 'isampler1D', 'isampler2D',
- 'isampler3D', 'isamplerCube', 'isampler1DArray', 'isampler2DArray', 'usampler1D', 'usampler2D',
- 'usampler3D', 'usamplerCube', 'usampler1DArray', 'usampler2DArray', 'sampler2DRect',
- 'sampler2DRectShadow', 'isampler2DRect', 'usampler2DRect', 'samplerBuffer', 'isamplerBuffer',
- 'usamplerBuffer', 'sampler2DMS', 'isampler2DMS', 'usampler2DMS', 'sampler2DMSArray',
- 'isampler2DMSArray', 'usampler2DMSArray', 'samplerCubeArray', 'samplerCubeArrayShadow',
- 'isamplerCubeArray', 'usamplerCubeArray', 'image1D', 'iimage1D', 'uimage1D', 'image2D',
- 'iimage2D', 'uimage2D', 'image3D', 'iimage3D', 'uimage3D', 'image2DRect', 'iimage2DRect',
- 'uimage2DRect', 'imageCube', 'iimageCube', 'uimageCube', 'imageBuffer', 'iimageBuffer',
- 'uimageBuffer', 'image1DArray', 'iimage1DArray', 'uimage1DArray', 'image2DArray', 'iimage2DArray',
- 'uimage2DArray', 'imageCubeArray', 'iimageCubeArray', 'uimageCubeArray', 'image2DMS',
- 'iimage2DMS', 'uimage2DMS', 'image2DMSArray', 'iimage2DMSArray', 'uimage2DMSArray',
- -- Reserved.
- 'long', 'short', 'half', 'fixed', 'unsigned', 'hvec2', 'hvec3', 'hvec4', 'fvec2', 'fvec3',
- 'fvec4', 'sampler3DRect'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Functions.
+token(lexer.FUNCTION, word_match{
'radians', 'degrees', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',
'asinh', 'acosh', 'atanh', 'pow', 'exp', 'log', 'exp2', 'log2', 'sqrt', 'inversesqrt', 'abs',
'sign', 'floor', 'trunc', 'round', 'roundEven', 'ceil', 'fract', 'mod', 'modf', 'min', 'max',
@@ -66,9 +56,10 @@
'interpolateAtCentroid', 'interpolateAtSample', 'interpolateAtOffset', 'noise1', 'noise2',
'noise3', 'noise4', 'EmitStreamVertex', 'EndStreamPrimitive', 'EmitVertex', 'EndPrimitive',
'barrier'
-})
+}) +
-lex:set_word_list(lexer.VARIABLE, {
+-- Variables.
+token(lexer.VARIABLE, word_match{
'gl_VertexID', 'gl_InstanceID', 'gl_Position', 'gl_PointSize', 'gl_ClipDistance',
'gl_PrimitiveIDIn', 'gl_InvocationID', 'gl_PrimitiveID', 'gl_Layer', 'gl_PatchVerticesIn',
'gl_TessLevelOuter', 'gl_TessLevelInner', 'gl_TessCoord', 'gl_FragCoord', 'gl_FrontFacing',
@@ -78,10 +69,10 @@
'gl_SecondaryColor', 'gl_Normal', 'gl_Vertex', 'gl_MultiTexCoord0', 'gl_MultiTexCoord1',
'gl_MultiTexCoord2', 'gl_MultiTexCoord3', 'gl_MultiTexCoord4', 'gl_MultiTexCoord5',
'gl_MultiTexCoord6', 'gl_MultiTexCoord7', 'gl_FogCoord'
-})
+}) +
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- '__LINE__', '__FILE__', '__VERSION__', --
+-- Constants.
+token(lexer.CONSTANT, word_match{
'gl_MaxVertexAttribs', 'gl_MaxVertexUniformComponents', 'gl_MaxVaryingFloats',
'gl_MaxVaryingComponents', 'gl_MaxVertexOutputComponents', 'gl_MaxGeometryInputComponents',
'gl_MaxGeometryOutputComponents', 'gl_MaxFragmentInputComponents',
@@ -108,10 +99,6 @@
'gl_BackLightProduct', 'gl_TextureEnvColor', 'gl_EyePlaneS', 'gl_EyePlaneT', 'gl_EyePlaneR',
'gl_EyePlaneQ', 'gl_ObjectPlaneS', 'gl_ObjectPlaneT', 'gl_ObjectPlaneR', 'gl_ObjectPlaneQ',
'gl_Fog'
-})
-
-lex:set_word_list(lexer.PREPROCESSOR, 'extension version', true)
-
-lexer.property['scintillua.comment'] = '//'
+}))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gnuplot.lua lexers/gnuplot.lua
--- /home/matej/repos/tmp/scintillua/lexers/gnuplot.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gnuplot.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,55 +1,33 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Gnuplot LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('gnuplot')
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
--- Functions.
-lex:add_rule('function', lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)))
-
--- Variables.
-lex:add_rule('variable', lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN)))
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-
--- Strings.
-local sq_str = lexer.range("'")
-local dq_str = lexer.range('"')
-local br_str = lexer.range('[', ']', true) + lexer.range('{', '}', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str + br_str))
-
--- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
-
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('-+~!$*%=<>&|^?:;()')))
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
+-- Keywords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
'cd', 'call', 'clear', 'exit', 'fit', 'help', 'history', 'if', 'load', 'pause', 'plot', 'using',
'with', 'index', 'every', 'smooth', 'thru', 'print', 'pwd', 'quit', 'replot', 'reread', 'reset',
'save', 'set', 'show', 'unset', 'shell', 'splot', 'system', 'test', 'unset', 'update'
-})
+}))
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Functions.
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
'abs', 'acos', 'acosh', 'arg', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'besj0', 'besj1',
'besy0', 'besy1', 'ceil', 'cos', 'cosh', 'erf', 'erfc', 'exp', 'floor', 'gamma', 'ibeta',
'inverf', 'igamma', 'imag', 'invnorm', 'int', 'lambertw', 'lgamma', 'log', 'log10', 'norm',
'rand', 'real', 'sgn', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'column', 'defined', 'tm_hour',
'tm_mday', 'tm_min', 'tm_mon', 'tm_sec', 'tm_wday', 'tm_yday', 'tm_year', 'valid'
-})
+}))
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
+-- Variables.
+lex:add_rule('variable', token(lexer.VARIABLE, word_match{
'angles', 'arrow', 'autoscale', 'bars', 'bmargin', 'border', 'boxwidth', 'clabel', 'clip',
'cntrparam', 'colorbox', 'contour', 'datafile', 'decimalsign', 'dgrid3d', 'dummy', 'encoding',
'fit', 'fontpath', 'format', 'functions', 'function', 'grid', 'hidden3d', 'historysize',
@@ -63,8 +41,21 @@
'y2mtics', 'y2range', 'y2tics', 'y2zeroaxis', 'ydata', 'ydtics', 'ylabel', 'ymtics', 'yrange',
'ytics', 'yzeroaxis', 'zdata', 'zdtics', 'cbdata', 'cbdtics', 'zero', 'zeroaxis', 'zlabel',
'zmtics', 'zrange', 'ztics', 'cblabel', 'cbmtics', 'cbrange', 'cbtics'
-})
+}))
+
+-- Identifiers.
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-lexer.property['scintillua.comment'] = '#'
+-- Strings.
+local sq_str = lexer.range("'")
+local dq_str = lexer.range('"')
+local br_str = lexer.range('[', ']', true) + lexer.range('{', '}', true)
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str + br_str))
+
+-- Comments.
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
+
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, S('-+~!$*%=<>&|^?:()')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/go.lua lexers/go.lua
--- /home/matej/repos/tmp/scintillua/lexers/go.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/go.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,71 +1,61 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Go LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('go')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'break', 'case', 'chan', 'const', 'continue', 'default', 'defer', 'else', 'fallthrough', 'for',
+ 'func', 'go', 'goto', 'if', 'import', 'interface', 'map', 'package', 'range', 'return', 'select',
+ 'struct', 'switch', 'type', 'var'
+}))
-- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
+lex:add_rule('constant', token(lexer.CONSTANT, word_match('true false iota nil')))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
+lex:add_rule('type', token(lexer.TYPE, word_match{
+ 'any', 'bool', 'byte', 'comparable', 'complex64', 'complex128', 'error', 'float32', 'float64',
+ 'int', 'int8', 'int16', 'int32', 'int64', 'rune', 'string', 'uint', 'uint8', 'uint16', 'uint32',
+ 'uint64', 'uintptr'
+}))
-- Functions.
-local builtin_func = -lpeg.B('.') *
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = lpeg.B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + method + func) * #(lexer.space^0 * '('))
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
+ 'append', 'cap', 'close', 'complex', 'copy', 'delete', 'imag', 'len', 'make', 'new', 'panic',
+ 'print', 'println', 'real', 'recover'
+}))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local sq_str = lexer.range("'", true)
local dq_str = lexer.range('"', true)
local raw_str = lexer.range('`', false, false)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str + raw_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str + raw_str))
-- Comments.
local line_comment = lexer.to_eol('//')
local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number * P('i')^-1))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number * P('i')^-1))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-*/%&|^<>=!~:;.,()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-*/%&|^<>=!~:;.,()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'break', 'case', 'chan', 'const', 'continue', 'default', 'defer', 'else', 'fallthrough', 'for',
- 'func', 'go', 'goto', 'if', 'import', 'interface', 'map', 'package', 'range', 'return', 'select',
- 'struct', 'switch', 'type', 'var'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, 'true false iota nil')
-
-lex:set_word_list(lexer.TYPE, {
- 'any', 'bool', 'byte', 'comparable', 'complex64', 'complex128', 'error', 'float32', 'float64',
- 'int', 'int8', 'int16', 'int32', 'int64', 'rune', 'string', 'uint', 'uint8', 'uint16', 'uint32',
- 'uint64', 'uintptr'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'append', 'cap', 'close', 'complex', 'copy', 'delete', 'imag', 'len', 'make', 'new', 'panic',
- 'print', 'println', 'real', 'recover'
-})
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/groovy.lua lexers/groovy.lua
--- /home/matej/repos/tmp/scintillua/lexers/groovy.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/groovy.lua 2022-11-29 23:51:43.330328988 +0100
@@ -49,7 +49,7 @@
local dq_str = lexer.range('"')
local tq_str = lexer.range("'''") + lexer.range('"""')
local string = token(lexer.STRING, tq_str + sq_str + dq_str)
-local regex_str = lexer.after_set('=~|!<>+-*?&,:;([{', lexer.range('/', true))
+local regex_str = #P('/') * lexer.last_char_includes('=~|!<>+-*?&,:;([{') * lexer.range('/', true)
local regex = token(lexer.REGEX, regex_str)
lex:add_rule('string', string + regex)
@@ -62,7 +62,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/gtkrc.lua lexers/gtkrc.lua
--- /home/matej/repos/tmp/scintillua/lexers/gtkrc.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/gtkrc.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,57 +1,52 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Gtkrc LPeg lexer.
-local lexer = lexer
-local word_match = lexer.word_match
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('gtkrc')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, word_match(
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match(
'binding class include module_path pixmap_path im_module_file style widget widget_class')))
-- Variables.
-lex:add_rule('variable', lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN)))
+lex:add_rule('variable', token(lexer.VARIABLE, word_match{
+ 'bg', 'fg', 'base', 'text', 'xthickness', 'ythickness', 'bg_pixmap', 'font', 'fontset',
+ 'font_name', 'stock', 'color', 'engine'
+}))
-- States.
-lex:add_rule('state', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
+lex:add_rule('state',
+ token('state', word_match('ACTIVE SELECTED NORMAL PRELIGHT INSENSITIVE TRUE FALSE')))
+lex:add_style('state', lexer.styles.constant)
-- Functions.
-lex:add_rule('function', lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)))
+lex:add_rule('function', token(lexer.FUNCTION, word_match('mix shade lighter darker')))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.alpha * (lexer.alnum + S('_-'))^0))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.alpha * (lexer.alnum + S('_-'))^0))
-- Strings.
local sq_str = lexer.range("'", true)
local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.digit^1 * ('.' * lexer.digit^1)^-1))
+lex:add_rule('number', token(lexer.NUMBER, lexer.digit^1 * ('.' * lexer.digit^1)^-1))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S(':=,*()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S(':=,*()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
--- Word lists.
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- 'bg', 'fg', 'base', 'text', 'xthickness', 'ythickness', 'bg_pixmap', 'font', 'fontset',
- 'font_name', 'stock', 'color', 'engine'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'ACTIVE', 'SELECTED', 'NORMAL', 'PRELIGHT', 'INSENSITIVE', 'TRUE', 'FALSE'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {'mix', 'shade', 'lighter', 'darker'})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/hare.lua lexers/hare.lua
--- /home/matej/repos/tmp/scintillua/lexers/hare.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/hare.lua 2022-11-29 23:51:43.330328988 +0100
@@ -49,12 +49,11 @@
lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%^!=&|?:;,.()[]{}<>')))
-- At rule.
-lex:add_rule('at_rule',
- token(lexer.ANNOTATION, '@' * word_match('noreturn offset init fini test symbol')))
+lex:add_rule('at_rule', token('at_rule', '@' * word_match('noreturn offset init fini test symbol')))
+lex:add_style('at_rule', lexer.styles.preprocessor)
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/haskell.lua lexers/haskell.lua
--- /home/matej/repos/tmp/scintillua/lexers/haskell.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/haskell.lua 2022-11-29 23:51:43.330328988 +0100
@@ -42,6 +42,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, op))
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/html.lua lexers/html.lua
--- /home/matej/repos/tmp/scintillua/lexers/html.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/html.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,63 +1,99 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- HTML LPeg lexer.
-local lexer = lexer
-local word_match = lexer.word_match
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {no_user_word_lists = true})
+local lex = lexer.new('html')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.range('<!--', '-->')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.range('<!--', '-->')))
-- Doctype.
-lex:add_rule('doctype',
- lex:tag(lexer.TAG .. '.doctype', lexer.range('<!' * word_match('doctype', true), '>')))
+lex:add_rule('doctype', token('doctype', lexer.range('<!' * word_match('doctype', true), '>')))
+lex:add_style('doctype', lexer.styles.comment)
--- Tags.
-local paired_tag = lex:tag(lexer.TAG, lex:word_match(lexer.TAG, true))
-local single_tag = lex:tag(lexer.TAG .. '.single', lex:word_match(lexer.TAG .. '.single', true))
-local known_tag = paired_tag + single_tag
-local unknown_tag = lex:tag(lexer.TAG .. '.unknown', (lexer.alnum + '-')^1)
-local tag = lex:tag(lexer.TAG .. '.chars', '<' * P('/')^-1) * (known_tag + unknown_tag) * -P(':')
-lex:add_rule('tag', tag)
+-- Elements.
+local single_element = token('single_element', '<' * P('/')^-1 * word_match(
+ {
+ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta',
+ 'param', 'source', 'track', 'wbr'
+ }, true))
+local paired_element = token('element', '<' * P('/')^-1 * word_match({
+ 'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'blockquote', 'body',
+ 'button', 'canvas', 'caption', 'cite', 'code', 'colgroup', 'content', 'data', 'datalist', 'dd',
+ 'decorator', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'element', 'em', 'fieldset',
+ 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header',
+ 'html', 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'menu',
+ 'menuitem', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p',
+ 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'shadow',
+ 'small', 'spacer', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td',
+ 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'u', 'ul', 'var', 'video'
+}, true))
+local known_element = single_element + paired_element
+local unknown_element = token('unknown_element', '<' * P('/')^-1 * (lexer.alnum + '-')^1)
+local element = (known_element + unknown_element) * -P(':')
+lex:add_rule('element', element)
+lex:add_style('single_element', lexer.styles.keyword)
+lex:add_style('element', lexer.styles.keyword)
+lex:add_style('unknown_element', lexer.styles.keyword .. {italics = true})
-- Closing tags.
-local tag_close = lex:tag(lexer.TAG .. '.chars', P('/')^-1 * '>')
+local tag_close = token('element', P('/')^-1 * '>')
lex:add_rule('tag_close', tag_close)
+-- Attributes.
+local known_attribute = token('attribute', word_match({
+ 'accept', 'accept-charset', 'accesskey', 'action', 'align', 'alt', 'async', 'autocomplete',
+ 'autofocus', 'autoplay', 'bgcolor', 'border', 'buffered', 'challenge', 'charset', 'checked',
+ 'cite', 'class', 'code', 'codebase', 'color', 'cols', 'colspan', 'content', 'contenteditable',
+ 'contextmenu', 'controls', 'coords', 'data', 'data-', 'datetime', 'default', 'defer', 'dir',
+ 'dirname', 'disabled', 'download', 'draggable', 'dropzone', 'enctype', 'for', 'form', 'headers',
+ 'height', 'hidden', 'high', 'href', 'hreflang', 'http-equiv', 'icon', 'id', 'ismap', 'itemprop',
+ 'keytype', 'kind', 'label', 'lang', 'language', 'list', 'loop', 'low', 'manifest', 'max',
+ 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'novalidate', 'open', 'optimum',
+ 'pattern', 'ping', 'placeholder', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel',
+ 'required', 'reversed', 'role', 'rows', 'rowspan', 'sandbox', 'scope', 'scoped', 'seamless',
+ 'selected', 'shape', 'size', 'sizes', 'span', 'spellcheck', 'src', 'srcdoc', 'srclang', 'start',
+ 'step', 'style', 'summary', 'tabindppex', 'target', 'title', 'type', 'usemap', 'value', 'width',
+ 'wrap'
+}, true) + ((P('data-') + 'aria-') * (lexer.alnum + '-')^1))
+local unknown_attribute = token('unknown_attribute', (lexer.alnum + '-')^1)
+local attribute = (known_attribute + unknown_attribute) * #(lexer.space^0 * '=')
+lex:add_rule('attribute', attribute)
+lex:add_style('attribute', lexer.styles.type)
+lex:add_style('unknown_attribute', lexer.styles.type .. {italics = true})
+
-- Equals.
-- TODO: performance is terrible on large files.
local in_tag = P(function(input, index)
local before = input:sub(1, index - 1)
local s, e = before:find('<[^>]-$'), before:find('>[^<]-$')
- if s and e then return s > e end
- if s then return true end
- return input:find('^[^<]->', index) ~= nil
+ if s and e then return s > e and index or nil end
+ if s then return index end
+ return input:find('^[^<]->', index) and index or nil
end)
-local equals = lex:tag(lexer.OPERATOR, '=') -- * in_tag
+local equals = token(lexer.OPERATOR, '=') -- * in_tag
-- lex:add_rule('equals', equals)
--- Attributes.
-local known_attribute = lex:tag(lexer.ATTRIBUTE, lex:word_match(lexer.ATTRIBUTE, true) +
- ((P('data-') + 'aria-') * (lexer.alnum + '-')^1))
-local unknown_attribute = lex:tag(lexer.ATTRIBUTE .. '.unknown', (lexer.alnum + '-')^1)
-local ws = lex:get_rule('whitespace')
-local attribute_eq = (known_attribute + unknown_attribute) * ws^-1 * equals
-lex:add_rule('attribute', attribute_eq)
-
-- Strings.
-local string = lex:tag(lexer.STRING, lexer.after_set('=', lexer.range("'") + lexer.range('"')))
+local string = #S('\'"') * lexer.last_char_includes('=') *
+ token(lexer.STRING, lexer.range("'") + lexer.range('"'))
lex:add_rule('string', string)
-- Numbers.
-local number = lex:tag(lexer.NUMBER, lexer.dec_num * P('%')^-1)
-lex:add_rule('number', lexer.after_set('=', number)) -- *in_tag)
+local number = token(lexer.NUMBER, lexer.dec_num * P('%')^-1)
+lex:add_rule('number', #lexer.digit * lexer.last_char_includes('=') * number) -- *in_tag)
-- Entities.
-lex:add_rule('entity', lex:tag(lexer.CONSTANT_BUILTIN .. '.entity',
- '&' * (lexer.any - lexer.space - ';')^1 * ';'))
+lex:add_rule('entity', token('entity', '&' * (lexer.any - lexer.space - ';')^1 * ';'))
+lex:add_style('entity', lexer.styles.comment)
-- Fold points.
local function disambiguate_lt(text, pos, line, s)
@@ -69,81 +105,44 @@
return 1
end
end
-lex:add_fold_point(lexer.TAG .. '.chars', '<', disambiguate_lt)
+lex:add_fold_point('element', '<', disambiguate_lt)
+lex:add_fold_point('unknown_element', '<', disambiguate_lt)
lex:add_fold_point(lexer.COMMENT, '<!--', '-->')
-- Tags that start embedded languages.
-- Export these patterns for proxy lexers (e.g. ASP) that need them.
-lex.embed_start_tag = tag * (ws * attribute_eq * ws^-1 * string)^0 * ws^-1 * tag_close
-lex.embed_end_tag = tag * tag_close
+lex.embed_start_tag = element * (ws * attribute * ws^-1 * equals * ws^-1 * string)^0 * ws^-1 *
+ tag_close
+lex.embed_end_tag = element * tag_close
-- Embedded CSS (<style type="text/css"> ... </style>).
local css = lexer.load('css')
-local style_tag = word_match('style', true)
-local css_start_rule = #('<' * style_tag * ('>' + P(function(input, index)
- if input:find('^%s+type%s*=%s*(["\'])text/css%1', index) then return true end
+local style_element = word_match('style', true)
+local css_start_rule = #('<' * style_element * ('>' + P(function(input, index)
+ if input:find('^%s+type%s*=%s*(["\'])text/css%1', index) then return index end
end))) * lex.embed_start_tag
-local css_end_rule = #('</' * style_tag * '>') * lex.embed_end_tag
+local css_end_rule = #('</' * style_element * ws^-1 * '>') * lex.embed_end_tag
lex:embed(css, css_start_rule, css_end_rule)
--- Embedded CSS in style="" attribute.
-local style = lexer.load('css', 'css.style')
-css_start_rule = #(P('style') * lexer.space^0 * '=') * attribute_eq * ws^-1 *
- lex:tag(lexer.STRING, '"')
-css_end_rule = lex:tag(lexer.STRING, '"')
-lex:embed(style, css_start_rule, css_end_rule) -- only double-quotes for now
-- Embedded JavaScript (<script type="text/javascript"> ... </script>).
local js = lexer.load('javascript')
-local script_tag = word_match('script', true)
-local js_start_rule = #('<' * script_tag * ('>' + P(function(input, index)
- if input:find('^%s+type%s*=%s*(["\'])text/javascript%1', index) then return true end
+local script_element = word_match('script', true)
+local js_start_rule = #('<' * script_element * ('>' + P(function(input, index)
+ if input:find('^%s+type%s*=%s*(["\'])text/javascript%1', index) then return index end
end))) * lex.embed_start_tag
-local js_end_rule = #('</' * script_tag * '>') * lex.embed_end_tag
+local js_end_rule = #('</' * script_element * ws^-1 * '>') * lex.embed_end_tag
+local js_line_comment = '//' * (lexer.nonnewline - js_end_rule)^0
+local js_block_comment = '/*' * (lexer.any - '*/' - js_end_rule)^0 * P('*/')^-1
+js:modify_rule('comment', token(lexer.COMMENT, js_line_comment + js_block_comment))
lex:embed(js, js_start_rule, js_end_rule)
-- Embedded CoffeeScript (<script type="text/coffeescript"> ... </script>).
local cs = lexer.load('coffeescript')
-script_tag = word_match('script', true)
-local cs_start_rule = #('<' * script_tag * P(function(input, index)
- if input:find('^[^>]+type%s*=%s*(["\'])text/coffeescript%1', index) then return true end
+script_element = word_match('script', true)
+local cs_start_rule = #('<' * script_element * P(function(input, index)
+ if input:find('^[^>]+type%s*=%s*(["\'])text/coffeescript%1', index) then return index end
end)) * lex.embed_start_tag
-local cs_end_rule = #('</' * script_tag * '>') * lex.embed_end_tag
+local cs_end_rule = #('</' * script_element * ws^-1 * '>') * lex.embed_end_tag
lex:embed(cs, cs_start_rule, cs_end_rule)
--- Word lists.
-lex:set_word_list(lexer.TAG .. '.single', {
- 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta',
- 'param', 'source', 'track', 'wbr'
-})
-
-lex:set_word_list(lexer.TAG, {
- 'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'blockquote', 'body',
- 'button', 'canvas', 'caption', 'cite', 'code', 'colgroup', 'content', 'data', 'datalist', 'dd',
- 'decorator', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'element', 'em', 'fieldset',
- 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header',
- 'html', 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'menu',
- 'menuitem', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p',
- 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'shadow',
- 'small', 'spacer', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td',
- 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'u', 'ul', 'var', 'video'
-})
-
-lex:set_word_list(lexer.ATTRIBUTE, {
- 'accept', 'accept-charset', 'accesskey', 'action', 'align', 'alt', 'async', 'autocomplete',
- 'autofocus', 'autoplay', 'bgcolor', 'border', 'buffered', 'challenge', 'charset', 'checked',
- 'cite', 'class', 'code', 'codebase', 'color', 'cols', 'colspan', 'content', 'contenteditable',
- 'contextmenu', 'controls', 'coords', 'data', 'data-', 'datetime', 'default', 'defer', 'dir',
- 'dirname', 'disabled', 'download', 'draggable', 'dropzone', 'enctype', 'for', 'form', 'headers',
- 'height', 'hidden', 'high', 'href', 'hreflang', 'http-equiv', 'icon', 'id', 'ismap', 'itemprop',
- 'keytype', 'kind', 'label', 'lang', 'language', 'list', 'loop', 'low', 'manifest', 'max',
- 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'novalidate', 'open', 'optimum',
- 'pattern', 'ping', 'placeholder', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel',
- 'required', 'reversed', 'role', 'rows', 'rowspan', 'sandbox', 'scope', 'scoped', 'seamless',
- 'selected', 'shape', 'size', 'sizes', 'span', 'spellcheck', 'src', 'srcdoc', 'srclang', 'start',
- 'step', 'style', 'summary', 'tabindex', 'target', 'title', 'type', 'usemap', 'value', 'width',
- 'wrap'
-})
-
-lexer.property['scintillua.comment'] = '<!--|-->'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/chuck.lua lexers/chuck.lua
--- /home/matej/repos/tmp/scintillua/lexers/chuck.lua 2022-11-30 11:15:03.673970821 +0100
+++ lexers/chuck.lua 2022-11-29 23:51:43.326328927 +0100
@@ -1,102 +1,68 @@
-- Copyright 2010-2022 Martin Morawetz. See LICENSE.
-- ChucK LPeg lexer.
-local lexer = lexer
-local word_match = lexer.word_match
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('chuck')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ -- Control structures.
+ 'break', 'continue', 'else', 'for', 'if', 'repeat', 'return', 'switch', 'until', 'while',
+ -- Other chuck keywords.
+ 'function', 'fun', 'spork', 'const', 'new'
+}))
-- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
+lex:add_rule('constant', token(lexer.CONSTANT, word_match{
+ -- Special values.
+ 'false', 'maybe', 'me', 'null', 'NULL', 'pi', 'true'
+}))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
+lex:add_rule('type', token(lexer.TYPE, word_match('float int time dur void same')))
-- Classes.
-lex:add_rule('class', lex:tag(lexer.CLASS, lex:word_match(lexer.CLASS)))
-
--- Functions.
-local std = 'Std.' * lex:word_match(lexer.FUNCTION_BUILTIN)
-local machine = 'Machine.' * lex:word_match(lexer.FUNCTION_BUILTIN .. '.machine')
-local math = 'Math.' * lex:word_match(lexer.FUNCTION_BUILTIN .. '.math')
-local func = lex:tag(lexer.FUNCTION, lexer.word) * #P('(')
-lex:add_rule('function', lex:tag(lexer.FUNCTION_BUILTIN, std + machine + math) + func)
-
--- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN,
- 'Math.' * lex:word_match(lexer.CONSTANT_BUILTIN .. '.math')))
+lex:add_rule('class', token(lexer.CLASS, word_match{
+ -- Class keywords.
+ 'class', 'extends', 'implements', 'interface', 'private', 'protected', 'public', 'pure', 'static',
+ 'super', 'this'
+}))
-- Global ugens.
-lex:add_rule('ugen', lex:tag(lexer.CONSTANT_BUILTIN .. '.ugen', word_match('dac adc blackhole')))
+lex:add_rule('ugen', token('ugen', word_match('dac adc blackhole')))
+lex:add_style('ugen', lexer.styles.constant)
-- Times.
-lex:add_rule('time', lex:tag(lexer.NUMBER, word_match('samp ms second minute hour day week')))
+lex:add_rule('time', token('time', word_match('samp ms second minute hour day week')))
+lex:add_style('time', lexer.styles.number)
-- Special special value.
-lex:add_rule('now', lex:tag(lexer.CONSTANT_BUILTIN .. '.now', word_match('now')))
+lex:add_rule('now', token('now', 'now'))
+lex:add_style('now', lexer.styles.constant .. {bold = true})
-- Strings.
local sq_str = P('L')^-1 * lexer.range("'", true)
local dq_str = P('L')^-1 * lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
local line_comment = lexer.to_eol('//', true)
local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;.()[]{}@')))
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- -- Control structures.
- 'break', 'continue', 'else', 'for', 'if', 'repeat', 'return', 'switch', 'until', 'while',
- -- Other chuck keywords.
- 'function', 'fun', 'spork', 'const', 'new'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'false', 'maybe', 'me', 'null', 'NULL', 'pi', 'true' -- special values
-})
-
-lex:set_word_list(lexer.TYPE, 'float int time dur void same')
-
--- Class keywords.
-lex:set_word_list(lexer.CLASS, {
- 'class', 'extends', 'implements', 'interface', 'private', 'protected', 'public', 'pure', 'static',
- 'super', 'this'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'abs', 'fabs', 'sgn', 'system', 'atoi', 'atof', 'getenv', 'setenv', 'mtof', 'ftom', 'powtodb',
- 'rmstodb', 'dbtopow', 'dbtorms'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN .. '.machine', {
- 'add', 'spork', 'remove', 'replace', 'status', 'crash'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN .. '.math', {
- 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'hypot', 'pow',
- 'sqrt', 'exp', 'log', 'log2', 'log10', 'random', 'random2', 'randomf', 'random2f', 'srandom',
- 'floor', 'ceil', 'round', 'trunc', 'fmod', 'remainder', 'min', 'max', 'nextpow2', 'isinf', 'isnan'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN .. '.math', {
- 'PI', 'TWO_PI', 'e', 'E', 'i', 'I', 'j', 'J', 'RANDOM_MAX'
-})
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;.()[]{}@')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/icon.lua lexers/icon.lua
--- /home/matej/repos/tmp/scintillua/lexers/icon.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/icon.lua 2022-11-29 23:51:43.330328988 +0100
@@ -55,7 +55,6 @@
lex:add_fold_point(lexer.PREPROCESSOR, 'ifdef', 'endif')
lex:add_fold_point(lexer.PREPROCESSOR, 'ifndef', 'endif')
lex:add_fold_point(lexer.KEYWORD, 'procedure', 'end')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/idl.lua lexers/idl.lua
--- /home/matej/repos/tmp/scintillua/lexers/idl.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/idl.lua 2022-11-29 23:51:43.330328988 +0100
@@ -47,6 +47,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('!<>=+-/*%&|^~.,:;?()[]{}')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/inform.lua lexers/inform.lua
--- /home/matej/repos/tmp/scintillua/lexers/inform.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/inform.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,5 +1,5 @@
-- Copyright 2010-2022 Jeff Stone. See LICENSE.
--- Inform 6 LPeg lexer for Scintillua.
+-- Inform LPeg lexer for Scintillua.
-- JMS 2010-04-25.
local lexer = require('lexer')
@@ -39,7 +39,7 @@
}))
-- Library actions.
-lex:add_rule('action', token(lexer.FUNCTION_BUILTIN, word_match{
+lex:add_rule('action', token('action', word_match{
'Answer', 'Ask', 'AskFor', 'Attack', 'Blow', 'Burn', 'Buy', 'Climb', 'Close', 'Consult', 'Cut',
'Dig', 'Disrobe', 'Drink', 'Drop', 'Eat', 'Empty', 'EmptyT', 'Enter', 'Examine', 'Exit', 'Fill',
'FullScore', 'GetOff', 'Give', 'Go', 'GoIn', 'Insert', 'Inv', 'InvTall', 'InvWide', 'Jump',
@@ -51,6 +51,7 @@
'Tell', 'Think', 'ThrowAt', 'ThrownAt', 'Tie', 'Touch', 'Transfer', 'Turn', 'Unlock', 'VagueGo',
'Verify', 'Version', 'Wait', 'Wake', 'WakeOther', 'Wave', 'WaveHands', 'Wear', 'Yes'
}))
+lex:add_style('action', lexer.styles.variable)
-- Identifiers.
lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
@@ -71,6 +72,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('@~=+-*/%^#=<>;:,.{}[]()&|?')))
-lexer.property['scintillua.comment'] = '!'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/ini.lua lexers/ini.lua
--- /home/matej/repos/tmp/scintillua/lexers/ini.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/ini.lua 2022-11-29 23:51:43.330328988 +0100
@@ -28,12 +28,12 @@
lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol(lexer.starts_line(S(';#')))))
-- Numbers.
-local integer = S('+-')^-1 * (lexer.hex_num + lexer.oct_num_('_') + lexer.dec_num_('_'))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local oct_num = '0' * S('01234567_')^1
+local integer = S('+-')^-1 * (lexer.hex_num + oct_num + dec)
lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, '='))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/io_lang.lua lexers/io_lang.lua
--- /home/matej/repos/tmp/scintillua/lexers/io_lang.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/io_lang.lua 2022-11-29 23:51:43.330328988 +0100
@@ -45,7 +45,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/java.lua lexers/java.lua
--- /home/matej/repos/tmp/scintillua/lexers/java.lua 2022-11-30 11:15:03.677970880 +0100
+++ lexers/java.lua 2022-11-29 23:51:43.330328988 +0100
@@ -3,140 +3,65 @@
-- Modified by Brian Schott.
local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('java')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Classes.
-lex:add_rule('classdef', lex:tag(lexer.KEYWORD, 'class') * lex:get_rule('whitespace') *
- lex:tag(lexer.CLASS, lexer.word))
+lex:add_rule('classdef', token(lexer.KEYWORD, 'class') * ws * token(lexer.CLASS, lexer.word))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
--- Functions.
-local builtin_func = lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = lpeg.B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + method + func) * #(lexer.space^0 * '('))
-
--- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN) +
- 'System.' * lexer.word_match('err in out')))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'abstract', 'assert', 'break', 'case', 'catch', 'class', 'const', 'continue', 'default', 'do',
+ 'else', 'enum', 'extends', 'final', 'finally', 'for', 'goto', 'if', 'implements', 'import',
+ 'instanceof', 'interface', 'native', 'new', 'package', 'private', 'protected', 'public', 'return',
+ 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient',
+ 'try', 'while', 'volatile',
+ -- Literals.
+ 'true', 'false', 'null'
+}))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
+lex:add_rule('type', token(lexer.TYPE, word_match{
+ 'boolean', 'byte', 'char', 'double', 'float', 'int', 'long', 'short', 'void', 'Boolean', 'Byte',
+ 'Character', 'Double', 'Float', 'Integer', 'Long', 'Short', 'String'
+}))
+
+-- Functions.
+lex:add_rule('function', token(lexer.FUNCTION, lexer.word) * #P('('))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local sq_str = lexer.range("'", true)
local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Comments.
local line_comment = lexer.to_eol('//', true)
local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number * S('LlFfDd')^-1))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number * S('LlFfDd')^-1))
-- Annotations.
-lex:add_rule('annotation', lex:tag(lexer.ANNOTATION, '@' * lexer.word))
+lex:add_rule('annotation', token('annotation', '@' * lexer.word))
+lex:add_style('annotation', lexer.styles.preprocessor)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;.()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;.()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'abstract', 'assert', 'break', 'case', 'catch', 'class', 'const', 'continue', 'default', 'do',
- 'else', 'enum', 'extends', 'final', 'finally', 'for', 'goto', 'if', 'implements', 'import',
- 'instanceof', 'interface', 'native', 'new', 'package', 'private', 'protected', 'public', 'return',
- 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient',
- 'try', 'while', 'volatile', --
- 'true', 'false', 'null' -- literals
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'clone', 'equals', 'finalize', 'getClass', 'hashCode', 'notify', 'notifyAll', 'toString', 'wait', --
- 'Boolean.compare', 'Boolean.getBoolean', 'Boolean.parseBoolean', 'Boolean.valueOf', --
- 'Byte.compare', 'Byte.decode', 'Byte.parseByte', 'Byte.valueOf', --
- 'Character.charCount', 'Character.codePointAt', 'Character.codePointBefore',
- 'Character.codePointCount', 'Character.compare', 'Character.digit', 'Character.forDigit',
- 'Character.getName', 'Character.getNumericValue', 'Character.getType', 'Character.isAlphabetic',
- 'Character.isDefined', 'Character.isDigit', 'Character.isIdentifierIgnorable',
- 'Character.isIdeographic', 'Character.isISOControl', 'Character.isJavaIdentifierPart',
- 'Character.isJavaIdentifierStart', 'Character.isLetter', 'Character.isLetterOrDigit',
- 'Character.isLowerCase', 'Character.isMirrored', 'Character.isSpaceChar',
- 'Character.isSupplementaryCodePoint', 'Character.isSurrogate', 'Character.isSurrogatePair',
- 'Character.isTitleCase', 'Character.isUnicodeIdentifierPart',
- 'Character.isUnicodeIdentifierStart', 'Character.isUpperCase', 'Character.isValidCodePoint',
- 'Character.isWhitespace', 'Character.offsetByCodePoints', 'Character.reverseBytes',
- 'Character.toChars', 'Character.toCodePoint', 'Character.toLowerCase', 'Character.toTitleCase',
- 'Character.toUpperCase', 'Character.valueOf', --
- 'Double.compare', 'Double.doubleToLongBits', 'Double.doubleToRawLongBits', 'Double.isInfinite',
- 'Double.longBitsToDouble', 'Double.parseDouble', 'Double.toHexString', 'Double.valueOf', --
- 'Integer.bitCount', 'Integer.compare', 'Integer.decode', 'Integer.getInteger',
- 'Integer.highestOneBit', 'Integer.lowestOneBit', 'Integer.numberOfLeadingZeros',
- 'Integer.numberOfTrailingZeros', 'Integer.parseInt', 'Integer.reverse', 'Integer.reverseBytes',
- 'Integer.rotateLeft', 'Integer.rotateRight', 'Integer.signum', 'Integer.toBinaryString',
- 'Integer.toHexString', 'Integer.toOctalString', 'Integer.valueOf', --
- 'Math.abs', 'Math.acos', 'Math.asin', 'Math.atan', 'Math.atan2', 'Math.cbrt', 'Math.ceil',
- 'Math.copySign', 'Math.cos', 'Math.cosh', 'Math.exp', 'Math.expm1', 'Math.floor',
- 'Math.getExponent', 'Math.hypot', 'Math.IEEEremainder', 'Math.log', 'Math.log10', 'Math.log1p',
- 'Math.max', 'Math.min', 'Math.nextAfter', 'Math.nextUp', 'Math.pow', 'Math.random', 'Math.rint',
- 'Math.round', 'Math.scalb', 'Math.signum', 'Math.sin', 'Math.sinh', 'Math.sqrt', 'Math.tan',
- 'Math.tanh', 'Math.toDegrees', 'Math.toRadians', 'Math.ulp', --
- 'Runtime.getRuntime', --
- 'String.copyValueOf', 'String.format', 'String.valueOf', --
- 'System.arraycopy', 'System.clearProperty', 'System.console', 'System.currentTimeMillis',
- 'System.exit', 'System.gc', 'System.getenv', 'System.getProperties', 'System.getProperty',
- 'System.getSecurityManager', 'System.identityHashCode', 'System.inheritedChannel',
- 'System.lineSeparator', 'System.load', 'System.loadLibrary', 'System.mapLibraryName',
- 'System.nanoTime', 'System.runFinalization', 'System.setErr', 'System.setIn', 'System.setOut',
- 'System.setProperties', 'System.setProperty', 'System.setSecurityManager', --
- 'Thread.activeCount', 'Thread.currentThread', 'Thread.dumpStack', 'Thread.enumerate',
- 'Thread.getAllStackTraces', 'Thread.getDefaultUncaughtExceptionHandler', 'Thread.holdsLock',
- 'Thread.interrupted', 'Thread.setDefaultUncaughtExceptionHandler', 'Thread.sleep', 'Thread.yield' --
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'Double.MAX_EXPONENT', 'Double.MAX_VALUE', 'Double.MIN_EXPONENT', 'Double.MIN_NORMAL',
- 'Double.MIN_VALUE', 'Double.NaN', 'Double.NEGATIVE_INFINITY', 'Double.POSITIVE_INFINITY', --
- 'Integer.MAX_VALUE', 'Integer.MIN_VALUE', --
- 'Math.E', 'Math.PI', --
- 'Thread.MAX_PRIORITY', 'Thread.MIN_PRIORITY', 'Thread.NORM_PRIORITY'
-})
-
-lex:set_word_list(lexer.TYPE, {
- 'boolean', 'byte', 'char', 'double', 'float', 'int', 'long', 'short', 'void', 'Boolean', 'Byte',
- 'Character', 'Class', 'Double', 'Enum', 'Float', 'Integer', 'Long', 'Object', 'Process',
- 'Runtime', 'Short', 'String', 'StringBuffer', 'StringBuilder', 'Thread', 'Throwable', 'Void',
- -- Exceptions.
- 'ArithmeticException', 'ArrayIndexOutOfBoundsException', 'ArrayStoreException',
- 'ClassCastException', 'ClassNotFoundException', 'CloneNotSupportedException',
- 'EnumConstantNotPresentException', 'Exception', 'IllegalAccessException',
- 'IllegalArgumentException', 'IllegalMonitorStateException', 'IllegalStateException',
- 'IllegalThreadStateException', 'IndexOutOfBoundsException', 'InstantiationException',
- 'InterruptedException', 'NegativeArraySizeException', 'NoSuchFieldException',
- 'NoSuchMethodException', 'NullPointerException', 'NumberFormatException',
- 'ReflectiveOperationException', 'RuntimeException', 'SecurityException',
- 'StringIndexOutOfBoundsException', 'TypeNotPresentException', 'UnsupportedOperationException',
- -- Errors.
- 'AbstractMethodError', 'AssertionError', 'BootstrapMethodError', 'ClassCircularityError',
- 'ClassFormatError', 'Error', 'ExceptionInInitializerError', 'IllegalAccessError',
- 'IncompatibleClassChangeError', 'InstantiationError', 'InternalError', 'LinkageError',
- 'NoClassDefFoundError', 'NoSuchFieldError', 'NoSuchMethodError', 'OutOfMemoryError',
- 'StackOverflowError', 'ThreadDeath', 'UnknownError', 'UnsatisfiedLinkError',
- 'UnsupportedClassVersionError', 'VerifyError', 'VirtualMachineError'
-})
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
+lex:add_fold_point(lexer.KEYWORD, lexer.fold_consecutive_lines('import'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/javascript.lua lexers/javascript.lua
--- /home/matej/repos/tmp/scintillua/lexers/javascript.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/javascript.lua 2022-11-29 23:51:43.330328988 +0100
@@ -1,56 +1,17 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- JavaScript LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('javascript')
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
--- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
-
--- Functions.
-local builtin_func = -B('.') *
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + method + func) * #(lexer.space^0 * '('))
-
--- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-
--- Comments.
-local line_comment = lexer.to_eol('//', true)
-local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
-
--- Strings.
-local sq_str = lexer.range("'")
-local dq_str = lexer.range('"')
-local bq_str = lexer.range('`')
-local string = lex:tag(lexer.STRING, sq_str + dq_str + bq_str)
-local regex_str = lexer.after_set('+-*%^!=&|?:;,([{<>', lexer.range('/', true) * S('igm')^0)
-local regex = lex:tag(lexer.REGEX, regex_str)
-lex:add_rule('string', string + regex)
-
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
-
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%^!=&|?:;,.()[]{}<>')))
-
--- Fold points.
-lex:add_fold_point(lexer.OPERATOR, '{', '}')
-lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
+-- Keywords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
'abstract', 'async', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class',
'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'export',
'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'get', 'goto', 'if',
@@ -58,9 +19,10 @@
'null', 'of', 'package', 'private', 'protected', 'public', 'return', 'set', 'short', 'static',
'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try',
'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield'
-})
+}))
-lex:set_word_list(lexer.TYPE, {
+-- Types.
+lex:add_rule('type', token(lexer.TYPE, word_match{
-- Fundamental objects.
'Object', 'Function', 'Boolean', 'Symbol',
-- Error Objects.
@@ -84,15 +46,45 @@
'Reflect', 'Proxy',
-- Other.
'Intl', 'WebAssembly'
-})
+}))
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Functions.
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'decodeURI', 'decodeURIComponent',
'encodeURI', 'encodeURIComponent'
-})
+}))
-lex:set_word_list(lexer.CONSTANT_BUILTIN, 'Infinity NaN undefined globalThis arguments')
+-- Constants.
+lex:add_rule('constant',
+ token(lexer.CONSTANT, word_match('Infinity NaN undefined globalThis arguments')))
-lexer.property['scintillua.comment'] = '//'
+-- Identifiers.
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
+
+-- Comments.
+local line_comment = lexer.to_eol('//', true)
+local block_comment = lexer.range('/*', '*/')
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
+
+-- Strings.
+local sq_str = lexer.range("'")
+local dq_str = lexer.range('"')
+local bq_str = lexer.range('`')
+local string = token(lexer.STRING, sq_str + dq_str + bq_str)
+local regex_str =
+ #P('/') * lexer.last_char_includes('+-*%^!=&|?:;,([{<>') * lexer.range('/', true) * S('igm')^0
+local regex = token(lexer.REGEX, regex_str)
+lex:add_rule('string', string + regex)
+
+-- Numbers.
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
+
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%^!=&|?:;,.()[]{}<>')))
+
+-- Fold points.
+lex:add_fold_point(lexer.OPERATOR, '{', '}')
+lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/jq.lua lexers/jq.lua
--- /home/matej/repos/tmp/scintillua/lexers/jq.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/jq.lua 2022-11-29 23:51:43.334329050 +0100
@@ -78,7 +78,6 @@
lex:add_fold_point(lexer.KEYWORD, 'if', 'end')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/json.lua lexers/json.lua
--- /home/matej/repos/tmp/scintillua/lexers/json.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/json.lua 2022-11-29 23:51:43.334329050 +0100
@@ -2,27 +2,39 @@
-- JSON LPeg lexer.
-- Based off of lexer code by Mitchell.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('json')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Strings.
local sq_str = lexer.range("'", true)
local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lexer.word_match('true false null')))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match('true false null')))
+
+-- Comments.
+local line_comment = lexer.to_eol('//', true)
+local block_comment = lexer.range('/*', '*/')
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+local integer = S('+-')^-1 * lexer.dec_num * S('Ll')^-1
+lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('[]{}:,')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('[]{}:,')))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
+lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/jsp.lua lexers/jsp.lua
--- /home/matej/repos/tmp/scintillua/lexers/jsp.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/jsp.lua 2022-11-29 23:51:43.334329050 +0100
@@ -1,20 +1,20 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- JSP LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {inherit = lexer.load('html')})
+local lex = lexer.new('jsp', {inherit = lexer.load('html')})
-- Embedded Java.
local java = lexer.load('java')
-local java_start_rule = lex:tag(lexer.PREPROCESSOR, '<%' * P('=')^-1)
-local java_end_rule = lex:tag(lexer.PREPROCESSOR, '%>')
+local java_start_rule = token('jsp_tag', '<%' * P('=')^-1)
+local java_end_rule = token('jsp_tag', '%>')
lex:embed(java, java_start_rule, java_end_rule, true)
+lex:add_style('jsp_tag', lexer.styles.embedded)
-- Fold points.
-lex:add_fold_point(lexer.PREPROCESSOR, '<%', '%>')
-
-lexer.property['scintillua.comment'] = '<!--|-->'
+lex:add_fold_point('jsp_tag', '<%', '%>')
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/julia.lua lexers/julia.lua
--- /home/matej/repos/tmp/scintillua/lexers/julia.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/julia.lua 2022-11-29 23:51:43.334329050 +0100
@@ -53,11 +53,12 @@
type_builtin_range + type_builtin_array))
-- Macro
-lex:add_rule('macro', token(lexer.PREPROCESSOR, '@' * (id + '.')))
+lex:add_rule('macro', token('macro', '@' * (id + '.')))
+lex:add_style('macro', lexer.styles.preprocessor)
-- Symbol
lex:add_rule('symbol', token('symbol', -B(P(':') + '<') * ':' * id))
-lex:add_style('symbol', lexer.styles.string)
+lex:add_style('symbol', lexer.styles.constant)
-- Function
lex:add_rule('function', token(lexer.FUNCTION, id * #(P('.')^-1 * '(')))
@@ -106,6 +107,4 @@
-- Operator
lex:add_rule('operator', token(lexer.OPERATOR, S('+-*/÷<>=!≠≈≤≥%^&|⊻~\\\':?.√')))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/latex.lua lexers/latex.lua
--- /home/matej/repos/tmp/scintillua/lexers/latex.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/latex.lua 2022-11-29 23:51:43.334329050 +0100
@@ -3,42 +3,48 @@
-- Modified by Brian Schott.
-- Modified by Robert Gieseke.
-local lexer = lexer
-local word_match = lexer.word_match
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('latex')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Comments.
local line_comment = lexer.to_eol('%')
local block_comment = lexer.range('\\begin' * P(' ')^0 * '{comment}',
'\\end' * P(' ')^0 * '{comment}')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Math environments.
local math_word = word_match('align displaymath eqnarray equation gather math multline')
local math_begin_end = (P('begin') + P('end')) * P(' ')^0 * '{' * math_word * P('*')^-1 * '}'
-lex:add_rule('math', lex:tag('environment.math', '$' + '\\' * (S('[]()') + math_begin_end)))
+lex:add_rule('math', token('math', '$' + '\\' * (S('[]()') + math_begin_end)))
+lex:add_style('math', lexer.styles['function'])
-- LaTeX environments.
-lex:add_rule('environment', lex:tag('environment', '\\' * (P('begin') + 'end') * P(' ')^0 * '{' *
+lex:add_rule('environment', token('environment', '\\' * (P('begin') + 'end') * P(' ')^0 * '{' *
lexer.word * P('*')^-1 * '}'))
+lex:add_style('environment', lexer.styles.keyword)
-- Sections.
-lex:add_rule('section', lex:tag('command.section', '\\' *
+lex:add_rule('section', token('section', '\\' *
word_match('part chapter section subsection subsubsection paragraph subparagraph') * P('*')^-1))
+lex:add_style('section', lexer.styles.class)
-- Commands.
-lex:add_rule('command', lex:tag('command', '\\' * (lexer.alpha^1 + S('#$&~_^%{}\\'))))
+lex:add_rule('command', token('command', '\\' * (lexer.alpha^1 + S('#$&~_^%{}\\'))))
+lex:add_style('command', lexer.styles.keyword)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('&#{}[]')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('&#{}[]')))
-- Fold points.
lex:add_fold_point(lexer.COMMENT, '\\begin', '\\end')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('%'))
lex:add_fold_point('environment', '\\begin', '\\end')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/ledger.lua lexers/ledger.lua
--- /home/matej/repos/tmp/scintillua/lexers/ledger.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/ledger.lua 2022-11-29 23:51:43.334329050 +0100
@@ -40,6 +40,4 @@
} + S('AYNDCIiOobh')
lex:add_rule('directive', token(lexer.KEYWORD, lexer.starts_line(S('!@')^-1 * directive_word)))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/less.lua lexers/less.lua
--- /home/matej/repos/tmp/scintillua/lexers/less.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/less.lua 2022-11-29 23:51:43.334329050 +0100
@@ -14,6 +14,7 @@
-- Variables.
lex:add_rule('variable', token(lexer.VARIABLE, '@' * (lexer.alnum + S('_-{}'))^1))
-lexer.property['scintillua.comment'] = '//'
+-- Fold points.
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/lexer.lua lexers/lexer.lua
--- /home/matej/repos/tmp/scintillua/lexers/lexer.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/lexer.lua 2022-11-29 23:51:43.334329050 +0100
@@ -8,17 +8,16 @@
--
-- ### Writing Lua Lexers
--
--- Lexers recognize and tag elements of source code for syntax highlighting. Scintilla (the
--- editing component behind [Textadept][] and [SciTE][]) traditionally uses static, compiled C++
--- lexers which are notoriously difficult to create and/or extend. On the other hand, Lua makes
--- it easy to to rapidly create new lexers, extend existing ones, and embed lexers within one
--- another. Lua lexers tend to be more readable than C++ lexers too.
---
--- While lexers can be written in plain Lua, Scintillua prefers using Parsing Expression
--- Grammars, or PEGs, composed with the Lua [LPeg library][]. As a result, this document is
--- devoted to writing LPeg lexers. The following table comes from the LPeg documentation and
--- summarizes all you need to know about constructing basic LPeg patterns. This module provides
--- convenience functions for creating and working with other more advanced patterns and concepts.
+-- Lexers highlight the syntax of source code. Scintilla (the editing component behind
+-- [Textadept][] and [SciTE][]) traditionally uses static, compiled C++ lexers which are
+-- notoriously difficult to create and/or extend. On the other hand, Lua makes it easy to to
+-- rapidly create new lexers, extend existing ones, and embed lexers within one another. Lua
+-- lexers tend to be more readable than C++ lexers too.
+--
+-- Lexers are Parsing Expression Grammars, or PEGs, composed with the Lua [LPeg library][]. The
+-- following table comes from the LPeg documentation and summarizes all you need to know about
+-- constructing basic LPeg patterns. This module provides convenience functions for creating
+-- and working with other more advanced patterns and concepts.
--
-- Operator | Description
-- -|-
@@ -31,15 +30,15 @@
-- `patt1 * patt2` | Matches `patt1` followed by `patt2`.
-- `patt1 + patt2` | Matches `patt1` or `patt2` (ordered choice).
-- `patt1 - patt2` | Matches `patt1` if `patt2` does not also match.
--- `-patt` | Matches if `patt` does not match, consuming no input.
+-- `-patt` | Equivalent to `("" - patt)`.
-- `#patt` | Matches `patt` but consumes no input.
--
-- The first part of this document deals with rapidly constructing a simple lexer. The next part
--- deals with more advanced techniques, such as embedding lexers within one another. Following
--- that is a discussion about code folding, or being able to tell Scintilla which code blocks
--- are "foldable" (temporarily hideable from view). After that are instructions on how to use
--- Lua lexers with the aforementioned Textadept and SciTE editors. Finally there are comments
--- on lexer performance and limitations.
+-- deals with more advanced techniques, such as custom coloring and embedding lexers within one
+-- another. Following that is a discussion about code folding, or being able to tell Scintilla
+-- which code blocks are "foldable" (temporarily hideable from view). After that are instructions
+-- on how to use Lua lexers with the aforementioned Textadept and SciTE editors. Finally there
+-- are comments on lexer performance and limitations.
--
-- [LPeg library]: http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html
-- [Textadept]: https://orbitalquark.github.io/textadept
@@ -47,12 +46,12 @@
--
-- ### Lexer Basics
--
--- The *lexers/* directory contains all of Scintillua's Lua lexers, including any new ones you
--- write. Before attempting to write one from scratch though, first determine if your programming
--- language is similar to any of the 100+ languages supported. If so, you may be able to copy
--- and modify, or inherit from that lexer, saving some time and effort. The filename of your
--- lexer should be the name of your programming language in lower case followed by a *.lua*
--- extension. For example, a new Lua lexer has the name *lua.lua*.
+-- The *lexers/* directory contains all lexers, including your new one. Before attempting to
+-- write one from scratch though, first determine if your programming language is similar to
+-- any of the 100+ languages supported. If so, you may be able to copy and modify that lexer,
+-- saving some time and effort. The filename of your lexer should be the name of your programming
+-- language in lower case followed by a *.lua* extension. For example, a new Lua lexer has the
+-- name *lua.lua*.
--
-- Note: Try to refrain from using one-character language names like "c", "d", or "r". For
-- example, Scintillua uses "ansi_c", "dmd", and "rstats", respectively.
@@ -60,167 +59,116 @@
-- #### New Lexer Template
--
-- There is a *lexers/template.txt* file that contains a simple template for a new lexer. Feel
--- free to use it, replacing the '?' with the name of your lexer. Consider this snippet from
+-- free to use it, replacing the '?'s with the name of your lexer. Consider this snippet from
-- the template:
--
-- -- ? LPeg lexer.
--
--- local lexer = lexer
+-- local lexer = require('lexer')
+-- local token, word_match = lexer.token, lexer.word_match
-- local P, S = lpeg.P, lpeg.S
--
--- local lex = lexer.new(...)
---
--- [... lexer rules ...]
+-- local lex = lexer.new('?')
--
--- -- Identifier.
--- local identifier = lex:tag(lexer.IDENTIFIER, lexer.word)
--- lex:add_rule('identifier', identifier)
+-- -- Whitespace.
+-- local ws = token(lexer.WHITESPACE, lexer.space^1)
+-- lex:add_rule('whitespace', ws)
--
--- [... more lexer rules ...]
+-- [...]
--
-- return lex
--
--- The first line of code is a Lua convention to store a global variable into a local variable
--- for quick access. The second line simply defines often used convenience variables. The third
--- and last lines [define](#lexer.new) and return the lexer object Scintillua uses; they are
--- very important and must be part of every lexer. Note the `...` passed to [`lexer.new()`]() is
--- literal: the lexer will assume the name of its filename or an alternative name specified by
--- [`lexer.load()`]() in embedded lexer applications. The fourth line uses something called a
--- "tag", an essential component of lexers. You will learn about tags shortly. The fifth line
--- defines a lexer grammar rule, which you will learn about later. (Be aware that it is common
--- practice to combine these two lines for short rules.) Note, however, the `local` prefix in
--- front of variables, which is needed so-as not to affect Lua's global environment. All in all,
--- this is a minimal, working lexer that you can build on.
---
--- #### Tags
---
--- Take a moment to think about your programming language's structure. What kind of key elements
--- does it have? Most languages have elements like keywords, strings, and comments. The
--- lexer's job is to break down source code into these elements and "tag" them for syntax
--- highlighting. Therefore, tags are an essential component of lexers. It is up to you how
--- specific your lexer is when it comes to tagging elements. Perhaps only distinguishing between
--- keywords and identifiers is necessary, or maybe recognizing constants and built-in functions,
--- methods, or libraries is desirable. The Lua lexer, for example, tags the following elements:
--- keywords, functions, constants, identifiers, strings, comments, numbers, labels, attributes,
--- and operators. Even though functions and constants are subsets of identifiers, Lua programmers
--- find it helpful for the lexer to distinguish between them all. It is perfectly acceptable
--- to just recognize keywords and identifiers.
---
--- In a lexer, LPeg patterns that match particular sequences of characters are tagged with a
--- tag name using the the [`lexer.tag()`]() function. Let us examine the "identifier" tag used
--- in the template shown earlier:
+-- The first 3 lines of code simply define often used convenience variables. The fourth and
+-- last lines [define](#lexer.new) and return the lexer object Scintilla uses; they are very
+-- important and must be part of every lexer. The fifth line defines something called a "token",
+-- an essential building block of lexers. You will learn about tokens shortly. The sixth line
+-- defines a lexer grammar rule, which you will learn about later, as well as token styles. (Be
+-- aware that it is common practice to combine these two lines for short rules.) Note, however,
+-- the `local` prefix in front of variables, which is needed so-as not to affect Lua's global
+-- environment. All in all, this is a minimal, working lexer that you can build on.
+--
+-- #### Tokens
+--
+-- Take a moment to think about your programming language's structure. What kind of key
+-- elements does it have? In the template shown earlier, one predefined element all languages
+-- have is whitespace. Your language probably also has elements like comments, strings, and
+-- keywords. Lexers refer to these elements as "tokens". Tokens are the fundamental "building
+-- blocks" of lexers. Lexers break down source code into tokens for coloring, which results
+-- in the syntax highlighting familiar to you. It is up to you how specific your lexer is
+-- when it comes to tokens. Perhaps only distinguishing between keywords and identifiers is
+-- necessary, or maybe recognizing constants and built-in functions, methods, or libraries is
+-- desirable. The Lua lexer, for example, defines 11 tokens: whitespace, keywords, built-in
+-- functions, constants, built-in libraries, identifiers, strings, comments, numbers, labels,
+-- and operators. Even though constants, built-in functions, and built-in libraries are subsets
+-- of identifiers, Lua programmers find it helpful for the lexer to distinguish between them
+-- all. It is perfectly acceptable to just recognize keywords and identifiers.
+--
+-- In a lexer, tokens consist of a token name and an LPeg pattern that matches a sequence of
+-- characters recognized as an instance of that token. Create tokens using the [`lexer.token()`]()
+-- function. Let us examine the "whitespace" token defined in the template shown earlier:
--
--- local identifier = lex:tag(lexer.IDENTIFIER, lexer.word)
+-- local ws = token(lexer.WHITESPACE, lexer.space^1)
--
-- At first glance, the first argument does not appear to be a string name and the second
-- argument does not appear to be an LPeg pattern. Perhaps you expected something like:
--
--- lex:tag('identifier', (lpeg.R('AZ', 'az') + '_') * (lpeg.R('AZ', 'az', '09') + '_')^0)
+-- local ws = token('whitespace', S('\t\v\f\n\r ')^1)
--
--- The `lexer` module actually provides a convenient list of common tag names and common LPeg
--- patterns for you to use. Tag names for programming languages include (but are not limited
--- to) [`lexer.DEFAULT`](), [`lexer.COMMENT`](), [`lexer.STRING`](), [`lexer.NUMBER`](),
--- [`lexer.KEYWORD`](), [`lexer.IDENTIFIER`](), [`lexer.OPERATOR`](), [`lexer.ERROR`](),
--- [`lexer.PREPROCESSOR`](), [`lexer.CONSTANT`](), [`lexer.CONSTANT_BUILTIN`](),
--- [`lexer.VARIABLE`](), [`lexer.VARIABLE_BUILTIN`](), [`lexer.FUNCTION`](),
--- [`lexer.FUNCTION_BUILTIN`](), [`lexer.FUNCTION_METHOD`](), [`lexer.CLASS`](), [`lexer.TYPE`](),
--- [`lexer.LABEL`](), [`lexer.REGEX`](), [`lexer.EMBEDDED`](), and [`lexer.ANNOTATION`](). Tag
--- names for markup languages include (but are not limited to) [`lexer.TAG`](),
--- [`lexer.ATTRIBUTE`](), [`lexer.HEADING`](), [`lexer.BOLD`](), [`lexer.ITALIC`](),
--- [`lexer.UNDERLINE`](), [`lexer.CODE`](), [`lexer.LINK`](), [`lexer.REFERENCE`](), and
--- [`lexer.LIST`](). Patterns include [`lexer.any`](), [`lexer.alpha`](), [`lexer.digit`](),
--- [`lexer.alnum`](), [`lexer.lower`](), [`lexer.upper`](), [`lexer.xdigit`](), [`lexer.graph`](),
--- [`lexer.print`](), [`lexer.punct`](), [`lexer.space`](), [`lexer.newline`](),
--- [`lexer.nonnewline`](), [`lexer.dec_num`](), [`lexer.hex_num`](), [`lexer.oct_num`](),
--- [`lexer.bin_num`](), [`lexer.integer`](), [`lexer.float`](), [`lexer.number`](), and
--- [`lexer.word`](). You may use your own tag names if none of the above fit your language,
--- but an advantage to using predefined tag names is that the language elements your lexer
--- recognizes will inherit any universal syntax highlighting color theme that your editor
--- uses. You can also "subclass" existing tag names by appending a '.*subclass*' string to
--- them. For example, the HTML lexer tags unknown tags as `lexer.TAG .. '.unknown'`. This gives
--- editors the opportunity to style those subclassed tags in a different way than normal tags,
--- or fall back to styling them as normal tags.
+-- The `lexer` module actually provides a convenient list of common token names and common LPeg
+-- patterns for you to use. Token names include [`lexer.DEFAULT`](), [`lexer.WHITESPACE`](),
+-- [`lexer.COMMENT`](), [`lexer.STRING`](), [`lexer.NUMBER`](), [`lexer.KEYWORD`](),
+-- [`lexer.IDENTIFIER`](), [`lexer.OPERATOR`](), [`lexer.ERROR`](), [`lexer.PREPROCESSOR`](),
+-- [`lexer.CONSTANT`](), [`lexer.VARIABLE`](), [`lexer.FUNCTION`](), [`lexer.CLASS`](),
+-- [`lexer.TYPE`](), [`lexer.LABEL`](), [`lexer.REGEX`](), and [`lexer.EMBEDDED`](). Patterns
+-- include [`lexer.any`](), [`lexer.alpha`](), [`lexer.digit`](), [`lexer.alnum`](),
+-- [`lexer.lower`](), [`lexer.upper`](), [`lexer.xdigit`](), [`lexer.graph`](), [`lexer.print`](),
+-- [`lexer.punct`](), [`lexer.space`](), [`lexer.newline`](), [`lexer.nonnewline`](),
+-- [`lexer.dec_num`](), [`lexer.hex_num`](), [`lexer.oct_num`](), [`lexer.integer`](),
+-- [`lexer.float`](), [`lexer.number`](), and [`lexer.word`](). You may use your own token names
+-- if none of the above fit your language, but an advantage to using predefined token names is
+-- that your lexer's tokens will inherit the universal syntax highlighting color theme used by
+-- your text editor.
--
--- ##### Example Tags
+-- ##### Example Tokens
--
--- So, how might you recognize and tag elements like keywords, comments, and strings? Here are
--- some examples.
+-- So, how might you define other tokens like keywords, comments, and strings? Here are some
+-- examples.
--
-- **Keywords**
--
--- Instead of matching _n_ keywords with _n_ `P('keyword_`_`n`_`')` ordered choices, use one
--- of of the following methods:
+-- Instead of matching _n_ keywords with _n_ `P('keyword_`_`n`_`')` ordered choices, use another
+-- convenience function: [`lexer.word_match()`](). It is much easier and more efficient to
+-- write word matches like:
--
--- 1. Use the convenience function [`lexer.word_match()`]() optionally coupled with
--- [`lexer.set_word_list()`](). It is much easier and more efficient to write word matches like:
+-- local keyword = token(lexer.KEYWORD, lexer.word_match{
+-- 'keyword_1', 'keyword_2', ..., 'keyword_n'
+-- })
--
--- local keyword = lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD))
--- [...]
--- lex:set_word_list(lexer.KEYWORD, {
--- 'keyword_1', 'keyword_2', ..., 'keyword_n'
--- })
---
--- local case_insensitive_word = lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD, true))
--- [...]
--- lex:set_word_list(lexer.KEYWORD, {
--- 'KEYWORD_1', 'keyword_2', ..., 'KEYword_n'
--- })
---
--- local hyphenated_keyword = lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD))
--- [...]
--- lex:set_word_list(lexer.KEYWORD, {
--- 'keyword-1', 'keyword-2', ..., 'keyword-n'
--- })
---
--- The benefit of using this method is that other lexers that inherit from, embed, or embed
--- themselves into your lexer can set, replace, or extend these word lists. For example,
--- the TypeScript lexer inherits from JavaScript, but extends JavaScript's keyword and type
--- lists with more options.
---
--- This method also allows applications that use your lexer to extend or replace your word
--- lists. For example, the Lua lexer includes keywords and functions for the latest version
--- of Lua (5.4 at the time of writing). However, editors using that lexer might want to use
--- keywords from Lua version 5.1, which is still quite popular.
---
--- Note that calling `lex:set_word_list()` is completely optional. Your lexer is allowed to
--- expect the editor using it to supply word lists. Scintilla-based editors can do so via
--- Scintilla's `ILexer5` interface.
---
--- 2. Use the lexer-agnostic form of [`lexer.word_match()`]():
---
--- local keyword = lex:tag(lexer.KEYWORD, lexer.word_match{
--- 'keyword_1', 'keyword_2', ..., 'keyword_n'
--- })
---
--- local case_insensitive_keyword = lex:tag(lexer.KEYWORD, lexer.word_match({
--- 'KEYWORD_1', 'keyword_2', ..., 'KEYword_n'
--- }, true))
---
--- local hyphened_keyword = lex:tag(lexer.KEYWORD, lexer.word_match{
--- 'keyword-1', 'keyword-2', ..., 'keyword-n'
--- })
+-- local case_insensitive_keyword = token(lexer.KEYWORD, lexer.word_match({
+-- 'KEYWORD_1', 'keyword_2', ..., 'KEYword_n'
+-- }, true))
--
--- For short keyword lists, you can use a single string of words. For example:
+-- local hyphened_keyword = token(lexer.KEYWORD, lexer.word_match{
+-- 'keyword-1', 'keyword-2', ..., 'keyword-n'
+-- })
--
--- local keyword = lex:tag(lexer.KEYWORD, lexer.word_match('key_1 key_2 ... key_n'))
+-- For short keyword lists, you can use a single string of words. For example:
--
--- You can use this method for static word lists that do not change, or where it does not
--- make sense to allow applications or other lexers to extend or replace a word list.
+-- local keyword = token(lexer.KEYWORD, lexer.word_match('key_1 key_2 ... key_n'))
--
-- **Comments**
--
--- Line-style comments with a prefix character(s) are easy to express:
+-- Line-style comments with a prefix character(s) are easy to express with LPeg:
--
--- local shell_comment = lex:tag(lexer.COMMENT, lexer.to_eol('#'))
--- local c_line_comment = lex:tag(lexer.COMMENT, lexer.to_eol('//', true))
+-- local shell_comment = token(lexer.COMMENT, lexer.to_eol('#'))
+-- local c_line_comment = token(lexer.COMMENT, lexer.to_eol('//', true))
--
--- The comments above start with a '#' or "//" and go to the end of the line (EOL). The second
--- comment recognizes the next line also as a comment if the current line ends with a '\'
--- escape character.
+-- The comments above start with a '#' or "//" and go to the end of the line. The second comment
+-- recognizes the next line also as a comment if the current line ends with a '\' escape character.
--
-- C-style "block" comments with a start and end delimiter are also easy to express:
--
--- local c_comment = lex:tag(lexer.COMMENT, lexer.range('/*', '*/'))
+-- local c_comment = token(lexer.COMMENT, lexer.range('/*', '*/'))
--
-- This comment starts with a "/\*" sequence and contains anything up to and including an ending
-- "\*/" sequence. The ending "\*/" is optional so the lexer can recognize unfinished comments
@@ -234,79 +182,73 @@
--
-- local dq_str = lexer.range('"')
-- local sq_str = lexer.range("'")
--- local string = lex:tag(lexer.STRING, dq_str + sq_str)
+-- local string = token(lexer.STRING, dq_str + sq_str)
--
-- In this case, the lexer treats '\' as an escape character in a string sequence.
--
-- **Numbers**
--
--- Most programming languages have the same format for integers and floats, so it might be as
--- simple as using a predefined LPeg pattern:
+-- Most programming languages have the same format for integer and float tokens, so it might
+-- be as simple as using a predefined LPeg pattern:
--
--- local number = lex:tag(lexer.NUMBER, lexer.number)
+-- local number = token(lexer.NUMBER, lexer.number)
--
-- However, some languages allow postfix characters on integers.
--
-- local integer = P('-')^-1 * (lexer.dec_num * S('lL')^-1)
--- local number = lex:tag(lexer.NUMBER, lexer.float + lexer.hex_num + integer)
---
--- Other languages allow separaters within numbers for better readability.
---
--- local number = lex:tag(lexer.NUMBER, lexer.number_('_')) -- recognize 1_000_000
+-- local number = token(lexer.NUMBER, lexer.float + lexer.hex_num + integer)
--
-- Your language may need other tweaks, but it is up to you how fine-grained you want your
-- highlighting to be. After all, you are not writing a compiler or interpreter!
--
-- #### Rules
--
--- Programming languages have grammars, which specify valid syntactic structure. For example,
--- comments usually cannot appear within a string, and valid identifiers (like variable names)
--- cannot be keywords. In Lua lexers, grammars consist of LPeg pattern rules, many of which
--- are tagged. Recall from the lexer template the [`lexer.add_rule()`]() call, which adds a
--- rule to the lexer's grammar:
+-- Programming languages have grammars, which specify valid token structure. For example,
+-- comments usually cannot appear within a string. Grammars consist of rules, which are simply
+-- combinations of tokens. Recall from the lexer template the [`lexer.add_rule()`]() call,
+-- which adds a rule to the lexer's grammar:
--
--- lex:add_rule('identifier', identifier)
+-- lex:add_rule('whitespace', ws)
--
-- Each rule has an associated name, but rule names are completely arbitrary and serve only to
-- identify and distinguish between different rules. Rule order is important: if text does not
-- match the first rule added to the grammar, the lexer tries to match the second rule added, and
--- so on. Right now this lexer simply matches identifiers under a rule named "identifier".
+-- so on. Right now this lexer simply matches whitespace tokens under a rule named "whitespace".
--
-- To illustrate the importance of rule order, here is an example of a simplified Lua lexer:
--
--- lex:add_rule('keyword', lex:tag(lexer.KEYWORD, ...))
--- lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, ...))
--- lex:add_rule('string', lex:tag(lexer.STRING, ...))
--- lex:add_rule('comment', lex:tag(lexer.COMMENT, ...))
--- lex:add_rule('number', lex:tag(lexer.NUMBER, ...))
--- lex:add_rule('label', lex:tag(lexer.LABEL, ...))
--- lex:add_rule('operator', lex:tag(lexer.OPERATOR, ...))
---
--- Notice how identifiers come _after_ keywords. In Lua, as with most programming languages,
--- the characters allowed in keywords and identifiers are in the same set (alphanumerics plus
--- underscores). If the lexer added the "identifier" rule before the "keyword" rule, all keywords
--- would match identifiers and thus would be incorrectly tagged (and likewise incorrectly
--- highlighted) as identifiers instead of keywords. The same idea applies to function names,
--- constants, etc. that you may want to distinguish between: their rules should come before
--- identifiers.
+-- lex:add_rule('whitespace', token(lexer.WHITESPACE, ...))
+-- lex:add_rule('keyword', token(lexer.KEYWORD, ...))
+-- lex:add_rule('identifier', token(lexer.IDENTIFIER, ...))
+-- lex:add_rule('string', token(lexer.STRING, ...))
+-- lex:add_rule('comment', token(lexer.COMMENT, ...))
+-- lex:add_rule('number', token(lexer.NUMBER, ...))
+-- lex:add_rule('label', token(lexer.LABEL, ...))
+-- lex:add_rule('operator', token(lexer.OPERATOR, ...))
+--
+-- Note how identifiers come after keywords. In Lua, as with most programming languages,
+-- the characters allowed in keywords and identifiers are in the same set (alphanumerics
+-- plus underscores). If the lexer added the "identifier" rule before the "keyword" rule,
+-- all keywords would match identifiers and thus incorrectly highlight as identifiers instead
+-- of keywords. The same idea applies to function, constant, etc. tokens that you may want to
+-- distinguish between: their rules should come before identifiers.
--
--- So what about text that does not match any rules? For example in Lua, the '!' character is
+-- So what about text that does not match any rules? For example in Lua, the '!' character is
-- meaningless outside a string or comment. Normally the lexer skips over such text. If instead
--- you want to highlight these "syntax errors", add a final rule:
+-- you want to highlight these "syntax errors", add an additional end rule:
--
--- lex:add_rule('keyword', keyword)
+-- lex:add_rule('whitespace', ws)
-- ...
--- lex:add_rule('error', lex:tag(lexer.ERROR, lexer.any))
+-- lex:add_rule('error', token(lexer.ERROR, lexer.any))
--
--- This identifies and tags any character not matched by an existing rule as a `lexer.ERROR`.
+-- This identifies and highlights any character not matched by an existing rule as a `lexer.ERROR`
+-- token.
--
--- Even though the rules defined in the examples above contain a single tagged pattern, rules may
--- consist of multiple tagged patterns. For example, the rule for an HTML tag could consist of a
--- tagged tag followed by an arbitrary number of tagged attributes, separated by whitespace. This
--- allows the lexer to produce all tags separately, but in a single, convenient rule. That rule
--- might look something like this:
+-- Even though the rules defined in the examples above contain a single token, rules may
+-- consist of multiple tokens. For example, a rule for an HTML tag could consist of a tag token
+-- followed by an arbitrary number of attribute tokens, allowing the lexer to highlight all
+-- tokens separately. That rule might look something like this:
--
--- local ws = lex:get_rule('whitespace') -- predefined rule for all lexers
-- lex:add_rule('tag', tag_start * (ws * attributes)^0 * tag_end^-1)
--
-- Note however that lexers with complex rules like these are more prone to lose track of their
@@ -314,16 +256,79 @@
--
-- #### Summary
--
--- Lexers primarily consist of tagged patterns and grammar rules. These patterns match language
--- elements like keywords, comments, and strings, and rules dictate the order in which patterns
--- are matched. At your disposal are a number of convenience patterns and functions for rapidly
--- creating a lexer. If you choose to use predefined tag names (or perhaps even subclassed
--- names) for your patterns, you do not have to update your editor's theme to specify how to
--- syntax-highlight those patterns. Your language's elements will inherit the default syntax
--- highlighting color theme your editor uses.
+-- Lexers primarily consist of tokens and grammar rules. At your disposal are a number of
+-- convenience patterns and functions for rapidly creating a lexer. If you choose to use
+-- predefined token names for your tokens, you do not have to define how the lexer highlights
+-- them. The tokens will inherit the default syntax highlighting color theme your editor uses.
--
-- ### Advanced Techniques
--
+-- #### Styles and Styling
+--
+-- The most basic form of syntax highlighting is assigning different colors to different
+-- tokens. Instead of highlighting with just colors, Scintilla allows for more rich highlighting,
+-- or "styling", with different fonts, font sizes, font attributes, and foreground and background
+-- colors, just to name a few. The unit of this rich highlighting is called a "style". Styles
+-- are simply Lua tables of properties. By default, lexers associate predefined token names like
+-- `lexer.WHITESPACE`, `lexer.COMMENT`, `lexer.STRING`, etc. with particular styles as part
+-- of a universal color theme. These predefined styles are contained in [`lexer.styles`](),
+-- and you may define your own styles. See that table's documentation for more information. As
+-- with token names, LPeg patterns, and styles, there is a set of predefined color names,
+-- but they vary depending on the current color theme in use. Therefore, it is generally not
+-- a good idea to manually define colors within styles in your lexer since they might not fit
+-- into a user's chosen color theme. Try to refrain from even using predefined colors in a
+-- style because that color may be theme-specific. Instead, the best practice is to either use
+-- predefined styles or derive new color-agnostic styles from predefined ones. For example, Lua
+-- "longstring" tokens use the existing `lexer.styles.string` style instead of defining a new one.
+--
+-- ##### Example Styles
+--
+-- Defining styles is pretty straightforward. An empty style that inherits the default theme
+-- settings is simply an empty table:
+--
+-- local style_nothing = {}
+--
+-- A similar style but with a bold font face looks like this:
+--
+-- local style_bold = {bold = true}
+--
+-- You can derive new styles from predefined ones without having to rewrite them. This operation
+-- leaves the old style unchanged. For example, if you had a "static variable" token whose
+-- style you wanted to base off of `lexer.styles.variable`, it would probably look like:
+--
+-- local style_static_var = lexer.styles.variable .. {italics = true}
+--
+-- The color theme files in the *lexers/themes/* folder give more examples of style definitions.
+--
+-- #### Token Styles
+--
+-- Lexers use the [`lexer.add_style()`]() function to assign styles to particular tokens. Recall
+-- the token definition and from the lexer template:
+--
+-- local ws = token(lexer.WHITESPACE, lexer.space^1)
+-- lex:add_rule('whitespace', ws)
+--
+-- Why is a style not assigned to the `lexer.WHITESPACE` token? As mentioned earlier, lexers
+-- automatically associate tokens that use predefined token names with a particular style. Only
+-- tokens with custom token names need manual style associations. As an example, consider a
+-- custom whitespace token:
+--
+-- local ws = token('custom_whitespace', lexer.space^1)
+--
+-- Assigning a style to this token looks like:
+--
+-- lex:add_style('custom_whitespace', lexer.styles.whitespace)
+--
+-- Do not confuse token names with rule names. They are completely different entities. In the
+-- example above, the lexer associates the "custom_whitespace" token with the existing style
+-- for `lexer.WHITESPACE` tokens. If instead you prefer to color the background of whitespace
+-- a shade of grey, it might look like:
+--
+-- lex:add_style('custom_whitespace', lexer.styles.whitespace .. {back = lexer.colors.grey})
+--
+-- Remember to refrain from assigning specific colors in styles, but in this case, all user
+-- color themes probably define `colors.grey`.
+--
-- #### Line Lexers
--
-- By default, lexers match the arbitrary chunks of text passed to them by Scintilla. These
@@ -333,16 +338,16 @@
-- line accordingly. To indicate that your lexer matches by line, create the lexer with an
-- extra parameter:
--
--- local lex = lexer.new(..., {lex_by_line = true})
+-- local lex = lexer.new('?', {lex_by_line = true})
--
-- Now the input text for the lexer is a single line at a time. Keep in mind that line lexers
--- do not have the ability to look ahead to subsequent lines.
+-- do not have the ability to look ahead at subsequent lines.
--
-- #### Embedded Lexers
--
--- Scintillua lexers embed within one another very easily, requiring minimal effort. In the
--- following sections, the lexer being embedded is called the "child" lexer and the lexer a child
--- is being embedded in is called the "parent". For example, consider an HTML lexer and a CSS
+-- Lexers embed within one another very easily, requiring minimal effort. In the following
+-- sections, the lexer being embedded is called the "child" lexer and the lexer a child is
+-- being embedded in is called the "parent". For example, consider an HTML lexer and a CSS
-- lexer. Either lexer stands alone for styling their respective HTML and CSS files. However, CSS
-- can be embedded inside HTML. In this specific case, the CSS lexer is the "child" lexer with
-- the HTML lexer being the "parent". Now consider an HTML lexer and a PHP lexer. This sounds
@@ -366,14 +371,15 @@
-- tag with a "type" attribute whose value is "text/css":
--
-- local css_tag = P('<style') * P(function(input, index)
--- if input:find('^[^>]+type="text/css"', index) then return true end
+-- if input:find('^[^>]+type="text/css"', index) then return index end
-- end)
--
-- This pattern looks for the beginning of a "style" tag and searches its attribute list for
-- the text "`type="text/css"`". (In this simplified example, the Lua pattern does not consider
-- whitespace between the '=' nor does it consider that using single quotes is valid.) If there
--- is a match, the functional pattern returns `true`. However, we ultimately want to style the
--- "style" tag as an HTML tag, so the actual start rule looks like this:
+-- is a match, the functional pattern returns a value instead of `nil`. In this case, the value
+-- returned does not matter because we ultimately want to style the "style" tag as an HTML tag,
+-- so the actual start rule looks like this:
--
-- local css_start_rule = #css_tag * tag
--
@@ -396,21 +402,18 @@
-- in this case, call [`lexer.embed()`]() with switched arguments. For example, in the PHP lexer:
--
-- local html = lexer.load('html')
--- local php_start_rule = lex:tag('php_tag', '<?php' * lexer.space)
--- local php_end_rule = lex:tag('php_tag', '?>')
+-- local php_start_rule = token('php_tag', '<?php ')
+-- local php_end_rule = token('php_tag', '?>')
+-- lex:add_style('php_tag', lexer.styles.embedded)
-- html:embed(lex, php_start_rule, php_end_rule)
--
--- Note that the use of a 'php_tag' tag will require the editor using the lexer to specify how
--- to highlight text with that tag. In order to avoid this, you could use the `lexer.PREPROCESSOR`
--- tag instead.
---
-- #### Lexers with Complex State
--
-- A vast majority of lexers are not stateful and can operate on any chunk of text in a
-- document. However, there may be rare cases where a lexer does need to keep track of some
-- sort of persistent state. Rather than using `lpeg.P` function patterns that set state
-- variables, it is recommended to make use of Scintilla's built-in, per-line state integers via
--- [`lexer.line_state`](). It was designed to accommodate up to 32 bit-flags for tracking state.
+-- [`lexer.line_state`](). It was designed to accommodate up to 32 bit flags for tracking state.
-- [`lexer.line_from_position()`]() will return the line for any position given to an `lpeg.P`
-- function pattern. (Any positions derived from that position argument will also work.)
--
@@ -435,11 +438,11 @@
-- lex:add_fold_point(lexer.OPERATOR, '{', '}')
-- lex:add_fold_point(lexer.COMMENT, '/*', '*/')
--
--- The first assignment states that any '{' or '}' that the lexer tagged as an `lexer.OPERATOR`
--- is a fold point. Likewise, the second assignment states that any "/\*" or "\*/" that the
--- lexer tagged as part of a `lexer.COMMENT` is a fold point. The lexer does not consider any
--- occurrences of these characters outside their tagged elements (such as in a string) as fold
--- points. How do you specify fold keywords? Here is an example for Lua:
+-- The first assignment states that any '{' or '}' that the lexer recognized as an `lexer.OPERATOR`
+-- token is a fold point. Likewise, the second assignment states that any "/\*" or "\*/" that
+-- the lexer recognizes as part of a `lexer.COMMENT` token is a fold point. The lexer does
+-- not consider any occurrences of these characters outside their defined tokens (such as in
+-- a string) as fold points. How do you specify fold keywords? Here is an example for Lua:
--
-- lex:add_fold_point(lexer.KEYWORD, 'if', 'end')
-- lex:add_fold_point(lexer.KEYWORD, 'do', 'end')
@@ -450,13 +453,12 @@
-- `case_insensitive_fold_points = true` option to [`lexer.new()`](), and specify keywords in
-- lower case.
--
--- If your lexer needs to do some additional processing in order to determine if a tagged element
--- is a fold point, pass a function to `lex:add_fold_point()` that returns an integer. A return
--- value of `1` indicates the element is a beginning fold point and a return value of `-1`
--- indicates the element is an ending fold point. A return value of `0` indicates the element
--- is not a fold point. For example:
+-- If your lexer needs to do some additional processing in order to determine if a token is
+-- a fold point, pass a function that returns an integer to `lex:add_fold_point()`. Returning
+-- `1` indicates the token is a beginning fold point and returning `-1` indicates the token is
+-- an ending fold point. Returning `0` indicates the token is not a fold point. For example:
--
--- local function fold_strange_element(text, pos, line, s, symbol)
+-- local function fold_strange_token(text, pos, line, s, symbol)
-- if ... then
-- return 1 -- beginning fold point
-- elseif ... then
@@ -465,13 +467,13 @@
-- return 0
-- end
--
--- lex:add_fold_point('strange_element', '|', fold_strange_element)
+-- lex:add_fold_point('strange_token', '|', fold_strange_token)
--
--- Any time the lexer encounters a '|' that is tagged as a "strange_element", it calls the
--- `fold_strange_element` function to determine if '|' is a fold point. The lexer calls these
--- functions with the following arguments: the text to identify fold points in, the beginning
--- position of the current line in the text to fold, the current line's text, the position in
--- the current line the fold point text starts at, and the fold point text itself.
+-- Any time the lexer encounters a '|' that is a "strange_token", it calls the `fold_strange_token`
+-- function to determine if '|' is a fold point. The lexer calls these functions with the
+-- following arguments: the text to identify fold points in, the beginning position of the
+-- current line in the text to fold, the current line's text, the position in the current line
+-- the fold point text starts at, and the fold point text itself.
--
-- #### Fold by Indentation
--
@@ -479,17 +481,17 @@
-- your lexer falls into this category and you would like to mark fold points based on changes
-- in indentation, create the lexer with a `fold_by_indentation = true` option:
--
--- local lex = lexer.new(..., {fold_by_indentation = true})
+-- local lex = lexer.new('?', {fold_by_indentation = true})
--
-- ### Using Lexers
--
-- **Textadept**
--
--- Place your lexer in your *~/.textadept/lexers/* directory so you do not overwrite it when
+-- Put your lexer in your *~/.textadept/lexers/* directory so you do not overwrite it when
-- upgrading Textadept. Also, lexers in this directory override default lexers. Thus, Textadept
-- loads a user *lua* lexer instead of the default *lua* lexer. This is convenient for tweaking
--- a default lexer to your liking. Then add a [file extension](#lexer.detect_extensions) for
--- your lexer if necessary.
+-- a default lexer to your liking. Then add a [file type](#textadept.file_types) for your lexer
+-- if necessary.
--
-- **SciTE**
--
@@ -497,82 +499,107 @@
-- or *SciTEGlobal.properties*. The contents of the *.properties* file should contain:
--
-- file.patterns.[lexer_name]=[file_patterns]
--- lexer.$(file.patterns.[lexer_name])=scintillua.[lexer_name]
--- keywords.$(file.patterns.[lexer_name])=scintillua
--- keywords2.$(file.patterns.[lexer_name])=scintillua
--- ...
--- keywords9.$(file.patterns.[lexer_name])=scintillua
+-- lexer.$(file.patterns.[lexer_name])=[lexer_name]
--
-- where `[lexer_name]` is the name of your lexer (minus the *.lua* extension) and
--- `[file_patterns]` is a set of file extensions to use your lexer for. The `keyword` settings are
--- only needed if another SciTE properties file has defined keyword sets for `[file_patterns]`.
--- The `scintillua` keyword setting instructs Scintillua to use the keyword sets defined within
--- the lexer. You can override a lexer's keyword set(s) by specifying your own in the same order
--- that the lexer calls `lex:set_word_list()`. For example, the Lua lexer's first set of keywords
--- is for reserved words, the second is for built-in global functions, the third is for library
--- functions, the fourth is for built-in global constants, and the fifth is for library constants.
---
--- SciTE assigns styles to tag names in order to perform syntax highlighting. Since the set of
--- tag names used for a given language changes, your *.properties* file should specify styles
--- for tag names instead of style numbers. For example:
+-- `[file_patterns]` is a set of file extensions to use your lexer for.
--
--- scintillua.styles.my_tag=$(scintillua.styles.keyword),bold
+-- Please note that Lua lexers ignore any styling information in *.properties* files. Your
+-- theme file in the *lexers/themes/* directory contains styling information.
--
-- ### Migrating Legacy Lexers
--
-- Legacy lexers are of the form:
--
--- local lexer = require('lexer')
--- local token, word_match = lexer.token, lexer.word_match
--- local P, S = lpeg.P, lpeg.S
+-- local l = require('lexer')
+-- local token, word_match = l.token, l.word_match
+-- local P, R, S = lpeg.P, lpeg.R, lpeg.S
--
--- local lex = lexer.new('?')
+-- local M = {_NAME = '?'}
--
--- -- Whitespace.
--- lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
+-- [... token and pattern definitions ...]
--
--- -- Keywords.
--- lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+-- M._rules = {
+-- {'rule', pattern},
-- [...]
--- }))
+-- }
--
--- [... other rule definitions ...]
---
--- -- Custom.
--- lex:add_rule('custom_rule', token('custom_token', ...))
--- lex:add_style('custom_token', lexer.styles.keyword .. {bold = true})
+-- M._tokenstyles = {
+-- 'token' = 'style',
+-- [...]
+-- }
--
--- -- Fold points.
--- lex:add_fold_point(lexer.OPERATOR, '{', '}')
+-- M._foldsymbols = {
+-- _patterns = {...},
+-- ['token'] = {['start'] = 1, ['end'] = -1},
+-- [...]
+-- }
--
--- return lex
+-- return M
--
--- While Scintillua will mostly handle such legacy lexers just fine without any changes, it is
+-- While Scintillua will handle such legacy lexers just fine without any changes, it is
-- recommended that you migrate yours. The migration process is fairly straightforward:
--
--- 1. `lexer` exists in the default lexer environment, so `require('lexer')` should be replaced
--- by simply `lexer`. (Keep in mind `local lexer = lexer` is a Lua idiom.)
--- 2. Every lexer created using [`lexer.new()`]() should no longer specify a lexer name by
--- string, but should instead use `...` (three dots), which evaluates to the lexer's filename
--- or alternative name in embedded lexer applications.
--- 3. Every lexer created using `lexer.new()` now includes a rule to match whitespace. Unless
--- your lexer has significant whitespace, you can remove your legacy lexer's whitespace
--- token and rule. Otherwise, your defined whitespace rule will replace the default one.
--- 4. The concept of tokens has been replaced with tags. Instead of calling a `token()` function,
--- call [`lex:tag()`](#lexer.tag) instead.
--- 5. Lexers now support replaceable word lists. Instead of calling [`lexer.word_match()`]()
--- with large word lists, call it as an instance method with an identifier string (typically
--- something like `lexer.KEYWORD`). Then at the end of the lexer (before `return lex`), call
--- [`lex:set_word_list()`](#lexer.set_word_list) with the same identifier and the usual
--- list of words to match. This allows users of your lexer to call `lex:set_word_list()`
--- with their own set of words should they wish to.
--- 6. Lexers no longer specify styling information. Remove any calls to `lex:add_style()`. You
--- may need to add styling information for custom tags to your editor's theme.
--- 7. `lexer.last_char_includes()` has been deprecated in favor of the new [`lexer.after_set()`]().
--- Use the character set and pattern as arguments to that new function.
+-- 1. Replace all instances of `l` with `lexer`, as it's better practice and results in less
+-- confusion.
+-- 2. Replace `local M = {_NAME = '?'}` with `local lex = lexer.new('?')`, where `?` is the
+-- name of your legacy lexer. At the end of the lexer, change `return M` to `return lex`.
+-- 3. Instead of defining rules towards the end of your lexer, define your rules as you define
+-- your tokens and patterns using [`lex:add_rule()`](#lexer.add_rule).
+-- 4. Similarly, any custom token names should have their styles immediately defined using
+-- [`lex:add_style()`](#lexer.add_style).
+-- 5. Optionally convert any table arguments passed to [`lexer.word_match()`]() to a
+-- space-separated string of words.
+-- 6. Replace any calls to `lexer.embed(M, child, ...)` and `lexer.embed(parent, M, ...)` with
+-- [`lex:embed`](#lexer.embed)`(child, ...)` and `parent:embed(lex, ...)`, respectively.
+-- 7. Define fold points with simple calls to [`lex:add_fold_point()`](#lexer.add_fold_point). No
+-- need to mess with Lua patterns anymore.
+-- 8. Any legacy lexer options such as `M._FOLDBYINDENTATION`, `M._LEXBYLINE`, `M._lexer`,
+-- etc. should be added as table options to [`lexer.new()`]().
+-- 9. Any external lexer rule fetching and/or modifications via `lexer._RULES` should be changed
+-- to use [`lexer.get_rule()`]() and [`lexer.modify_rule()`]().
--
-- As an example, consider the following sample legacy lexer:
--
+-- local l = require('lexer')
+-- local token, word_match = l.token, l.word_match
+-- local P, R, S = lpeg.P, lpeg.R, lpeg.S
+--
+-- local M = {_NAME = 'legacy'}
+--
+-- local ws = token(l.WHITESPACE, l.space^1)
+-- local comment = token(l.COMMENT, '#' * l.nonnewline^0)
+-- local string = token(l.STRING, l.delimited_range('"'))
+-- local number = token(l.NUMBER, l.float + l.integer)
+-- local keyword = token(l.KEYWORD, word_match{'foo', 'bar', 'baz'})
+-- local custom = token('custom', P('quux'))
+-- local identifier = token(l.IDENTIFIER, l.word)
+-- local operator = token(l.OPERATOR, S('+-*/%^=<>,.()[]{}'))
+--
+-- M._rules = {
+-- {'whitespace', ws},
+-- {'keyword', keyword},
+-- {'custom', custom},
+-- {'identifier', identifier},
+-- {'string', string},
+-- {'comment', comment},
+-- {'number', number},
+-- {'operator', operator}
+-- }
+--
+-- M._tokenstyles = {
+-- 'custom' = l.STYLE_KEYWORD .. ',bold'
+-- }
+--
+-- M._foldsymbols = {
+-- _patterns = {'[{}]'},
+-- [l.OPERATOR] = {['{'] = 1, ['}'] = -1}
+-- }
+--
+-- return M
+--
+-- Following the migration steps would yield:
+--
-- local lexer = require('lexer')
-- local token, word_match = lexer.token, lexer.word_match
-- local P, S = lpeg.P, lpeg.S
@@ -593,39 +620,15 @@
--
-- return lex
--
--- Following the migration steps would yield:
---
--- local lexer = lexer
--- local P, S = lpeg.P, lpeg.S
---
--- local lex = lexer.new(...)
---
--- lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
--- lex:add_rule('custom', lex:tag('custom', 'quux'))
--- lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
--- lex:add_rule('string', lex:tag(lexer.STRING, lexer.range('"')))
--- lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
--- lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
--- lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-*/%^=<>,.()[]{}')))
---
--- lex:add_fold_point(lexer.OPERATOR, '{', '}')
---
--- lex:set_word_list(lexer.KEYWORD, {'foo', 'bar', 'baz'})
---
--- return lex
---
--- Any editors using this lexer would have to add a style for the 'custom' tag.
---
-- ### Considerations
--
-- #### Performance
--
-- There might be some slight overhead when initializing a lexer, but loading a file from disk
--- into Scintilla is usually more expensive. Actually painting the syntax highlighted text to
--- the screen is often more expensive than the lexing operation. On modern computer systems,
--- I see no difference in speed between Lua lexers and Scintilla's C++ ones. Optimize lexers for
--- speed by re-arranging `lexer.add_rule()` calls so that the most common rules match first. Do
--- keep in mind that order matters for similar rules.
+-- into Scintilla is usually more expensive. On modern computer systems, I see no difference in
+-- speed between Lua lexers and Scintilla's C++ ones. Optimize lexers for speed by re-arranging
+-- `lexer.add_rule()` calls so that the most common rules match first. Do keep in mind that
+-- order matters for similar rules.
--
-- In some cases, folding may be far more expensive than lexing, particularly in lexers with a
-- lot of potential fold points. If your lexer is exhibiting signs of slowness, try disabling
@@ -635,23 +638,13 @@
--
-- #### Limitations
--
--- Embedded preprocessor languages like PHP cannot completely embed themselves into their parent
--- languages because the parent's tagged patterns do not support start and end rules. This
--- mostly goes unnoticed, but code like
+-- Embedded preprocessor languages like PHP cannot completely embed in their parent languages
+-- in that the parent's tokens do not support start and end rules. This mostly goes unnoticed,
+-- but code like
--
-- <div id="<?php echo $id; ?>">
--
--- will not style correctly. Also, these types of languages cannot currently embed themselves
--- into their parent's child languages either.
---
--- A language cannot embed itself into something like an interpolated string because it is
--- possible that if lexing starts within the embedded entity, it will not be detected as such,
--- so a child to parent transition cannot happen. For example, the following Ruby code will
--- not style correctly:
---
--- sum = "1 + 2 = #{1 + 2}"
---
--- Also, there is the potential for recursion for languages embedding themselves within themselves.
+-- will not style correctly.
--
-- #### Troubleshooting
--
@@ -663,9 +656,9 @@
--
-- Poorly written lexers have the ability to crash Scintilla (and thus its containing application),
-- so unsaved data might be lost. However, I have only observed these crashes in early lexer
--- development, when syntax errors or pattern errors are present. Once the lexer actually
--- starts processing and tagging text (either correctly or incorrectly, it does not matter),
--- I have not observed any crashes.
+-- development, when syntax errors or pattern errors are present. Once the lexer actually starts
+-- styling text (either correctly or incorrectly, it does not matter), I have not observed
+-- any crashes.
--
-- #### Acknowledgements
--
@@ -674,71 +667,45 @@
--
-- [lexer post]: http://lua-users.org/lists/lua-l/2007-04/msg00116.html
-- @field DEFAULT (string)
--- The tag name for default elements.
+-- The token name for default tokens.
+-- @field WHITESPACE (string)
+-- The token name for whitespace tokens.
-- @field COMMENT (string)
--- The tag name for comment elements.
+-- The token name for comment tokens.
-- @field STRING (string)
--- The tag name for string elements.
+-- The token name for string tokens.
-- @field NUMBER (string)
--- The tag name for number elements.
+-- The token name for number tokens.
-- @field KEYWORD (string)
--- The tag name for keyword elements.
+-- The token name for keyword tokens.
-- @field IDENTIFIER (string)
--- The tag name for identifier elements.
+-- The token name for identifier tokens.
-- @field OPERATOR (string)
--- The tag name for operator elements.
+-- The token name for operator tokens.
-- @field ERROR (string)
--- The tag name for error elements.
+-- The token name for error tokens.
-- @field PREPROCESSOR (string)
--- The tag name for preprocessor elements.
+-- The token name for preprocessor tokens.
-- @field CONSTANT (string)
--- The tag name for constant elements.
+-- The token name for constant tokens.
-- @field VARIABLE (string)
--- The tag name for variable elements.
+-- The token name for variable tokens.
-- @field FUNCTION (string)
--- The tag name for function elements.
+-- The token name for function tokens.
-- @field CLASS (string)
--- The tag name for class elements.
+-- The token name for class tokens.
-- @field TYPE (string)
--- The tag name for type elements.
+-- The token name for type tokens.
-- @field LABEL (string)
--- The tag name for label elements.
+-- The token name for label tokens.
-- @field REGEX (string)
--- The tag name for regex elements.
--- @field EMBEDDED (string)
--- The tag name for embedded elements.
--- @field FUNCTION_BUILTIN (string)
--- The tag name for builtin function elements.
--- @field CONSTANT_BUILTIN (string)
--- The tag name for builtin constant elements.
--- @field FUNCTION_METHOD (string)
--- The tag name for function method elements.
--- @field TAG (string)
--- The tag name for function tag elements, typically in markup.
--- @field ATTRIBUTE (string)
--- The tag name for function attribute elements, typically in markup.
--- @field VARIABLE_BUILTIN (string)
--- The tag name for builtin variable elements.
--- @field HEADING (string)
--- The tag name for heading elements, typically in markup.
--- @field BOLD (string)
--- The tag name for bold elements, typically in markup.
--- @field ITALIC (string)
--- The tag name for builtin italic elements, typically in markup.
--- @field UNDERLINE (string)
--- The tag name for underlined elements, typically in markup.
--- @field CODE (string)
--- The tag name for code elements, typically in markup.
--- @field LINK (string)
--- The tag name for link elements, typically in markup.
--- @field REFERENCE (string)
--- The tag name for reference elements, typically in markup.
--- @field ANNOTATION (string)
--- The tag name for annotation elements.
--- @field LIST (string)
--- The tag name for list item elements, typically in markup.
+-- The token name for regex tokens.
-- @field any (pattern)
-- A pattern that matches any single character.
+-- @field ascii (pattern)
+-- A pattern that matches any ASCII character (codes 0 to 127).
+-- @field extend (pattern)
+-- A pattern that matches any ASCII extended character (codes 0 to 255).
-- @field alpha (pattern)
-- A pattern that matches any alphabetic character ('A'-'Z', 'a'-'z').
-- @field digit (pattern)
@@ -751,8 +718,12 @@
-- A pattern that matches any upper case character ('A'-'Z').
-- @field xdigit (pattern)
-- A pattern that matches any hexadecimal digit ('0'-'9', 'A'-'F', 'a'-'f').
+-- @field cntrl (pattern)
+-- A pattern that matches any control character (ASCII codes 0 to 31).
-- @field graph (pattern)
-- A pattern that matches any graphical character ('!' to '~').
+-- @field print (pattern)
+-- A pattern that matches any printable character (' ' to '~').
-- @field punct (pattern)
-- A pattern that matches any punctuation character ('!' to '/', ':' to '@', '[' to ''',
-- '{' to '~').
@@ -768,15 +739,13 @@
-- A pattern that matches a hexadecimal number.
-- @field oct_num (pattern)
-- A pattern that matches an octal number.
--- @field bin_num (pattern)
--- A pattern that matches a binary number.
-- @field integer (pattern)
--- A pattern that matches either a decimal, hexadecimal, octal, or binary number.
+-- A pattern that matches either a decimal, hexadecimal, or octal number.
-- @field float (pattern)
-- A pattern that matches a floating point number.
-- @field number (pattern)
-- A pattern that matches a typical number, either a floating point, decimal, hexadecimal,
--- octal, or binary number.
+-- or octal number.
-- @field word (pattern)
-- A pattern that matches a typical word. Words begin with a letter or underscore and consist
-- of alphanumeric and underscore characters.
@@ -786,195 +755,226 @@
-- Flag indicating that the line is blank.
-- @field FOLD_HEADER (number)
-- Flag indicating the line is fold point.
+-- @field fold_level (table, Read-only)
+-- Table of fold level bit-masks for line numbers starting from 1.
+-- Fold level masks are composed of an integer level combined with any of the following bits:
+--
+-- * `lexer.FOLD_BASE`
+-- The initial fold level.
+-- * `lexer.FOLD_BLANK`
+-- The line is blank.
+-- * `lexer.FOLD_HEADER`
+-- The line is a header, or fold point.
+-- @field indent_amount (table, Read-only)
+-- Table of indentation amounts in character columns, for line numbers starting from 1.
+-- @field line_state (table)
+-- Table of integer line states for line numbers starting from 1.
+-- Line states can be used by lexers for keeping track of persistent states.
+-- @field property (table)
+-- Map of key-value string pairs.
+-- @field property_expanded (table, Read-only)
+-- Map of key-value string pairs with `$()` and `%()` variable replacement performed in values.
+-- @field property_int (table, Read-only)
+-- Map of key-value pairs with values interpreted as numbers, or `0` if not found.
+-- @field style_at (table, Read-only)
+-- Table of style names at positions in the buffer starting from 1.
+-- @field folding (boolean)
+-- Whether or not folding is enabled for the lexers that support it.
+-- This option is disabled by default.
+-- This is an alias for `lexer.property['fold'] = '1|0'`.
+-- @field fold_on_zero_sum_lines (boolean)
+-- Whether or not to mark as a fold point lines that contain both an ending and starting fold
+-- point. For example, `} else {` would be marked as a fold point.
+-- This option is disabled by default. This is an alias for
+-- `lexer.property['fold.on.zero.sum.lines'] = '1|0'`.
+-- @field fold_compact (boolean)
+-- Whether or not blank lines after an ending fold point are included in that
+-- fold.
+-- This option is disabled by default.
+-- This is an alias for `lexer.property['fold.compact'] = '1|0'`.
+-- @field fold_by_indentation (boolean)
+-- Whether or not to fold based on indentation level if a lexer does not have
+-- a folder.
+-- Some lexers automatically enable this option. It is disabled by default.
+-- This is an alias for `lexer.property['fold.by.indentation'] = '1|0'`.
+-- @field fold_line_groups (boolean)
+-- Whether or not to fold multiple, consecutive line groups (such as line comments and import
+-- statements) and only show the top line.
+-- This option is disabled by default.
+-- This is an alias for `lexer.property['fold.line.groups'] = '1|0'`.
module('lexer')]=]
-local lpeg = _G.lpeg or require('lpeg') -- Scintillua's Lua environment defines _G.lpeg
-local P, R, S, V, B = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.B
-local Ct, Cc, Cp, Cmt, C = lpeg.Ct, lpeg.Cc, lpeg.Cp, lpeg.Cmt, lpeg.C
+if not require then
+ -- Substitute for Lua's require() function, which does not require the package module to
+ -- be loaded.
+ -- Note: all modules must be in the global namespace, which is the case in LexerLPeg's default
+ -- Lua State.
+ function require(name) return name == 'lexer' and M or _G[name] end
+end
+
+local print = function(...)
+ local args = table.pack(...)
+ local msg = {}
+ for i = 1, args.n do
+ msg[#msg + 1] = tostring(args[i])
+ end
+ vis:info(table.concat(msg, ' '))
+end
+
+lpeg = require('lpeg')
+local lpeg_P, lpeg_R, lpeg_S, lpeg_V = lpeg.P, lpeg.R, lpeg.S, lpeg.V
+local lpeg_Ct, lpeg_Cc, lpeg_Cp = lpeg.Ct, lpeg.Cc, lpeg.Cp
+local lpeg_Cmt, lpeg_C = lpeg.Cmt, lpeg.C
+local lpeg_match = lpeg.match
--- Default tags.
-local default = {
- 'whitespace', 'comment', 'string', 'number', 'keyword', 'identifier', 'operator', 'error',
- 'preprocessor', 'constant', 'variable', 'function', 'class', 'type', 'label', 'regex', 'embedded',
- 'function.builtin', 'constant.builtin', 'function.method', 'tag', 'attribute', 'variable.builtin',
- 'heading', 'bold', 'italic', 'underline', 'code', 'link', 'reference', 'annotation', 'list'
-}
-for _, name in ipairs(default) do M[name:upper():gsub('%.', '_')] = name end
--- Names for predefined Scintilla styles.
--- Having these here simplifies style number handling between Scintillua and Scintilla.
-local predefined = {
- 'default', 'line.number', 'brace.light', 'brace.bad', 'control.char', 'indent.guide', 'call.tip',
- 'fold.display.text'
-}
-for _, name in ipairs(predefined) do M[name:upper():gsub('%.', '_')] = name end
-
----
--- Creates and returns a pattern that tags pattern *patt* with name *name* in lexer *lexer*.
--- If *name* is not a predefined tag name, its Scintilla style will likely need to be defined
--- by the editor or theme using this lexer.
--- @param lexer The lexer to tag the given pattern in.
--- @param name The name to use.
--- @param patt The LPeg pattern to tag.
--- @return pattern
--- @usage local number = lex:tag(lexer.NUMBER, lexer.number)
--- @usage local addition = lex:tag('addition', '+' * lexer.word)
--- @name tag
-function M.tag(lexer, name, patt)
- if not lexer._TAGS then
- -- Create the initial maps for tag names to style numbers and styles.
- local tags = {}
- for i = 1, #default do tags[default[i]] = i end
- for i = 1, #predefined do tags[predefined[i]] = i + 32 end
- lexer._TAGS, lexer._num_styles = tags, #default + 1
- lexer._extra_tags = {}
- end
- if not assert(lexer._TAGS, 'not a lexer instance')[name] then
- local num_styles = lexer._num_styles
- if num_styles == 33 then num_styles = num_styles + 8 end -- skip predefined
- assert(num_styles <= 256, 'too many styles defined (256 MAX)')
- lexer._TAGS[name], lexer._num_styles = num_styles, num_styles + 1
- lexer._extra_tags[name] = true
- -- If the lexer is a proxy or a child that embedded itself, make this tag name known to
- -- the parent lexer.
- if lexer._lexer then lexer._lexer:tag(name, false) end
+-- Searches for the given *name* in the given *path*.
+-- This is a safe implementation of Lua 5.2's `package.searchpath()` function that does not
+-- require the package module to be loaded.
+local function searchpath(name, path)
+ local tried = {}
+ for part in path:gmatch('[^;]+') do
+ local filename = part:gsub('%?', name)
+ local ok, errmsg = loadfile(filename)
+ if ok or not errmsg:find('cannot open') then return filename end
+ tried[#tried + 1] = string.format("no file '%s'", filename)
end
- return Cc(name) * (P(patt) / 0) * Cp()
+ return nil, table.concat(tried, '\n')
end
--- Returns a unique grammar rule name for the given lexer's i-th word list.
-local function word_list_id(lexer, i) return lexer._name .. '_wordlist' .. i end
-
---
--- Either returns a pattern for lexer *lexer* (if given) that matches one word in the word list
--- identified by string *word_list*, ignoring case if *case_sensitive* is `true`, or, if *lexer*
--- is not given, creates and returns a pattern that matches any single word in list or string
--- *word_list*, ignoring case if *case_insensitive* is `true`.
--- This is a convenience function for simplifying a set of ordered choice word patterns and
--- potentially allowing downstream users to configure word lists.
--- If there is ultimately no word list set via `set_word_list()`, no error will be raised,
--- but the returned pattern will not match anything.
--- @param lexer Optional lexer to match a word in a wordlist for. This parameter may be omitted
--- for lexer-agnostic matching.
--- @param word_list Either a string name of the word list to match from if *lexer* is given,
--- or, if *lexer* is omitted, a list of words or a string list of words separated by spaces.
--- @param case_insensitive Optional boolean flag indicating whether or not the word match is
--- case-insensitive. The default value is `false`.
--- @return pattern
--- @usage lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
--- @usage local keyword = lex:tag(lexer.KEYWORD, lexer.word_match{'foo', 'bar', 'baz'})
--- @usage local keyword = lex:tag(lexer.KEYWORD, lexer.word_match({'foo-bar', 'foo-baz',
--- 'bar-foo', 'bar-baz', 'baz-foo', 'baz-bar'}, true))
--- @usage local keyword = lex:tag(lexer.KEYWORD, lexer.word_match('foo bar baz'))
--- @see set_word_list
--- @name word_match
-function M.word_match(lexer, word_list, case_insensitive)
- if type(lexer) == 'table' and getmetatable(lexer) then
- if lexer._lexer then
- -- If this lexer is a proxy (e.g. rails), get the true parent (ruby) in order to get the
- -- parent's word list. If this lexer is a child embedding itself (e.g. php), continue
- -- getting its word list, not the parent's (html).
- local parent = lexer._lexer
- if not parent._CHILDREN or not parent._CHILDREN[lexer] then lexer = parent end
- end
-
- if not lexer._WORDLISTS then lexer._WORDLISTS = {case_insensitive = {}} end
- local i = lexer._WORDLISTS[word_list] or #lexer._WORDLISTS + 1
- lexer._WORDLISTS[word_list], lexer._WORDLISTS[i] = i, '' -- empty placeholder word list
- lexer._WORDLISTS.case_insensitive[i] = case_insensitive
- return V(word_list_id(lexer, i))
- end
-
- -- Lexer-agnostic word match.
- word_list, case_insensitive = lexer, word_list
-
- if type(word_list) == 'string' then
- local words = word_list -- space-separated list of words
- word_list = {}
- for word in words:gmatch('%S+') do word_list[#word_list + 1] = word end
- end
+-- Map of color name strings to color values in `0xBBGGRR` or `"#RRGGBB"` format.
+-- Note: for applications running within a terminal emulator, only 16 color values are recognized,
+-- regardless of how many colors a user's terminal actually supports. (A terminal emulator's
+-- settings determines how to actually display these recognized color values, which may end up
+-- being mapped to a completely different color set.) In order to use the light variant of a
+-- color, some terminals require a style's `bold` attribute must be set along with that normal
+-- color. Recognized color values are black (0x000000), red (0x000080), green (0x008000), yellow
+-- (0x008080), blue (0x800000), magenta (0x800080), cyan (0x808000), white (0xC0C0C0), light black
+-- (0x404040), light red (0x0000FF), light green (0x00FF00), light yellow (0x00FFFF), light blue
+-- (0xFF0000), light magenta (0xFF00FF), light cyan (0xFFFF00), and light white (0xFFFFFF).
+-- @name colors
+-- @class table
+M.colors = setmetatable({}, {
+ __index = function(_, name)
+ local color = M.property['color.' .. name]
+ return tonumber(color) or color
+ end, __newindex = function(_, name, color) M.property['color.' .. name] = color end
+})
- local word_chars = M.alnum + '_'
- local extra_chars = ''
- for _, word in ipairs(word_list) do
- word_list[case_insensitive and word:lower() or word] = true
- for char in word:gmatch('[^%w_%s]') do
- if not extra_chars:find(char, 1, true) then extra_chars = extra_chars .. char end
+-- A style object that distills into a property string that can be read by the LPeg lexer.
+local style_obj = {}
+style_obj.__index = style_obj
+
+-- Create a style object from a style name, property table, or legacy style string.
+function style_obj.new(name_or_props)
+ local prop_string = tostring(name_or_props)
+ if type(name_or_props) == 'string' and name_or_props:find('^[%w_]+$') then
+ prop_string = string.format('$(style.%s)', name_or_props)
+ elseif type(name_or_props) == 'table' then
+ local settings = {}
+ for k, v in pairs(name_or_props) do
+ settings[#settings + 1] = type(v) ~= 'boolean' and string.format('%s:%s', k, v) or
+ string.format('%s%s', v and '' or 'not', k)
end
+ prop_string = table.concat(settings, ',')
end
- if extra_chars ~= '' then word_chars = word_chars + S(extra_chars) end
-
- -- Optimize small word sets as ordered choice. "Small" is arbitrary.
- if #word_list <= 6 and not case_insensitive then
- local choice = P(false)
- for _, word in ipairs(word_list) do choice = choice + word:match('%S+') end
- return choice * -word_chars
- end
-
- return Cmt(word_chars^1, function(input, index, word)
- if case_insensitive then word = word:lower() end
- return word_list[word]
- end)
+ return setmetatable({prop_string = prop_string}, style_obj)
end
----
--- Sets in lexer *lexer* the word list identified by string or number *name* to string or
--- list *word_list*, appending to any existing word list if *append* is `true`.
--- This only has an effect if *lexer* uses `word_match()` to reference the given list.
--- Case-insensitivity is specified by `word_match()`.
--- @param lexer The lexer to add the given word list to.
--- @param name The string name or number of the word list to set.
--- @param word_list A list of words or a string list of words separated by spaces.
--- @param append Whether or not to append *word_list* to the existing word list (if any). The
+-- Returns a new style based on this one with the properties defined in the given table or
+-- legacy style string.
+function style_obj.__concat(self, props)
+ if type(props) == 'table' then props = tostring(style_obj.new(props)) end
+ return setmetatable({prop_string = string.format('%s,%s', self.prop_string, props)}, style_obj)
+end
+
+-- Returns this style object as property string for use with the LPeg lexer.
+function style_obj.__tostring(self) return self.prop_string end
+
+---
+-- Map of style names to style definition tables.
+--
+-- Style names consist of the following default names as well as the token names defined by lexers.
+--
+-- * `default`: The default style all others are based on.
+-- * `line_number`: The line number margin style.
+-- * `control_char`: The style of control character blocks.
+-- * `indent_guide`: The style of indentation guides.
+-- * `call_tip`: The style of call tip text. Only the `font`, `size`, `fore`, and `back` style
+-- definition fields are supported.
+-- * `fold_display_text`: The style of text displayed next to folded lines.
+-- * `class`, `comment`, `constant`, `embedded`, `error`, `function`, `identifier`, `keyword`,
+-- `label`, `number`, `operator`, `preprocessor`, `regex`, `string`, `type`, `variable`,
+-- `whitespace`: Some token names used by lexers. Some lexers may define more token names,
+-- so this list is not exhaustive.
+-- * *`lang`*`_whitespace`: A special style for whitespace tokens in lexer name *lang*. It
+-- inherits from `whitespace`, and is used in place of it for all lexers.
+--
+-- Style definition tables may contain the following fields:
+--
+-- * `font`: String font name.
+-- * `size`: Integer font size.
+-- * `bold`: Whether or not the font face is bold. The default value is `false`.
+-- * `weight`: Integer weight or boldness of a font, between 1 and 999.
+-- * `italics`: Whether or not the font face is italic. The default value is `false`.
+-- * `underlined`: Whether or not the font face is underlined. The default value is `false`.
+-- * `fore`: Font face foreground color in `0xBBGGRR` or `"#RRGGBB"` format.
+-- * `back`: Font face background color in `0xBBGGRR` or `"#RRGGBB"` format.
+-- * `eolfilled`: Whether or not the background color extends to the end of the line. The
-- default value is `false`.
--- @see word_match
--- @name set_word_list
-function M.set_word_list(lexer, name, word_list, append)
- if word_list == 'scintillua' then return end -- for SciTE
- if lexer._lexer then
- -- If this lexer is a proxy (e.g. rails), get the true parent (ruby) in order to set the
- -- parent's word list. If this lexer is a child embedding itself (e.g. php), continue
- -- setting its word list, not the parent's (html).
- local parent = lexer._lexer
- if not parent._CHILDREN or not parent._CHILDREN[lexer] then lexer = parent end
- end
-
- assert(lexer._WORDLISTS, 'lexer has no word lists')
- local i = tonumber(lexer._WORDLISTS[name]) or name -- lexer._WORDLISTS[name] --> i
- if type(i) ~= 'number' or i > #lexer._WORDLISTS then return end -- silently return
-
- if type(word_list) == 'string' then
- local list = {}
- for word in word_list:gmatch('%S+') do list[#list + 1] = word end
- word_list = list
- end
-
- if not append or lexer._WORDLISTS[i] == '' then
- lexer._WORDLISTS[i] = word_list
- else
- local list = lexer._WORDLISTS[i]
- for _, word in ipairs(word_list) do list[#list + 1] = word end
+-- * `case`: Font case: `'u'` for upper, `'l'` for lower, and `'m'` for normal, mixed case. The
+-- default value is `'m'`.
+-- * `visible`: Whether or not the text is visible. The default value is `true`.
+-- * `changeable`: Whether the text is changeable instead of read-only. The default value is
+-- `true`.
+-- @class table
+-- @name styles
+M.styles = setmetatable({}, {
+ __index = function(_, name) return style_obj.new(name) end, __newindex = function(_, name, style)
+ if getmetatable(style) ~= style_obj then style = style_obj.new(style) end
+ M.property['style.' .. name] = tostring(style)
end
+})
- lexer._grammar_table = nil -- invalidate
+-- Default styles.
+local default = {
+ 'nothing', 'whitespace', 'comment', 'string', 'number', 'keyword', 'identifier', 'operator',
+ 'error', 'preprocessor', 'constant', 'variable', 'function', 'class', 'type', 'label', 'regex',
+ 'embedded'
+}
+for _, name in ipairs(default) do
+ M[name:upper()] = name
+ M['STYLE_' .. name:upper()] = style_obj.new(name) -- backward compatibility
+end
+-- Predefined styles.
+local predefined = {
+ 'default', 'line_number', 'brace_light', 'brace_bad', 'control_char', 'indent_guide', 'call_tip',
+ 'fold_display_text'
+}
+for _, name in ipairs(predefined) do
+ M[name:upper()] = name
+ M['STYLE_' .. name:upper()] = style_obj.new(name) -- backward compatibility
end
---
-- Adds pattern *rule* identified by string *id* to the ordered list of rules for lexer *lexer*.
-- @param lexer The lexer to add the given rule to.
-- @param id The id associated with this rule. It does not have to be the same as the name
--- passed to `tag()`.
+-- passed to `token()`.
-- @param rule The LPeg pattern of the rule.
-- @see modify_rule
-- @name add_rule
function M.add_rule(lexer, id, rule)
if lexer._lexer then lexer = lexer._lexer end -- proxy; get true parent
- if not lexer._rules then lexer._rules = {} end
- if id == 'whitespace' and lexer._rules[id] then -- legacy
- lexer:modify_rule(id, rule)
- return
- end
- lexer._rules[#lexer._rules + 1], lexer._rules[id] = id, rule
- lexer._grammar_table = nil -- invalidate
+ if not lexer._RULES then
+ lexer._RULES = {}
+ -- Contains an ordered list (by numerical index) of rule names. This is used in conjunction
+ -- with lexer._RULES for building _TOKENRULE.
+ lexer._RULEORDER = {}
+ end
+ lexer._RULES[id] = rule
+ lexer._RULEORDER[#lexer._RULEORDER + 1] = id
+ lexer:build_grammar()
end
---
@@ -985,14 +985,10 @@
-- @name modify_rule
function M.modify_rule(lexer, id, rule)
if lexer._lexer then lexer = lexer._lexer end -- proxy; get true parent
- assert(lexer._rules[id], 'rule does not exist')
- lexer._rules[id] = rule
- lexer._grammar_table = nil -- invalidate
+ lexer._RULES[id] = rule
+ lexer:build_grammar()
end
--- Returns a unique grammar rule name for the given lexer's rule name.
-local function rule_id(lexer, name) return lexer._name .. '.' .. name end
-
---
-- Returns the rule identified by string *id*.
-- @param lexer The lexer to fetch a rule from.
@@ -1001,60 +997,52 @@
-- @name get_rule
function M.get_rule(lexer, id)
if lexer._lexer then lexer = lexer._lexer end -- proxy; get true parent
- if id == 'whitespace' then return V(rule_id(lexer, id)) end -- special case
- return assert(lexer._rules[id], 'rule does not exist')
+ return lexer._RULES[id]
end
---
--- Embeds child lexer *child* in parent lexer *lexer* using patterns *start_rule* and *end_rule*,
--- which signal the beginning and end of the embedded lexer, respectively.
--- @param lexer The parent lexer.
--- @param child The child lexer.
--- @param start_rule The pattern that signals the beginning of the embedded lexer.
--- @param end_rule The pattern that signals the end of the embedded lexer.
--- @usage html:embed(css, css_start_rule, css_end_rule)
--- @usage html:embed(lex, php_start_rule, php_end_rule) -- from php lexer
--- @name embed
-function M.embed(lexer, child, start_rule, end_rule)
- if lexer._lexer then lexer = lexer._lexer end -- proxy; get true parent
-
- -- Add child rules.
- assert(child._rules, 'cannot embed lexer with no rules')
- if not child._start_rules then child._start_rules = {} end
- if not child._end_rules then child._end_rules = {} end
- child._start_rules[lexer], child._end_rules[lexer] = start_rule, end_rule
- if not lexer._CHILDREN then lexer._CHILDREN = {} end
- lexer._CHILDREN[#lexer._CHILDREN + 1], lexer._CHILDREN[child] = child, true
-
- -- Add child tags.
- for name in pairs(child._extra_tags) do lexer:tag(name, true) end
-
- -- Add child fold symbols.
- if child._fold_points then
- for tag_name, symbols in pairs(child._fold_points) do
- if tag_name ~= '_symbols' then
- for symbol, v in pairs(symbols) do lexer:add_fold_point(tag_name, symbol, v) end
- end
- end
- end
-
- -- Add child word lists.
- if child._WORDLISTS then
- for name, i in pairs(child._WORDLISTS) do
- if type(name) == 'string' and type(i) == 'number' then
- name = child._name .. '.' .. name
- lexer:word_match(name) -- for side effects
- lexer:set_word_list(name, child._WORDLISTS[i])
- end
- end
- end
-
- child._lexer = lexer -- use parent's rules if child is embedding itself
+-- Associates string *token_name* in lexer *lexer* with style table *style*.
+-- *style* may have the following fields:
+--
+-- * `font`: String font name.
+-- * `size`: Integer font size.
+-- * `bold`: Whether or not the font face is bold. The default value is `false`.
+-- * `weight`: Integer weight or boldness of a font, between 1 and 999.
+-- * `italics`: Whether or not the font face is italic. The default value is `false`.
+-- * `underlined`: Whether or not the font face is underlined. The default value is `false`.
+-- * `fore`: Font face foreground color in `0xBBGGRR` or `"#RRGGBB"` format.
+-- * `back`: Font face background color in `0xBBGGRR` or `"#RRGGBB"` format.
+-- * `eolfilled`: Whether or not the background color extends to the end of the line. The
+-- default value is `false`.
+-- * `case`: Font case, `'u'` for upper, `'l'` for lower, and `'m'` for normal, mixed case. The
+-- default value is `'m'`.
+-- * `visible`: Whether or not the text is visible. The default value is `true`.
+-- * `changeable`: Whether the text is changeable instead of read-only. The default value is
+-- `true`.
+--
+-- Field values may also contain "$(property.name)" expansions for properties defined in Scintilla,
+-- theme files, etc.
+-- @param lexer The lexer to add a style to.
+-- @param token_name The name of the token to associated with the style.
+-- @param style A style string for Scintilla.
+-- @usage lex:add_style('longstring', lexer.styles.string)
+-- @usage lex:add_style('deprecated_func', lexer.styles['function'] .. {italics = true}
+-- @usage lex:add_style('visible_ws', lexer.styles.whitespace .. {back = lexer.colors.grey}
+-- @name add_style
+function M.add_style(lexer, token_name, style)
+ local num_styles = lexer._numstyles
+ if num_styles == 33 then num_styles = num_styles + 8 end -- skip predefined
+ if num_styles >= 256 then print('Too many styles defined (256 MAX)') end
+ lexer._TOKENSTYLES[token_name], lexer._numstyles = num_styles, num_styles + 1
+ if type(style) == 'table' and not getmetatable(style) then style = style_obj.new(style) end
+ lexer._EXTRASTYLES[token_name] = tostring(style)
+ -- If the lexer is a proxy or a child that embedded itself, copy this style to the parent lexer.
+ if lexer._lexer then lexer._lexer:add_style(token_name, style) end
end
---
--- Adds to lexer *lexer* a fold point whose beginning and end points are tagged with string
--- *tag_name* tags and have string content *start_symbol* and *end_symbol*, respectively.
+-- Adds to lexer *lexer* a fold point whose beginning and end tokens are string *token_name*
+-- tokens with string content *start_symbol* and *end_symbol*, respectively.
-- In the event that *start_symbol* may or may not be a fold point depending on context, and that
-- additional processing is required, *end_symbol* may be a function that ultimately returns
-- `1` (indicating a beginning fold point), `-1` (indicating an ending fold point), or `0`
@@ -1066,252 +1054,203 @@
-- * `s`: The position of *start_symbol* in *line*.
-- * `symbol`: *start_symbol* itself.
-- @param lexer The lexer to add a fold point to.
--- @param tag_name The tag name for text that indicates a fold point.
+-- @param token_name The token name of text that indicates a fold point.
-- @param start_symbol The text that indicates the beginning of a fold point.
-- @param end_symbol Either the text that indicates the end of a fold point, or a function that
-- returns whether or not *start_symbol* is a beginning fold point (1), an ending fold point
-- (-1), or not a fold point at all (0).
-- @usage lex:add_fold_point(lexer.OPERATOR, '{', '}')
-- @usage lex:add_fold_point(lexer.KEYWORD, 'if', 'end')
+-- @usage lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
-- @usage lex:add_fold_point('custom', function(text, pos, line, s, symbol) ... end)
-- @name add_fold_point
-function M.add_fold_point(lexer, tag_name, start_symbol, end_symbol)
- if not lexer._fold_points then lexer._fold_points = {_symbols = {}} end
- local symbols = lexer._fold_points._symbols
- if not lexer._fold_points[tag_name] then lexer._fold_points[tag_name] = {} end
- if lexer._case_insensitive_fold_points then
+function M.add_fold_point(lexer, token_name, start_symbol, end_symbol)
+ if not lexer._FOLDPOINTS then lexer._FOLDPOINTS = {_SYMBOLS = {}} end
+ local symbols = lexer._FOLDPOINTS._SYMBOLS
+ if not lexer._FOLDPOINTS[token_name] then lexer._FOLDPOINTS[token_name] = {} end
+ if lexer._CASEINSENSITIVEFOLDPOINTS then
start_symbol = start_symbol:lower()
if type(end_symbol) == 'string' then end_symbol = end_symbol:lower() end
end
-
if type(end_symbol) == 'string' then
if not symbols[end_symbol] then symbols[#symbols + 1], symbols[end_symbol] = end_symbol, true end
- lexer._fold_points[tag_name][start_symbol] = 1
- lexer._fold_points[tag_name][end_symbol] = -1
+ lexer._FOLDPOINTS[token_name][start_symbol] = 1
+ lexer._FOLDPOINTS[token_name][end_symbol] = -1
else
- lexer._fold_points[tag_name][start_symbol] = end_symbol -- function or int
+ lexer._FOLDPOINTS[token_name][start_symbol] = end_symbol -- function or int
end
if not symbols[start_symbol] then
symbols[#symbols + 1], symbols[start_symbol] = start_symbol, true
end
-
-- If the lexer is a proxy or a child that embedded itself, copy this fold point to the
-- parent lexer.
- if lexer._lexer then lexer._lexer:add_fold_point(tag_name, start_symbol, end_symbol) end
+ if lexer._lexer then lexer._lexer:add_fold_point(token_name, start_symbol, end_symbol) end
end
--- Recursively adds the rules for the given lexer and its children to the given grammar.
--- @param g The grammar to add rules to.
--- @param lexer The lexer whose rules to add.
-local function add_lexer(g, lexer)
- local rule = P(false)
-
- -- Add this lexer's rules.
- for _, name in ipairs(lexer._rules) do
- local id = rule_id(lexer, name)
- g[id] = lexer._rules[name] -- ['lua.keyword'] = keyword_patt
- rule = rule + V(id) -- V('lua.keyword') + V('lua.function') + V('lua.constant') + ...
- end
- local any_id = lexer._name .. '_fallback'
- g[any_id] = lexer:tag(M.DEFAULT, M.any) -- ['lua_fallback'] = any_char
- rule = rule + V(any_id) -- ... + V('lua.operator') + V('lua_fallback')
-
- -- Add this lexer's word lists.
- if lexer._WORDLISTS then
- for i = 1, #lexer._WORDLISTS do
- local id = word_list_id(lexer, i)
- local list, case_insensitive = lexer._WORDLISTS[i], lexer._WORDLISTS.case_insensitive[i]
- local patt = list ~= '' and M.word_match(list, case_insensitive) or P(false)
- g[id] = patt -- ['lua_wordlist.1'] = word_match_patt or P(false)
- end
- end
-
- -- Add this child lexer's end rules.
- if lexer._end_rules then
- for parent, end_rule in pairs(lexer._end_rules) do
- local back_id = lexer._name .. '_to_' .. parent._name
- g[back_id] = end_rule -- ['css_to_html'] = css_end_rule
- rule = rule - V(back_id) + -- (V('css.property') + ... + V('css_fallback')) - V('css_to_html')
- V(back_id) * V(parent._name) -- V('css_to_html') * V('html')
- end
- end
-
- -- Add this child lexer's start rules.
- if lexer._start_rules then
- for parent, start_rule in pairs(lexer._start_rules) do
- local to_id = parent._name .. '_to_' .. lexer._name
- g[to_id] = start_rule * V(lexer._name) -- ['html_to_css'] = css_start_rule * V('css')
+-- (Re)constructs `lexer._TOKENRULE`.
+local function join_tokens(lexer)
+ local patterns, order = lexer._RULES, lexer._RULEORDER
+ local token_rule = patterns[order[1]]
+ for i = 2, #order do token_rule = token_rule + patterns[order[i]] end
+ lexer._TOKENRULE = token_rule + M.token(M.DEFAULT, M.any)
+ return lexer._TOKENRULE
+end
+
+-- Metatable for Scintillua grammars.
+-- These grammars are just tables ultimately passed to `lpeg.P()`.
+local grammar_mt = {
+ __index = {
+ -- Adds lexer *lexer* and any of its embedded lexers to this grammar.
+ -- @param lexer The lexer to add.
+ add_lexer = function(self, lexer)
+ local lexer_name = lexer._PARENTNAME or lexer._NAME
+ local token_rule = lexer:join_tokens()
+ for _, child in ipairs(lexer._CHILDREN) do
+ if child._CHILDREN then self:add_lexer(child) end
+ local rules = child._EMBEDDEDRULES[lexer_name]
+ local rules_token_rule = self['__' .. child._NAME] or rules.token_rule
+ self[child._NAME] = (-rules.end_rule * rules_token_rule)^0 * rules.end_rule^-1 *
+ lpeg_V(lexer_name)
+ local embedded_child = '_' .. child._NAME
+ self[embedded_child] = rules.start_rule * (-rules.end_rule * rules_token_rule)^0 *
+ rules.end_rule^-1
+ token_rule = lpeg_V(embedded_child) + token_rule
+ end
+ self['__' .. lexer_name] = token_rule -- can contain embedded lexer rules
+ self[lexer_name] = token_rule^0
end
- end
+ }
+}
- -- Finish adding this lexer's rules.
- local rule_id = lexer._name .. '_rule'
- g[rule_id] = rule -- ['lua_rule'] = V('lua.keyword') + ... + V('lua_fallback')
- g[lexer._name] = V(rule_id)^0 -- ['lua'] = V('lua_rule')^0
-
- -- Add this lexer's children's rules.
- -- TODO: preprocessor languages like PHP should also embed themselves into their parent's
- -- children like HTML's CSS and Javascript.
- if not lexer._CHILDREN then return end
- for _, child in ipairs(lexer._CHILDREN) do
- add_lexer(g, child)
- local to_id = lexer._name .. '_to_' .. child._name
- g[rule_id] = V(to_id) + g[rule_id] -- ['html_rule'] = V('html_to_css') + V('html.comment') + ...
-
- -- Add a child's inherited parent's rules (e.g. rhtml parent with rails child inheriting ruby).
- if child._parent_name then
- local name = child._name
- child._name = child._parent_name -- ensure parent and transition rule names are correct
- add_lexer(g, child)
- child._name = name -- restore
- local to_id = lexer._name .. '_to_' .. child._parent_name
- g[rule_id] = V(to_id) + g[rule_id] -- ['html_rule'] = V('html_to_ruby') + V('html.comment') + ...
- end
+-- (Re)constructs `lexer._GRAMMAR`.
+-- @param initial_rule The name of the rule to start lexing with. The default value is
+-- `lexer._NAME`. Multilang lexers use this to start with a child rule if necessary.
+local function build_grammar(lexer, initial_rule)
+ if not lexer._RULES then return end
+ if lexer._CHILDREN then
+ if not initial_rule then initial_rule = lexer._NAME end
+ local grammar = setmetatable({initial_rule}, grammar_mt)
+ grammar:add_lexer(lexer)
+ lexer._INITIALRULE = initial_rule
+ lexer._GRAMMAR = lpeg_Ct(lpeg_P(grammar))
+ else
+ lexer._GRAMMAR = lpeg_Ct(lexer:join_tokens()^0)
end
end
--- Returns a grammar for the given lexer and initial rule, (re)constructing it if necessary.
--- @param lexer The lexer to build a grammar for.
--- @param init_style The current style. Multiple-language lexers use this to determine which
--- language to start lexing in.
-local function build_grammar(lexer, init_style)
- if not lexer._rules then return end
- if not lexer._initial_rule then lexer._initial_rule = lexer._parent_name or lexer._name end
- if not lexer._grammar_table then
- local grammar = {lexer._initial_rule}
- if not lexer._parent_name then
- add_lexer(grammar, lexer)
- -- {'lua',
- -- ['lua.keyword'] = patt, ['lua.function'] = patt, ...,
- -- ['lua_wordlist.1'] = patt, ['lua_wordlist.2'] = patt, ...,
- -- ['lua_rule'] = V('lua.keyword') + ... + V('lua_fallback'),
- -- ['lua'] = V('lua_rule')^0
- -- }
- -- {'html'
- -- ['html.comment'] = patt, ['html.doctype'] = patt, ...,
- -- ['html_wordlist.1'] = patt, ['html_wordlist.2'] = patt, ...,
- -- ['html_rule'] = V('html_to_css') * V('css') + V('html.comment') + ... + V('html_fallback'),
- -- ['html'] = V('html')^0,
- -- ['css.property'] = patt, ['css.value'] = patt, ...,
- -- ['css_wordlist.1'] = patt, ['css_wordlist.2'] = patt, ...,
- -- ['css_to_html'] = patt,
- -- ['css_rule'] = ((V('css.property') + ... + V('css_fallback')) - V('css_to_html')) +
- -- V('css_to_html') * V('html'),
- -- ['html_to_css'] = patt,
- -- ['css'] = V('css_rule')^0
- -- }
- else
- local name = lexer._name
- lexer._name = lexer._parent_name -- ensure parent and transition rule names are correct
- add_lexer(grammar, lexer)
- lexer._name = name -- restore
- -- {'html',
- -- ...
- -- ['html_rule'] = V('html_to_php') * V('php') + V('html_to_css') * V('css') +
- -- V('html.comment') + ... + V('html_fallback'),
- -- ...
- -- ['php.keyword'] = patt, ['php.type'] = patt, ...,
- -- ['php_wordlist.1'] = patt, ['php_wordlist.2'] = patt, ...,
- -- ['php_to_html'] = patt,
- -- ['php_rule'] = ((V('php.keyword') + ... + V('php_fallback')) - V('php_to_html')) +
- -- V('php_to_html') * V('html')
- -- ['html_to_php'] = patt,
- -- ['php'] = V('php_rule')^0
- -- }
- end
- lexer._grammar, lexer._grammar_table = Ct(P(grammar)), grammar
- end
-
- -- For multilang lexers, build a new grammar whose initial rule is the current language
- -- if necessary. LPeg does not allow a variable initial rule.
- if lexer._CHILDREN then
- for tag, style_num in pairs(lexer._TAGS) do
- if style_num == init_style then
- local lexer_name = tag:match('^whitespace%.(.+)$') or lexer._parent_name or lexer._name
- if lexer._initial_rule == lexer_name then break end
- lexer._initial_rule = lexer_name
- lexer._grammar_table[1] = lexer._initial_rule
- lexer._grammar = Ct(P(lexer._grammar_table))
- return lexer._grammar
+---
+-- Embeds child lexer *child* in parent lexer *lexer* using patterns *start_rule* and *end_rule*,
+-- which signal the beginning and end of the embedded lexer, respectively.
+-- @param lexer The parent lexer.
+-- @param child The child lexer.
+-- @param start_rule The pattern that signals the beginning of the embedded lexer.
+-- @param end_rule The pattern that signals the end of the embedded lexer.
+-- @usage html:embed(css, css_start_rule, css_end_rule)
+-- @usage html:embed(lex, php_start_rule, php_end_rule) -- from php lexer
+-- @name embed
+function M.embed(lexer, child, start_rule, end_rule)
+ if lexer._lexer then lexer = lexer._lexer end -- proxy; get true parent
+ -- Add child rules.
+ if not child._EMBEDDEDRULES then child._EMBEDDEDRULES = {} end
+ if not child._RULES then error('Cannot embed lexer with no rules') end
+ child._EMBEDDEDRULES[lexer._NAME] = {
+ start_rule = start_rule, token_rule = child:join_tokens(), end_rule = end_rule
+ }
+ if not lexer._CHILDREN then lexer._CHILDREN = {} end
+ local children = lexer._CHILDREN
+ children[#children + 1] = child
+ -- Add child styles.
+ for token, style in pairs(child._EXTRASTYLES) do lexer:add_style(token, style) end
+ -- Add child fold symbols.
+ if child._FOLDPOINTS then
+ for token_name, symbols in pairs(child._FOLDPOINTS) do
+ if token_name ~= '_SYMBOLS' then
+ for symbol, v in pairs(symbols) do lexer:add_fold_point(token_name, symbol, v) end
end
end
end
-
- return lexer._grammar
+ lexer:build_grammar()
+ child._lexer = lexer -- use parent's tokens if child is embedding itself
end
---
-- Lexes a chunk of text *text* (that has an initial style number of *init_style*) using lexer
--- *lexer*, returning a list of tag names and positions.
+-- *lexer*, returning a table of token names and positions.
-- @param lexer The lexer to lex text with.
-- @param text The text in the buffer to lex.
-- @param init_style The current style. Multiple-language lexers use this to determine which
-- language to start lexing in.
--- @return list of tag names and positions.
+-- @return table of token names and positions.
-- @name lex
function M.lex(lexer, text, init_style)
- local grammar = build_grammar(lexer, init_style)
- if not grammar then return {M.DEFAULT, #text + 1} end
- if M._standalone then M._text, M.line_state = text, {} end
-
- if lexer._lex_by_line then
- local line_from_position = M.line_from_position
- local function append(tags, line_tags, offset)
- for i = 1, #line_tags, 2 do
- tags[#tags + 1], tags[#tags + 2] = line_tags[i], line_tags[i + 1] + offset
+ if not lexer._GRAMMAR then return {M.DEFAULT, #text + 1} end
+ if not lexer._LEXBYLINE then
+ -- For multilang lexers, build a new grammar whose initial_rule is the current language.
+ if lexer._CHILDREN then
+ for style, style_num in pairs(lexer._TOKENSTYLES) do
+ if style_num == init_style then
+ local lexer_name = style:match('^(.+)_whitespace') or lexer._PARENTNAME or lexer._NAME
+ if lexer._INITIALRULE ~= lexer_name then lexer:build_grammar(lexer_name) end
+ break
+ end
+ end
+ end
+ return lpeg_match(lexer._GRAMMAR, text)
+ else
+ local function append(tokens, line_tokens, offset)
+ for i = 1, #line_tokens, 2 do
+ tokens[#tokens + 1] = line_tokens[i]
+ tokens[#tokens + 1] = line_tokens[i + 1] + offset
end
end
- local tags = {}
+ local tokens = {}
local offset = 0
- rawset(M, 'line_from_position', function(pos) return line_from_position(pos + offset) end)
+ local grammar = lexer._GRAMMAR
for line in text:gmatch('[^\r\n]*\r?\n?') do
- local line_tags = grammar:match(line)
- if line_tags then append(tags, line_tags, offset) end
+ local line_tokens = lpeg_match(grammar, line)
+ if line_tokens then append(tokens, line_tokens, offset) end
offset = offset + #line
- -- Use the default tag to the end of the line if none was specified.
- if tags[#tags] ~= offset + 1 then
- tags[#tags + 1], tags[#tags + 2] = 'default', offset + 1
+ -- Use the default style to the end of the line if none was specified.
+ if tokens[#tokens] ~= offset then
+ tokens[#tokens + 1], tokens[#tokens + 2] = 'default', offset + 1
end
end
- rawset(M, 'line_from_position', line_from_position)
- return tags
+ return tokens
end
-
- return grammar:match(text)
end
---
-- Determines fold points in a chunk of text *text* using lexer *lexer*, returning a table of
-- fold levels associated with line numbers.
--- *text* starts on line number *start_line* with a beginning fold level of *start_level*
--- in the buffer.
+-- *text* starts at position *start_pos* on line number *start_line* with a beginning fold
+-- level of *start_level* in the buffer.
-- @param lexer The lexer to fold text with.
-- @param text The text in the buffer to fold.
+-- @param start_pos The position in the buffer *text* starts at, counting from 1.
-- @param start_line The line number *text* starts on, counting from 1.
-- @param start_level The fold level *text* starts on.
-- @return table of fold levels associated with line numbers.
-- @name fold
-function M.fold(lexer, text, start_line, start_level)
+function M.fold(lexer, text, start_pos, start_line, start_level)
local folds = {}
if text == '' then return folds end
local fold = M.property_int['fold'] > 0
local FOLD_BASE = M.FOLD_BASE
local FOLD_HEADER, FOLD_BLANK = M.FOLD_HEADER, M.FOLD_BLANK
- if M._standalone then M._text, M.line_state = text, {} end
- if fold and lexer._fold_points then
+ if fold and lexer._FOLDPOINTS then
local lines = {}
for p, l in (text .. '\n'):gmatch('()(.-)\r?\n') do lines[#lines + 1] = {p, l} end
- local fold_zero_sum_lines = M.property_int['fold.scintillua.on.zero.sum.lines'] > 0
- local fold_compact = M.property_int['fold.scintillua.compact'] > 0
- local fold_points = lexer._fold_points
- local fold_point_symbols = fold_points._symbols
+ local fold_zero_sum_lines = M.property_int['fold.on.zero.sum.lines'] > 0
+ local fold_compact = M.property_int['fold.compact'] > 0
+ local fold_points = lexer._FOLDPOINTS
+ local fold_point_symbols = fold_points._SYMBOLS
local style_at, fold_level = M.style_at, M.fold_level
local line_num, prev_level = start_line, start_level
local current_level = prev_level
for _, captures in ipairs(lines) do
local pos, line = captures[1], captures[2]
if line ~= '' then
- if lexer._case_insensitive_fold_points then line = line:lower() end
+ if lexer._CASEINSENSITIVEFOLDPOINTS then line = line:lower() end
local ranges = {}
local function is_valid_range(s, e)
if not s or not e then return false end
@@ -1334,11 +1273,7 @@
local word_before = s > 1 and line:find('^[%w_]', s - 1)
local word_after = line:find('^[%w_]', e + 1)
if not word or not (word_before or word_after) then
- local style_name = style_at[pos + s - 1]
- local symbols = fold_points[style_name]
- if not symbols and style_name:find('%.') then
- symbols = fold_points[style_name:match('^[^.]+')]
- end
+ local symbols = fold_points[style_at[start_pos + pos - 1 + s - 1]]
local level = symbols and symbols[symbol]
if type(level) == 'function' then
level = level(text, pos, line, s, symbol)
@@ -1377,8 +1312,7 @@
end
line_num = line_num + 1
end
- elseif fold and
- (lexer._fold_by_indentation or M.property_int['fold.scintillua.by.indentation'] > 0) then
+ elseif fold and (lexer._FOLDBYINDENTATION or M.property_int['fold.by.indentation'] > 0) then
-- Indentation based folding.
-- Calculate indentation per line.
local indentation = {}
@@ -1444,239 +1378,197 @@
-- is `false`.
-- * `case_insensitive_fold_points`: Whether or not fold points added via
-- `lexer.add_fold_point()` ignore case. The default value is `false`.
--- * `no_user_word_lists`: Does not automatically allocate word lists that can be set by
--- users. This should really only be set by non-programming languages like markup languages.
-- * `inherit`: Lexer to inherit from. The default value is `nil`.
-- @usage lexer.new('rhtml', {inherit = lexer.load('html')})
-- @name new
function M.new(name, opts)
- local lexer = setmetatable({
- _name = assert(name, 'lexer name expected'), _lex_by_line = opts and opts['lex_by_line'],
- _fold_by_indentation = opts and opts['fold_by_indentation'],
- _case_insensitive_fold_points = opts and opts['case_insensitive_fold_points'],
- _no_user_word_lists = opts and opts['no_user_word_lists'], _lexer = opts and opts['inherit']
- }, {
+ local lexer = {
+ _NAME = assert(name, 'lexer name expected'), _LEXBYLINE = opts and opts['lex_by_line'],
+ _FOLDBYINDENTATION = opts and opts['fold_by_indentation'],
+ _CASEINSENSITIVEFOLDPOINTS = opts and opts['case_insensitive_fold_points'],
+ _lexer = opts and opts['inherit']
+ }
+
+ -- Create the initial maps for token names to style numbers and styles.
+ local token_styles = {}
+ for i = 1, #default do token_styles[default[i]] = i end
+ for i = 1, #predefined do token_styles[predefined[i]] = i + 32 end
+ lexer._TOKENSTYLES, lexer._numstyles = token_styles, #default + 1
+ lexer._EXTRASTYLES = {}
+
+ return setmetatable(lexer, {
__index = {
- tag = M.tag, word_match = M.word_match, set_word_list = M.set_word_list,
add_rule = M.add_rule, modify_rule = M.modify_rule, get_rule = M.get_rule,
- add_fold_point = M.add_fold_point, embed = M.embed, lex = M.lex, fold = M.fold, --
- add_style = function() end -- legacy
+ add_style = M.add_style, add_fold_point = M.add_fold_point, join_tokens = join_tokens,
+ build_grammar = build_grammar, embed = M.embed, lex = M.lex, fold = M.fold
}
})
-
- -- Add initial whitespace rule.
- -- Use a unique whitespace tag name since embedded lexing relies on these unique names.
- lexer:add_rule('whitespace', lexer:tag('whitespace.' .. name, M.space^1))
-
- return lexer
end
--- When using Scintillua as a standalone module, some tables and functions that depend on
--- Scintilla do not exist. Create a substitute for them.
-local function initialize_standalone_library()
- M.property = setmetatable({['scintillua.lexers'] = package.path:gsub('/%?%.lua', '')}, {
- __index = function() return '' end, __newindex = function(t, k, v) rawset(t, k, tostring(v)) end
- })
- M.property_int = setmetatable({}, {
- __index = function(t, k) return tonumber(M.property[k]) or 0 end,
- __newindex = function() error('read-only property') end
- })
-
- M.line_from_position = function(pos)
- local line = 1
- for s in M._text:gmatch('[^\n]*()') do
- if pos <= s then return line end
- line = line + 1
+-- Legacy support for older lexers.
+-- Processes the `lex._rules`, `lex._tokenstyles`, and `lex._foldsymbols` tables. Since legacy
+-- lexers may be processed up to twice, ensure their default styles and rules are not processed
+-- more than once.
+local function process_legacy_lexer(lexer)
+ local function warn(msg) --[[io.stderr:write(msg, "\n")]]end
+ if not lexer._LEGACY then
+ lexer._LEGACY = true
+ warn("lexers as tables are deprecated; use 'lexer.new()'")
+ local token_styles = {}
+ for i = 1, #default do token_styles[default[i]] = i end
+ for i = 1, #predefined do token_styles[predefined[i]] = i + 32 end
+ lexer._TOKENSTYLES, lexer._numstyles = token_styles, #default + 1
+ lexer._EXTRASTYLES = {}
+ setmetatable(lexer, getmetatable(M.new('')))
+ if lexer._rules then
+ warn("lexer '_rules' table is deprecated; use 'add_rule()'")
+ for _, rule in ipairs(lexer._rules) do lexer:add_rule(rule[1], rule[2]) end
end
- return line - 1 -- should not get to here
end
-
- M.indent_amount = setmetatable({}, {
- __index = function(_, line)
- local current_line = 1
- for s in M._text:gmatch('()[^\n]*') do
- if current_line == line then
- return #M._text:match('^[ \t]*', s):gsub('\t', string.rep(' ', 8))
- end
- current_line = current_line + 1
+ if lexer._tokenstyles then
+ warn("lexer '_tokenstyles' table is deprecated; use 'add_style()'")
+ for token, style in pairs(lexer._tokenstyles) do
+ -- If this legacy lexer is being processed a second time, only add styles added since
+ -- the first processing.
+ if not lexer._TOKENSTYLES[token] then lexer:add_style(token, style) end
+ end
+ end
+ if lexer._foldsymbols then
+ warn("lexer '_foldsymbols' table is deprecated; use 'add_fold_point()'")
+ for token_name, symbols in pairs(lexer._foldsymbols) do
+ if type(symbols) == 'table' and token_name ~= '_patterns' then
+ for symbol, v in pairs(symbols) do lexer:add_fold_point(token_name, symbol, v) end
end
end
- })
-
- M._standalone = true
-end
-
--- Searches for the given *name* in the given *path*.
--- This is a safe implementation of Lua 5.2's `package.searchpath()` function that does not
--- require the package module to be loaded.
-local function searchpath(name, path)
- local tried = {}
- for part in path:gmatch('[^;]+') do
- local filename = part:gsub('%?', name)
- local ok, errmsg = loadfile(filename)
- if ok or not errmsg:find('cannot open') then return filename end
- tried[#tried + 1] = string.format("no file '%s'", filename)
+ if lexer._foldsymbols._case_insensitive then lexer._CASEINSENSITIVEFOLDPOINTS = true end
+ elseif lexer._fold then
+ lexer.fold = function(self, ...) return lexer._fold(...) end
end
- return nil, table.concat(tried, '\n')
end
+local lexers = {} -- cache of loaded lexers
---
--- Initializes or loads and then returns the lexer of string name *name*.
+-- Initializes or loads and returns the lexer of string name *name*.
-- Scintilla calls this function in order to load a lexer. Parent lexers also call this function
-- in order to load child lexers and vice-versa. The user calls this function in order to load
-- a lexer when using Scintillua as a Lua library.
-- @param name The name of the lexing language.
-- @param alt_name The alternate name of the lexing language. This is useful for embedding the
--- same child lexer with multiple sets of start and end tags.
+-- same child lexer with multiple sets of start and end tokens.
+-- @param cache Flag indicating whether or not to load lexers from the cache. This should only
+-- be `true` when initially loading a lexer (e.g. not from within another lexer for embedding
+-- purposes). The default value is `false`.
-- @return lexer object
-- @name load
-function M.load(name, alt_name)
- assert(name, 'no lexer given')
- if not M.property then initialize_standalone_library() end
-
- -- Load the language lexer with its rules, tags, etc.
- local path = M.property['scintillua.lexers']:gsub(';', '/?.lua;') .. '/?.lua'
- local ro_lexer = setmetatable({
- WHITESPACE = 'whitespace.' .. (alt_name or name) -- legacy
- }, {__index = M})
- local env = {
- 'assert', 'error', 'ipairs', 'math', 'next', 'pairs', 'print', 'select', 'string', 'table',
- 'tonumber', 'tostring', 'type', 'utf8', '_VERSION', lexer = ro_lexer, lpeg = lpeg, --
- require = function() return ro_lexer end -- legacy
- }
- for _, name in ipairs(env) do env[name] = _G[name] end
- local lexer = assert(loadfile(assert(searchpath(name, path)), 't', env))(alt_name or name)
+function M.load(name, alt_name, cache)
+ if cache and lexers[alt_name or name] then return lexers[alt_name or name] end
+
+ -- When using Scintillua as a stand-alone module, the `property`, `property_int`, and
+ -- `property_expanded` tables do not exist (they are not useful). Create them in order prevent
+ -- errors from occurring.
+ if not M.property then
+ M.property = setmetatable({['lexer.lpeg.home'] = package.path:gsub('/%?%.lua', '')}, {
+ __index = function() return '' end,
+ __newindex = function(t, k, v) rawset(t, k, tostring(v)) end
+ })
+ M.property_int = setmetatable({}, {
+ __index = function(t, k) return tonumber(M.property[k]) or 0 end,
+ __newindex = function() error('read-only property') end
+ })
+ M.property_expanded = setmetatable({}, {
+ __index = function(t, key)
+ return M.property[key]:gsub('[$%%](%b())', function(key) return t[key:sub(2, -2)] end)
+ end, __newindex = function() error('read-only property') end
+ })
+ end
+
+ -- Load the language lexer with its rules, styles, etc.
+ -- However, replace the default `WHITESPACE` style name with a unique whitespace style name
+ -- (and then automatically add it afterwards), since embedded lexing relies on these unique
+ -- whitespace style names. Note that loading embedded lexers changes `WHITESPACE` again,
+ -- so when adding it later, do not reference the potentially incorrect value.
+ M.WHITESPACE = (alt_name or name) .. '_whitespace'
+ local path = M.property['lexer.lpeg.home']:gsub(';', '/?.lua;') .. '/?.lua'
+ local lexer = dofile(assert(searchpath('lexers/'..name, path)))
assert(lexer, string.format("'%s.lua' did not return a lexer", name))
+ if alt_name then lexer._NAME = alt_name end
+ if not getmetatable(lexer) or lexer._LEGACY then
+ -- A legacy lexer may need to be processed a second time in order to pick up any `_tokenstyles`
+ -- or `_foldsymbols` added after `lexer.embed_lexer()`.
+ process_legacy_lexer(lexer)
+ if lexer._lexer and lexer._lexer._LEGACY then
+ process_legacy_lexer(lexer._lexer) -- mainly for `_foldsymbols` edits
+ end
+ end
+ lexer:add_style((alt_name or name) .. '_whitespace', M.styles.whitespace)
-- If the lexer is a proxy or a child that embedded itself, set the parent to be the main
- -- lexer. Keep a reference to the old parent name since embedded child start and end rules
- -- reference and use that name.
+ -- lexer. Keep a reference to the old parent name since embedded child rules reference and
+ -- use that name.
if lexer._lexer then
lexer = lexer._lexer
- lexer._parent_name, lexer._name = lexer._name, alt_name or name
+ lexer._PARENTNAME, lexer._NAME = lexer._NAME, alt_name or name
end
+ if cache then lexers[alt_name or name] = lexer end
return lexer
end
----
--- Map of file extensions, without the '.' prefix, to their associated lexer names.
--- This map has precedence over Scintillua's built-in map.
--- @see detect
--- @class table
--- @name detect_extensions
-M.detect_extensions = {}
-
----
--- Map of line patterns to their associated lexer names.
--- These are Lua string patterns, not LPeg patterns.
--- This map has precedence over Scintillua's built-in map.
--- @see detect
--- @class table
--- @name detect_patterns
-M.detect_patterns = {}
-
----
--- Returns the name of the lexer often associated with filename *filename* and/or content
--- line *line*.
--- @param filename Optional string filename. The default value is read from the
--- 'lexer.scintillua.filename' property.
--- @param line Optional string first content line, such as a shebang line. The default value
--- is read from the 'lexer.scintillua.line' property.
--- @return string lexer name to pass to `load()`, or `nil` if none was detected
--- @see detect_extensions
--- @see detect_patterns
--- @see load
--- @name detect
-function M.detect(filename, line)
- if not filename then filename = M.property and M.property['lexer.scintillua.filename'] or '' end
- if not line then line = M.property and M.property['lexer.scintillua.line'] or '' end
-
- -- Locally scoped in order to avoid persistence in memory.
- -- LuaFormatter off
- local extensions = {--[[Actionscript]]as='actionscript',asc='actionscript',--[[Ada]]adb='ada',ads='ada',--[[ANTLR]]g='antlr',g4='antlr',--[[APDL]]ans='apdl',inp='apdl',mac='apdl',--[[APL]]apl='apl',--[[Applescript]]applescript='applescript',--[[ASM]]asm='asm',ASM='asm',s='asm',S='asm',--[[ASP]]asa='asp',asp='asp',hta='asp',--[[AutoHotkey]]ahk='autohotkey',--[[AutoIt]]au3='autoit',a3x='autoit',--[[AWK]]awk='awk',--[[Batch]]bat='batch',cmd='batch',--[[BibTeX]]bib='bibtex',--[[Boo]]boo='boo',--[[C#]]cs='csharp',--[[C/C++]]c='ansi_c',C='ansi_c',cc='cpp',cpp='cpp',cxx='cpp',['c++']='cpp',h='cpp',hh='cpp',hpp='cpp',hxx='cpp',['h++']='cpp',--[[ChucK]]ck='chuck',--[[Clojure]]clj='clojure',cljs='clojure',cljc='clojure',edn='clojure',--[[CMake]]cmake='cmake',['cmake.in']='cmake',ctest='cmake',['ctest.in']='cmake',--[[CoffeeScript]]coffee='coffeescript',--[[Crystal]]cr='crystal',--[[CSS]]css='css',--[[CUDA]]cu='cuda',cuh='cuda',--[[D]]d='dmd',di='dmd',--[[Dart]]dart='dart',--[[Desktop]]desktop='desktop',--[[diff]]diff='diff',patch='diff',--[[Dockerfile]]Dockerfile='dockerfile',--[[dot]]dot='dot',--[[Eiffel]]e='eiffel',eif='eiffel',--[[Elixir]]ex='elixir',exs='elixir',--[[Elm]]elm='elm',--[[Erlang]]erl='erlang',hrl='erlang',--[[F#]]fs='fsharp',--[[Fantom]]fan='fantom',--[[Faust]]dsp='faust',--[[Fennel]]fnl='fennel',--[[Fish]]fish='fish',--[[Forth]]forth='forth',frt='forth',--[[Fortran]]f='fortran',['for']='fortran',ftn='fortran',fpp='fortran',f77='fortran',f90='fortran',f95='fortran',f03='fortran',f08='fortran',--[[fstab]]fstab='fstab',--[[Gap]]gd='gap',gi='gap',gap='gap',--[[Gemini]]gmi='gemini',--[[Gettext]]po='gettext',pot='gettext',--[[Gherkin]]feature='gherkin',--[[Gleam]]gleam='gleam',--[[GLSL]]glslf='glsl',glslv='glsl',--[[GNUPlot]]dem='gnuplot',plt='gnuplot',--[[Go]]go='go',--[[Groovy]]groovy='groovy',gvy='groovy',--[[Gtkrc]]gtkrc='gtkrc',--[[Hare]]ha='hare',--[[Haskell]]hs='haskell',--[[HTML]]htm='html',html='html',shtm='html',shtml='html',xhtml='html',vue='html',--[[Icon]]icn='icon',--[[IDL]]idl='idl',odl='idl',--[[Inform]]ni='inform',--[[ini]]cfg='ini',cnf='ini',inf='ini',ini='ini',reg='ini',--[[Io]]io='io_lang',--[[Java]]bsh='java',java='java',--[[Javascript]]js='javascript',jsfl='javascript',--[[jq]]jq='jq',--[[JSON]]json='json',--[[JSP]]jsp='jsp',--[[Julia]]jl='julia',--[[LaTeX]]bbl='latex',dtx='latex',ins='latex',ltx='latex',tex='latex',sty='latex',--[[Ledger]]ledger='ledger',journal='ledger',--[[LESS]]less='less',--[[LilyPond]]lily='lilypond',ly='lilypond',--[[Lisp]]cl='lisp',el='lisp',lisp='lisp',lsp='lisp',--[[Literate Coffeescript]]litcoffee='litcoffee',--[[Logtalk]]lgt='logtalk',--[[Lua]]lua='lua',--[[Makefile]]GNUmakefile='makefile',iface='makefile',mak='makefile',makefile='makefile',Makefile='makefile',--[[Man]]['1']='man',['2']='man',['3']='man',['4']='man',['5']='man',['6']='man',['7']='man',['8']='man',['9']='man',['1x']='man',['2x']='man',['3x']='man',['4x']='man',['5x']='man',['6x']='man',['7x']='man',['8x']='man',['9x']='man',--[[Markdown]]md='markdown',--[[Meson]]['meson.build']='meson',--[[MoonScript]]moon='moonscript',--[[Myrddin]]myr='myrddin',--[[Nemerle]]n='nemerle',--[[Networkd]]link='networkd',network='networkd',netdev='networkd',--[[Nim]]nim='nim',--[[NSIS]]nsh='nsis',nsi='nsis',nsis='nsis',--[[Objective C]]m='objective_c',mm='objective_c',objc='objective_c',--[[OCaml]]caml='caml',ml='caml',mli='caml',mll='caml',mly='caml',--[[Pascal]]dpk='pascal',dpr='pascal',p='pascal',pas='pascal',--[[Perl]]al='perl',perl='perl',pl='perl',pm='perl',pod='perl',--[[PHP]]inc='php',php='php',php3='php',php4='php',phtml='php',--[[PICO-8]]p8='pico8',--[[Pike]]pike='pike',pmod='pike',--[[PKGBUILD]]PKGBUILD='pkgbuild',--[[Pony]]pony='pony',--[[Postscript]]eps='ps',ps='ps',--[[PowerShell]]ps1='powershell',--[[Prolog]]prolog='prolog',--[[Properties]]props='props',properties='props',--[[Protobuf]]proto='protobuf',--[[Pure]]pure='pure',--[[Python]]sc='python',py='python',pyw='python',--[[R]]R='rstats',Rout='rstats',Rhistory='rstats',Rt='rstats',['Rout.save']='rstats',['Rout.fail']='rstats',--[[Reason]]re='reason',--[[REBOL]]r='rebol',reb='rebol',--[[reST]]rst='rest',--[[Rexx]]orx='rexx',rex='rexx',--[[RHTML]]erb='rhtml',rhtml='rhtml',--[[RouterOS]]rsc='routeros',--[[RPM Spec]]spec='rpmspec',--[[Ruby]]Rakefile='ruby',rake='ruby',rb='ruby',rbw='ruby',--[[Rust]]rs='rust',--[[Sass CSS]]sass='sass',scss='sass',--[[Scala]]scala='scala',--[[Scheme]]sch='scheme',scm='scheme',--[[Shell]]bash='bash',bashrc='bash',bash_profile='bash',configure='bash',csh='bash',ksh='bash',mksh='bash',sh='bash',zsh='bash',--[[Smalltalk]]changes='smalltalk',st='smalltalk',sources='smalltalk',--[[SML]]sml='sml',fun='sml',sig='sml',--[[SNOBOL4]]sno='snobol4',SNO='snobol4',--[[Spin]]spin='spin',--[[SQL]]ddl='sql',sql='sql',--[[Systemd]]automount='systemd',device='systemd',mount='systemd',path='systemd',scope='systemd',service='systemd',slice='systemd',socket='systemd',swap='systemd',target='systemd',timer='systemd',--[[TaskPaper]]taskpaper='taskpaper',--[[Tcl]]tcl='tcl',tk='tcl',--[[Texinfo]]texi='texinfo',--[[TOML]]toml='toml',--[[Txt2tags]]t2t='txt2tags',--[[TypeScript]]ts='typescript',--[[Vala]]vala='vala',--[[vCard]]vcf='vcard',vcard='vcard',--[[Verilog]]v='verilog',ver='verilog',--[[VHDL]]vh='vhdl',vhd='vhdl',vhdl='vhdl',--[[Visual Basic]]bas='vb',cls='vb',ctl='vb',dob='vb',dsm='vb',dsr='vb',frm='vb',pag='vb',vb='vb',vba='vb',vbs='vb',--[[WSF]]wsf='wsf',--[[XML]]dtd='xml',svg='xml',xml='xml',xsd='xml',xsl='xml',xslt='xml',xul='xml',--[[Xs]]xs='xs',xsin='xs',xsrc='xs',--[[Xtend]]xtend='xtend',--[[YAML]]yaml='yaml',yml='yaml',--[[Zig]]zig='zig'}
- local patterns = {['^#!.+[/ ][gm]?awk']='awk',['^#!.+[/ ]lua']='lua',['^#!.+[/ ]octave']='matlab',['^#!.+[/ ]perl']='perl',['^#!.+[/ ]php']='php',['^#!.+[/ ]python']='python',['^#!.+[/ ]ruby']='ruby',['^#!.+[/ ]bash']='bash',['^#!.+/m?ksh']='bash',['^#!.+/sh']='bash',['^%s*class%s+%S+%s*<%s*ApplicationController']='rails',['^%s*class%s+%S+%s*<%s*ActionController::Base']='rails',['^%s*class%s+%S+%s*<%s*ActiveRecord::Base']='rails',['^%s*class%s+%S+%s*<%s*ActiveRecord::Migration']='rails',['^%s*<%?xml%s']='xml',['^#cloud%-config']='yaml'}
- -- LuaFormatter on
-
- for patt, name in ipairs(M.detect_patterns) do if line:find(patt) then return name end end
- for patt, name in pairs(patterns) do if line:find(patt) then return name end end
- local name_or_ext = filename:match('[^/\\.]+$')
- return M.detect_extensions[name_or_ext] or extensions[name_or_ext]
-end
-
-- The following are utility functions lexers will have access to.
-- Common patterns.
-M.any = P(1)
-M.alpha = R('AZ', 'az')
-M.digit = R('09')
-M.alnum = R('AZ', 'az', '09')
-M.lower = R('az')
-M.upper = R('AZ')
-M.xdigit = R('09', 'AF', 'af')
-M.graph = R('!~')
-M.punct = R('!/', ':@', '[\'', '{~')
-M.space = S('\t\v\f\n\r ')
+M.any = lpeg_P(1)
+M.alpha = lpeg_R('AZ', 'az')
+M.digit = lpeg_R('09')
+M.alnum = lpeg_R('AZ', 'az', '09')
+M.lower = lpeg_R('az')
+M.upper = lpeg_R('AZ')
+M.xdigit = lpeg_R('09', 'AF', 'af')
+M.graph = lpeg_R('!~')
+M.punct = lpeg_R('!/', ':@', '[\'', '{~')
+M.space = lpeg_S('\t\v\f\n\r ')
-M.newline = P('\r')^-1 * '\n'
+M.newline = lpeg_P('\r')^-1 * '\n'
M.nonnewline = 1 - M.newline
----
--- Returns a pattern that matches a decimal number, whose digits may be separated by character *c*.
--- @name dec_num_
-function M.dec_num_(c) return M.digit * (P(c)^-1 * M.digit)^0 end
----
--- Returns a pattern that matches a hexadecimal number, whose digits may be separated by
--- character *c*.
--- @name hex_num_
-function M.hex_num_(c) return '0' * S('xX') * (P(c)^-1 * M.xdigit)^1 end
----
--- Returns a pattern that matches an octal number, whose digits may be separated by character *c*.
--- @name oct_num_
-function M.oct_num_(c) return '0' * (P(c)^-1 * R('07'))^1 * -M.xdigit end
----
--- Returns a pattern that matches a binary number, whose digits may be separated by character *c*.
--- @name bin_num_
-function M.bin_num_(c) return '0' * S('bB') * (P(c)^-1 * S('01'))^1 * -M.xdigit end
----
--- Returns a pattern that matches either a decimal, hexadecimal, octal, or binary number,
--- whose digits may be separated by character *c*.
--- @name integer_
-function M.integer_(c)
- return S('+-')^-1 * (M.hex_num_(c) + M.bin_num_(c) + M.oct_num_(c) + M.dec_num_(c))
-end
-local function exp_(c) return S('eE') * S('+-')^-1 * M.digit * (P(c)^-1 * M.digit)^0 end
----
--- Returns a pattern that matches a floating point number, whose digits may be separated by
--- character *c*.
--- @name float_
-function M.float_(c)
- return S('+-')^-1 *
- ((M.dec_num_(c)^-1 * '.' * M.dec_num_(c) + M.dec_num_(c) * '.' * M.dec_num_(c)^-1 * -P('.')) *
- exp_(c)^-1 + (M.dec_num_(c) * exp_(c)))
-end
----
--- Returns a pattern that matches a typical number, either a floating point, decimal, hexadecimal,
--- octal, or binary number, and whose digits may be separated by character *c*.
--- @name number_
-function M.number_(c) return M.float_(c) + M.integer_(c) end
-
-M.dec_num = M.dec_num_(false)
-M.hex_num = M.hex_num_(false)
-M.oct_num = M.oct_num_(false)
-M.bin_num = M.bin_num_(false)
-M.integer = M.integer_(false)
-M.float = M.float_(false)
-M.number = M.number_(false)
+M.dec_num = M.digit^1
+M.hex_num = '0' * lpeg_S('xX') * M.xdigit^1
+M.oct_num = '0' * lpeg_R('07')^1
+M.integer = lpeg_S('+-')^-1 * (M.hex_num + M.oct_num + M.dec_num)
+M.float = lpeg_S('+-')^-1 *
+ ((M.digit^0 * '.' * M.digit^1 + M.digit^1 * '.' * M.digit^0 * -lpeg_P('.')) *
+ (lpeg_S('eE') * lpeg_S('+-')^-1 * M.digit^1)^-1 +
+ (M.digit^1 * lpeg_S('eE') * lpeg_S('+-')^-1 * M.digit^1))
+M.number = M.float + M.integer
M.word = (M.alpha + '_') * (M.alnum + '_')^0
+-- Deprecated.
+M.nonnewline_esc = 1 - (M.newline + '\\') + '\\' * M.any
+M.ascii = lpeg_R('\000\127')
+M.extend = lpeg_R('\000\255')
+M.cntrl = lpeg_R('\000\031')
+M.print = lpeg_R(' ~')
+
+---
+-- Creates and returns a token pattern with token name *name* and pattern *patt*.
+-- If *name* is not a predefined token name, its style must be defined via `lexer.add_style()`.
+-- @param name The name of token. If this name is not a predefined token name, then a style
+-- needs to be assiciated with it via `lexer.add_style()`.
+-- @param patt The LPeg pattern associated with the token.
+-- @return pattern
+-- @usage local ws = token(lexer.WHITESPACE, lexer.space^1)
+-- @usage local annotation = token('annotation', '@' * lexer.word)
+-- @name token
+function M.token(name, patt)
+ return lpeg_Cc(name) * patt * lpeg_Cp()
+end
+
---
-- Creates and returns a pattern that matches from string or pattern *prefix* until the end of
-- the line.
-- *escape* indicates whether the end of the line can be escaped with a '\' character.
--- @param prefix Optional string or pattern prefix to start matching at. The default value is
--- any non-newline character.
+-- @param prefix String or pattern prefix to start matching at.
-- @param escape Optional flag indicating whether or not newlines can be escaped by a '\'
-- character. The default value is `false`.
-- @return pattern
@@ -1684,8 +1576,7 @@
-- @usage local line_comment = lexer.to_eol(S('#;'))
-- @name to_eol
function M.to_eol(prefix, escape)
- return (prefix or M.nonnewline) *
- (not escape and M.nonnewline or 1 - (M.newline + '\\') + '\\' * M.any)^0
+ return prefix * (not escape and M.nonnewline or M.nonnewline_esc)^0
end
---
@@ -1719,123 +1610,239 @@
local any = M.any - e
if single_line then any = any - '\n' end
if balanced then any = any - s end
- -- Only allow escapes by default for ranges with identical, single-character string delimiters.
- if escapes == nil then escapes = type(s) == 'string' and #s == 1 and s == e end
+ if escapes == nil then
+ -- Only allow escapes by default for ranges with identical, single-character string delimiters.
+ escapes = type(s) == 'string' and #s == 1 and s == e
+ end
if escapes then any = any - '\\' + '\\' * M.any end
- if balanced and s ~= e then return P{s * (any + V(1))^0 * P(e)^-1} end
- return s * any^0 * P(e)^-1
+ if balanced and s ~= e then
+ return lpeg_P{s * (any + lpeg_V(1))^0 * lpeg_P(e)^-1}
+ else
+ return s * any^0 * lpeg_P(e)^-1
+ end
end
----
--- Creates and returns a pattern that matches pattern *patt* only when it comes after one of
--- the characters in string *set* (or when there are no characters behind *patt*), skipping
--- over any characters in string *skip*, which is whitespace by default.
--- @param set String character set like one passed to `lpeg.S()`.
--- @param patt The LPeg pattern to match after a set character.
--- @param skip String character set to skip over. The default value is ' \t\r\n\v\f' (whitespace).
--- @usage local regex = lexer.after_set('+-*!%^&|=,([{', lexer.range('/'))
--- @name after_set
-function M.after_set(set, patt, skip)
- if not skip then skip = ' \t\r\n\v\f' end
- local set_chars, skip_chars = {}, {}
- for _, byte in utf8.codes(set) do set_chars[byte] = true end
- for _, byte in utf8.codes(skip) do skip_chars[byte] = true end
- return (B(S(set)) + -B(1)) * patt + Cmt(C(patt), function(input, index, match, ...)
- local pos = index - #match
- if #skip > 0 then while pos > 1 and skip_chars[input:byte(pos - 1)] do pos = pos - 1 end end
- if pos == 1 or set_chars[input:byte(pos - 1)] then return index, ... end
- return nil
- end)
+-- Deprecated function. Use `lexer.range()` instead.
+-- Creates and returns a pattern that matches a range of text bounded by *chars* characters.
+-- This is a convenience function for matching more complicated delimited ranges like strings
+-- with escape characters and balanced parentheses. *single_line* indicates whether or not the
+-- range must be on a single line, *no_escape* indicates whether or not to ignore '\' as an
+-- escape character, and *balanced* indicates whether or not to handle balanced ranges like
+-- parentheses and requires *chars* to be composed of two characters.
+-- @param chars The character(s) that bound the matched range.
+-- @param single_line Optional flag indicating whether or not the range must be on a single line.
+-- @param no_escape Optional flag indicating whether or not the range end character may be
+-- escaped by a '\\' character.
+-- @param balanced Optional flag indicating whether or not to match a balanced range, like the
+-- "%b" Lua pattern. This flag only applies if *chars* consists of two different characters
+-- (e.g. "()").
+-- @return pattern
+-- @usage local dq_str_escapes = lexer.delimited_range('"')
+-- @usage local dq_str_noescapes = lexer.delimited_range('"', false, true)
+-- @usage local unbalanced_parens = lexer.delimited_range('()')
+-- @usage local balanced_parens = lexer.delimited_range('()', false, false, true)
+-- @see range
+-- @name delimited_range
+function M.delimited_range(chars, single_line, no_escape, balanced)
+ print("lexer.delimited_range() is deprecated, use lexer.range()")
+ local s = chars:sub(1, 1)
+ local e = #chars == 2 and chars:sub(2, 2) or s
+ local range
+ local b = balanced and s or ''
+ local n = single_line and '\n' or ''
+ if no_escape then
+ local invalid = lpeg_S(e .. n .. b)
+ range = M.any - invalid
+ else
+ local invalid = lpeg_S(e .. n .. b) + '\\'
+ range = M.any - invalid + '\\' * M.any
+ end
+ if balanced and s ~= e then
+ return lpeg_P{s * (range + lpeg_V(1))^0 * e}
+ else
+ return s * range^0 * lpeg_P(e)^-1
+ end
end
---
--- Creates and returns a pattern that matches pattern *patt* only at the beginning of a line,
--- or after any line indentation if *allow_indent* is `true`.
+-- Creates and returns a pattern that matches pattern *patt* only at the beginning of a line.
-- @param patt The LPeg pattern to match on the beginning of a line.
--- @param allow_indent Whether or not to consider line indentation as the start of a line. The
--- default value is `false`.
-- @return pattern
--- @usage local preproc = lex:tag(lexer.PREPROCESSOR, lexer.starts_line(lexer.to_eol('#')))
+-- @usage local preproc = token(lexer.PREPROCESSOR, lexer.starts_line(lexer.to_eol('#')))
-- @name starts_line
-function M.starts_line(patt, allow_indent)
- return M.after_set('\r\n\v\f', patt, allow_indent and ' \t' or '')
+function M.starts_line(patt)
+ return lpeg_Cmt(lpeg_C(patt), function(input, index, match, ...)
+ local pos = index - #match
+ if pos == 1 then return index, ... end
+ local char = input:sub(pos - 1, pos - 1)
+ if char == '\n' or char == '\r' or char == '\f' then return index, ... end
+ end)
end
-M.colors = {} -- legacy
-M.styles = setmetatable({}, { -- legacy
- __index = function() return setmetatable({}, {__concat = function() return nil end}) end
-})
-M.property_expanded = setmetatable({}, {__index = function() return '' end}) -- legacy
-
--- Legacy function for creates and returns a token pattern with token name *name* and pattern
--- *patt*.
--- Use `tag()` instead.
--- @param name The name of token.
--- @param patt The LPeg pattern associated with the token.
--- @return pattern
--- @usage local number = token(lexer.NUMBER, lexer.number)
--- @usage local addition = token('addition', '+' * lexer.word)
--- @name token
--- @see tag
-function M.token(name, patt) return Cc(name) * (P(patt) / 0) * Cp() end
-
--- Legacy function that creates and returns a pattern that verifies the first non-whitespace
--- character behind the current match position is in string set *s*.
+---
+-- Creates and returns a pattern that verifies the first non-whitespace character behind the
+-- current match position is in string set *s*.
-- @param s String character set like one passed to `lpeg.S()`.
-- @return pattern
--- @usage local regex = #P('/') * lexer.last_char_includes('+-*!%^&|=,([{') * lexer.range('/')
+-- @usage local regex = lexer.last_char_includes('+-*!%^&|=,([{') * lexer.range('/')
-- @name last_char_includes
-function M.last_char_includes(s) return M.after_set(s, true) end
-
-function M.fold_consecutive_lines() end -- legacy
+function M.last_char_includes(s)
+ s = string.format('[%s]', s:gsub('[-%%%[]', '%%%1'))
+ return lpeg_P(function(input, index)
+ if index == 1 then return index end
+ local i = index
+ while input:sub(i - 1, i - 1):match('[ \t\r\n\f]') do i = i - 1 end
+ if input:sub(i - 1, i - 1):match(s) then return index end
+ end)
+end
---[[ The functions and fields below were defined in C.
+-- Deprecated function. Use `lexer.range()` instead.
+-- Returns a pattern that matches a balanced range of text that starts with string *start_chars*
+-- and ends with string *end_chars*.
+-- With single-character delimiters, this function is identical to `delimited_range(start_chars ..
+-- end_chars, false, true, true)`.
+-- @param start_chars The string starting a nested sequence.
+-- @param end_chars The string ending a nested sequence.
+-- @return pattern
+-- @usage local nested_comment = lexer.nested_pair('/*', '*/')
+-- @see range
+-- @name nested_pair
+function M.nested_pair(start_chars, end_chars)
+ print("lexer.nested_pair() is deprecated, use lexer.range()")
+ local s, e = start_chars, lpeg_P(end_chars)^-1
+ return lpeg_P{s * (M.any - s - end_chars + lpeg_V(1))^0 * e}
+end
---
--- Read-only table of fold level bit-masks for line numbers starting from 1.
--- Fold level masks are composed of an integer level combined with any of the following bits:
---
--- * `lexer.FOLD_BASE`
--- The initial fold level.
--- * `lexer.FOLD_BLANK`
--- The line is blank.
--- * `lexer.FOLD_HEADER`
--- The line is a header, or fold point.
--- @class table
--- @name fold_level
-local fold_level
+-- Creates and returns a pattern that matches any single word in list or string *words*.
+-- *case_insensitive* indicates whether or not to ignore case when matching words.
+-- This is a convenience function for simplifying a set of ordered choice word patterns.
+-- @param word_list A list of words or a string list of words separated by spaces.
+-- @param case_insensitive Optional boolean flag indicating whether or not the word match is
+-- case-insensitive. The default value is `false`.
+-- @param word_chars Unused legacy parameter.
+-- @return pattern
+-- @usage local keyword = token(lexer.KEYWORD, word_match{'foo', 'bar', 'baz'})
+-- @usage local keyword = token(lexer.KEYWORD, word_match({'foo-bar', 'foo-baz', 'bar-foo',
+-- 'bar-baz', 'baz-foo', 'baz-bar'}, true))
+-- @usage local keyword = token(lexer.KEYWORD, word_match('foo bar baz'))
+-- @name word_match
+function M.word_match(word_list, case_insensitive, word_chars)
+ if type(case_insensitive) == 'string' or type(word_chars) == 'boolean' then
+ -- Legacy `word_match(word_list, word_chars, case_insensitive)` form.
+ word_chars, case_insensitive = case_insensitive, word_chars
+ elseif type(word_list) == 'string' then
+ local words = word_list -- space-separated list of words
+ word_list = {}
+ for word in words:gsub('%-%-[^\n]+', ''):gmatch('%S+') do word_list[#word_list + 1] = word end
+ end
+ if not word_chars then word_chars = '' end
+ for _, word in ipairs(word_list) do
+ word_list[case_insensitive and word:lower() or word] = true
+ for char in word:gmatch('[^%w_%s]') do
+ if not word_chars:find(char, 1, true) then word_chars = word_chars .. char end
+ end
+ end
+ local chars = M.alnum + '_'
+ if word_chars ~= '' then chars = chars + lpeg_S(word_chars) end
+ return lpeg_Cmt(chars^1, function(input, index, word)
+ if case_insensitive then word = word:lower() end
+ return word_list[word] and index or nil
+ end)
+end
----
--- Read-only table of indentation amounts in character columns, for line numbers starting from 1.
--- @class table
--- @name indent_amount
-local indent_amount
+-- Deprecated legacy function. Use `parent:embed()` instead.
+-- Embeds child lexer *child* in parent lexer *parent* using patterns *start_rule* and *end_rule*,
+-- which signal the beginning and end of the embedded lexer, respectively.
+-- @param parent The parent lexer.
+-- @param child The child lexer.
+-- @param start_rule The pattern that signals the beginning of the embedded lexer.
+-- @param end_rule The pattern that signals the end of the embedded lexer.
+-- @usage lexer.embed_lexer(M, css, css_start_rule, css_end_rule)
+-- @usage lexer.embed_lexer(html, M, php_start_rule, php_end_rule)
+-- @usage lexer.embed_lexer(html, ruby, ruby_start_rule, ruby_end_rule)
+-- @see embed
+-- @name embed_lexer
+function M.embed_lexer(parent, child, start_rule, end_rule)
+ if not getmetatable(parent) then process_legacy_lexer(parent) end
+ if not getmetatable(child) then process_legacy_lexer(child) end
+ parent:embed(child, start_rule, end_rule)
+end
+
+-- Determines if the previous line is a comment.
+-- This is used for determining if the current comment line is a fold point.
+-- @param prefix The prefix string defining a comment.
+-- @param text The text passed to a fold function.
+-- @param pos The pos passed to a fold function.
+-- @param line The line passed to a fold function.
+-- @param s The s passed to a fold function.
+local function prev_line_is_comment(prefix, text, pos, line, s)
+ local start = line:find('%S')
+ if start < s and not line:find(prefix, start, true) then return false end
+ local p = pos - 1
+ if text:sub(p, p) == '\n' then
+ p = p - 1
+ if text:sub(p, p) == '\r' then p = p - 1 end
+ if text:sub(p, p) ~= '\n' then
+ while p > 1 and text:sub(p - 1, p - 1) ~= '\n' do p = p - 1 end
+ while text:sub(p, p):find('^[\t ]$') do p = p + 1 end
+ return text:sub(p, p + #prefix - 1) == prefix
+ end
+ end
+ return false
+end
----
--- Table of integer line states for line numbers starting from 1.
--- Line states can be used by lexers for keeping track of persistent states. For example,
--- the output lexer uses this to mark lines that have warnings or errors.
--- @class table
--- @name line_state
-local line_state
+-- Determines if the next line is a comment.
+-- This is used for determining if the current comment line is a fold point.
+-- @param prefix The prefix string defining a comment.
+-- @param text The text passed to a fold function.
+-- @param pos The pos passed to a fold function.
+-- @param line The line passed to a fold function.
+-- @param s The s passed to a fold function.
+local function next_line_is_comment(prefix, text, pos, line, s)
+ local p = text:find('\n', pos + s)
+ if p then
+ p = p + 1
+ while text:sub(p, p):find('^[\t ]$') do p = p + 1 end
+ return text:sub(p, p + #prefix - 1) == prefix
+ end
+ return false
+end
---
--- Map of key-value string pairs.
--- @class table
--- @name property
-local property
+-- Returns for `lexer.add_fold_point()` the parameters needed to fold consecutive lines that
+-- start with string *prefix*.
+-- @param prefix The prefix string (e.g. a line comment).
+-- @usage lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('--'))
+-- @usage lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
+-- @usage lex:add_fold_point(lexer.KEYWORD, lexer.fold_consecutive_lines('import'))
+-- @name fold_consecutive_lines
+function M.fold_consecutive_lines(prefix)
+ local property_int = M.property_int
+ return prefix, function(text, pos, line, s)
+ if property_int['fold.line.groups'] == 0 then return 0 end
+ if s > 1 and line:match('^%s*()') < s then return 0 end
+ local prev_line_comment = prev_line_is_comment(prefix, text, pos, line, s)
+ local next_line_comment = next_line_is_comment(prefix, text, pos, line, s)
+ if not prev_line_comment and next_line_comment then return 1 end
+ if prev_line_comment and not next_line_comment then return -1 end
+ return 0
+ end
+end
----
--- Read-only map of key-value pairs with values interpreted as numbers, or `0` if not found.
--- @class table
--- @name property_int
-local property_int
+-- Deprecated legacy function. Use `lexer.fold_consecutive_lines()` instead.
+-- Returns a fold function (to be passed to `lexer.add_fold_point()`) that folds consecutive
+-- line comments that start with string *prefix*.
+-- @param prefix The prefix string defining a line comment.
+-- @usage lex:add_fold_point(lexer.COMMENT, '--', lexer.fold_line_comments('--'))
+-- @usage lex:add_fold_point(lexer.COMMENT, '//', lexer.fold_line_comments('//'))
+-- @name fold_line_comments
+function M.fold_line_comments(prefix)
+ print('lexer.fold_line_comments() is deprecated, use lexer.fold_consecutive_lines()')
+ return select(2, M.fold_consecutive_lines(prefix))
+end
----
--- Read-only table of style names at positions in the buffer starting from 1.
--- @class table
--- @name style_at
-local style_at
+--[[ The functions and fields below were defined in C.
---
-- Returns the line number (starting from 1) of the line that contains position *pos*, which
diff -uNr /home/matej/repos/tmp/scintillua/lexers/LICENSE lexers/LICENSE
--- /home/matej/repos/tmp/scintillua/lexers/LICENSE 1970-01-01 01:00:00.000000000 +0100
+++ lexers/LICENSE 2022-11-29 23:49:09.999974329 +0100
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2007-2017 Mitchell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff -uNr /home/matej/repos/tmp/scintillua/lexers/lilypond.lua lexers/lilypond.lua
--- /home/matej/repos/tmp/scintillua/lexers/lilypond.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/lilypond.lua 2022-11-29 23:51:43.334329050 +0100
@@ -27,6 +27,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S("{}'~<>|")))
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/lisp.lua lexers/lisp.lua
--- /home/matej/repos/tmp/scintillua/lexers/lisp.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/lisp.lua 2022-11-29 23:51:43.334329050 +0100
@@ -31,7 +31,7 @@
}))
-- Identifiers.
-local word = lexer.alpha * (lexer.alnum + S('_-'))^0
+local word = lexer.alpha * (lexer.alnum + '_' + '-')^0
lex:add_rule('identifier', token(lexer.IDENTIFIER, word))
-- Strings.
@@ -45,6 +45,10 @@
-- Numbers.
lex:add_rule('number', token(lexer.NUMBER, P('-')^-1 * lexer.digit^1 * (S('./') * lexer.digit^1)^-1))
+-- Entities.
+lex:add_rule('entity', token('entity', '&' * word))
+lex:add_style('entity', lexer.styles.variable)
+
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('<>=*/+-`@%()')))
@@ -53,7 +57,6 @@
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '#|', '|#')
-
-lexer.property['scintillua.comment'] = ';'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines(';'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/litcoffee.lua lexers/litcoffee.lua
--- /home/matej/repos/tmp/scintillua/lexers/litcoffee.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/litcoffee.lua 2022-11-29 23:51:43.334329050 +0100
@@ -10,8 +10,8 @@
-- Embedded CoffeeScript.
local coffeescript = lexer.load('coffeescript')
-local coffee_start_rule = token(lexer.EMBEDDED, (P(' ')^4 + P('\t')))
-local coffee_end_rule = token(lexer.EMBEDDED, lexer.newline)
+local coffee_start_rule = token(lexer.STYLE_EMBEDDED, (P(' ')^4 + P('\t')))
+local coffee_end_rule = token(lexer.STYLE_EMBEDDED, lexer.newline)
lex:embed(coffeescript, coffee_start_rule, coffee_end_rule)
-- Use 'markdown_whitespace' instead of lexer.WHITESPACE since the latter would expand to
diff -uNr /home/matej/repos/tmp/scintillua/lexers/logtalk.lua lexers/logtalk.lua
--- /home/matej/repos/tmp/scintillua/lexers/logtalk.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/logtalk.lua 2022-11-29 23:51:43.334329050 +0100
@@ -59,6 +59,4 @@
}
lex:modify_rule('operator', token(lexer.OPERATOR, word_match(operators)) + lex:get_rule('operator'))
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/lua.lua lexers/lua.lua
--- /home/matej/repos/tmp/scintillua/lexers/lua.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/lua.lua 2022-11-29 23:51:43.334329050 +0100
@@ -2,31 +2,117 @@
-- Lua LPeg lexer.
-- Original written by Peter Odding, 2007/04/04.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local B, P, S = lpeg.B, lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('lua')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', 'in', 'local',
+ 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+ -- Added in 5.2.
+ 'goto'
+}))
--- Functions.
-local non_field = -B('.') + B('_G.') + B('..')
-local builtin_func = lex:word_match(lexer.FUNCTION_BUILTIN)
-local lib_func = lex:word_match(lexer.FUNCTION_BUILTIN .. '.library')
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = B(':') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function',
- method + ((non_field * lex:tag(lexer.FUNCTION_BUILTIN, builtin_func + lib_func)) + func) *
- #(lexer.space^0 * S('({\'"')))
+-- Functions and deprecated functions.
+local func = token(lexer.FUNCTION, word_match{
+ 'assert', 'collectgarbage', 'dofile', 'error', 'getmetatable', 'ipairs', 'load', 'loadfile',
+ 'next', 'pairs', 'pcall', 'print', 'rawequal', 'rawget', 'rawset', 'require', 'select',
+ 'setmetatable', 'tonumber', 'tostring', 'type', 'xpcall',
+ -- Added in 5.2.
+ 'rawlen',
+ -- Added in 5.4.
+ 'warn'
+})
+local deprecated_func = token('deprecated_function', word_match{
+ -- Deprecated in 5.2.
+ 'getfenv', 'loadstring', 'module', 'setfenv', 'unpack'
+})
+lex:add_rule('function', -B('.') * (func + deprecated_func))
+lex:add_style('deprecated_function', lexer.styles['function'] .. {italics = true})
-- Constants.
-local builtin_const = lex:word_match(lexer.CONSTANT_BUILTIN)
-local lib_const = lex:word_match(lexer.CONSTANT_BUILTIN .. '.library')
-lex:add_rule('constant', non_field * lex:tag(lexer.CONSTANT_BUILTIN, builtin_const + lib_const))
+lex:add_rule('constant', token(lexer.CONSTANT, -B('.') * word_match{
+ '_G', '_VERSION',
+ -- Added in 5.2.
+ '_ENV'
+}))
+
+-- Libraries and deprecated libraries.
+local library = token('library', word_match{
+ -- Coroutine.
+ 'coroutine', 'coroutine.create', 'coroutine.resume', 'coroutine.running', 'coroutine.status',
+ 'coroutine.wrap', 'coroutine.yield',
+ -- Coroutine added in 5.3.
+ 'coroutine.isyieldable',
+ -- Coroutine added in 5.4.
+ 'coroutine.close',
+ -- Module.
+ 'package', 'package.cpath', 'package.loaded', 'package.loadlib', 'package.path',
+ 'package.preload',
+ -- Module added in 5.2.
+ 'package.config', 'package.searchers', 'package.searchpath',
+ -- UTF-8 added in 5.3.
+ 'utf8', 'utf8.char', 'utf8.charpattern', 'utf8.codepoint', 'utf8.codes', 'utf8.len',
+ 'utf8.offset',
+ -- String.
+ 'string', 'string.byte', 'string.char', 'string.dump', 'string.find', 'string.format',
+ 'string.gmatch', 'string.gsub', 'string.len', 'string.lower', 'string.match', 'string.rep',
+ 'string.reverse', 'string.sub', 'string.upper',
+ -- String added in 5.3.
+ 'string.pack', 'string.packsize', 'string.unpack',
+ -- Table.
+ 'table', 'table.concat', 'table.insert', 'table.remove', 'table.sort',
+ -- Table added in 5.2.
+ 'table.pack', 'table.unpack',
+ -- Table added in 5.3.
+ 'table.move',
+ -- Math.
+ 'math', 'math.abs', 'math.acos', 'math.asin', 'math.atan', 'math.ceil', 'math.cos', 'math.deg',
+ 'math.exp', 'math.floor', 'math.fmod', 'math.huge', 'math.log', 'math.max', 'math.min',
+ 'math.modf', 'math.pi', 'math.rad', 'math.random', 'math.randomseed', 'math.sin', 'math.sqrt',
+ 'math.tan',
+ -- Math added in 5.3.
+ 'math.maxinteger', 'math.mininteger', 'math.tointeger', 'math.type', 'math.ult',
+ -- IO.
+ 'io', 'io.close', 'io.flush', 'io.input', 'io.lines', 'io.open', 'io.output', 'io.popen',
+ 'io.read', 'io.stderr', 'io.stdin', 'io.stdout', 'io.tmpfile', 'io.type', 'io.write',
+ -- OS.
+ 'os', 'os.clock', 'os.date', 'os.difftime', 'os.execute', 'os.exit', 'os.getenv', 'os.remove',
+ 'os.rename', 'os.setlocale', 'os.time', 'os.tmpname',
+ -- Debug.
+ 'debug', 'debug.debug', 'debug.gethook', 'debug.getinfo', 'debug.getlocal', 'debug.getmetatable',
+ 'debug.getregistry', 'debug.getupvalue', 'debug.sethook', 'debug.setlocal', 'debug.setmetatable',
+ 'debug.setupvalue', 'debug.traceback',
+ -- Debug added in 5.2.
+ 'debug.getuservalue', 'debug.setuservalue', 'debug.upvalueid', 'debug.upvaluejoin'
+})
+local deprecated_library = token('deprecated_library', word_match{
+ -- Module deprecated in 5.2.
+ 'package.loaders', 'package.seeall',
+ -- Table deprecated in 5.2.
+ 'table.maxn',
+ -- Math deprecated in 5.2.
+ 'math.log10',
+ -- Math deprecated in 5.3.
+ 'math.atan2', 'math.cosh', 'math.frexp', 'math.ldexp', 'math.pow', 'math.sinh', 'math.tanh',
+ -- Bit32 deprecated in 5.3.
+ 'bit32', 'bit32.arshift', 'bit32.band', 'bit32.bnot', 'bit32.bor', 'bit32.btest', 'bit32.extract',
+ 'bit32.lrotate', 'bit32.lshift', 'bit32.replace', 'bit32.rrotate', 'bit32.rshift', 'bit32.xor',
+ -- Debug deprecated in 5.2.
+ 'debug.getfenv', 'debug.setfenv'
+})
+lex:add_rule('library', -B('.') * (library + deprecated_library))
+lex:add_style('library', lexer.styles.type)
+lex:add_style('deprecated_library', lexer.styles.type .. {italics = true})
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local sq_str = lexer.range("'")
@@ -35,27 +121,28 @@
local _, e = input:find(']' .. eq .. ']', index, true)
return (e or #input) + 1
end)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str) +
- lex:tag(lexer.STRING .. '.longstring', longstring))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str) + token('longstring', longstring))
+lex:add_style('longstring', lexer.styles.string)
-- Comments.
local line_comment = lexer.to_eol('--')
local block_comment = '--' * longstring
-lex:add_rule('comment', lex:tag(lexer.COMMENT, block_comment + line_comment))
+lex:add_rule('comment', token(lexer.COMMENT, block_comment + line_comment))
-- Numbers.
local lua_integer = P('-')^-1 * (lexer.hex_num + lexer.dec_num)
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.float + lua_integer))
+lex:add_rule('number', token(lexer.NUMBER, lexer.float + lua_integer))
-- Labels.
-lex:add_rule('label', lex:tag(lexer.LABEL, '::' * lexer.word * '::'))
+lex:add_rule('label', token(lexer.LABEL, '::' * lexer.word * '::'))
-- Attributes.
-lex:add_rule('attribute', lex:tag(lexer.ATTRIBUTE, '<' * lexer.space^0 *
- lexer.word_match('const close') * lexer.space^0 * '>'))
+lex:add_rule('attribute', token('attribute', '<' * lexer.space^0 * word_match('const close') *
+ lexer.space^0 * '>'))
+lex:add_style('attribute', lexer.styles.class)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, '..' + S('+-*/%^#=<>&|~;:,.{}[]()')))
+lex:add_rule('operator', token(lexer.OPERATOR, '..' + S('+-*/%^#=<>&|~;:,.{}[]()')))
-- Fold points.
local function fold_longcomment(text, pos, line, s, symbol)
@@ -72,73 +159,10 @@
lex:add_fold_point(lexer.KEYWORD, 'repeat', 'until')
lex:add_fold_point(lexer.COMMENT, '[', fold_longcomment)
lex:add_fold_point(lexer.COMMENT, ']', fold_longcomment)
-lex:add_fold_point(lexer.FUNCTION .. '.longstring', '[', ']')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('--'))
+lex:add_fold_point('longstring', '[', ']')
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', 'in', 'local',
- 'or', 'nil', 'not', 'repeat', 'return', 'then', 'true', 'until', 'while', --
- 'goto' -- 5.2
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'assert', 'collectgarbage', 'dofile', 'error', 'getmetatable', 'ipairs', 'load', 'loadfile',
- 'next', 'pairs', 'pcall', 'print', 'rawequal', 'rawget', 'rawset', 'require', 'select',
- 'setmetatable', 'tonumber', 'tostring', 'type', 'xpcall', --
- 'rawlen', -- 5.2
- 'warn' -- 5.4
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN .. '.library', {
- 'coroutine.create', 'coroutine.resume', 'coroutine.running', 'coroutine.status', 'coroutine.wrap',
- 'coroutine.yield', --
- 'coroutine.isyieldable', -- 5.3
- 'coroutine.close', -- 5.4
- 'package.loadlib', --
- 'package.searchpath', -- 5.2
- 'utf8.char', 'utf8.codepoint', 'utf8.codes', 'utf8.len', 'utf8.offset', -- 5.3
- 'string.byte', 'string.char', 'string.dump', 'string.find', 'string.format', 'string.gmatch',
- 'string.gsub', 'string.len', 'string.lower', 'string.match', 'string.rep', 'string.reverse',
- 'string.sub', 'string.upper', --
- 'string.pack', 'string.packsize', 'string.unpack', -- 5.3
- 'table.concat', 'table.insert', 'table.remove', 'table.sort', --
- 'table.pack', 'table.unpack', -- 5.2
- 'table.move', -- 5.3
- 'math.abs', 'math.acos', 'math.asin', 'math.atan', 'math.ceil', 'math.cos', 'math.deg',
- 'math.exp', 'math.floor', 'math.fmod', 'math.log', 'math.max', 'math.min', 'math.modf',
- 'math.rad', 'math.random', 'math.randomseed', 'math.sin', 'math.sqrt', 'math.tan', --
- 'math.tointeger', 'math.type', 'math.ult', -- 5.3
- 'io.close', 'io.flush', 'io.input', 'io.lines', 'io.open', 'io.output', 'io.popen', 'io.read',
- 'io.tmpfile', 'io.type', 'io.write', --
- 'os.clock', 'os.date', 'os.difftime', 'os.execute', 'os.exit', 'os.getenv', 'os.remove',
- 'os.rename', 'os.setlocale', 'os.time', 'os.tmpname', --
- 'debug', 'debug.debug', 'debug.gethook', 'debug.getinfo', 'debug.getlocal', 'debug.getmetatable',
- 'debug.getregistry', 'debug.getupvalue', 'debug.sethook', 'debug.setlocal', 'debug.setmetatable',
- 'debug.setupvalue', 'debug.traceback', --
- 'debug.getuservalue', 'debug.setuservalue', 'debug.upvalueid', 'debug.upvaluejoin' -- 5.2
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- '_G', '_VERSION', --
- '_ENV' -- 5.2
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN .. '.library', {
- 'coroutine', --
- 'package', 'package.cpath', 'package.loaded', 'package.path', 'package.preload', --
- 'package.config', 'package.searchers', -- 5.2
- 'utf8', 'utf8.charpattern', -- 5.3
- 'string', --
- 'table', --
- 'math', 'math.huge', 'math.pi', --
- 'math.maxinteger', 'math.mininteger', -- 5.3
- 'io', 'io.stderr', 'io.stdin', 'io.stdout', --
- 'os'
-})
-
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/makefile.lua lexers/makefile.lua
--- /home/matej/repos/tmp/scintillua/lexers/makefile.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/makefile.lua 2022-11-29 23:51:43.334329050 +0100
@@ -1,121 +1,88 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Makefile LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
-
-local lex = lexer.new(..., {lex_by_line = true})
-
--- Function definition.
-local word = (lexer.any - lexer.space - S('$:,#=(){}'))^1
-local func_name = lex:tag(lexer.FUNCTION, word)
-local ws = lex:get_rule('whitespace')
-local eq = lex:tag(lexer.OPERATOR, '=')
-lex:add_rule('function_def',
- lex:tag(lexer.KEYWORD, lexer.word_match('define')) * ws * func_name * ws^-1 * eq)
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
+
+local lex = lexer.new('makefile', {lex_by_line = true})
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, P('!')^-1 * lex:word_match(lexer.KEYWORD, true)))
+lex:add_rule('keyword', token(lexer.KEYWORD, P('!')^-1 * word_match({
+ -- GNU Make conditionals.
+ 'ifeq', 'ifneq', 'ifdef', 'ifndef', 'else', 'endif',
+ -- Other conditionals.
+ 'if', 'elseif', 'elseifdef', 'elseifndef',
+ -- Directives and other keywords.
+ 'define', 'endef', 'export', 'include', 'override', 'private', 'undefine', 'unexport', 'vpath'
+}, true)))
-- Targets.
-local special_target = lex:tag(lexer.CONSTANT_BUILTIN, '.' * lex:word_match('special_targets'))
--- local normal_target = lex:tag('target', (lexer.any - lexer.space - S(':+?!=#'))^1)
-local target = special_target -- + normal_target * (ws * normal_target)^0
-lex:add_rule('target', lexer.starts_line(target * ws^-1 * #(':' * lexer.space)))
-
--- Variable and function assignments.
-local func_assign = func_name * ws^-1 * eq *
- #P(function(input, index) return input:find('%$%(%d%)', index) end)
-local builtin_var = lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN))
-local var_name = lex:tag(lexer.VARIABLE, word)
-local var_assign = (builtin_var + var_name) * ws^-1 *
- lex:tag(lexer.OPERATOR, S(':+?!')^-1 * '=' + '::=')
-lex:add_rule('assign', lexer.starts_line(func_assign + var_assign, true) + B(': ') * var_assign)
+local special_target = token(lexer.CONSTANT, word_match{
+ '.PHONY', '.SUFFIXES', '.DEFAULT', '.PRECIOUS', '.INTERMEDIATE', '.SECONDARY', '.SECONDEXPANSION',
+ '.DELETE_ON_ERROR', '.IGNORE', '.LOW_RESOLUTION_TIME', '.SILENT', '.EXPORT_ALL_VARIABLES',
+ '.NOTPARALLEL', '.ONESHELL', '.POSIX'
+})
+local normal_target = token('target', (lexer.any - lexer.space - S(':#='))^1)
+local target_list = normal_target * (ws * normal_target)^0
+lex:add_rule('target', lexer.starts_line((special_target + target_list) * ws^0 * #(':' * -P('='))))
+lex:add_style('target', lexer.styles.label)
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S(':(){}|')))
+-- Variables.
+local word_char = lexer.any - lexer.space - S(':#=(){}')
+local assign = S(':+?')^-1 * '='
+local expanded_var = '$' * ('(' * word_char^1 * ')' + '{' * word_char^1 * '}')
+local auto_var = '$' * S('@%<?^+|*')
+local special_var = word_match{
+ 'MAKEFILE_LIST', '.DEFAULT_GOAL', 'MAKE_RESTARTS', '.RECIPEPREFIX', '.VARIABLES', '.FEATURES',
+ '.INCLUDE_DIRS', 'GPATH', 'MAKECMDGOALS', 'MAKESHELL', 'SHELL', 'VPATH'
+} * #(ws^0 * assign)
+local implicit_var = word_match{
+ -- Some common variables.
+ 'AR', 'AS', 'CC', 'CXX', 'CPP', 'FC', 'M2C', 'PC', 'CO', 'GET', 'LEX', 'YACC', 'LINT', 'MAKEINFO',
+ 'TEX', 'TEXI2DVI', 'WEAVE', 'CWEAVE', 'TANGLE', 'CTANGLE', 'RM',
+ -- Some common flag variables.
+ 'ARFLAGS', 'ASFLAGS', 'CFLAGS', 'CXXFLAGS', 'COFLAGS', 'CPPFLAGS', 'FFLAGS', 'GFLAGS', 'LDFLAGS',
+ 'LDLIBS', 'LFLAGS', 'YFLAGS', 'PFLAGS', 'RFLAGS', 'LINTFLAGS',
+ -- Other.
+ 'DESTDIR', 'MAKE', 'MAKEFLAGS', 'MAKEOVERRIDES', 'MFLAGS'
+} * #(ws^0 * assign)
+local variable = token(lexer.VARIABLE, expanded_var + auto_var + special_var + implicit_var)
+local computed_var = token(lexer.OPERATOR, '$' * S('({')) * token(lexer.FUNCTION, word_match{
+ -- Functions for String Substitution and Analysis.
+ 'subst', 'patsubst', 'strip', 'findstring', 'filter', 'filter-out', 'sort', 'word', 'wordlist',
+ 'words', 'firstword', 'lastword',
+ -- Functions for File Names.
+ 'dir', 'notdir', 'suffix', 'basename', 'addsuffix', 'addprefix', 'join', 'wildcard', 'realpath',
+ 'abspath',
+ -- Functions for Conditionals.
+ 'if', 'or', 'and',
+ -- Miscellaneous Functions.
+ 'foreach', 'call', 'value', 'eval', 'origin', 'flavor', 'shell',
+ -- Functions That Control Make.
+ 'error', 'warning', 'info'
+})
+lex:add_rule('variable', variable + computed_var)
--- Strings.
-lex:add_rule('string', lexer.range("'", true) + lexer.range('"', true))
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, assign + S(':$(){}')))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, word))
-
--- Functions.
-local builtin_func = lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local call_func = lex:tag(lexer.FUNCTION_BUILTIN, 'call') * ws * func_name
-local func = lex:tag(lexer.OPERATOR, '$' * S('({')) * (call_func + builtin_func)
-lex:add_rule('function', func)
-
--- Variables.
-local auto_var = lex:tag(lexer.OPERATOR, '$') * lex:tag(lexer.VARIABLE_BUILTIN, S('@%<?^+|*')) +
- lex:tag(lexer.OPERATOR, '$(') * lex:tag(lexer.VARIABLE_BUILTIN, S('@%<?^+*') * S('DF'))
-local var_ref = lex:tag(lexer.OPERATOR, P('$(') + '${') * (builtin_var + var_name)
-local var = auto_var + var_ref
-lex:add_rule('variable', var)
+lex:add_rule('identifier', token(lexer.IDENTIFIER, word_char^1))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
--- Embedded Bash in target rules.
+-- Embedded Bash.
local bash = lexer.load('bash')
bash:modify_rule('variable',
- lex:tag(lexer.VARIABLE, '$$' * word) + func + var + bash:get_rule('variable'))
-local bash_start_rule = lex:tag(lexer.WHITESPACE, '\t') + lex:tag(lexer.OPERATOR, ';')
-local bash_end_rule = lex:tag(lexer.WHITESPACE, '\n')
+ token(lexer.VARIABLE, '$$' * word_char^1) + bash:get_rule('variable') + variable)
+local bash_start_rule = token(lexer.WHITESPACE, '\t') + token(lexer.OPERATOR, ';')
+local bash_end_rule = token(lexer.WHITESPACE, '\n')
lex:embed(bash, bash_start_rule, bash_end_rule)
--- Embedded Bash in $(shell ...) calls.
-local shell = lexer.load('bash', 'bash.shell')
-bash_start_rule = #P('$(shell') * func
-bash_end_rule = -B('\\') * lex:tag(lexer.OPERATOR, ')')
-lex:embed(shell, bash_start_rule, bash_end_rule)
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'define', 'endef', -- multi-line
- 'else', 'endif', 'ifdef', 'ifeq', 'ifndef', 'ifneq', -- conditionals
- 'export', 'include', 'load', 'override', 'undefine', 'unexport', 'vpath', -- directives
- 'private', --
- 'if', 'elseif', 'elseifdef', 'elseifndef' -- non-Make conditionals
-})
-
-lex:set_word_list('special_targets', {
- 'DEFAULT', 'DELETE_ON_ERROR', 'EXPORT_ALL_VARIABLES', 'IGNORE', 'INTERMEDIATE',
- 'LOW_RESOLUTION_TIME', 'NOTPARALLEL', 'ONESHELL', 'PHONY', 'POSIX', 'PRECIOUS', 'SECONDARY',
- 'SECONDEXPANSION', 'SILENT', 'SUFFIXES'
-})
-
-lex:set_word_list(lexer.VARIABLE_BUILTIN, {
- -- Special.
- '.DEFAULT_GOAL', '.FEATURES', '.INCLUDE_DIRS', '.LIBPATTERNS', '.LOADED', '.RECIPEPREFIX',
- '.SHELLFLAGS', '.SHELLSTATUS', '.VARIABLES', --
- 'COMSPEC', 'MAKESHELL', 'SHELL', -- choosing the shell
- 'GPATH', 'VPATH', -- search
- -- Make.
- 'MAKE', 'MAKECMDGOALS', 'MAKEFILES', 'MAKEFILE_LIST', 'MAKEFLAGS', 'MAKELEVEL', 'MAKEOVERRIDES',
- 'MAKE_RESTARTS', 'MAKE_TERMERR', 'MAKE_TERMOUT', 'MFLAGS',
- -- Other.
- 'CURDIR', 'OUTPUT_OPTION', 'SUFFIXES',
- -- Implicit.
- 'AR', 'ARFLAGS', 'AS', 'ASFLAGS', 'CC', 'CFLAGS', 'CO', 'COFLAGS', 'CPP', 'CPPFLAGS', 'CTANGLE',
- 'CWEAVE', 'CXX', 'CXXFLAGS', 'FC', 'FFLAGS', 'GET', 'GFLAGS', 'LDFLAGS', 'LDLIBS', 'LEX',
- 'LFLAGS', 'LINT', 'LINTFLAGS', 'M2C', 'MAKEINFO', 'PC', 'PFLAGS', 'RFLAGS', 'RM', 'TANGLE', 'TEX',
- 'TEXI2DVI', 'WEAVE', 'YACC', 'YFLAGS', --
- 'bindir', 'DESTDIR', 'exec_prefix', 'libexecdir', 'prefix', 'sbindir' -- directory
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- -- Filename.
- 'abspath', 'addprefix', 'addsuffix', 'basename', 'dir', 'join', 'notdir', 'realpath', 'suffix',
- 'wildcard', --
- 'and', 'if', 'or', -- conditional
- 'error', 'info', 'warning', -- control
- 'filter', 'filter-out', 'findstring', 'firstword', 'lastword', 'patsubst', 'sort', 'strip',
- -- Text.
- 'subst', 'word', 'wordlist', 'words', --
- 'call', 'eval', 'file', 'flavor', 'foreach', 'origin', 'shell', 'value' -- other
-})
-
-lexer.property['scintillua.comment'] = '#'
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/markdown.lua lexers/markdown.lua
--- /home/matej/repos/tmp/scintillua/lexers/markdown.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/markdown.lua 2022-11-29 23:51:43.334329050 +0100
@@ -1,66 +1,75 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Markdown LPeg lexer.
-local lexer = lexer
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {no_user_word_lists = true})
-
--- Distinguish between horizontal and vertical space so html start rule has a chance to match.
-lex:modify_rule('whitespace', lex:tag(lexer.WHITESPACE, S(' \t')^1 + S('\r\n')^1))
+local lex = lexer.new('markdown')
-- Block elements.
-local function h(n)
- return lex:tag(string.format('%s.h%s', lexer.HEADING, n),
- lexer.to_eol(lexer.starts_line(string.rep('#', n))))
-end
+local function h(n) return token('h' .. n, lexer.to_eol(lexer.starts_line(string.rep('#', n)))) end
lex:add_rule('header', h(6) + h(5) + h(4) + h(3) + h(2) + h(1))
+local font_size = tonumber(lexer.property_expanded['style.default']:match('size:(%d+)')) or 10
+local function add_header_style(n)
+ lex:add_style('h' .. n, {fore = lexer.colors.red, size = (font_size + (6 - n))})
+end
+for i = 1, 6 do add_header_style(i) end
-lex:add_rule('hr',
- lex:tag('hr', lpeg.Cmt(lexer.starts_line(lpeg.C(S('*-_')), true), function(input, index, c)
- local line = input:match('[^\r\n]*', index):gsub('[ \t]', '')
- if line:find('[^' .. c .. ']') or #line < 2 then return nil end
- return (select(2, input:find('\r?\n', index)) or #input) + 1 -- include \n for eolfilled styles
+lex:add_rule('blockquote',
+ token(lexer.STRING, lpeg.Cmt(lexer.starts_line(S(' \t')^0 * '>'), function(input, index)
+ local _, e = input:find('\n[ \t]*\r?\n', index)
+ return (e or #input) + 1
end)))
-lex:add_rule('list', lex:tag(lexer.LIST,
- lexer.starts_line(lexer.digit^1 * '.' + S('*+-'), true) * S(' \t')))
+lex:add_rule('list', token('list',
+ lexer.starts_line(S(' \t')^0 * (S('*+-') + lexer.digit^1 * '.')) * S(' \t')))
+lex:add_style('list', lexer.styles.constant)
-local hspace = lexer.space - '\n'
+local hspace = S('\t\v\f\r ')
local blank_line = '\n' * hspace^0 * ('\n' + P(-1))
-local code_line = lexer.starts_line((B(' ') + B('\t')) * lexer.to_eol(), true)
-local code_block = lexer.range(lexer.starts_line('```', true), '\n```' * hspace^0 * ('\n' + P(-1)))
+local code_line = lexer.to_eol(lexer.starts_line(P(' ')^4 + '\t') * -P('<')) * lexer.newline^-1
+local code_block = lexer.range(lexer.starts_line('```'), '\n```' * hspace^0 * ('\n' + P(-1)))
local code_inline = lpeg.Cmt(lpeg.C(P('`')^1), function(input, index, bt)
-- `foo`, ``foo``, ``foo`bar``, `foo``bar` are all allowed.
local _, e = input:find('[^`]' .. bt .. '%f[^`]', index)
return (e or #input) + 1
end)
-lex:add_rule('block_code', lex:tag(lexer.CODE, code_line + code_block + code_inline))
+lex:add_rule('block_code', token('code', code_line + code_block + code_inline))
+lex:add_style('code', lexer.styles.embedded .. {eolfilled = true})
-lex:add_rule('blockquote',
- lex:tag(lexer.STRING, lpeg.Cmt(lexer.starts_line('>', true), function(input, index)
- local _, e = input:find('\n[ \t]*\r?\n', index) -- the next blank line (possibly with indentation)
- return (e or #input) + 1
+lex:add_rule('hr',
+ token('hr', lpeg.Cmt(lexer.starts_line(S(' \t')^0 * lpeg.C(S('*-_'))), function(input, index, c)
+ local line = input:match('[^\r\n]*', index):gsub('[ \t]', '')
+ if line:find('[^' .. c .. ']') or #line < 2 then return nil end
+ return (select(2, input:find('\r?\n', index)) or #input) + 1
end)))
+lex:add_style('hr', {back = lexer.colors.black, eolfilled = true})
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, S(' \t')^1 + S('\v\r\n')^1)
+lex:add_rule('whitespace', ws)
-- Span elements.
-lex:add_rule('escape', lex:tag(lexer.DEFAULT, P('\\') * 1))
+lex:add_rule('escape', token(lexer.DEFAULT, P('\\') * 1))
-local link_text = lexer.range('[', ']', true)
+local ref_link_label = token('link_label', lexer.range('[', ']', true) * ':')
+local ref_link_url = token('link_url', (lexer.any - lexer.space)^1)
+local ref_link_title = token(lexer.STRING, lexer.range('"', true, false) +
+ lexer.range("'", true, false) + lexer.range('(', ')', true))
+lex:add_rule('link_label', ref_link_label * ws * ref_link_url * (ws * ref_link_title)^-1)
+lex:add_style('link_label', lexer.styles.label)
+lex:add_style('link_url', {underlined = true})
+
+local link_label = P('!')^-1 * lexer.range('[', ']', true)
local link_target =
'(' * (lexer.any - S(') \t'))^0 * (S(' \t')^1 * lexer.range('"', false, false))^-1 * ')'
+local link_ref = S(' \t')^0 * lexer.range('[', ']', true)
local link_url = 'http' * P('s')^-1 * '://' * (lexer.any - lexer.space)^1 +
('<' * lexer.alpha^2 * ':' * (lexer.any - lexer.space - '>')^1 * '>')
-lex:add_rule('link', lex:tag(lexer.LINK, P('!')^-1 * link_text * link_target + link_url))
-
-local link_ref = lex:tag(lexer.REFERENCE, link_text * S(' \t')^0 * lexer.range('[', ']', true))
-local ref_link_label = lex:tag(lexer.REFERENCE, lexer.range('[', ']', true) * ':')
-local ws = lex:get_rule('whitespace')
-local ref_link_url = lex:tag(lexer.LINK, (lexer.any - lexer.space)^1)
-local ref_link_title = lex:tag(lexer.STRING, lexer.range('"', true, false) +
- lexer.range("'", true, false) + lexer.range('(', ')', true))
-lex:add_rule('link_ref', link_ref + ref_link_label * ws * ref_link_url * (ws * ref_link_title)^-1)
+lex:add_rule('link', token('link', link_label * (link_target + link_ref) + link_url))
+lex:add_style('link', {underlined = true})
local punct_space = lexer.punct + lexer.space
@@ -69,25 +78,27 @@
-- delimited ranges are not sufficient.
local function flanked_range(s, not_inword)
local fl_char = lexer.any - s - lexer.space
- local left_fl = B(punct_space - s) * s * #fl_char + s * #(fl_char - lexer.punct)
- local right_fl = B(lexer.punct) * s * #(punct_space - s) + B(fl_char) * s
+ local left_fl = lpeg.B(punct_space - s) * s * #fl_char + s * #(fl_char - lexer.punct)
+ local right_fl = lpeg.B(lexer.punct) * s * #(punct_space - s) + lpeg.B(fl_char) * s
return left_fl * (lexer.any - blank_line - (not_inword and s * #punct_space or s))^0 * right_fl
end
local asterisk_strong = flanked_range('**')
-local underscore_strong = (B(punct_space) + #lexer.starts_line('_')) * flanked_range('__', true) *
- #(punct_space + -1)
-lex:add_rule('strong', lex:tag(lexer.BOLD, asterisk_strong + underscore_strong))
+local underscore_strong = (lpeg.B(punct_space) + #lexer.starts_line('_')) *
+ flanked_range('__', true) * #(punct_space + -1)
+lex:add_rule('strong', token('strong', asterisk_strong + underscore_strong))
+lex:add_style('strong', {bold = true})
local asterisk_em = flanked_range('*')
-local underscore_em = (B(punct_space) + #lexer.starts_line('_')) * flanked_range('_', true) *
+local underscore_em = (lpeg.B(punct_space) + #lexer.starts_line('_')) * flanked_range('_', true) *
#(punct_space + -1)
-lex:add_rule('em', lex:tag(lexer.ITALIC, asterisk_em + underscore_em))
+lex:add_rule('em', token('em', asterisk_em + underscore_em))
+lex:add_style('em', {italics = true})
-- Embedded HTML.
local html = lexer.load('html')
-local start_rule = lexer.starts_line(P(' ')^-3) * #P('<') * html:get_rule('tag') -- P(' ')^4 starts code_line
-local end_rule = #blank_line * ws
+local start_rule = lexer.starts_line(P(' ')^-3) * #P('<') * html:get_rule('element') -- P(' ')^4 starts code_line
+local end_rule = token(lexer.DEFAULT, blank_line) -- TODO: lexer.WHITESPACE errors
lex:embed(html, start_rule, end_rule)
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/matlab.lua lexers/matlab.lua
--- /home/matej/repos/tmp/scintillua/lexers/matlab.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/matlab.lua 2022-11-29 23:51:43.334329050 +0100
@@ -77,7 +77,7 @@
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.COMMENT, '%{', '%}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('%'))
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/mediawiki.lua lexers/mediawiki.lua
--- /home/matej/repos/tmp/scintillua/lexers/mediawiki.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/mediawiki.lua 2022-11-29 23:51:43.334329050 +0100
@@ -12,22 +12,28 @@
lex:add_rule('comment', token(lexer.COMMENT, lexer.range('<!--', '-->')))
-- HTML-like tags
-local tag_start = token(lexer.TAG, '<' * P('/')^-1 * lexer.alnum^1 * lexer.space^0)
+local tag_start = token('tag_start', '<' * P('/')^-1 * lexer.alnum^1 * lexer.space^0)
local dq_str = '"' * ((lexer.any - S('>"\\')) + ('\\' * lexer.any))^0 * '"'
-local tag_attr = token(lexer.ATTRIBUTE, lexer.alpha^1 * lexer.space^0 *
+local tag_attr = token('tag_attr', lexer.alpha^1 * lexer.space^0 *
('=' * lexer.space^0 * (dq_str + (lexer.any - lexer.space - '>')^0)^-1)^0 * lexer.space^0)
-local tag_end = token(lexer.TAG, P('/')^-1 * '>')
+local tag_end = token('tag_end', P('/')^-1 * '>')
lex:add_rule('tag', tag_start * tag_attr^0 * tag_end)
+lex:add_style('tag_start', lexer.styles.keyword)
+lex:add_style('tag_attr', lexer.styles.type)
+lex:add_style('tag_end', lexer.styles.keyword)
-- Link
lex:add_rule('link', token(lexer.STRING, S('[]')))
-lex:add_rule('internal_link', B('[[') * token(lexer.LINK, (lexer.any - '|' - ']]')^1))
+lex:add_rule('internal_link', B('[[') * token('link_article', (lexer.any - '|' - ']]')^1))
+lex:add_style('link_article', lexer.styles.string .. {underlined = true})
-- Templates and parser functions.
lex:add_rule('template', token(lexer.OPERATOR, S('{}')))
lex:add_rule('parser_func',
- B('{{') * token(lexer.FUNCTION, '#' * lexer.alpha^1 + lexer.upper^1 * ':'))
-lex:add_rule('template_name', B('{{') * token(lexer.LINK, (lexer.any - S('{}|'))^1))
+ B('{{') * token('parser_func', '#' * lexer.alpha^1 + lexer.upper^1 * ':'))
+lex:add_rule('template_name', B('{{') * token('template_name', (lexer.any - S('{}|'))^1))
+lex:add_style('parser_func', lexer.styles['function'])
+lex:add_style('template_name', lexer.styles.operator .. {underlined = true})
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('-=|#~!')))
@@ -38,6 +44,4 @@
'__TOC__ __FORCETOC__ __NOTOC__ __NOEDITSECTION__ __NOCC__ __NOINDEX__')) * #lexer.space)
lex:add_style('behavior_switch', lexer.styles.keyword)
-lexer.property['scintillua.comment'] = '<!--|-->'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/meson.lua lexers/meson.lua
--- /home/matej/repos/tmp/scintillua/lexers/meson.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/meson.lua 2022-11-29 23:51:43.334329050 +0100
@@ -71,7 +71,8 @@
'compiled', 'returncode', 'stderr', 'stdout'
}
-- A method call must be followed by an opening parenthesis.
-lex:add_rule('method', token(lexer.FUNCTION_METHOD, method_names * #(lexer.space^0 * '(')))
+lex:add_rule('method', token('method', method_names * #(lexer.space^0 * '(')))
+lex:add_style('method', lexer.styles['function'])
-- Function.
-- https://mesonbuild.com/Reference-manual.html#functions
@@ -122,6 +123,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('()[]{}-=+/%:.,?<>')))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/moonscript.lua lexers/moonscript.lua
--- /home/matej/repos/tmp/scintillua/lexers/moonscript.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/moonscript.lua 2022-11-29 23:51:43.334329050 +0100
@@ -12,7 +12,7 @@
-- Table keys.
lex:add_rule('tbl_key', token('tbl_key', lexer.word * ':' + ':' * lexer.word))
-lex:add_style('tbl_key', lexer.styles.regex)
+lex:add_style('tbl_key', lexer.STYLE_REGEX)
-- Keywords.
lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
@@ -48,7 +48,7 @@
}))
-- Libraries.
-lex:add_rule('library', token(lexer.FUNCTION_BUILTIN, word_match{
+lex:add_rule('library', token('library', word_match{
-- Coroutine.
'coroutine', 'coroutine.create', 'coroutine.resume', 'coroutine.running', 'coroutine.status',
'coroutine.wrap', 'coroutine.yield',
@@ -106,6 +106,7 @@
-- Debug functions.
'debug.upvalue'
}))
+lex:add_style('library', lexer.styles.type)
-- Identifiers.
local identifier = token(lexer.IDENTIFIER, lexer.word)
@@ -120,7 +121,8 @@
local _, e = input:find(']' .. eq .. ']', index, true)
return (e or #input) + 1
end)
-lex:add_rule('string', token(lexer.STRING, sq_str + dq_str) + token(lexer.STRING, longstring))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str) + token('longstring', longstring))
+lex:add_style('longstring', lexer.styles.string)
-- Comments.
local line_comment = lexer.to_eol('--')
@@ -139,6 +141,4 @@
lex:add_rule('symbol', token('symbol', S('(){}[]')))
lex:add_style('symbol', lexer.styles.embedded)
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/myrddin.lua lexers/myrddin.lua
--- /home/matej/repos/tmp/scintillua/lexers/myrddin.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/myrddin.lua 2022-11-29 23:51:43.334329050 +0100
@@ -49,6 +49,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('`#_+-/*%<>~!=^&|~:;,.()[]{}')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/nemerle.lua lexers/nemerle.lua
--- /home/matej/repos/tmp/scintillua/lexers/nemerle.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/nemerle.lua 2022-11-29 23:51:43.334329050 +0100
@@ -60,7 +60,6 @@
lex:add_fold_point(lexer.PREPROCESSOR, 'ifndef', 'endif')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/networkd.lua lexers/networkd.lua
--- /home/matej/repos/tmp/scintillua/lexers/networkd.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/networkd.lua 2022-11-29 23:51:43.334329050 +0100
@@ -90,12 +90,12 @@
lex:add_rule('comment', token(lexer.COMMENT, lexer.starts_line(lexer.to_eol(S(';#')))))
-- Numbers.
-local integer = S('+-')^-1 * (lexer.hex_num + lexer.oct_num_('_') + lexer.dec_num_('_'))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local oct_num = '0' * S('01234567_')^1
+local integer = S('+-')^-1 * (lexer.hex_num + oct_num + dec)
lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, '='))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/nim.lua lexers/nim.lua
--- /home/matej/repos/tmp/scintillua/lexers/nim.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/nim.lua 2022-11-29 23:51:43.334329050 +0100
@@ -86,12 +86,17 @@
lex:add_rule('comment', token(lexer.COMMENT, block_comment + line_comment))
-- Numbers.
-lex:add_rule('number', token(lexer.NUMBER, lexer.float_('_') + lexer.integer_('_') *
- ("'" * S('iIuUfF') * (P('8') + '16' + '32' + '64'))^-1))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local hex = '0' * S('xX') * lexer.xdigit^1 * ('_' * lexer.xdigit^1)^0
+local bin = '0' * S('bB') * S('01')^1 * ('_' * S('01')^1)^0 * -lexer.xdigit
+local oct = '0o' * lpeg.R('07')^1
+local integer = S('+-')^-1 * (bin + hex + oct + dec) *
+ ("'" * S('iIuUfF') * (P('8') + '16' + '32' + '64'))^-1
+local float = lexer.digit^1 * ('_' * lexer.digit^1)^0 * ('.' * ('_' * lexer.digit)^0)^-1 * S('eE') *
+ S('+-')^-1 * lexer.digit^1 * ('_' * lexer.digit^1)^0
+lex:add_rule('number', token(lexer.NUMBER, float + integer))
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('=+-*/<>@$~&%|!?^.:\\`()[]{},;')))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/nsis.lua lexers/nsis.lua
--- /home/matej/repos/tmp/scintillua/lexers/nsis.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/nsis.lua 2022-11-29 23:51:43.334329050 +0100
@@ -145,6 +145,4 @@
-- Identifiers.
lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/objective_c.lua lexers/objective_c.lua
--- /home/matej/repos/tmp/scintillua/lexers/objective_c.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/objective_c.lua 2022-11-29 23:51:43.334329050 +0100
@@ -63,7 +63,6 @@
lex:add_fold_point(lexer.PREPROCESSOR, 'ifndef', 'endif')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/output.lua lexers/output.lua
--- /home/matej/repos/tmp/scintillua/lexers/output.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/output.lua 1970-01-01 01:00:00.000000000 +0100
@@ -1,97 +0,0 @@
--- Copyright 2022 Mitchell. See LICENSE.
--- LPeg lexer for tool output.
--- If a warning or error is recognized, tags its filename, line, column (if available),
--- and message, and sets the line state to 1 for an error (first bit), and 2 for a warning
--- (second bit).
--- This is similar to Lexilla's errorlist lexer.
-
-local lexer = lexer
-local starts_line = lexer.starts_line
-local P, S = lpeg.P, lpeg.S
-
-local lex = lexer.new(..., {lex_by_line = true})
-
--- Tags a pattern as plain text.
-local function text(patt) return lex:tag(lexer.DEFAULT, patt) end
-
--- Tags a pattern as a filename.
-local function filename(patt) return lex:tag('filename', patt) end
-
--- Typical line and column number patterns.
-local line = text('line ')^-1 * lex:tag('line', lexer.dec_num)
-local column = lex:tag('column', lexer.dec_num)
-
--- Tags a pattern as an error/warning/etc. message.
-local function message(patt) return lex:tag('message', patt) end
-
--- Immediately marks the current line as an error.
--- This should only be specified at the end of a rule, or else LPeg may backtrack and mistakenly
--- mark a non-error line.
-local function mark_error(_, pos)
- lexer.line_state[lexer.line_from_position(pos)] = 1
- return true
-end
-
--- Immediately marks the current line as a warning.
--- This should only be specified at the end of a rule, or else LPeg may backtrack and mistakenly
--- mark a non-warning line.
-local function mark_warning(_, pos)
- lexer.line_state[lexer.line_from_position(pos)] = 2
- return true
-end
-
--- filename:line: message (ruby)
--- filename:line:col: message (c, cpp, go, ...)
--- filename: line X: message (bash)
-local c_filename = filename((lexer.nonnewline - ':')^1)
-local colon = text(':' * P(' ')^-1)
-local warning = message(lexer.to_eol('warning: ')) * mark_warning
-local note = message(lexer.to_eol('note: ')) -- do not mark
-local error = message(lexer.to_eol()) * mark_error
-lex:add_rule('common', starts_line(c_filename) * colon * line * colon * (column * colon)^-1 *
- (warning + note + error))
-
--- prog: filename:line: message (awk, lua)
-lex:add_rule('prog', starts_line(text(lexer.word)) * colon * c_filename * colon * line * colon *
- (warning + error))
-
--- File "filename", line X (python)
-local py_filename = filename((lexer.nonnewline - '"')^1)
-lex:add_rule('python',
- starts_line(text('File "'), true) * py_filename * text('", ') * line * mark_error)
-
--- filename(line): error: message (d, cuda)
-local lparen, rparen = text('('), text(')')
-local d_filename = filename((lexer.nonnewline - '(')^1)
-local d_error = message(lexer.to_eol(S('Ee') * 'rror')) * mark_error
-lex:add_rule('dmd', starts_line(d_filename) * lparen * line * rparen * colon * d_error)
-
--- "filename" line X: message (gnuplot)
-local gp_filename = filename((lexer.nonnewline - '"')^1)
-lex:add_rule('gnuplot', starts_line(text('"')) * gp_filename * text('" ') * line * colon * error)
-
--- at com.path(filename:line) (java)
-lex:add_rule('java',
- starts_line(text('at ' * (lexer.nonnewline - '(')^1), true) * lparen * c_filename * colon * line *
- rparen * mark_error)
-
--- message in filename on line X (php)
-lex:add_rule('php', starts_line(message((lexer.nonnewline - ' in ')^1)) * text(' in ') *
- filename((lexer.nonnewline - ' on ')^1) * text(' on ') * line * mark_error)
-
--- filename(line, col): message (vb, csharp, fsharp, ...)
-lex:add_rule('vb',
- starts_line(filename((lexer.nonnewline - '(')^1)) * lparen * line * text(', ') * column * rparen *
- colon * error)
-
--- message at filename line X (perl)
-lex:add_rule('perl', starts_line(message((lexer.nonnewline - ' at ')^1)) * text(' at ') *
- filename((lexer.nonnewline - ' line ')^1) * text(' line ') * line * mark_error)
-
--- CMake Error at filename:line: (cmake)
-lex:add_rule('cmake',
- starts_line(text('CMake Error at ')) * c_filename * colon * line * colon * mark_error)
-
-lex:add_rule('any_line', lex:tag(lexer.DEFAULT, lexer.to_eol()))
-
-return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/pascal.lua lexers/pascal.lua
--- /home/matej/repos/tmp/scintillua/lexers/pascal.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/pascal.lua 2022-11-29 23:51:43.334329050 +0100
@@ -59,6 +59,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('.,;^@:=<>+-/*()[]')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/perl.lua lexers/perl.lua
--- /home/matej/repos/tmp/scintillua/lexers/perl.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/perl.lua 2022-11-29 23:51:43.334329050 +0100
@@ -1,16 +1,52 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Perl LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('perl')
+
+-- Whitespace.
+lex:add_rule('perl', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'STDIN', 'STDOUT', 'STDERR', 'BEGIN', 'END', 'CHECK', 'INIT', --
+ 'require', 'use', --
+ 'break', 'continue', 'do', 'each', 'else', 'elsif', 'foreach', 'for', 'if', 'last', 'local', 'my',
+ 'next', 'our', 'package', 'return', 'sub', 'unless', 'until', 'while', '__FILE__', '__LINE__',
+ '__PACKAGE__', --
+ 'and', 'or', 'not', 'eq', 'ne', 'lt', 'gt', 'le', 'ge'
+}))
-- Markers.
-lex:add_rule('marker', lex:tag(lexer.COMMENT, lexer.word_match('__DATA__ __END__') * lexer.any^0))
+lex:add_rule('marker', token(lexer.COMMENT, word_match('__DATA__ __END__') * lexer.any^0))
+
+-- Functions.
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
+ 'abs', 'accept', 'alarm', 'atan2', 'bind', 'binmode', 'bless', 'caller', 'chdir', 'chmod',
+ 'chomp', 'chop', 'chown', 'chr', 'chroot', 'closedir', 'close', 'connect', 'cos', 'crypt',
+ 'dbmclose', 'dbmopen', 'defined', 'delete', 'die', 'dump', 'each', 'endgrent', 'endhostent',
+ 'endnetent', 'endprotoent', 'endpwent', 'endservent', 'eof', 'eval', 'exec', 'exists', 'exit',
+ 'exp', 'fcntl', 'fileno', 'flock', 'fork', 'format', 'formline', 'getc', 'getgrent', 'getgrgid',
+ 'getgrnam', 'gethostbyaddr', 'gethostbyname', 'gethostent', 'getlogin', 'getnetbyaddr',
+ 'getnetbyname', 'getnetent', 'getpeername', 'getpgrp', 'getppid', 'getpriority', 'getprotobyname',
+ 'getprotobynumber', 'getprotoent', 'getpwent', 'getpwnam', 'getpwuid', 'getservbyname',
+ 'getservbyport', 'getservent', 'getsockname', 'getsockopt', 'glob', 'gmtime', 'goto', 'grep',
+ 'hex', 'import', 'index', 'int', 'ioctl', 'join', 'keys', 'kill', 'lcfirst', 'lc', 'length',
+ 'link', 'listen', 'localtime', 'log', 'lstat', 'map', 'mkdir', 'msgctl', 'msgget', 'msgrcv',
+ 'msgsnd', 'new', 'oct', 'opendir', 'open', 'ord', 'pack', 'pipe', 'pop', 'pos', 'printf', 'print',
+ 'prototype', 'push', 'quotemeta', 'rand', 'readdir', 'read', 'readlink', 'recv', 'redo', 'ref',
+ 'rename', 'reset', 'reverse', 'rewinddir', 'rindex', 'rmdir', 'scalar', 'seekdir', 'seek',
+ 'select', 'semctl', 'semget', 'semop', 'send', 'setgrent', 'sethostent', 'setnetent', 'setpgrp',
+ 'setpriority', 'setprotoent', 'setpwent', 'setservent', 'setsockopt', 'shift', 'shmctl', 'shmget',
+ 'shmread', 'shmwrite', 'shutdown', 'sin', 'sleep', 'socket', 'socketpair', 'sort', 'splice',
+ 'split', 'sprintf', 'sqrt', 'srand', 'stat', 'study', 'substr', 'symlink', 'syscall', 'sysread',
+ 'sysseek', 'system', 'syswrite', 'telldir', 'tell', 'tied', 'tie', 'time', 'times', 'truncate',
+ 'ucfirst', 'uc', 'umask', 'undef', 'unlink', 'unpack', 'unshift', 'untie', 'utime', 'values',
+ 'vec', 'wait', 'waitpid', 'wantarray', 'warn', 'write'
+}))
-- Strings.
local delimiter_matches = {['('] = ')', ['['] = ']', ['{'] = '}', ['<'] = '>'}
@@ -66,95 +102,49 @@
local lit_array = 'qw' * literal_delimited
local lit_cmd = 'qx' * literal_delimited
local lit_tr = (P('tr') + 'y') * literal_delimited2 * S('cds')^0
-local string = lex:tag(lexer.STRING,
+local string = token(lexer.STRING,
sq_str + dq_str + cmd_str + heredoc + lit_str + lit_array + lit_cmd + lit_tr)
-local regex_str = lexer.after_set('-<>+*!~\\=%&|^?:;([{', lexer.range('/', true) * S('imosx')^0)
+local regex_str = #P('/') * lexer.last_char_includes('-<>+*!~\\=%&|^?:;([{') *
+ lexer.range('/', true) * S('imosx')^0
local lit_regex = 'qr' * literal_delimited * S('imosx')^0
local lit_match = 'm' * literal_delimited * S('cgimosx')^0
local lit_sub = 's' * literal_delimited2 * S('ecgimosx')^0
-local regex = lex:tag(lexer.REGEX, regex_str + lit_regex + lit_match + lit_sub)
+local regex = token(lexer.REGEX, regex_str + lit_regex + lit_match + lit_sub)
lex:add_rule('string', string + regex)
--- Functions.
-lex:add_rule('function_builtin',
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)) *
- #(lexer.space^0 * P('(')^-1))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = lpeg.B('->') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (method + func) * #(lexer.space^0 * '('))
-
--- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
-
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
local line_comment = lexer.to_eol('#', true)
local block_comment = lexer.range(lexer.starts_line('=' * lexer.alpha), lexer.starts_line('=cut'))
-lex:add_rule('comment', lex:tag(lexer.COMMENT, block_comment + line_comment))
+lex:add_rule('comment', token(lexer.COMMENT, block_comment + line_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number_('_')))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local hex = '0' * S('xX') * lexer.xdigit^1 * ('_' * lexer.xdigit^1)^0
+local bin = '0' * S('bB') * S('01')^1 * ('_' * S('01')^1)^0 * -lexer.xdigit
+local integer = S('+-')^-1 * (hex + bin + dec)
+lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Variables.
-local builtin_var_s = '$' *
- (lpeg.R('09') + S('!"$%&\'()+,-./:;<=>?@\\]_`|~') + '^' * S('ACDEFHILMNOPRSTVWX')^-1 + 'ARGV')
-local builtin_var_a = '@' * (S('+-_F') + 'ARGV' + 'INC' + 'ISA')
-local builtin_var_h = '%' * (S('+-!') + '^' * S('H')^-1 + 'ENV' + 'INC' + 'SIG')
-lex:add_rule('variable_builtin',
- lex:tag(lexer.VARIABLE_BUILTIN, builtin_var_s + builtin_var_a + builtin_var_h))
-local special_var = '$' *
- ('^' * S('ADEFHILMOPSTWX')^-1 + S('\\"[]\'&`+*.,;=%~?@<>(|/!-') + ':' * (lexer.any - ':') +
- (P('$') * -lexer.word) + lexer.digit^1)
+-- LuaFormatter off
+local special_var = '$' * (
+ '^' * S('ADEFHILMOPSTWX')^-1 +
+ S('\\"[]\'&`+*.,;=%~?@<>(|/!-') +
+ ':' * (lexer.any - ':') +
+ P('$') * -lexer.word +
+ lexer.digit^1)
+-- LuaFormatter on
local plain_var = ('$#' + S('$@%')) * P('$')^0 * lexer.word + '$#'
-lex:add_rule('variable', lex:tag(lexer.VARIABLE, special_var + plain_var))
+lex:add_rule('variable', token(lexer.VARIABLE, special_var + plain_var))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('-<>+*!~\\=/%&|^.,?:;()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('-<>+*!~\\=/%&|^.,?:;()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'STDIN', 'STDOUT', 'STDERR', 'BEGIN', 'END', 'CHECK', 'INIT', --
- 'require', 'use', --
- 'break', 'continue', 'do', 'each', 'else', 'elsif', 'foreach', 'for', 'if', 'last', 'local', 'my',
- 'next', 'our', 'package', 'return', 'sub', 'unless', 'until', 'while', '__FILE__', '__LINE__',
- '__PACKAGE__', --
- 'and', 'or', 'not', 'eq', 'ne', 'lt', 'gt', 'le', 'ge'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'abs', 'accept', 'alarm', 'atan2', 'bind', 'binmode', 'bless', 'caller', 'chdir', 'chmod',
- 'chomp', 'chop', 'chown', 'chr', 'chroot', 'closedir', 'close', 'connect', 'cos', 'crypt',
- 'dbmclose', 'dbmopen', 'defined', 'delete', 'die', 'dump', 'each', 'endgrent', 'endhostent',
- 'endnetent', 'endprotoent', 'endpwent', 'endservent', 'eof', 'eval', 'exec', 'exists', 'exit',
- 'exp', 'fcntl', 'fileno', 'flock', 'fork', 'format', 'formline', 'getc', 'getgrent', 'getgrgid',
- 'getgrnam', 'gethostbyaddr', 'gethostbyname', 'gethostent', 'getlogin', 'getnetbyaddr',
- 'getnetbyname', 'getnetent', 'getpeername', 'getpgrp', 'getppid', 'getpriority', 'getprotobyname',
- 'getprotobynumber', 'getprotoent', 'getpwent', 'getpwnam', 'getpwuid', 'getservbyname',
- 'getservbyport', 'getservent', 'getsockname', 'getsockopt', 'glob', 'gmtime', 'goto', 'grep',
- 'hex', 'import', 'index', 'int', 'ioctl', 'join', 'keys', 'kill', 'lcfirst', 'lc', 'length',
- 'link', 'listen', 'localtime', 'log', 'lstat', 'map', 'mkdir', 'msgctl', 'msgget', 'msgrcv',
- 'msgsnd', 'new', 'oct', 'opendir', 'open', 'ord', 'pack', 'pipe', 'pop', 'pos', 'printf', 'print',
- 'prototype', 'push', 'quotemeta', 'rand', 'readdir', 'read', 'readlink', 'recv', 'redo', 'ref',
- 'rename', 'reset', 'reverse', 'rewinddir', 'rindex', 'rmdir', 'scalar', 'seekdir', 'seek',
- 'select', 'semctl', 'semget', 'semop', 'send', 'setgrent', 'sethostent', 'setnetent', 'setpgrp',
- 'setpriority', 'setprotoent', 'setpwent', 'setservent', 'setsockopt', 'shift', 'shmctl', 'shmget',
- 'shmread', 'shmwrite', 'shutdown', 'sin', 'sleep', 'socket', 'socketpair', 'sort', 'splice',
- 'split', 'sprintf', 'sqrt', 'srand', 'stat', 'study', 'substr', 'symlink', 'syscall', 'sysread',
- 'sysseek', 'system', 'syswrite', 'telldir', 'tell', 'tied', 'tie', 'time', 'times', 'truncate',
- 'ucfirst', 'uc', 'umask', 'undef', 'unlink', 'unpack', 'unshift', 'untie', 'utime', 'values',
- 'vec', 'wait', 'waitpid', 'wantarray', 'warn', 'write'
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'ARGV', 'ARGVOUT', 'DATA', 'ENV', 'INC', 'SIG', 'STDERR', 'STDIN', 'STDOUT'
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/php.lua lexers/php.lua
--- /home/matej/repos/tmp/scintillua/lexers/php.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/php.lua 2022-11-29 23:51:43.334329050 +0100
@@ -1,31 +1,60 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- PHP LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('php')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ -- Reserved words (http://php.net/manual/en/reserved.keywords.php)
+ '__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch',
+ 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else',
+ 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval',
+ 'exit', 'extends', 'final', 'finally', 'fn', 'for', 'foreach', 'function', 'global', 'goto', 'if',
+ 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list',
+ 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once',
+ 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor',
+ 'yield', 'from',
+ -- Reserved classes (http://php.net/manual/en/reserved.classes.php)
+ 'Directory', 'stdClass', '__PHP_Incomplete_Class', 'Exception', 'ErrorException',
+ 'php_user_filter', 'Closure', 'Generator', 'ArithmeticError', 'AssertionError',
+ 'DivisionByZeroError', 'Error', 'Throwable', 'ParseError', 'TypeError', 'self', 'static', 'parent'
+}))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
-
--- Functions.
-local word = (lexer.alpha + '_' + lpeg.R('\127\255')) * (lexer.alnum + '_' + lpeg.R('\127\255'))^0
-local func = lex:tag(lexer.FUNCTION, word)
-local method = lpeg.B('->') * lex:tag(lexer.FUNCTION_METHOD, word)
-lex:add_rule('function', (method + func) * #(lexer.space^0 * '('))
+lex:add_rule('type', token(lexer.TYPE,
+ word_match('int float bool string true false null void iterable object')))
-- Constants.
-lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
+lex:add_rule('constant', token(lexer.CONSTANT, word_match{
+ -- Compile-time (https://www.php.net/manual/en/reserved.keywords.php)
+ '__CLASS__', '__DIR__', '__FILE__', '__FUNCTION__', '__LINE__', '__METHOD__', '__NAMESPACE__',
+ '__TRAIT__',
+ -- Reserved (https://www.php.net/manual/en/reserved.constants.php)
+ 'PHP_VERSION', 'PHP_MAJOR_VERSION', 'PHP_MINOR_VERSION', 'PHP_RELEASE_VERSION', 'PHP_VERSION_ID',
+ 'PHP_EXTRA_VERSION', 'PHP_ZTS', 'PHP_DEBUG', 'PHP_MAXPATHLEN', 'PHP_OS', 'PHP_OS_FAMILY',
+ 'PHP_SAPI', 'PHP_EOL', 'PHP_INT_MAX', 'PHP_INT_MIN', 'PHP_INT_SIZE', 'PHP_FLOAT_DIG',
+ 'PHP_FLOAT_EPSILON', 'PHP_FLOAT_MIN', 'PHP_FLOAT_MAX', 'DEFAULT_INCLUDE_PATH', 'PEAR_INSTALL_DIR',
+ 'PEAR_EXTENSION_DIR', 'PHP_EXTENSION_DIR', 'PHP_PREFIX', 'PHP_BINDIR', 'PHP_BINARY', 'PHP_MANDIR',
+ 'PHP_LIBDIR', 'PHP_DATADIR', 'PHP_SYSCONFDIR', 'PHP_LOCALSTATEDIR', 'PHP_CONFIG_FILE_PATH',
+ 'PHP_CONFIG_FILE_SCAN_DIR', 'PHP_SHLIB_SUFFIX', 'PHP_FD_SETSIZE', 'E_ERROR', 'E_WARNING',
+ 'E_PARSE', 'E_NOTICE', 'E_CORE_ERROR', 'E_CORE_WARNING', 'E_COMPILE_ERROR', 'E_USER_ERROR',
+ 'E_USER_WARNING', 'E_USER_NOTICE', 'E_DEPRECATED', 'E_DEPRECATED', 'E_USER_DEPRECATED', 'E_ALL',
+ 'E_STRICT', '__COMPILER_HALT_OFFSET__'
+}))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, word))
+local word = (lexer.alpha + '_' + lpeg.R('\127\255')) * (lexer.alnum + '_' + lpeg.R('\127\255'))^0
+lex:add_rule('identifier', token(lexer.IDENTIFIER, word))
-- Variables.
-lex:add_rule('variable', lex:tag(lexer.VARIABLE, '$' * word))
+lex:add_rule('variable', token(lexer.VARIABLE, '$' * word))
-- Strings.
local sq_str = lexer.range("'")
@@ -34,74 +63,39 @@
local heredoc = '<<<' * P(function(input, index)
local _, e, delimiter = input:find('([%a_][%w_]*)[\n\r\f]+', index)
if delimiter then
- _, e = input:find('[\n\r\f]+' .. delimiter, e)
+ e = select(2, input:find('[\n\r\f]+' .. delimiter, e))
return e and e + 1
end
end)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str + bq_str + heredoc))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str + bq_str + heredoc))
-- TODO: interpolated code.
-- Comments.
local line_comment = lexer.to_eol(P('//') + '#')
local block_comment = lexer.range('/*', '*/')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, block_comment + line_comment))
+lex:add_rule('comment', token(lexer.COMMENT, block_comment + line_comment))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('!@%^*&()-+=|/?.,;:<>[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('!@%^*&()-+=|/?.,;:<>[]{}')))
-- Embedded in HTML.
local html = lexer.load('html')
-- Embedded PHP.
-local php_start_rule = lex:tag(lexer.PREPROCESSOR, '<?' * ('php' * lexer.space)^-1)
-local php_end_rule = lex:tag(lexer.PREPROCESSOR, '?>')
+local php_start_rule = token('php_tag', '<?' * ('php' * lexer.space)^-1)
+local php_end_rule = token('php_tag', '?>')
html:embed(lex, php_start_rule, php_end_rule)
+lex:add_style('php_tag', lexer.styles.embedded)
-- Fold points.
-lex:add_fold_point(lexer.PREPROCESSOR, '<?', '?>')
+lex:add_fold_point('php_tag', '<?', '?>')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.OPERATOR, '(', ')')
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- -- Reserved words (http://php.net/manual/en/reserved.keywords.php)
- '__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch',
- 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else',
- 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval',
- 'exit', 'extends', 'final', 'finally', 'fn', 'for', 'foreach', 'function', 'global', 'goto', 'if',
- 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list',
- 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once',
- 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor',
- 'yield', 'from',
- -- Reserved classes (http://php.net/manual/en/reserved.classes.php)
- 'Directory', 'stdClass', '__PHP_Incomplete_Class', 'Exception', 'ErrorException',
- 'php_user_filter', 'Closure', 'Generator', 'ArithmeticError', 'AssertionError',
- 'DivisionByZeroError', 'Error', 'Throwable', 'ParseError', 'TypeError', 'self', 'static', 'parent'
-})
-
-lex:set_word_list(lexer.TYPE, 'int float bool string true false null void iterable object')
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- -- Compile-time (https://www.php.net/manual/en/reserved.keywords.php)
- '__CLASS__', '__DIR__', '__FILE__', '__FUNCTION__', '__LINE__', '__METHOD__', '__NAMESPACE__',
- '__TRAIT__',
- -- Reserved (https://www.php.net/manual/en/reserved.constants.php)
- 'PHP_VERSION', 'PHP_MAJOR_VERSION', 'PHP_MINOR_VERSION', 'PHP_RELEASE_VERSION', 'PHP_VERSION_ID',
- 'PHP_EXTRA_VERSION', 'PHP_ZTS', 'PHP_DEBUG', 'PHP_MAXPATHLEN', 'PHP_OS', 'PHP_OS_FAMILY',
- 'PHP_SAPI', 'PHP_EOL', 'PHP_INT_MAX', 'PHP_INT_MIN', 'PHP_INT_SIZE', 'PHP_FLOAT_DIG',
- 'PHP_FLOAT_EPSILON', 'PHP_FLOAT_MIN', 'PHP_FLOAT_MAX', 'DEFAULT_INCLUDE_PATH', 'PEAR_INSTALL_DIR',
- 'PEAR_EXTENSION_DIR', 'PHP_EXTENSION_DIR', 'PHP_PREFIX', 'PHP_BINDIR', 'PHP_BINARY', 'PHP_MANDIR',
- 'PHP_LIBDIR', 'PHP_DATADIR', 'PHP_SYSCONFDIR', 'PHP_LOCALSTATEDIR', 'PHP_CONFIG_FILE_PATH',
- 'PHP_CONFIG_FILE_SCAN_DIR', 'PHP_SHLIB_SUFFIX', 'PHP_FD_SETSIZE', 'E_ERROR', 'E_WARNING',
- 'E_PARSE', 'E_NOTICE', 'E_CORE_ERROR', 'E_CORE_WARNING', 'E_COMPILE_ERROR', 'E_USER_ERROR',
- 'E_USER_WARNING', 'E_USER_NOTICE', 'E_DEPRECATED', 'E_DEPRECATED', 'E_USER_DEPRECATED', 'E_ALL',
- 'E_STRICT', '__COMPILER_HALT_OFFSET__'
-})
-
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/pico8.lua lexers/pico8.lua
--- /home/matej/repos/tmp/scintillua/lexers/pico8.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/pico8.lua 2022-11-29 23:51:43.334329050 +0100
@@ -2,34 +2,36 @@
-- PICO-8 lexer.
-- http://www.lexaloffle.com/pico-8.php
-local lexer = lexer
-local word_match = lexer.word_match
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('pico8')
+
+-- Whitespace
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords
lex:add_rule('keyword',
- lex:tag(lexer.KEYWORD, lexer.word_match('__gff__ __map__ __sfx__ __music__')))
+ token(lexer.KEYWORD, word_match('__lua__ __gfx__ __gff__ __map__ __sfx__ __music__')))
-- Identifiers
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('//', true)))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('//', true)))
-- Numbers
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.integer))
+lex:add_rule('number', token(lexer.NUMBER, lexer.integer))
-- Operators
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, '_'))
+lex:add_rule('operator', token(lexer.OPERATOR, '_'))
-- Embed Lua into PICO-8.
local lua = lexer.load('lua')
-local lua_start_rule = lex:tag(lexer.KEYWORD, word_match('__lua__'))
-local lua_end_rule = lex:tag(lexer.KEYWORD, word_match('__gfx__'))
+local lua_start_rule = token('pico8_tag', '__lua__')
+local lua_end_rule = token('pico8_tag', '__gfx__')
lex:embed(lua, lua_start_rule, lua_end_rule)
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_style('pico8_tag', lexer.styles.embedded)
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/pike.lua lexers/pike.lua
--- /home/matej/repos/tmp/scintillua/lexers/pike.lua 2022-11-30 11:15:03.681970939 +0100
+++ lexers/pike.lua 2022-11-29 23:51:43.334329050 +0100
@@ -48,7 +48,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/pkgbuild.lua lexers/pkgbuild.lua
--- /home/matej/repos/tmp/scintillua/lexers/pkgbuild.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/pkgbuild.lua 2022-11-29 23:51:43.334329050 +0100
@@ -73,7 +73,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/pony.lua lexers/pony.lua
--- /home/matej/repos/tmp/scintillua/lexers/pony.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/pony.lua 2022-11-29 23:51:43.334329050 +0100
@@ -91,6 +91,4 @@
-- Qualifiers.
lex:add_rule('qualifier', token(lexer.LABEL, '#' * word_match('read send share any alias')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/powershell.lua lexers/powershell.lua
--- /home/matej/repos/tmp/scintillua/lexers/powershell.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/powershell.lua 2022-11-29 23:51:43.334329050 +0100
@@ -57,6 +57,4 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/prolog.lua lexers/prolog.lua
--- /home/matej/repos/tmp/scintillua/lexers/prolog.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/prolog.lua 2022-11-29 23:51:43.334329050 +0100
@@ -30,8 +30,9 @@
local lex = lexer.new('prolog')
-local dialect = lexer.property['prolog.dialect']
-if dialect ~= 'gprolog' and dialog ~= 'swipl' then dialect = 'iso' end
+local dialects = setmetatable({gprolog = 'gprolog', swipl = 'swipl'},
+ {__index = function(_, _) return 'iso' end})
+local dialect = dialects[lexer.property['prolog.dialect']]
-- Directives.
local directives = {}
@@ -349,6 +350,4 @@
local dq_str = lexer.range('"', true)
lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/props.lua lexers/props.lua
--- /home/matej/repos/tmp/scintillua/lexers/props.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/props.lua 2022-11-29 23:51:43.334329050 +0100
@@ -1,36 +1,32 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Props LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {lex_by_line = true})
+local lex = lexer.new('props', {lex_by_line = true})
--- Identifiers.
-lex:add_rule('identifier',
- lex:tag(lexer.IDENTIFIER, (lexer.alpha + S('.-_')) * (lexer.alnum + S('.-_')^0)))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Colors.
local xdigit = lexer.xdigit
-lex:add_rule('color',
- lex:tag(lexer.NUMBER, '#' * xdigit * xdigit * xdigit * xdigit * xdigit * xdigit))
+lex:add_rule('color', token('color', '#' * xdigit * xdigit * xdigit * xdigit * xdigit * xdigit))
+lex:add_style('color', lexer.styles.number)
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-- Equals.
-lex:add_rule('equals', lex:tag(lexer.OPERATOR, '='))
+lex:add_rule('equals', token(lexer.OPERATOR, '='))
-- Strings.
local sq_str = lexer.range("'")
local dq_str = lexer.range('"')
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Variables.
-lex:add_rule('variable',
- lex:tag(lexer.OPERATOR, '$(') * lex:tag(lexer.VARIABLE, (lexer.nonnewline - lexer.space - ')')^0) *
- lex:tag(lexer.OPERATOR, ')'))
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('variable', token(lexer.VARIABLE, '$' * lexer.range('(', ')', true)))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/protobuf.lua lexers/protobuf.lua
--- /home/matej/repos/tmp/scintillua/lexers/protobuf.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/protobuf.lua 2022-11-29 23:51:43.334329050 +0100
@@ -43,6 +43,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('<>=|;,.()[]{}')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/ps.lua lexers/ps.lua
--- /home/matej/repos/tmp/scintillua/lexers/ps.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/ps.lua 2022-11-29 23:51:43.334329050 +0100
@@ -44,6 +44,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('[]{}')))
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/pure.lua lexers/pure.lua
--- /home/matej/repos/tmp/scintillua/lexers/pure.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/pure.lua 2022-11-29 23:51:43.334329050 +0100
@@ -45,6 +45,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, '..' + S('+-/*%<>~!=^&|?~:;,.()[]{}@#$`\\\'')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/python.lua lexers/python.lua
--- /home/matej/repos/tmp/scintillua/lexers/python.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/python.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,125 +1,106 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Python LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
local token, word_match = lexer.token, lexer.word_match
-local P, S, B = lpeg.P, lpeg.S, lpeg.B
+local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {fold_by_indentation = true})
+local lex = lexer.new('python', {fold_by_indentation = true})
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Classes.
-lex:add_rule('classdef', lex:tag(lexer.KEYWORD, 'class') * lex:get_rule('whitespace') *
- lex:tag(lexer.CLASS, lexer.word))
+lex:add_rule('classdef', token(lexer.KEYWORD, 'class') * ws * token(lexer.CLASS, lexer.word))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'and', 'as', 'assert', 'async', 'await', 'break', 'continue', 'def', 'del', 'elif', 'else',
+ 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda',
+ 'nonlocal', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield',
+ -- Descriptors/attr access.
+ '__get__', '__set__', '__delete__', '__slots__',
+ -- Class.
+ '__new__', '__init__', '__del__', '__repr__', '__str__', '__cmp__', '__index__', '__lt__',
+ '__le__', '__gt__', '__ge__', '__eq__', '__ne__', '__hash__', '__nonzero__', '__getattr__',
+ '__getattribute__', '__setattr__', '__delattr__', '__call__',
+ -- Operator.
+ '__add__', '__sub__', '__mul__', '__div__', '__floordiv__', '__mod__', '__divmod__', '__pow__',
+ '__and__', '__xor__', '__or__', '__lshift__', '__rshift__', '__nonzero__', '__neg__', '__pos__',
+ '__abs__', '__invert__', '__iadd__', '__isub__', '__imul__', '__idiv__', '__ifloordiv__',
+ '__imod__', '__ipow__', '__iand__', '__ixor__', '__ior__', '__ilshift__', '__irshift__',
+ -- Conversions.
+ '__int__', '__long__', '__float__', '__complex__', '__oct__', '__hex__', '__coerce__',
+ -- Containers.
+ '__len__', '__getitem__', '__missing__', '__setitem__', '__delitem__', '__contains__', '__iter__',
+ '__getslice__', '__setslice__', '__delslice__',
+ -- Module and class attribs.
+ '__doc__', '__name__', '__dict__', '__file__', '__path__', '__module__', '__bases__', '__class__',
+ '__self__',
+ -- Stdlib/sys.
+ '__builtin__', '__future__', '__main__', '__import__', '__stdin__', '__stdout__', '__stderr__',
+ -- Other.
+ '__debug__', '__doc__', '__import__', '__name__'
+}))
-- Functions.
-local builtin_func = -B('.') *
- lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-local special_func = lex:tag(lexer.FUNCTION_BUILTIN .. '.special',
- lex:word_match(lexer.FUNCTION_BUILTIN .. '.special'))
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-local method = B('.') * lex:tag(lexer.FUNCTION_METHOD, lexer.word)
-lex:add_rule('function', (builtin_func + special_func + method + func) * #(lexer.space^0 * '('))
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
+ 'abs', 'all', 'any', 'apply', 'basestring', 'bool', 'buffer', 'callable', 'chr', 'classmethod',
+ 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod',
+ 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'frozenset', 'getattr',
+ 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance',
+ 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'object',
+ 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr',
+ 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super',
+ 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'
+}))
-- Constants.
-local builtin_const = lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN))
-local attr = lex:tag(lexer.ATTRIBUTE, B('.') * lex:word_match(lexer.ATTRIBUTE) + '__name__')
-lex:add_rule('constant', builtin_const + attr)
-
--- Strings.
-local sq_str = lexer.range("'", true)
-local dq_str = lexer.range('"', true)
-local tq_str = lexer.range("'''") + lexer.range('"""')
-lex:add_rule('string', lex:tag(lexer.STRING, (S('fFrRbBrR') * S('rRfFrRbB') + S('ruRUfFbB'))^-1 *
- (tq_str + sq_str + dq_str)))
+lex:add_rule('constant', token(lexer.CONSTANT, word_match{
+ 'ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'DeprecationWarning',
+ 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError',
+ 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError',
+ 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None',
+ 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning',
+ 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration',
+ 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError',
+ 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
+ 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning',
+ 'ZeroDivisionError'
+}))
+
+-- Self.
+lex:add_rule('self', token('self', 'self'))
+lex:add_style('self', lexer.styles.type)
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#', true)))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#', true)))
+
+-- Strings.
+local sq_str = P('u')^-1 * lexer.range("'", true)
+local dq_str = P('U')^-1 * lexer.range('"', true)
+local tq_str = lexer.range("'''") + lexer.range('"""')
+-- TODO: raw_strs cannot end in single \.
+local raw_sq_str = P('u')^-1 * 'r' * lexer.range("'", false, false)
+local raw_dq_str = P('U')^-1 * 'R' * lexer.range('"', false, false)
+lex:add_rule('string', token(lexer.STRING, tq_str + sq_str + dq_str + raw_sq_str + raw_dq_str))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number_('_') * S('jJ')^-1))
+local dec = lexer.dec_num * S('Ll')^-1
+local bin = '0b' * S('01')^1 * ('_' * S('01')^1)^0
+local oct = lexer.oct_num * S('Ll')^-1
+local integer = S('+-')^-1 * (bin + lexer.hex_num + oct + dec)
+lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Decorators.
-lex:add_rule('decorator', lex:tag(lexer.ANNOTATION, '@' * lexer.word))
+lex:add_rule('decorator', token('decorator', lexer.to_eol('@')))
+lex:add_style('decorator', lexer.styles.preprocessor)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('!@%^&*()[]{}-=+/|:;.,<>~')))
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif',
- 'else', 'except', 'False', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
- 'lambda', 'None', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'True', 'try', 'while',
- 'with', 'yield'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'abs', 'aiter', 'all', 'any', 'anext', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes',
- 'callable', 'chr', 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
- 'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals',
- 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
- 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord',
- 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
- 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip', '__import__'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN .. '.special', {
- '__new__', '__init__', '__del__', '__repr__', '__str__', '__bytes', '__format__', '__lt__',
- '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__hash__', '__bool__', --
- '__getattr__', '__getattribute__', '__setattr__', '__delattr__', '__dir__', --
- '__get__', '__set__', '__delete__', '__slots__', --
- '__init_subclass__', '__set_name__', --
- '__instancecheck__', '__subclasscheck__', --
- '__class_getitem__', --
- '__call__', --
- '__len__', '__length_hint', '__getitem__', '__setitem__', '__delitem__', '__missing__',
- '__iter__', '__reversed__', '__contains__', --
- '__add__', '__sub__', '__mul__', '__matmul__', '__truediv__', '__floordiv__', '__mod__',
- '__divmod__', '__pow__', '__lshift__', '__rshift__', '__and__', '__xor__', '__or__', --
- '__radd__', '__rsub__', '__rmul__', '__rmatmul__', '__rtruediv__', '__rfloordiv__', '__rmod__',
- '__rdivmod__', '__rpow__', '__rlshift__', '__rrshift__', '__rand__', '__rxor__', '__ror__', --
- '__iadd__', '__isub__', '__imul__', '__imatmul__', '__itruediv__', '__ifloordiv__', '__imod__',
- '__idivmod__', '__ipow__', '__ilshift__', '__irshift__', '__iand__', '__ixor__', '__ior__', --
- '__neg__', '__pos__', '__abs__', '__invert__', '__complex__', '__int__', '__float__', '__index__',
- '__round__', '__trunc__', '__floor__', '__ceil__', --
- '__enter__', '__exit__', --
- '__match_args__', --
- '__await__', --
- '__aiter__', '__anext__', '__aenter__', '__aexit__' --
-})
-
-lex:set_word_list(lexer.CONSTANT_BUILTIN, {
- 'BaseException', 'Exception', 'Exception', 'ArithmeticError', 'BufferError', 'LookupError', --
- 'AssertionError', 'AttributeError', 'EOFError', 'FloatingPointError', 'GeneratorExit',
- 'ImportError', 'ModuleNotFoundError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
- 'MemoryError', 'NameError', 'NotImplementedError', 'OSError', 'OverflowError', 'RecursionError',
- 'ReferenceError', 'RuntimeError', 'StopIteration', 'StopAsyncIteration', 'SyntaxError',
- 'IndentationError', 'TabError', 'SystemError', 'SystemExit', 'TypeError', 'UnboundLocalError',
- 'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'ValueError',
- 'ZeroDivisionError', --
- 'EnvironmentError', 'IOError', 'WindowsError', --
- 'BlockingIOError', 'ChildProcessError', 'ConnectionError', 'BrokenPipeError',
- 'ConnectionAbortedError', 'ConnectionRefusedError', 'FileExistsError', 'FileNotFoundError',
- 'InterruptedError', 'IsADirectoryError', 'NotADirectoryError', 'PermissionError',
- 'ProcessLookupError', 'TimeoutError', --
- 'Warning', 'UserWarning', 'DeprecationWarning', 'PendingDeprecationWarning', 'SyntaxWarning',
- 'RuntimeWarning', 'FutureWarning', 'ImportWarning', 'UnicodeWarning', 'BytesWarning',
- 'ResourceWarning'
-})
-
-lex:set_word_list(lexer.ATTRIBUTE, {
- '__doc__', '__name__', '__qualname__', '__module__', '__defaults__', '__code__', '__globals__',
- '__dict__', '__closure__', '__annotations__', '__kwdefaults__', --
- '__file__', '__bases__', --
- '__class__', --
- '__self__', '__func__' --
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('operator', token(lexer.OPERATOR, S('!%^&*()[]{}-=+/|:;.,?<>~`')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rails.lua lexers/rails.lua
--- /home/matej/repos/tmp/scintillua/lexers/rails.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rails.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,13 +1,17 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Ruby on Rails LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {inherit = lexer.load('ruby')})
+local lex = lexer.new('rails', {inherit = lexer.load('ruby')})
--- Word lists.
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
+-- Whitespace
+lex:modify_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
+
+-- Functions.
+lex:modify_rule('function', token(lexer.FUNCTION, word_match{
-- ActionPack.
'before_filter', 'skip_before_filter', 'skip_after_filter', 'after_filter', 'around_filter',
'filter', 'filter_parameter_logging', 'layout', 'require_dependency', 'render', 'render_action',
@@ -34,8 +38,6 @@
-- ActiveSupport.
'alias_method_chain', 'alias_attribute', 'delegate', 'cattr_accessor', 'mattr_accessor',
'returning', 'memoize'
-}, true)
-
-lexer.property['scintillua.comment'] = '#'
+}) + lex:get_rule('function'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rc.lua lexers/rc.lua
--- /home/matej/repos/tmp/scintillua/lexers/rc.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rc.lua 2022-11-29 23:51:43.338329111 +0100
@@ -46,7 +46,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/README.md lexers/README.md
--- /home/matej/repos/tmp/scintillua/lexers/README.md 1970-01-01 01:00:00.000000000 +0100
+++ lexers/README.md 2022-11-29 23:51:43.326328927 +0100
@@ -0,0 +1,103 @@
+Lua LPeg lexers for vis
+=======================
+
+Vis reuses the [Lua](http://www.lua.org/) [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/)
+based lexers from the [Scintillua](https://orbitalquark.github.io/scintillua/index.html) project.
+
+# Vis integration
+
+Vis searches the lexers in the following locations (check the end of the
+`:help` output for the exact paths used by your binary):
+
+ * `$VIS_PATH/lexers`
+ * `./lua/lexers` relative to the binary location (using `/proc/self/exe`)
+ * `$XDG_CONFIG_HOME/vis/lexers` where `$XDG_CONFIG_HOME` refers to
+ `$HOME/.config` if unset.
+ * `/etc/vis/lexers`
+ * `/usr/local/share/vis/lexers` or `/usr/share/vis/lexers` depending on
+ the build configuration
+ * `package.path` the standard Lua search path is queried for `lexers/$name`
+
+At runtime a specific lexer can be loded by means of `:set syntax <name>`
+where `<name>` corresponds to the filename without the `.lua` extension.
+
+# Adding new lexers
+
+To add a new lexer, start with the template quoted below or a lexer of a
+similar language. Read the
+[lexer module documentation](https://orbitalquark.github.io/scintillua/api.html#lexer).
+The [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/) introduction might also
+be useful.
+
+For development purposes it is recommended to test the lexers from a lua
+script as described in the
+[Scintillua manual](https://orbitalquark.github.io/scintillua/manual.html#Using.Scintillua.as.a.Lua.Library).
+
+To enable auto syntax highlighting when opening a file you can associate your
+new lexer with a set of file extensions by adding a corresponding entry into
+the table found in [`plugins/filetype.lua`](../plugins/filetype.lua) file.
+
+Changes to existing lexers should also be sent upstream for consideration.
+
+A template for new lexers:
+
+```lua
+-- Copyright 2006-2021 Mitchell. See LICENSE.
+-- ? LPeg lexer.
+
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
+local P, S = lpeg.P, lpeg.S
+
+local lex = lexer.new('?')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
+
+-- Keywords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match[[
+ keyword1 keyword2 keyword3
+]]))
+
+-- Identifiers.
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
+
+-- Strings.
+local sq_str = lexer.range("'")
+local dq_str = lexer.range('"')
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
+
+-- Comments.
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
+
+-- Numbers.
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
+
+-- Operators.
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-*/%^=<>,.{}[]()')))
+
+-- Fold points.
+lex:add_fold_point(lexer.KEYWORD, 'start', 'end')
+lex:add_fold_point(lexer.OPERATOR, '{', '}')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
+
+return lex
+```
+
+# Color Themes
+
+The [`../themes directory`](../themes) contains the color
+schemes. Depending on the number of colors supported by your terminal,
+vis will start with either the [`default-16`](../themes/default-16.lua)
+or [`default-256`](../themes/default-256.lua) theme. Symlink it to
+your prefered style or add a command like the following one to your
+`visrc.lua`:
+
+```
+vis:command("set theme solarized")
+```
+
+# Dependencies
+
+ * [Lua](http://www.lua.org/) 5.1 or greater
+ * [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/) 1.0.0 or greater
diff -uNr /home/matej/repos/tmp/scintillua/lexers/reason.lua lexers/reason.lua
--- /home/matej/repos/tmp/scintillua/lexers/reason.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/reason.lua 2022-11-29 23:51:43.338329111 +0100
@@ -62,6 +62,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('=<>+-*/.,:;~!#%^&|?[](){}')))
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rebol.lua lexers/rebol.lua
--- /home/matej/repos/tmp/scintillua/lexers/rebol.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rebol.lua 2022-11-29 23:51:43.338329111 +0100
@@ -96,8 +96,7 @@
-- Fold points.
lex:add_fold_point(lexer.COMMENT, '{', '}')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines(';'))
lex:add_fold_point(lexer.OPERATOR, '[', ']')
-lexer.property['scintillua.comment'] = ';'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rest.lua lexers/rest.lua
--- /home/matej/repos/tmp/scintillua/lexers/rest.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rest.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,14 +1,54 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- reStructuredText LPeg lexer.
-local lexer = require('lexer')
-local token, word_match, starts_line = lexer.token, lexer.word_match, lexer.starts_line
+local l = require('lexer')
+local token, word_match, starts_line = l.token, l.word_match, l.starts_line
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new('rest')
+local M = {_NAME = 'rest'}
+
+-- Whitespace.
+local ws = token(l.WHITESPACE, S(' \t')^1 + l.newline^1)
+local any_indent = S(' \t')^0
+
+-- Section titles (2 or more characters).
+local adornment_chars = lpeg.C(S('!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'))
+local adornment = lpeg.C(adornment_chars^2 * any_indent) * (l.newline + -1)
+local overline = lpeg.Cmt(starts_line(adornment), function(input, index, adm, c)
+ if not adm:find('^%' .. c .. '+%s*$') then return nil end
+ local rest = input:sub(index)
+ local lines = 1
+ for line, e in rest:gmatch('([^\r\n]+)()') do
+ if lines > 1 and line:match('^(%' .. c .. '+)%s*$') == adm then
+ return index + e - 1
+ end
+ if lines > 3 or #line > #adm then return nil end
+ lines = lines + 1
+ end
+ return #input + 1
+end)
+local underline = lpeg.Cmt(starts_line(adornment), function(_, index, adm, c)
+ local pos = adm:match('^%' .. c .. '+%s*()$')
+ return pos and index - #adm + pos - 1 or nil
+end)
+-- Token needs to be a predefined one in order for folder to work.
+local title = token(l.CONSTANT, overline + underline)
+
+-- Lists.
+local bullet_list = S('*+-') -- TODO: '•‣⁃', as lpeg does not support UTF-8
+local enum_list = P('(')^-1 *
+ (l.digit^1 + S('ivxlcmIVXLCM')^1 + l.alnum + '#') * S('.)')
+local field_list = ':' * (l.any - ':')^1 * P(':')^-1
+local option_word = l.alnum * (l.alnum + '-')^0
+local option = S('-/') * option_word * (' ' * option_word)^-1 +
+ '--' * option_word * ('=' * option_word)^-1
+local option_list = option * (',' * l.space^1 * option)^-1
+local list = #(l.space^0 * (S('*+-:/') + enum_list)) *
+ starts_line(token('list', l.space^0 *
+ (option_list + bullet_list + enum_list + field_list) * l.space))
-- Literal block.
-local block = '::' * (lexer.newline + -1) * function(input, index)
+local block = P('::') * (l.newline + -1) * function(input, index)
local rest = input:sub(index)
local level, quote = #rest:match('^([ \t]*)')
for pos, indent, line in rest:gmatch('()[ \t]*()([^\r\n]+)') do
@@ -19,61 +59,33 @@
end
return #input + 1
end
-lex:add_rule('literal_block', token('literal_block', block))
-lex:add_style('literal_block', lexer.styles.embedded .. {eolfilled = true})
+local literal_block = token('literal_block', block)
--- Lists.
-local option_word = lexer.alnum * (lexer.alnum + '-')^0
-local option = S('-/') * option_word * (' ' * option_word)^-1 +
- ('--' * option_word * ('=' * option_word)^-1)
-local option_list = option * (',' * lexer.space^1 * option)^-1
-local bullet_list = S('*+-') -- TODO: '•‣⁃', as lpeg does not support UTF-8
-local enum_list = P('(')^-1 * (lexer.digit^1 + S('ivxlcmIVXLCM')^1 + lexer.alnum + '#') * S('.)')
-local field_list = ':' * (lexer.any - ':')^1 * P(':')^-1
-lex:add_rule('list', #(lexer.space^0 * (S('*+-:/') + enum_list)) *
- starts_line(token(lexer.LIST,
- lexer.space^0 * (option_list + bullet_list + enum_list + field_list) * lexer.space)))
+-- Line block.
+local line_block_char = token(l.OPERATOR, starts_line(any_indent * '|'))
-local any_indent = S(' \t')^0
-local word = lexer.alpha * (lexer.alnum + S('-.+'))^0
-local prefix = any_indent * '.. '
+local word = l.alpha * (l.alnum + S('-.+'))^0
-- Explicit markup blocks.
-local footnote_label = '[' * (lexer.digit^1 + '#' * word^-1 + '*') * ']'
-local footnote = token('footnote_block', prefix * footnote_label * lexer.space)
+local prefix = any_indent * '.. '
+local footnote_label = '[' * (l.digit^1 + '#' * word^-1 + '*') * ']'
+local footnote = token('footnote_block', prefix * footnote_label * l.space)
local citation_label = '[' * word * ']'
-local citation = token('citation_block', prefix * citation_label * lexer.space)
+local citation = token('citation_block', prefix * citation_label * l.space)
local link = token('link_block', prefix * '_' *
- (lexer.range('`') + (P('\\') * 1 + lexer.nonnewline - ':')^1) * ':' * lexer.space)
-lex:add_rule('markup_block', #prefix * starts_line(footnote + citation + link))
-lex:add_style('footnote_block', lexer.styles.label)
-lex:add_style('citation_block', lexer.styles.label)
-lex:add_style('link_block', lexer.styles.label)
-
--- Sphinx code block.
-local indented_block = function(input, index)
- local rest = input:sub(index)
- local level = #rest:match('^([ \t]*)')
- for pos, indent, line in rest:gmatch('()[ \t]*()([^\r\n]+)') do
- if indent - pos < level and line ~= ' ' or level == 0 and pos > 1 then return index + pos - 1 end
- end
- return #input + 1
-end
-local code_block =
- prefix * 'code-block::' * S(' \t')^1 * lexer.nonnewline^0 * (lexer.newline + -1) * indented_block
-lex:add_rule('code_block', #prefix * token('code_block', starts_line(code_block)))
-lex:add_style('code_block', lexer.styles.embedded .. {eolfilled = true})
+ (l.range('`') + (P('\\') * 1 + l.nonnewline - ':')^1) * ':' * l.space)
+local markup_block = #prefix * starts_line(footnote + citation + link)
-- Directives.
-local known_directive = token('directive', prefix * word_match{
+local directive_type = word_match({
-- Admonitions
- 'attention', 'caution', 'danger', 'error', 'hint', 'important', 'note', 'tip', 'warning',
- 'admonition',
+ 'attention', 'caution', 'danger', 'error', 'hint', 'important', 'note', 'tip',
+ 'warning', 'admonition',
-- Images
'image', 'figure',
-- Body elements
- 'topic', 'sidebar', 'line-block', 'parsed-literal', 'code', 'math', 'rubric', 'epigraph',
- 'highlights', 'pull-quote', 'compound', 'container',
+ 'topic', 'sidebar', 'line-block', 'parsed-literal', 'code', 'math', 'rubric',
+ 'epigraph', 'highlights', 'pull-quote', 'compound', 'container',
-- Table
'table', 'csv-table', 'list-table',
-- Document parts
@@ -85,101 +97,128 @@
-- Directives for substitution definitions
'replace', 'unicode', 'date',
-- Miscellaneous
- 'include', 'raw', 'class', 'role', 'default-role', 'title', 'restructuredtext-test-directive'
-} * '::' * lexer.space)
-local sphinx_directive = token('sphinx_directive', prefix * word_match{
+ 'include', 'raw', 'class', 'role', 'default-role', 'title',
+ 'restructuredtext-test-directive',
+}, '-')
+local known_directive = token('directive', prefix * directive_type * '::' *
+ l.space)
+local sphinx_directive_type = word_match({
-- The TOC tree.
'toctree',
-- Paragraph-level markup.
- 'note', 'warning', 'versionadded', 'versionchanged', 'deprecated', 'seealso', 'rubric',
- 'centered', 'hlist', 'glossary', 'productionlist',
+ 'note', 'warning', 'versionadded', 'versionchanged', 'deprecated', 'seealso',
+ 'rubric', 'centered', 'hlist', 'glossary', 'productionlist',
-- Showing code examples.
'highlight', 'literalinclude',
-- Miscellaneous
'sectionauthor', 'index', 'only', 'tabularcolumns'
-} * '::' * lexer.space)
-local unknown_directive = token('unknown_directive', prefix * word * '::' * lexer.space)
-lex:add_rule('directive',
- #prefix * starts_line(known_directive + sphinx_directive + unknown_directive))
-lex:add_style('directive', lexer.styles.keyword)
-lex:add_style('sphinx_directive', lexer.styles.keyword .. {bold = true})
-lex:add_style('unknown_directive', lexer.styles.keyword .. {italics = true})
-
--- Substitution definitions.
-lex:add_rule('substitution', #prefix * token('substitution', starts_line(prefix * lexer.range('|') *
- lexer.space^1 * word * '::' * lexer.space)))
-lex:add_style('substitution', lexer.styles.variable)
-
--- Comments.
-local line_comment = lexer.to_eol(prefix)
-local bprefix = any_indent * '..'
-local block_comment = bprefix * lexer.newline * indented_block
-lex:add_rule('comment', #bprefix * token(lexer.COMMENT, starts_line(line_comment + block_comment)))
+}, '-')
+local sphinx_directive = token('sphinx_directive', prefix *
+ sphinx_directive_type * '::' * l.space)
+local unknown_directive = token('unknown_directive', prefix * word * '::' *
+ l.space)
+local directive = #prefix * starts_line(known_directive + sphinx_directive +
+ unknown_directive)
--- Section titles (2 or more characters).
-local adornment_chars = lpeg.C(S('!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'))
-local adornment = lpeg.C(adornment_chars^2 * any_indent) * (lexer.newline + -1)
-local overline = lpeg.Cmt(starts_line(adornment), function(input, index, adm, c)
- if not adm:find('^%' .. c .. '+%s*$') then return nil end
+-- Sphinx code block.
+local indented_block = function(input, index)
local rest = input:sub(index)
- local lines = 1
- for line, e in rest:gmatch('([^\r\n]+)()') do
- if lines > 1 and line:match('^(%' .. c .. '+)%s*$') == adm then return index + e - 1 end
- if lines > 3 or #line > #adm then return nil end
- lines = lines + 1
+ local level = #rest:match('^([ \t]*)')
+ for pos, indent, line in rest:gmatch('()[ \t]*()([^\r\n]+)') do
+ if indent - pos < level and line ~= ' ' or level == 0 and pos > 1 then
+ return index + pos - 1
+ end
end
return #input + 1
-end)
-local underline = lpeg.Cmt(starts_line(adornment), function(_, index, adm, c)
- local pos = adm:match('^%' .. c .. '+%s*()$')
- return pos and index - #adm + pos - 1 or nil
-end)
--- Token needs to be a predefined one in order for folder to work.
-lex:add_rule('title', token(lexer.HEADING, overline + underline))
+end
+local code_block = prefix * 'code-block::' * S(' \t')^1 * l.nonnewline^0 *
+ (l.newline + -1) * indented_block
+local sphinx_block = #prefix * token('code_block', starts_line(code_block))
--- Line block.
-lex:add_rule('line_block_char', token(lexer.OPERATOR, starts_line(any_indent * '|')))
+-- Substitution definitions.
+local substitution = #prefix * token('substitution',
+ starts_line(prefix * l.range('|') * l.space^1 * word * '::' * l.space))
--- Whitespace.
-lex:add_rule('whitespace', token(lexer.WHITESPACE, S(' \t')^1 + lexer.newline^1))
+-- Comments.
+local line_comment = l.to_eol(prefix)
+local bprefix = any_indent * '..'
+local block_comment = bprefix * l.newline * indented_block
+local comment = #bprefix * token(l.COMMENT, starts_line(line_comment +
+ block_comment))
-- Inline markup.
-local strong = token(lexer.BOLD, lexer.range('**'))
-local em = token(lexer.ITALIC, lexer.range('*'))
-local inline_literal = token('inline_literal', lexer.range('``'))
-local postfix_link = (word + lexer.range('`')) * '_' * P('_')^-1
-local prefix_link = '_' * lexer.range('`')
-local link_ref = token(lexer.LINK, postfix_link + prefix_link)
+local em = token('em', l.range('*'))
+local strong = token('strong', l.range('**', '**'))
local role = token('role', ':' * word * ':' * (word * ':')^-1)
-local interpreted = role^-1 * token('interpreted', lexer.range('`')) * role^-1
-local footnote_ref = token(lexer.REFERENCE, footnote_label * '_')
-local citation_ref = token(lexer.REFERENCE, citation_label * '_')
-local substitution_ref = token('substitution', lexer.range('|', true) * ('_' * P('_')^-1)^-1)
-local link = token(lexer.LINK,
- lexer.alpha * (lexer.alnum + S('-.'))^1 * ':' * (lexer.alnum + S('/.+-%@'))^1)
-lex:add_rule('inline_markup',
- (strong + em + inline_literal + link_ref + interpreted + footnote_ref + citation_ref +
- substitution_ref + link) * -lexer.alnum)
-lex:add_style('inline_literal', lexer.styles.embedded)
-lex:add_style('role', lexer.styles.class)
-lex:add_style('interpreted', lexer.styles.string)
+local interpreted = role^-1 * token('interpreted', l.range('`')) * role^-1
+local inline_literal = token('inline_literal', l.range('``', '``'))
+local postfix_link = (word + l.range('`')) * '_' * P('_')^-1
+local prefix_link = '_' * l.range('`')
+local link_ref = token('link', postfix_link + prefix_link)
+local footnote_ref = token('footnote', footnote_label * '_')
+local citation_ref = token('citation', citation_label * '_')
+local substitution_ref = token('substitution', l.range('|', true) *
+ ('_' * P('_')^-1)^-1)
+local link = token('link', l.alpha * (l.alnum + S('-.'))^1 * ':' *
+ (l.alnum + S('/.+-%@'))^1)
+local inline_markup = (strong + em + inline_literal + link_ref + interpreted +
+ footnote_ref + citation_ref + substitution_ref + link) * -l.alnum
-- Other.
-lex:add_rule('non_space', token(lexer.DEFAULT, lexer.alnum * (lexer.any - lexer.space)^0))
-lex:add_rule('escape', token(lexer.DEFAULT, '\\' * lexer.any))
+local non_space = token(l.DEFAULT, l.alnum * (l.any - l.space)^0)
+local escape = token(l.DEFAULT, '\\' * l.any)
+
+M._rules = {
+ {'literal_block', literal_block},
+ {'list', list},
+ {'markup_block', markup_block},
+ {'code_block', sphinx_block},
+ {'directive', directive},
+ {'substitution', substitution},
+ {'comment', comment},
+ {'title', title},
+ {'line_block_char', line_block_char},
+ {'whitespace', ws},
+ {'inline_markup', inline_markup},
+ {'non_space', non_space},
+ {'escape', escape}
+}
+
+M._tokenstyles = {
+ list = l.STYLE_TYPE,
+ literal_block = l.STYLE_EMBEDDED .. ',eolfilled',
+ footnote_block = l.STYLE_LABEL,
+ citation_block = l.STYLE_LABEL,
+ link_block = l.STYLE_LABEL,
+ directive = l.STYLE_KEYWORD,
+ sphinx_directive = l.STYLE_KEYWORD .. ',bold',
+ unknown_directive = l.STYLE_KEYWORD .. ',italics',
+ code_block = l.STYLE_EMBEDDED .. ',eolfilled',
+ substitution = l.STYLE_VARIABLE,
+ strong = 'bold',
+ em = 'italics',
+ role = l.STYLE_CLASS,
+ interpreted = l.STYLE_STRING,
+ inline_literal = l.STYLE_EMBEDDED,
+ link = 'underlined',
+ footnote = 'underlined',
+ citation = 'underlined',
+}
--- Section-based folding.
local sphinx_levels = {
['#'] = 0, ['*'] = 1, ['='] = 2, ['-'] = 3, ['^'] = 4, ['"'] = 5
}
-function lex:fold(text, start_pos, start_line, start_level)
+-- Section-based folding.
+M._fold = function(text, start_pos, start_line, start_level)
local folds, line_starts = {}, {}
- for pos in (text .. '\n'):gmatch('().-\r?\n') do line_starts[#line_starts + 1] = pos end
- local style_at, CONSTANT, level = lexer.style_at, lexer.CONSTANT, start_level
- local sphinx = lexer.property_int['fold.scintillua.rest.by.sphinx.convention'] > 0
- local FOLD_BASE = lexer.FOLD_BASE
- local FOLD_HEADER, FOLD_BLANK = lexer.FOLD_HEADER, lexer.FOLD_BLANK
+ for pos in (text .. '\n'):gmatch('().-\r?\n') do
+ line_starts[#line_starts + 1] = pos
+ end
+ local style_at, CONSTANT, level = l.style_at, l.CONSTANT, start_level
+ local sphinx = l.property_int['fold.by.sphinx.convention'] > 0
+ local FOLD_BASE = l.FOLD_BASE
+ local FOLD_HEADER, FOLD_BLANK = l.FOLD_HEADER, l.FOLD_BLANK
for i = 1, #line_starts do
local pos, next_pos = line_starts[i], line_starts[i + 1]
local c = text:sub(pos, pos)
@@ -198,18 +237,16 @@
return folds
end
--- lexer.property['fold.by.sphinx.convention'] = '0'
+l.property['fold.by.sphinx.convention'] = '0'
--[[ Embedded languages.
-local bash = lexer.load('bash')
+local bash = l.load('bash')
local bash_indent_level
local start_rule =
- #(prefix * 'code-block' * '::' * lexer.space^1 * 'bash' * (lexer.newline + -1)) *
+ #(prefix * 'code-block' * '::' * l.space^1 * 'bash' * (l.newline + -1)) *
sphinx_directive * token('bash_begin', P(function(input, index)
bash_indent_level = #input:match('^([ \t]*)', index)
return index
end))]]
-lexer.property['scintillua.comment'] = '.. '
-
-return lex
+return M
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rexx.lua lexers/rexx.lua
--- /home/matej/repos/tmp/scintillua/lexers/rexx.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rexx.lua 2022-11-29 23:51:43.338329111 +0100
@@ -71,8 +71,7 @@
lex:add_fold_point(lexer.KEYWORD, 'do', 'end')
lex:add_fold_point(lexer.KEYWORD, 'select', 'return')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('--'))
-- lex:add_fold_point(lexer.OPERATOR, ':', ?)
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rhtml.lua lexers/rhtml.lua
--- /home/matej/repos/tmp/scintillua/lexers/rhtml.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rhtml.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,20 +1,20 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- RHTML LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {inherit = lexer.load('html')})
+local lex = lexer.new('rhtml', {inherit = lexer.load('html')})
-- Embedded Ruby.
local ruby = lexer.load('rails')
-local ruby_start_rule = lex:tag(lexer.PREPROCESSOR, '<%' * P('=')^-1)
-local ruby_end_rule = lex:tag(lexer.PREPROCESSOR, '%>')
+local ruby_start_rule = token('rhtml_tag', '<%' * P('=')^-1)
+local ruby_end_rule = token('rhtml_tag', '%>')
lex:embed(ruby, ruby_start_rule, ruby_end_rule)
+lex:add_style('rhtml_tag', lexer.styles.embedded)
-- Fold points.
-lex:add_fold_point(lexer.PREPROCESSOR, '<%', '%>')
-
-lexer.property['scintillua.comment'] = '<!--|-->'
+lex:add_fold_point('rhtml_tag', '<%', '%>')
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/routeros.lua lexers/routeros.lua
--- /home/matej/repos/tmp/scintillua/lexers/routeros.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/routeros.lua 2022-11-29 23:51:43.338329111 +0100
@@ -54,7 +54,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rpmspec.lua lexers/rpmspec.lua
--- /home/matej/repos/tmp/scintillua/lexers/rpmspec.lua 2022-11-30 11:24:39.014531645 +0100
+++ lexers/rpmspec.lua 1970-01-01 01:00:00.000000000 +0100
@@ -1,33 +0,0 @@
--- Copyright 2022 Matej Cepl mcepl.att.cepl.eu. See LICENSE.
-
-local lexer = require('lexer')
-local token, word_match = lexer.token, lexer.word_match
-local P, S = lpeg.P, lpeg.S
-
-local lex = lexer.new('rpmspec')
-
--- Whitespace.
-lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-
--- Comments.
-lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-
--- Strings.
-lex:add_rule('string', token(lexer.STRING, lexer.range('"')))
-
--- Keywords.
-lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
- 'Prereq', 'Summary', 'Name', 'Version', 'Packager', 'Requires', 'Recommends', 'Suggests',
- 'Supplements', 'Enhances', 'Icon', 'URL', 'Source', 'Patch', 'Prefix', 'Packager', 'Group',
- 'License', 'Release', 'BuildRoot', 'Distribution', 'Vendor', 'Provides', 'ExclusiveArch',
- 'ExcludeArch', 'ExclusiveOS', 'Obsoletes', 'BuildArch', 'BuildArchitectures', 'BuildRequires',
- 'BuildConflicts', 'BuildPreReq', 'Conflicts', 'AutoRequires', 'AutoReq', 'AutoReqProv',
- 'AutoProv', 'Epoch'
-}))
-
--- Macros
-lex:add_rule('command', token(lexer.FUNCTION, '%' * lexer.word))
-
-lexer.property['scintillua.comment'] = '#'
-
-return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rstats.lua lexers/rstats.lua
--- /home/matej/repos/tmp/scintillua/lexers/rstats.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rstats.lua 2022-11-29 23:51:43.338329111 +0100
@@ -46,7 +46,6 @@
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/ruby.lua lexers/ruby.lua
--- /home/matej/repos/tmp/scintillua/lexers/ruby.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/ruby.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,27 +1,42 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- Ruby LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('ruby')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'BEGIN', 'END', 'alias', 'and', 'begin', 'break', 'case', 'class', 'def', 'defined?', 'do',
+ 'else', 'elsif', 'end', 'ensure', 'false', 'for', 'if', 'in', 'module', 'next', 'nil', 'not',
+ 'or', 'redo', 'rescue', 'retry', 'return', 'self', 'super', 'then', 'true', 'undef', 'unless',
+ 'until', 'when', 'while', 'yield', '__FILE__', '__LINE__'
+}))
-- Functions.
-local builtin_func = lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
-lex:add_rule('function', -lpeg.B('.') * builtin_func * -S('.:|'))
+lex:add_rule('function', token(lexer.FUNCTION, word_match{
+ 'at_exit', 'autoload', 'binding', 'caller', 'catch', 'chop', 'chop!', 'chomp', 'chomp!', 'eval',
+ 'exec', 'exit', 'exit!', 'extend', 'fail', 'fork', 'format', 'gets', 'global_variables', 'gsub',
+ 'gsub!', 'include', 'iterator?', 'lambda', 'load', 'local_variables', 'loop', 'module_function',
+ 'open', 'p', 'print', 'printf', 'proc', 'putc', 'puts', 'raise', 'rand', 'readline', 'readlines',
+ 'require', 'require_relative', 'select', 'sleep', 'split', 'sprintf', 'srand', 'sub', 'sub!',
+ 'syscall', 'system', 'test', 'trace_var', 'trap', 'untrace_var'
+}) * -S('.:|'))
-- Identifiers.
local word_char = lexer.alnum + S('_!?')
local word = (lexer.alpha + '_') * word_char^0
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, word))
-- Comments.
local line_comment = lexer.to_eol('#', true)
local block_comment = lexer.range(lexer.starts_line('=begin'), lexer.starts_line('=end'))
-lex:add_rule('comment', lex:tag(lexer.COMMENT, block_comment + line_comment))
+lex:add_rule('comment', token(lexer.COMMENT, block_comment + line_comment))
-- Strings.
local delimiter_matches = {['('] = ')', ['['] = ']', ['{'] = '}'}
@@ -51,36 +66,42 @@
local s, e, indented, _, delimiter = input:find('([%-~]?)(["`]?)([%a_][%w_]*)%2[\n\r\f;]+', index)
if s == index and delimiter then
local end_heredoc = (#indented > 0 and '[\n\r\f]+ *' or '[\n\r\f]+')
- s, e = input:find(end_heredoc .. delimiter, e)
+ e = select(2, input:find(end_heredoc .. delimiter, e))
return e and e + 1 or #input + 1
end
end)
-local string = lex:tag(lexer.STRING, (sq_str + dq_str + lit_str + heredoc + cmd_str + lit_cmd +
+local string = token(lexer.STRING, (sq_str + dq_str + lit_str + heredoc + cmd_str + lit_cmd +
lit_array) * S('f')^-1)
-- TODO: regex_str fails with `obj.method /patt/` syntax.
-local regex_str = lexer.after_set('!%^&*([{-=+|:;,?<>~', lexer.range('/', true) * S('iomx')^0)
+local regex_str =
+ #P('/') * lexer.last_char_includes('!%^&*([{-=+|:;,?<>~') * lexer.range('/', true) * S('iomx')^0
local lit_regex = '%r' * literal_delimited * S('iomx')^0
-local regex = lex:tag(lexer.REGEX, regex_str + lit_regex)
+local regex = token(lexer.REGEX, regex_str + lit_regex)
lex:add_rule('string', string + regex)
-- Numbers.
-local numeric_literal = '?' * (lexer.any - lexer.space) * -word_char -- TODO: meta, control, etc.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number_('_') * S('ri')^-1 + numeric_literal))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0 * S('ri')^-1
+local bin = '0b' * S('01')^1 * ('_' * S('01')^1)^0 * -lexer.xdigit
+local integer = S('+-')^-1 * (bin + lexer.hex_num + lexer.oct_num + dec)
+-- TODO: meta, control, etc. for numeric_literal.
+local numeric_literal = '?' * (lexer.any - lexer.space) * -word_char
+lex:add_rule('number', token(lexer.NUMBER, lexer.float * S('ri')^-1 + integer + numeric_literal))
-- Variables.
local global_var = '$' *
(word + S('!@L+`\'=~/\\,.;<>_*"$?:') + lexer.digit + '-' * S('0FadiIKlpvw'))
local class_var = '@@' * word
local inst_var = '@' * word
-lex:add_rule('variable', lex:tag(lexer.VARIABLE, global_var + class_var + inst_var))
+lex:add_rule('variable', token(lexer.VARIABLE, global_var + class_var + inst_var))
-- Symbols.
-lex:add_rule('symbol', lex:tag(lexer.STRING .. '.symbol', ':' * P(function(input, index)
- if input:sub(index - 2, index - 2) ~= ':' then return true end
+lex:add_rule('symbol', token('symbol', ':' * P(function(input, index)
+ if input:sub(index - 2, index - 2) ~= ':' then return index end
end) * (word_char^1 + sq_str + dq_str)))
+lex:add_style('symbol', lexer.styles.constant)
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('!%^&*()[]{}-=+/|:;.,?<>~')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('!%^&*()[]{}-=+/|:;.,?<>~')))
-- Fold points.
local function disambiguate(text, pos, line, s)
@@ -102,24 +123,6 @@
lex:add_fold_point(lexer.OPERATOR, '[', ']')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '=begin', '=end')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'BEGIN', 'END', 'alias', 'and', 'begin', 'break', 'case', 'class', 'def', 'defined?', 'do',
- 'else', 'elsif', 'end', 'ensure', 'false', 'for', 'if', 'in', 'module', 'next', 'nil', 'not',
- 'or', 'redo', 'rescue', 'retry', 'return', 'self', 'super', 'then', 'true', 'undef', 'unless',
- 'until', 'when', 'while', 'yield', '__FILE__', '__LINE__'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'at_exit', 'autoload', 'binding', 'caller', 'catch', 'chop', 'chop!', 'chomp', 'chomp!', 'eval',
- 'exec', 'exit', 'exit!', 'extend', 'fail', 'fork', 'format', 'gets', 'global_variables', 'gsub',
- 'gsub!', 'include', 'iterator?', 'lambda', 'load', 'local_variables', 'loop', 'module_function',
- 'open', 'p', 'print', 'printf', 'proc', 'putc', 'puts', 'raise', 'rand', 'readline', 'readlines',
- 'require', 'require_relative', 'select', 'sleep', 'split', 'sprintf', 'srand', 'sub', 'sub!',
- 'syscall', 'system', 'test', 'trace_var', 'trap', 'untrace_var'
-})
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/rust.lua lexers/rust.lua
--- /home/matej/repos/tmp/scintillua/lexers/rust.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/rust.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,17 +1,31 @@
-- Copyright 2015-2022 Alejandro Baez (https://keybase.io/baez). See LICENSE.
-- Rust LPeg lexer.
-local lexer = lexer
+local lexer = require("lexer")
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
local C, Cmt = lpeg.C, lpeg.Cmt
-local lex = lexer.new(...)
+local lex = lexer.new('rust')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
+-- https://github.com/rust-lang/rust/blob/stable/src/libsyntax_pos/symbol.rs
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
+ 'Self', 'abstract', 'as', 'async', 'auto', 'await', 'become', 'box', 'break', 'catch', 'const',
+ 'continue', 'crate', 'default', 'do', 'dyn', 'else', 'enum', 'extern', 'false', 'final', 'fn',
+ 'for', 'if', 'impl', 'in', 'let', 'loop', 'macro', 'match', 'mod', 'move', 'mut', 'override',
+ 'priv', 'pub', 'ref', 'return', 'self', 'static', 'struct', 'super', 'trait', 'true', 'try',
+ 'type', 'typeof', 'union', 'unsafe', 'unsized', 'use', 'virtual', 'where', 'while', 'yield'
+}))
+
+-- Macro names.
+lex:add_rule('macro', token(lexer.FUNCTION, lexer.word * S("!")))
--- Library types.
-lex:add_rule('library', lex:tag(lexer.TYPE, lexer.upper * (lexer.lower + lexer.dec_num)^1))
+-- Library types
+lex:add_rule('library', token(lexer.LABEL, lexer.upper * (lexer.lower + lexer.dec_num)^1))
-- Numbers.
local identifier = P('r#')^-1 * lexer.word
@@ -22,7 +36,7 @@
local float = decimal_literal *
(Cmt(opt_cap('.' * decimal_literal) * opt_cap(S('eE') * S('+-')^-1 * integer_suffix(digit)) *
opt_cap(P('f32') + 'f64'), function(input, index, decimals, exponent, type)
- return decimals ~= '' or exponent ~= '' or type ~= ''
+ return decimals ~= "" or exponent ~= "" or type ~= ""
end) + '.' * -(S('._') + identifier))
local function prefixed_integer(prefix, digit) return P(prefix) * integer_suffix(digit) end
local bin = prefixed_integer('0b', S('01'))
@@ -30,13 +44,11 @@
local hex = prefixed_integer('0x', lexer.xdigit)
local integer = (bin + oct + hex + decimal_literal) *
(S('iu') * (P('8') + '16' + '32' + '64' + '128' + 'size'))^-1
-lex:add_rule('number', lex:tag(lexer.NUMBER, float + integer))
+lex:add_rule('number', token(lexer.NUMBER, float + integer))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
-
--- Lifetime annotation.
-lex:add_rule('lifetime', lex:tag(lexer.OPERATOR, S('<&') * P("'")))
+lex:add_rule('type', token(lexer.TYPE, word_match(
+ '() bool isize usize char str u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64')))
-- Strings.
local sq_str = P('b')^-1 * lexer.range("'", true)
@@ -45,61 +57,26 @@
local _, e = input:find('"' .. hashes, index, true)
return (e or #input) + 1
end)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str + raw_str))
-
--- Functions.
-local builtin_macros = lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN) * '!')
-local macros = lex:tag(lexer.FUNCTION, lexer.word * '!')
-local func = lex:tag(lexer.FUNCTION, lexer.word)
-lex:add_rule('function', (builtin_macros + macros + func) * #(lexer.space^0 * '('))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str + raw_str))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, identifier))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, identifier))
-- Comments.
local line_comment = lexer.to_eol('//', true)
local block_comment = lexer.range('/*', '*/', false, false, true)
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
-- Attributes.
-lex:add_rule('preprocessor', lex:tag(lexer.PREPROCESSOR, '#' * lexer.range('[', ']', true)))
+lex:add_rule('preprocessor', token(lexer.PREPROCESSOR, '#' * lexer.range('[', ']', true)))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>!=`^~@&|?#~:;,.()[]{}')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=`^~@&|?#~:;,.()[]{}')))
-- Fold points.
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
--- https://doc.rust-lang.org/std/#keywords
-lex:set_word_list(lexer.KEYWORD, {
- 'SelfTy', 'as', 'async', 'await', 'break', 'const', 'continue', 'crate', 'dyn', 'else', 'enum',
- 'extern', 'false', 'fn', 'for', 'if', 'impl', 'in', 'let', 'loop', 'match', 'mod', 'move', 'mut',
- 'pub', 'ref', 'return', 'self', 'static', 'struct', 'super', 'trait', 'true', 'type', 'union',
- 'unsafe', 'use', 'where', 'while'
-})
-
--- https://doc.rust-lang.org/std/#primitives
-lex:set_word_list(lexer.TYPE, {
- 'never', 'array', 'bool', 'char', 'f32', 'f64', 'fn', 'i8', 'i16', 'i32', 'i64', 'i128', 'isize',
- 'pointer', 'reference', 'slice', 'str', 'tuple', 'u8', 'u16', 'u32', 'u64', 'u128', 'unit',
- 'usize'
-})
-
-lex:set_word_list(lexer.FUNCTION_BUILTIN, {
- 'assert', 'assert_eq', 'assert_ne', 'cfg', 'column', 'compile_error', 'concat', 'dbg',
- 'debug_assert', 'debug_assert_eq', 'debug_assert_ne', 'env', 'eprint', 'eprintln', 'file',
- 'format', 'format_args', 'include', 'include_bytes', 'include_str', 'line', 'matches',
- 'module_path', 'option_env', 'panic', 'print', 'println', 'stringify', 'thread_local', 'todo',
- 'unimplemented', 'unreachable', 'vec', 'write', 'writeln',
- -- Experimental
- 'concat_bytes', 'concat_idents', 'const_format_args', 'format_args_nl', 'log_syntax',
- 'trace_macros',
- -- Deprecated
- 'try'
-})
-
-lexer.property['scintillua.comment'] = '//'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/sass.lua lexers/sass.lua
--- /home/matej/repos/tmp/scintillua/lexers/sass.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/sass.lua 2022-11-29 23:51:43.338329111 +0100
@@ -2,20 +2,23 @@
-- Sass CSS preprocessor LPeg lexer.
-- http://sass-lang.com
-local lexer = lexer
+local lexer = require('lexer')
+local token = lexer.token
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {inherit = lexer.load('css')})
+local lex = lexer.new('sass', {inherit = lexer.load('css')})
-- Line comments.
-lex:add_rule('line_comment', lex:tag(lexer.COMMENT, lexer.to_eol('//')))
+lex:add_rule('line_comment', token(lexer.COMMENT, lexer.to_eol('//')))
-- Variables.
-lex:add_rule('variable', lex:tag(lexer.VARIABLE, '$' * (lexer.alnum + S('_-'))^1))
+lex:add_rule('variable', token(lexer.VARIABLE, '$' * (lexer.alnum + S('_-'))^1))
-- Mixins.
-lex:add_rule('mixin', lex:tag(lexer.PREPROCESSOR, '@' * lexer.word))
+lex:add_rule('mixin', token('mixin', '@' * lexer.word))
+lex:add_style('mixin', lexer.styles['function'])
-lexer.property['scintillua.comment'] = '//'
+-- Fold points.
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/scala.lua lexers/scala.lua
--- /home/matej/repos/tmp/scintillua/lexers/scala.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/scala.lua 2022-11-29 23:51:43.338329111 +0100
@@ -55,7 +55,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/scheme.lua lexers/scheme.lua
--- /home/matej/repos/tmp/scintillua/lexers/scheme.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/scheme.lua 2022-11-29 23:51:43.338329111 +0100
@@ -169,7 +169,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.COMMENT, '#|', '|#')
-
-lexer.property['scintillua.comment'] = ';'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines(';'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/smalltalk.lua lexers/smalltalk.lua
--- /home/matej/repos/tmp/scintillua/lexers/smalltalk.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/smalltalk.lua 2022-11-29 23:51:43.338329111 +0100
@@ -41,6 +41,4 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '[', ']')
-lexer.property['scintillua.comment'] = '"|"'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/sml.lua lexers/sml.lua
--- /home/matej/repos/tmp/scintillua/lexers/sml.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/sml.lua 2022-11-29 23:51:43.338329111 +0100
@@ -88,6 +88,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('!*/+-^:@=<>()[]{},;._|#%&$?~`\\')))
-lexer.property['scintillua.comment'] = '(*)'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/snobol4.lua lexers/snobol4.lua
--- /home/matej/repos/tmp/scintillua/lexers/snobol4.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/snobol4.lua 2022-11-29 23:51:43.338329111 +0100
@@ -66,6 +66,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S'¬?$.!%*/#+-@⊥&^~\\='))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/spin.lua lexers/spin.lua
--- /home/matej/repos/tmp/scintillua/lexers/spin.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/spin.lua 2022-11-29 23:51:43.338329111 +0100
@@ -65,6 +65,4 @@
'<-' + '<-=' + '->' + '->=' + '><' + '><=' + '&=' + '|=' + 'and=' + 'or=' + '==' + '===' + '<>' +
'<>=' + '<=' + '>=' + '=<' + '=<=' + '=>' + '=>=' + '..' + S('+-/*<>~!&=^|?:.()[]@#\\')))
-lexer.property['scintillua.comment'] = "'"
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/sql.lua lexers/sql.lua
--- /home/matej/repos/tmp/scintillua/lexers/sql.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/sql.lua 2022-11-29 23:51:43.338329111 +0100
@@ -59,6 +59,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S(',()')))
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/strace.lua lexers/strace.lua
--- /home/matej/repos/tmp/scintillua/lexers/strace.lua 2022-11-30 11:15:31.590381699 +0100
+++ lexers/strace.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,31 +1,35 @@
--- Copyright 2017-2022 Marc André Tanner. See LICENSE.
+-- Copyright 2017-2021 Marc André Tanner. See LICENSE.
-- strace(1) output lexer
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local S, B = lpeg.S, lpeg.B
-local lex = lexer.new(..., {lex_by_line = true})
+local lex = lexer.new('strace', {lex_by_line = true})
+
+-- Whitespace
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Syscall
-lex:add_rule('syscall', lex:tag(lexer.FUNCTION, lexer.starts_line(lexer.word)))
+lex:add_rule('syscall', token(lexer.KEYWORD, lexer.starts_line(lexer.word)))
-- Upper case constants
-lex:add_rule('constant',
- lex:tag(lexer.CONSTANT, (lexer.upper + '_') * (lexer.upper + lexer.digit + '_')^0))
+lex:add_rule('constant', token(lexer.CONSTANT,
+ (lexer.upper + '_') * (lexer.upper + lexer.digit + '_')^0))
-- Single and double quoted strings
local sq_str = lexer.range("'", true)
local dq_str = lexer.range('"', true)
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Comments and text in parentheses at the line end
local comment = lexer.range('/*', '*/')
local description = lexer.range('(', ')') * lexer.newline
-lex:add_rule('comment', lex:tag(lexer.COMMENT, comment + description))
+lex:add_rule('comment', token(lexer.COMMENT, comment + description))
-lex:add_rule('result', lex:tag(lexer.TYPE, B(' = ') * lexer.integer))
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.float + lexer.integer))
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}')))
+lex:add_rule('result', token(lexer.TYPE, B(' = ') * lexer.integer))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('number', token(lexer.NUMBER, lexer.float + lexer.integer))
+lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>~!=^&|?~:;,.()[]{}')))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/systemd.lua lexers/systemd.lua
--- /home/matej/repos/tmp/scintillua/lexers/systemd.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/systemd.lua 2022-11-29 23:51:43.338329111 +0100
@@ -122,12 +122,12 @@
lex:add_rule('comment', token(lexer.COMMENT, lexer.starts_line(lexer.to_eol(S(';#')))))
-- Numbers.
-local integer = S('+-')^-1 * (lexer.hex_num + lexer.oct_num_('_') + lexer.dec_num_('_'))
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local oct_num = '0' * S('01234567_')^1
+local integer = S('+-')^-1 * (lexer.hex_num + oct_num + dec)
lex:add_rule('number', token(lexer.NUMBER, lexer.float + integer))
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, '='))
-lexer.property['scintillua.comment'] = '#'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/taskpaper.lua lexers/taskpaper.lua
--- /home/matej/repos/tmp/scintillua/lexers/taskpaper.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/taskpaper.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,27 +1,39 @@
-- Copyright (c) 2016-2022 Larry Hynes. See LICENSE.
-- Taskpaper LPeg lexer
-local lexer = lexer
+local lexer = require('lexer')
+local token = lexer.token
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {lex_by_line = true})
+local lex = lexer.new('taskpaper', {lex_by_line = true})
+
+local delimiter = P(' ') + P('\t')
-- Notes.
-local delimiter = lpeg.B(' ') + lpeg.B('\t')
-lex:add_rule('note', delimiter * lex:tag('note', lexer.to_eol(lexer.alnum)))
+lex:add_rule('note', token('note', delimiter^1 * lexer.to_eol(lexer.alnum)))
+lex:add_style('note', lexer.styles.constant)
-- Tasks.
-lex:add_rule('task', delimiter * lex:tag(lexer.LIST, '-'))
+lex:add_rule('task', token('task', delimiter^1 * '-' + lexer.newline))
+lex:add_style('task', lexer.styles['function'])
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Projects.
-lex:add_rule('project', lex:tag(lexer.HEADING,
- lexer.range(lexer.starts_line(lexer.alnum), ':') * lexer.newline))
+lex:add_rule('project',
+ token('project', lexer.range(lexer.starts_line(lexer.alnum), ':') * lexer.newline))
+lex:add_style('project', lexer.styles.label)
-- Tags.
-lex:add_rule('extended_tag', lex:tag(lexer.TAG .. '.extended', '@' * lexer.word * '(' *
+lex:add_rule('extended_tag', token('extended_tag', '@' * lexer.word * '(' *
(lexer.word + lexer.digit + '-')^1 * ')'))
-lex:add_rule('day_tag', lex:tag(lexer.TAG .. '.day', (P('@today') + '@tomorrow')))
-lex:add_rule('overdue_tag', lex:tag(lexer.TAG .. '.overdue', '@overdue'))
-lex:add_rule('plain_tag', lex:tag(lexer.TAG .. '.plain', '@' * lexer.word))
+lex:add_style('extended_tag', lexer.styles.comment)
+lex:add_rule('day_tag', token('day_tag', (P('@today') + '@tomorrow')))
+lex:add_style('day_tag', lexer.styles.class)
+lex:add_rule('overdue_tag', token('overdue_tag', '@overdue'))
+lex:add_style('overdue_tag', lexer.styles.preprocessor)
+lex:add_rule('plain_tag', token('plain_tag', '@' * lexer.word))
+lex:add_style('plain_tag', lexer.styles.comment)
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/tcl.lua lexers/tcl.lua
--- /home/matej/repos/tmp/scintillua/lexers/tcl.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/tcl.lua 2022-11-29 23:51:43.338329111 +0100
@@ -16,7 +16,7 @@
lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#' * P(function(input, index)
local i = index - 2
while i > 0 and input:find('^[ \t]', i) do i = i - 1 end
- if i < 1 or input:find('^[\r\n;]', i) then return true end
+ if i < 1 or input:find('^[\r\n;]', i) then return index end
end))))
-- Separator (semicolon).
@@ -41,7 +41,6 @@
-- Fold points.
lex:add_fold_point(lexer.KEYWORD, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/template.txt lexers/template.txt
--- /home/matej/repos/tmp/scintillua/lexers/template.txt 2022-11-30 11:15:03.685970998 +0100
+++ lexers/template.txt 1970-01-01 01:00:00.000000000 +0100
@@ -1,40 +0,0 @@
--- Copyright 2022 Mitchell. See LICENSE.
--- ? LPeg lexer.
-
-local lexer = lexer
-local P, S = lpeg.P, lpeg.S
-
-local lex = lexer.new(...)
-
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
-
--- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-
--- Strings.
-local sq_str = lexer.range("'")
-local dq_str = lexer.range('"')
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
-
--- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
-
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
-
--- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('+-*/%^=<>,.{}[]()')))
-
--- Fold points.
-lex:add_fold_point(lexer.KEYWORD, 'start', 'end')
-lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- 'keyword1', 'keyword2', 'keyword3'
-})
-
-lexer.property['scintillua.comment'] = '#'
-
-return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/texinfo.lua lexers/texinfo.lua
--- /home/matej/repos/tmp/scintillua/lexers/texinfo.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/texinfo.lua 2022-11-29 23:51:43.338329111 +0100
@@ -24,61 +24,17 @@
large documents.
]]
-local lexer = lexer
+local lexer = require('lexer')
local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('texinfo')
--- Directives.
-lex:add_rule('directive',
- lex:tag('command', ('@end' * lexer.space^1 + '@') * lex:word_match('directive', true)))
-
--- Chapters.
-lex:add_rule('chapter', lex:tag('command.section',
- ('@end' * lexer.space^1 + '@') * lex:word_match('chapter', true)))
-
--- Common keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, ('@end' * lexer.space^1 + '@') *
- lex:word_match(lexer.KEYWORD, true)))
-
--- Italics
-local nested_braces = lexer.range('{', '}', false, false, true)
-lex:add_rule('emph', lex:tag(lexer.ITALIC, '@emph' * nested_braces))
-
--- Bold
-lex:add_rule('strong', lex:tag(lexer.BOLD, '@strong' * nested_braces))
-
--- Identifiers
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
-
--- Strings.
-lex:add_rule('string', lex:tag(lexer.STRING, nested_braces))
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
--- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
-
--- Comments.
-local line_comment = lexer.to_eol('@c', true)
--- local line_comment_long = lexer.to_eol('@comment', true)
-local block_comment = lexer.range('@ignore', '@end ignore')
-lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment))
-
--- Fold points.
-lex:add_fold_point('command', '@titlepage', '@end titlepage')
-lex:add_fold_point('command', '@copying', '@end copying')
-lex:add_fold_point('command', '@ifset', '@end ifset')
-lex:add_fold_point('command', '@tex', '@end tex')
-lex:add_fold_point('command', '@itemize', '@end itemize')
-lex:add_fold_point('command', '@enumerate', '@end enumerate')
-lex:add_fold_point('command', '@multitable', '@end multitable')
-lex:add_fold_point('command', '@example', '@end example')
-lex:add_fold_point('command', '@smallexample', '@end smallexample')
-lex:add_fold_point('command', '@cartouche', '@end cartouche')
-lex:add_fold_point('command', '@startchapter', '@end startchapter')
-
--- Word lists.
-lex:set_word_list('directive', {
+-- Directives.
+local directives_base = word_match({
'end',
-- Custom keywords for chapter folding
'startchapter', 'endchapter',
@@ -119,9 +75,12 @@
-- not implemented
-- Ending a Texinfo document (page 4, column 2)
'bye'
-})
+}, true)
+lex:add_rule('directive', token('directives', ('@end' * lexer.space^1 + '@') * directives_base))
+lex:add_style('directives', lexer.styles['function'])
-lex:set_word_list('chapter', {
+-- Chapters.
+local chapters_base = word_match({
-- Chapter structuring (page 1, column 2)
'lowersections', 'raisesections', 'part',
-- Chapter structuring > Numbered, included in contents (page 1, column 2)
@@ -136,9 +95,12 @@
'appendixsubsubsec', 'appendixsubsubsection',
-- Chapter structuring > Unumbered, not included in contents, no new page (page 1, column 3)
'chapheading', 'majorheading', 'heading', 'subheading', 'subsubheading'
-})
+}, true)
+lex:add_rule('chapter', token('chapters', ('@end' * lexer.space^1 + '@') * chapters_base))
+lex:add_style('chapters', lexer.styles.class)
-lex:set_word_list(lexer.KEYWORD, {
+-- Common keywords.
+local keyword_base = word_match({
'end',
-- Beginning a Texinfo document (page 1, column 1)
'setfilename', 'settitle', 'insertcopying',
@@ -200,8 +162,44 @@
'sp', 'page', 'need', 'group', 'vskip'
-- Definition commands (page 3, column 2)
-- not implemented
-})
+}, true)
+lex:add_rule('keyword', token(lexer.KEYWORD, ('@end' * lexer.space^1 + '@') * keyword_base))
+
+-- Italics
+local nested_braces = lexer.range('{', '}', false, false, true)
+lex:add_rule('emph', token('emph', '@emph' * nested_braces))
+lex:add_style('emph', lexer.styles.string .. {italics = true})
+
+-- Bold
+lex:add_rule('strong', token('strong', '@strong' * nested_braces))
+lex:add_style('strong', lexer.styles.string .. {bold = true})
+
+-- Identifiers
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-lexer.property['scintillua.comment'] = '@c'
+-- Strings.
+lex:add_rule('string', token(lexer.STRING, nested_braces))
+
+-- Numbers.
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
+
+-- Comments.
+local line_comment = lexer.to_eol('@c', true)
+-- local line_comment_long = lexer.to_eol('@comment', true)
+local block_comment = lexer.range('@ignore', '@end ignore')
+lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
+
+-- Fold points.
+lex:add_fold_point('directives', '@titlepage', '@end titlepage')
+lex:add_fold_point('directives', '@copying', '@end copying')
+lex:add_fold_point('directives', '@ifset', '@end ifset')
+lex:add_fold_point('directives', '@tex', '@end tex')
+lex:add_fold_point('directives', '@itemize', '@end itemize')
+lex:add_fold_point('directives', '@enumerate', '@end enumerate')
+lex:add_fold_point('directives', '@multitable', '@end multitable')
+lex:add_fold_point('directives', '@example', '@end example')
+lex:add_fold_point('directives', '@smallexample', '@end smallexample')
+lex:add_fold_point('directives', '@cartouche', '@end cartouche')
+lex:add_fold_point('directives', '@startchapter', '@end startchapter')
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/tex.lua lexers/tex.lua
--- /home/matej/repos/tmp/scintillua/lexers/tex.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/tex.lua 2022-11-29 23:51:43.338329111 +0100
@@ -2,27 +2,31 @@
-- Plain TeX LPeg lexer.
-- Modified by Robert Gieseke.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('tex')
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('%')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('%')))
-- TeX environments.
-lex:add_rule('environment', lex:tag('environment', '\\' * (P('begin') + 'end') * lexer.word))
+lex:add_rule('environment', token('environment', '\\' * (P('begin') + 'end') * lexer.word))
+lex:add_style('environment', lexer.styles.keyword)
-- Commands.
-lex:add_rule('command', lex:tag('command', '\\' * (lexer.alpha^1 + S('#$&~_^%{}'))))
+lex:add_rule('command', token(lexer.KEYWORD, '\\' * (lexer.alpha^1 + S('#$&~_^%{}'))))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('$&#{}[]')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('$&#{}[]')))
-- Fold points.
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('%'))
lex:add_fold_point('environment', '\\begin', '\\end')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-lexer.property['scintillua.comment'] = '%'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/toml.lua lexers/toml.lua
--- /home/matej/repos/tmp/scintillua/lexers/toml.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/toml.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,27 +1,31 @@
-- Copyright 2015-2022 Alejandro Baez (https://keybase.io/baez). See LICENSE.
-- TOML LPeg lexer.
-local lexer = lexer
+local lexer = require("lexer")
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {fold_by_indentation = true})
+local lex = lexer.new('toml', {fold_by_indentation = true})
--- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lexer.word_match('true false')))
+-- Whitespace
+lex:add_rule('whitespace', token(lexer.WHITESPACE, S(' \t')^1 + lexer.newline^1))
+
+-- kewwords.
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match('true false')))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
local sq_str = lexer.range("'")
local dq_str = lexer.range('"')
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('#')))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('=+-,.{}[]()')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('=+-,.{}[]()')))
-- Datetime.
local year = lexer.digit * lexer.digit * lexer.digit * lexer.digit
@@ -33,12 +37,12 @@
local seconds = lexer.digit * lexer.digit
local fraction = '.' * lexer.digit^0
local time = hours * ':' * minutes * ':' * seconds * fraction^-1
+local T = S(' \t')^1 + S('tT')
local zone = 'Z' + S(' \t')^0 * S('-+') * hours * (':' * minutes)^-1
-lex:add_rule('datetime', lex:tag(lexer.NUMBER .. '.timestamp', date * (S('tT \t') * time * zone^-1)))
+lex:add_rule('datetime', token('timestamp', date * (T * time * zone^-1)))
+lex:add_style('timestamp', lexer.styles.number)
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number))
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_rule('number', token(lexer.NUMBER, lexer.number))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/txt2tags.lua lexers/txt2tags.lua
--- /home/matej/repos/tmp/scintillua/lexers/txt2tags.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/txt2tags.lua 2022-11-29 23:51:43.338329111 +0100
@@ -16,7 +16,7 @@
-- Titles
local alphanumeric = lexer.alnum + S('_-')
-local header_label = token('header_label_start', '[') * token(lexer.LABEL, alphanumeric^1) *
+local header_label = token('header_label_start', '[') * token('header_label', alphanumeric^1) *
token('header_label_end', ']')
local function h(level)
local equal = string.rep('=', level) * (lexer.nonnewline - '=')^1 * string.rep('=', level)
@@ -36,29 +36,29 @@
(delimiter * nonspace * (lexer.nonnewline - nonspace * delimiter)^0 * nonspace * delimiter *
S(delimiter)^0))
end
-local bold = span(lexer.BOLD, '**')
-local italic = span(lexer.ITALIC, '//')
-local underline = span(lexer.UNDERLINE, '__')
+local bold = span('bold', '**')
+local italic = span('italic', '//')
+local underline = span('underline', '__')
local strike = span('strike', '--')
-local mono = span(lexer.CODE, '``')
-local raw = span(lexer.DEFAULT, '""')
+local mono = span('mono', '``')
+local raw = span('raw', '""')
local tagged = span('tagged', "''")
local inline = bold + italic + underline + strike + mono + raw + tagged
-- Link.
-local email = token(lexer.LINK,
+local email = token('email',
(nonspace - '@')^1 * '@' * (nonspace - '.')^1 * ('.' * (nonspace - S('.?'))^1)^1 *
('?' * nonspace^1)^-1)
-local host = token(lexer.LINK,
+local host = token('host',
word_match('www ftp', true) * (nonspace - '.')^0 * '.' * (nonspace - '.')^1 * '.' *
(nonspace - S(',.'))^1)
-local url = token(lexer.LINK,
+local url = token('url',
(nonspace - '://')^1 * '://' * (nonspace - ',' - '.')^1 * ('.' * (nonspace - S(',./?#'))^1)^1 *
('/' * (nonspace - S('./?#'))^0 * ('.' * (nonspace - S(',.?#'))^1)^0)^0 *
('?' * (nonspace - '#')^1)^-1 * ('#' * nonspace^0)^-1)
-local label_with_address = token(lexer.LABEL, '[') * lexer.space^0 *
- token(lexer.LABEL, ((nonspace - ']')^1 * lexer.space^1)^1) * token(lexer.LINK, (nonspace - ']')^1) *
- token(lexer.LABEL, ']')
+local label_with_address = token('label_start', '[') * lexer.space^0 *
+ token('address_label', ((nonspace - ']')^1 * lexer.space^1)^1) *
+ token('address', (nonspace - ']')^1) * token('label_end', ']')
local link = label_with_address + url + host + email
-- Line.
@@ -68,22 +68,22 @@
local image_only = token('image_start', '[') * token('image', (nonspace - ']')^1) *
token('image_end', ']')
local image_link = token('image_link_start', '[') * image_only *
- token('image_link_sep', lexer.space^1) * token(lexer.LINK, (nonspace - ']')^1) *
+ token('image_link_sep', lexer.space^1) * token('image_link', (nonspace - ']')^1) *
token('image_link_end', ']')
local image = image_link + image_only
-- Macro.
-local macro = token(lexer.PREPROCESSOR, '%%' * (nonspace - '(')^1 * lexer.range('(', ')', true)^-1)
+local macro = token('macro', '%%' * (nonspace - '(')^1 * lexer.range('(', ')', true)^-1)
-- Verbatim.
local verbatim_line = lexer.to_eol(lexer.starts_line('```') * S(' \t'))
local verbatim_block = lexer.range(lexer.starts_line('```'))
-local verbatim_area = token(lexer.CODE, verbatim_block + verbatim_line)
+local verbatim_area = token('verbatim_area', verbatim_block + verbatim_line)
-- Raw.
local raw_line = lexer.to_eol(lexer.starts_line('"""') * S(' \t'))
local raw_block = lexer.range(lexer.starts_line('"""'))
-local raw_area = token(lexer.DEFAULT, raw_block + raw_line)
+local raw_area = token('raw_area', raw_block + raw_line)
-- Tagged.
local tagged_line = lexer.to_eol(lexer.starts_line('\'\'\'') * S(' \t'))
@@ -121,9 +121,24 @@
for n = 5, 1, -1 do
lex:add_style('h' .. n, {fore = lexer.colors.red, size = font_size + (6 - n)})
end
+lex:add_style('header_label', lexer.styles.label)
+lex:add_style('email', {underlined = true})
+lex:add_style('host', {underlined = true})
+lex:add_style('url', {underlined = true})
+lex:add_style('address_label', lexer.styles.label)
+lex:add_style('address', {underlined = true})
lex:add_style('image', {fore = lexer.colors.green})
+lex:add_style('image_link', {underlined = true})
+lex:add_style('macro', lexer.styles.preprocessor)
+lex:add_style('bold', {bold = true})
+lex:add_style('italic', {italics = true})
+lex:add_style('underline', {underlined = true})
lex:add_style('strike', {italics = true}) -- a strike style is not available
+lex:add_style('mono', {font = 'mono'})
+lex:add_style('raw', {back = lexer.colors.grey})
lex:add_style('tagged', lexer.styles.embedded)
+lex:add_style('verbatim_area', {font = 'mono'}) -- in consistency with mono
+lex:add_style('raw_area', {back = lexer.colors.grey}) -- in consistency with raw
lex:add_style('tagged_area', lexer.styles.embedded) -- in consistency with tagged
lex:add_style('table_sep', {fore = lexer.colors.green})
lex:add_style('header_cell_content', {fore = lexer.colors.green})
diff -uNr /home/matej/repos/tmp/scintillua/lexers/typescript.lua lexers/typescript.lua
--- /home/matej/repos/tmp/scintillua/lexers/typescript.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/typescript.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,18 +1,23 @@
-- Copyright 2021-2022 Mitchell. See LICENSE.
-- TypeScript LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {inherit = lexer.load('javascript')})
+local lex = lexer.new('typescript', {inherit = lexer.load('javascript')})
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, 'abstract as constructor declare is module namespace require type',
- true)
+-- Whitespace
+lex:modify_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-lex:set_word_list(lexer.TYPE, 'boolean number bigint string unknown any void never symbol object',
- true)
-
-lexer.property['scintillua.comment'] = '//'
+-- Keywords.
+lex:modify_rule('keyword', token(lexer.KEYWORD, word_match[[
+ abstract as constructor declare is module namespace require type
+]]) + lex:get_rule('keyword'))
+
+-- Types.
+lex:modify_rule('type', token(lexer.TYPE, word_match[[
+ boolean number bigint string unknown any void never symbol object
+]]) + lex:get_rule('type'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/vala.lua lexers/vala.lua
--- /home/matej/repos/tmp/scintillua/lexers/vala.lua 2022-11-30 11:15:03.685970998 +0100
+++ lexers/vala.lua 2022-11-29 23:51:43.338329111 +0100
@@ -56,7 +56,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/vb.lua lexers/vb.lua
--- /home/matej/repos/tmp/scintillua/lexers/vb.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/vb.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,31 +1,49 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- VisualBasic LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(..., {case_insensitive_fold_points = true})
+local lex = lexer.new('vb', {case_insensitive_fold_points = true})
+
+-- Whitespace.
+lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
-- Keywords.
-lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD, true)))
+lex:add_rule('keyword', token(lexer.KEYWORD, word_match({
+ -- Control.
+ 'If', 'Then', 'Else', 'ElseIf', 'While', 'Wend', 'For', 'To', 'Each', 'In', 'Step', 'Case',
+ 'Select', 'Return', 'Continue', 'Do', 'Until', 'Loop', 'Next', 'With', 'Exit',
+ -- Operators.
+ 'Mod', 'And', 'Not', 'Or', 'Xor', 'Is',
+ -- Storage types.
+ 'Call', 'Class', 'Const', 'Dim', 'ReDim', 'Preserve', 'Function', 'Sub', 'Property', 'End', 'Set',
+ 'Let', 'Get', 'New', 'Randomize', 'Option', 'Explicit', 'On', 'Error', 'Execute', 'Module',
+ -- Storage modifiers.
+ 'Private', 'Public', 'Default',
+ -- Constants.
+ 'Empty', 'False', 'Nothing', 'Null', 'True'
+}, true)))
-- Types.
-lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE, true)))
+lex:add_rule('type', token(lexer.TYPE, word_match(
+ 'Boolean Byte Char Date Decimal Double Long Object Short Single String', true)))
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol("'" + lexer.word_match('rem', true))))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol("'" + word_match('rem', true))))
-- Identifiers.
-lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
+lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Strings.
-lex:add_rule('string', lex:tag(lexer.STRING, lexer.range('"', true, false)))
+lex:add_rule('string', token(lexer.STRING, lexer.range('"', true, false)))
-- Numbers.
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number * S('LlUuFf')^-2))
+lex:add_rule('number', token(lexer.NUMBER, lexer.number * S('LlUuFf')^-2))
-- Operators.
-lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('=><+-*^&:.,_()')))
+lex:add_rule('operator', token(lexer.OPERATOR, S('=><+-*^&:.,_()')))
-- Fold points.
lex:add_fold_point(lexer.KEYWORD, 'If', 'End If')
@@ -42,27 +60,4 @@
lex:add_fold_point(lexer.KEYWORD, 'Class', 'End Class')
lex:add_fold_point(lexer.KEYWORD, 'Try', 'End Try')
--- Word lists.
-lex:set_word_list(lexer.KEYWORD, {
- -- Control.
- 'If', 'Then', 'Else', 'ElseIf', 'While', 'Wend', 'For', 'To', 'Each', 'In', 'Step', 'Case',
- 'Select', 'Return', 'Continue', 'Do', 'Until', 'Loop', 'Next', 'With', 'Exit',
- -- Operators.
- 'Mod', 'And', 'Not', 'Or', 'Xor', 'Is',
- -- Storage types.
- 'Call', 'Class', 'Const', 'Dim', 'ReDim', 'Preserve', 'Function', 'Sub', 'Property', 'End', 'Set',
- 'Let', 'Get', 'New', 'Randomize', 'Option', 'Explicit', 'On', 'Error', 'Execute', 'Module',
- -- Storage modifiers.
- 'Private', 'Public', 'Default',
- -- Constants.
- 'Empty', 'False', 'Nothing', 'Null', 'True'
-})
-
-lex:set_word_list(lexer.TYPE, {
- 'Boolean', 'Byte', 'Char', 'Date', 'Decimal', 'Double', 'Long', 'Object', 'Short', 'Single',
- 'String'
-})
-
-lexer.property['scintillua.comment'] = "'"
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/vbscript.lua lexers/vbscript.lua
--- /home/matej/repos/tmp/scintillua/lexers/vbscript.lua 1970-01-01 01:00:00.000000000 +0100
+++ lexers/vbscript.lua 2022-11-29 23:51:43.338329111 +0100
@@ -0,0 +1,63 @@
+-- Copyright 2006-2017 Mitchell mitchell.att.foicica.com. See LICENSE.
+-- VisualBasic LPeg lexer.
+
+local l = require('lexer')
+local token, word_match = l.token, l.word_match
+local P, R, S = lpeg.P, lpeg.R, lpeg.S
+
+local M = {_NAME = 'vbscript'}
+
+-- Whitespace.
+local ws = token(l.WHITESPACE, l.space^1)
+
+-- Comments.
+local comment = token(l.COMMENT, (P("'") + word_match({'rem'}, nil, true)) * l.nonnewline^0)
+
+-- Strings.
+local string = token(l.STRING, l.range('"', true, true))
+
+-- Numbers.
+local number = token(l.NUMBER, (l.float + l.integer) * S('LlUuFf')^-2)
+
+-- Keywords.
+local keyword = token(l.KEYWORD, word_match({
+ -- Control.
+ 'If', 'Then', 'Else', 'ElseIf', 'While', 'Wend', 'For', 'To', 'Each',
+ 'In', 'Step', 'Case', 'Select', 'Return', 'Continue', 'Do',
+ 'Until', 'Loop', 'Next', 'With', 'Exit',
+ -- Operators.
+ 'Mod', 'And', 'Not', 'Or', 'Xor', 'Is',
+ -- Storage types.
+ 'Call', 'Class', 'Const', 'Dim', 'ReDim', 'Preserve', 'Function', 'Sub',
+ 'Property', 'End', 'Set', 'Let', 'Get', 'New', 'Randomize', 'Option',
+ 'Explicit', 'On', 'Error', 'Execute',
+ -- Storage modifiers.
+ 'Private', 'Public', 'Default',
+ -- Constants.
+ 'Empty', 'False', 'Nothing', 'Null', 'True'
+}, nil, true))
+
+-- Types.
+local type = token(l.TYPE, word_match({
+ 'Boolean', 'Byte', 'Char', 'Date', 'Decimal', 'Double', 'Long', 'Object',
+ 'Short', 'Single', 'String'
+}, nil, true))
+
+-- Identifiers.
+local identifier = token(l.IDENTIFIER, l.word)
+
+-- Operators.
+local operator = token(l.OPERATOR, S('=><+-*^&:.,_()'))
+
+M._rules = {
+ {'whitespace', ws},
+ {'keyword', keyword},
+ {'type', type},
+ {'comment', comment},
+ {'identifier', identifier},
+ {'string', string},
+ {'number', number},
+ {'operator', operator},
+}
+
+return M
diff -uNr /home/matej/repos/tmp/scintillua/lexers/verilog.lua lexers/verilog.lua
--- /home/matej/repos/tmp/scintillua/lexers/verilog.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/verilog.lua 2022-11-29 23:51:43.338329111 +0100
@@ -83,7 +83,6 @@
lex:add_fold_point(lexer.OPERATOR, '(', ')')
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/vhdl.lua lexers/vhdl.lua
--- /home/matej/repos/tmp/scintillua/lexers/vhdl.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/vhdl.lua 2022-11-29 23:51:43.338329111 +0100
@@ -67,6 +67,4 @@
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('=/!:;<>+-/*%&|^~()')))
-lexer.property['scintillua.comment'] = '--'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/wsf.lua lexers/wsf.lua
--- /home/matej/repos/tmp/scintillua/lexers/wsf.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/wsf.lua 2022-11-29 23:51:43.338329111 +0100
@@ -2,85 +2,89 @@
-- WSF LPeg lexer (based on XML).
-- Contributed by Jeff Stone.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('wsf')
+
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
-- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.range('<!--', '-->')))
+lex:add_rule('comment', token(lexer.COMMENT, lexer.range('<!--', '-->')))
-- Elements.
-local identifier = (lexer.alpha + S('_-')) * (lexer.alnum + S('_-'))^0
-local tag = lex:tag(lexer.TAG, '<' * P('/')^-1 * identifier)
-lex:add_rule('tag', tag)
+local alpha = lpeg.R('az', 'AZ', '\127\255')
+local word_char = lexer.alnum + S('_-:.?')
+local identifier = (alpha + S('_-:.?')) * word_char^0
+local element = token('element', '<' * P('/')^-1 * identifier)
+lex:add_rule('element', element)
+lex:add_style('element', lexer.styles.keyword)
-- Closing tags.
-local tag_close = lex:tag(lexer.TAG, P('/')^-1 * '>')
+local tag_close = token('element', P('/')^-1 * '>')
lex:add_rule('tag_close', tag_close)
+-- Attributes.
+local attribute = token('attribute', identifier) * #(lexer.space^0 * '=')
+lex:add_rule('attribute', attribute)
+lex:add_style('attribute', lexer.styles.type)
+
-- Equals.
--- TODO: performance is terrible on large files.
local in_tag = P(function(input, index)
local before = input:sub(1, index - 1)
local s, e = before:find('<[^>]-$'), before:find('>[^<]-$')
- if s and e then return s > e end
- if s then return true end
- return input:find('^[^<]->', index) ~= nil
+ if s and e then return s > e and index or nil end
+ if s then return index end
+ return input:find('^[^<]->', index) and index or nil
end)
-local equals = lex:tag(lexer.OPERATOR, '=') -- * in_tag
--- lex:add_rule('equals', equals)
-
--- Attributes.
-local ws = lex:get_rule('whitespace')
-local attribute_eq = lex:tag(lexer.ATTRIBUTE, identifier) * ws^-1 * equals
-lex:add_rule('attribute', attribute_eq)
+local equals = token(lexer.OPERATOR, '=') * in_tag
+lex:add_rule('equals', equals)
-- Strings.
local sq_str = lexer.range("'", false, false)
local dq_str = lexer.range('"', false, false)
-local string = lex:tag(lexer.STRING, lexer.after_set('=', sq_str + dq_str))
+local string = #S('\'"') * lexer.last_char_includes('=') * token(lexer.STRING, sq_str + dq_str)
lex:add_rule('string', string)
-- Numbers.
-local number = lex:tag(lexer.NUMBER, lexer.dec_num * P('%')^-1)
-lex:add_rule('number', lexer.after_set('=', number)) -- * in_tag)
+local number = token(lexer.NUMBER, lexer.dec_num * P('%')^-1)
+lex:add_rule('number', #lexer.digit * lexer.last_char_includes('=') * number * in_tag)
-- Entities.
-local predefined = lex:tag(lexer.CONSTANT_BUILTIN .. '.entity',
- '&' * lexer.word_match('lt gt amp apos quot') * ';')
-local general = lex:tag(lexer.CONSTANT .. '.entity', '&' * identifier * ';')
-lex:add_rule('entity', predefined + general)
+lex:add_rule('entity', token('entity', '&' * word_match('lt gt amp apos quot') * ';'))
+lex:add_style('entity', lexer.styles.operator)
-- Fold points.
local function disambiguate_lt(text, pos, line, s) return not line:find('^</', s) and 1 or -1 end
-lex:add_fold_point(lexer.TAG, '<', disambiguate_lt)
-lex:add_fold_point(lexer.TAG, '/>', -1)
+lex:add_fold_point('element', '<', disambiguate_lt)
+lex:add_fold_point('element', '/>', -1)
lex:add_fold_point(lexer.COMMENT, '<!--', '-->')
-- Finally, add JavaScript and VBScript as embedded languages
-- Tags that start embedded languages.
-local embed_start_tag = tag * (ws * attribute_eq * ws^-1 * string)^0 * ws^-1 * tag_close
-local embed_end_tag = tag * tag_close
+local embed_start_tag = element * (ws^1 * attribute * ws^0 * equals * ws^0 * string)^0 * ws^0 *
+ tag_close
+local embed_end_tag = element * tag_close
-- Embedded JavaScript.
local js = lexer.load('javascript')
local js_start_rule = #(P('<script') * (P(function(input, index)
- if input:find('^%s+language%s*=%s*(["\'])[jJ][ava]*[sS]cript%1', index) then return true end
+ if input:find('^%s+language%s*=%s*(["\'])[jJ][ava]*[sS]cript%1', index) then return index end
end) + '>')) * embed_start_tag -- <script language="javascript">
-local js_end_rule = #P('</script>') * embed_end_tag -- </script>
+local js_end_rule = #('</script' * ws^0 * '>') * embed_end_tag -- </script>
lex:embed(js, js_start_rule, js_end_rule)
-- Embedded VBScript.
local vbs = lexer.load('vb', 'vbscript')
local vbs_start_rule = #(P('<script') * (P(function(input, index)
- if input:find('^%s+language%s*=%s*(["\'])[vV][bB][sS]cript%1', index) then return true end
+ if input:find('^%s+language%s*=%s*(["\'])[vV][bB][sS]cript%1', index) then return index end
end) + '>')) * embed_start_tag -- <script language="vbscript">
-local vbs_end_rule = #P('</script>') * embed_end_tag -- </script>
+local vbs_end_rule = #('</script' * ws^0 * '>') * embed_end_tag -- </script>
lex:embed(vbs, vbs_start_rule, vbs_end_rule)
-lexer.property['scintillua.comment'] = '<!--|-->'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/xml.lua lexers/xml.lua
--- /home/matej/repos/tmp/scintillua/lexers/xml.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/xml.lua 2022-11-29 23:51:43.338329111 +0100
@@ -1,72 +1,78 @@
-- Copyright 2006-2022 Mitchell. See LICENSE.
-- XML LPeg lexer.
-local lexer = lexer
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S = lpeg.P, lpeg.S
-local lex = lexer.new(...)
+local lex = lexer.new('xml')
--- Comments and CDATA.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.range('<!--', '-->')))
-lex:add_rule('cdata', lex:tag('cdata', lexer.range('<![CDATA[', ']]>')))
+-- Whitespace.
+local ws = token(lexer.WHITESPACE, lexer.space^1)
+lex:add_rule('whitespace', ws)
--- Doctype.
-local ws = lex:get_rule('whitespace')
-local identifier = (lexer.alpha + S('_-')) * (lexer.alnum + S('_-'))^0
-local doctype = lex:tag(lexer.TAG .. '.doctype', '<!DOCTYPE') * ws *
- lex:tag(lexer.TAG .. '.doctype', identifier) * (ws * identifier)^-1 * (1 - P('>'))^0 *
- lex:tag(lexer.TAG .. '.doctype', '>')
+-- Comments and CDATA.
+lex:add_rule('comment', token(lexer.COMMENT, lexer.range('<!--', '-->')))
+lex:add_rule('cdata', token('cdata', lexer.range('<![CDATA[', ']]>')))
+lex:add_style('cdata', lexer.styles.comment)
+
+-- Doctypes and other markup tags.
+local alpha = lpeg.R('az', 'AZ', '\127\255')
+local word_char = lexer.alnum + S('_-:.??')
+local identifier = (alpha + S('_-:.?')) * word_char^0
+local doctype = token('doctype', '<!DOCTYPE') * ws * token('doctype', identifier) *
+ (ws * identifier)^-1 * (1 - P('>'))^0 * token('doctype', '>')
lex:add_rule('doctype', doctype)
+lex:add_style('doctype', lexer.styles.comment)
-- Processing instructions.
-lex:add_rule('proc_insn', lex:tag(lexer.TAG .. '.pi', '<?' * identifier + '?>'))
+lex:add_rule('proc_insn', token('proc_insn', '<?' * (1 - P('?>'))^0 * P('?>')^-1))
+lex:add_style('proc_insn', lexer.styles.comment)
--- Tags.
-local namespace = lex:tag(lexer.OPERATOR, ':') * lex:tag(lexer.LABEL, identifier)
-lex:add_rule('element', lex:tag(lexer.TAG, '<' * P('/')^-1 * identifier) * namespace^-1)
+-- Elements.
+local namespace = token(lexer.OPERATOR, ':') * token('namespace', identifier)
+lex:add_rule('element', token('element', '<' * P('/')^-1 * identifier) * namespace^-1)
+lex:add_style('element', lexer.styles.keyword)
+lex:add_style('namespace', lexer.styles.class)
-- Closing tags.
-lex:add_rule('close_tag', lex:tag(lexer.TAG, P('/')^-1 * '>'))
+lex:add_rule('close_tag', token('element', P('/')^-1 * '>'))
+
+-- Attributes.
+lex:add_rule('attribute', token('attribute', identifier) * namespace^-1 * #(lexer.space^0 * '='))
+lex:add_style('attribute', lexer.styles.type)
-- Equals.
-- TODO: performance is terrible on large files.
local in_tag = P(function(input, index)
local before = input:sub(1, index - 1)
local s, e = before:find('<[^>]-$'), before:find('>[^<]-$')
- if s and e then return s > e end
- if s then return true end
- return input:find('^[^<]->', index) ~= nil
+ if s and e then return s > e and index or nil end
+ if s then return index end
+ return input:find('^[^<]->', index) and index or nil
end)
-local equals = lex:tag(lexer.OPERATOR, '=') -- * in_tag
--- lex:add_rule('equal', equals)
-
--- Attributes.
-local attribute_eq = lex:tag(lexer.ATTRIBUTE, identifier) * namespace^-1 * ws^-1 * equals
-lex:add_rule('attribute', attribute_eq)
+-- lex:add_rule('equal', token(lexer.OPERATOR, '=')) -- * in_tag
-- Strings.
local sq_str = lexer.range("'", false, false)
local dq_str = lexer.range('"', false, false)
-lex:add_rule('string', lex:tag(lexer.STRING, lexer.after_set('=', sq_str + dq_str)))
+lex:add_rule('string',
+ #S('\'"') * lexer.last_char_includes('=') * token(lexer.STRING, sq_str + dq_str))
-- Numbers.
-local number = lex:tag(lexer.NUMBER, lexer.dec_num * P('%')^-1)
-lex:add_rule('number', lexer.after_set('=', number)) -- *in_tag)
+local number = token(lexer.NUMBER, lexer.dec_num * P('%')^-1)
+lex:add_rule('number', #lexer.digit * lexer.last_char_includes('=') * number) -- *in_tag)
-- Entities.
-local predefined = lex:tag(lexer.CONSTANT_BUILTIN .. '.entity',
- '&' * lexer.word_match('lt gt amp apos quot') * ';')
-local general = lex:tag(lexer.CONSTANT .. '.entity', '&' * identifier * ';')
-lex:add_rule('entity', predefined + general)
+lex:add_rule('entity', token('entity', '&' * word_match('lt gt amp apos quot') * ';'))
+lex:add_style('entity', lexer.styles.operator)
-- Fold Points.
local function disambiguate_lt(text, pos, line, s) return not line:find('^</', s) and 1 or -1 end
-lex:add_fold_point(lexer.TAG, '<', disambiguate_lt)
-lex:add_fold_point(lexer.TAG, '/>', -1)
+lex:add_fold_point('element', '<', disambiguate_lt)
+lex:add_fold_point('element', '/>', -1)
lex:add_fold_point(lexer.COMMENT, '<!--', '-->')
lex:add_fold_point('cdata', '<![CDATA[', ']]>')
-lexer.property['scintillua.comment'] = '<!--|-->'
-
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/xs.lua lexers/xs.lua
--- /home/matej/repos/tmp/scintillua/lexers/xs.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/xs.lua 2022-11-29 23:51:43.338329111 +0100
@@ -54,7 +54,6 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '#'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('#'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/xtend.lua lexers/xtend.lua
--- /home/matej/repos/tmp/scintillua/lexers/xtend.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/xtend.lua 2022-11-29 23:51:43.338329111 +0100
@@ -41,7 +41,8 @@
lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Templates.
-lex:add_rule('template', token(lexer.EMBEDDED, lexer.range("'''")))
+lex:add_rule('template', token('template', lexer.range("'''")))
+lex:add_style('template', lexer.styles.embedded)
-- Strings.
local sq_str = lexer.range("'", true)
@@ -71,7 +72,8 @@
lex:add_rule('number', token(lexer.NUMBER, float + hex + dec))
-- Annotations.
-lex:add_rule('annotation', token(lexer.ANNOTATION, '@' * lexer.word))
+lex:add_rule('annotation', token('annotation', '@' * lexer.word))
+lex:add_style('annotation', lexer.styles.preprocessor)
-- Operators.
lex:add_rule('operator', token(lexer.OPERATOR, S('+-/*%<>!=^&|?~:;.()[]{}#')))
@@ -82,7 +84,7 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
+lex:add_fold_point(lexer.KEYWORD, lexer.fold_consecutive_lines('import'))
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/yaml.lua lexers/yaml.lua
--- /home/matej/repos/tmp/scintillua/lexers/yaml.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/yaml.lua 2022-11-29 23:51:43.338329111 +0100
@@ -2,59 +2,33 @@
-- YAML LPeg lexer.
-- It does not keep track of indentation perfectly.
-local lexer = lexer
-local word_match = lexer.word_match
+local lexer = require('lexer')
+local token, word_match = lexer.token, lexer.word_match
local P, S, B = lpeg.P, lpeg.S, lpeg.B
-local lex = lexer.new(..., {fold_by_indentation = true})
+local lex = lexer.new('yaml', {fold_by_indentation = true})
--- Distinguish between horizontal and vertical space so indenting tabs can be marked as errors.
-local tab_indent = lex:tag(lexer.ERROR .. '.indent', lexer.starts_line('\t', true))
-lex:modify_rule('whitespace', tab_indent + lex:tag(lexer.WHITESPACE, S(' \r\n')^1 + P('\t')^1))
-
--- Document boundaries.
-lex:add_rule('doc_bounds', lex:tag(lexer.OPERATOR, lexer.starts_line(P('---') + '...')))
+-- Whitespace.
+local indent = #lexer.starts_line(S(' \t')) *
+ (token(lexer.WHITESPACE, ' ') + token('indent_error', '\t'))^1
+lex:add_rule('indent', indent)
+lex:add_style('indent_error', {back = lexer.colors.red})
+lex:add_rule('whitespace', token(lexer.WHITESPACE, S(' \t')^1 + lexer.newline^1))
-- Keys.
-local word = (lexer.alnum + '-')^1
-lex:add_rule('key', -P('- ') * lex:tag(lexer.STRING, word * (S(' \t_')^1 * word^-1)^0) *
- #P(':' * lexer.space))
-
--- Collections.
-lex:add_rule('collection', lex:tag(lexer.OPERATOR,
- lexer.after_set('?-:\n', S('?-') * #P(' '), ' \t') + ':' * #P(lexer.space) + S('[]{}') + ',' *
- #P(' ')))
-
--- Alias indicators.
-local anchor = lex:tag(lexer.OPERATOR, '&') * lex:tag(lexer.LABEL, word)
-local alias = lex:tag(lexer.OPERATOR, '*') * lex:tag(lexer.LABEL, word)
-lex:add_rule('alias', anchor + alias)
-
--- Tags.
-local explicit_tag = '!!' * word_match{
- 'map', 'omap', 'pairs', 'set', 'seq', -- collection
- 'binary', 'bool', 'float', 'int', 'merge', 'null', 'str', 'timestamp', 'value', 'yaml' -- scalar
-}
-local verbatim_tag = '!' * lexer.range('<', '>', true)
-local short_tag = '!' * word * ('!' * (1 - lexer.space)^1)^-1
-lex:add_rule('tag', lex:tag(lexer.TYPE, explicit_tag + verbatim_tag + short_tag))
-
--- Comments.
-lex:add_rule('comment', lex:tag(lexer.COMMENT, lexer.to_eol('#')))
-
--- Reserved.
-lex:add_rule('reserved',
- B(S(':,') * ' ') * lex:tag(lexer.ERROR, S('@`') + lexer.starts_line(S('@`'))))
+local word = (lexer.alpha + '-' * -lexer.space) * (lexer.alnum + '-')^0
+lex:add_rule('key', token(lexer.KEYWORD, word * (S(' \t_')^1 * word^-1)^0) * #(':' * lexer.space))
-- Constants.
-local scalar_end = #(S(' \t')^0 * lexer.newline + S(',]}') + -1)
-lex:add_rule('constant',
- lex:tag(lexer.CONSTANT_BUILTIN, word_match('null true false', true)) * scalar_end)
+lex:add_rule('constant', B(lexer.space) * token(lexer.CONSTANT, word_match('null true false', true)))
-- Strings.
local sq_str = lexer.range("'")
local dq_str = lexer.range('"')
-lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str) * (scalar_end + #P(':' * lexer.space)))
+lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
+
+-- Comments.
+lex:add_rule('comment', B(lexer.space) * token(lexer.COMMENT, lexer.to_eol('#')))
-- Timestamps.
local year = lexer.digit * lexer.digit * lexer.digit * lexer.digit
@@ -66,39 +40,45 @@
local seconds = lexer.digit * lexer.digit
local fraction = '.' * lexer.digit^0
local time = hours * ':' * minutes * ':' * seconds * fraction^-1
-local zone = 'Z' + S(' \t')^-1 * S('-+') * hours * (':' * minutes)^-1
-lex:add_rule('timestamp', lex:tag(lexer.NUMBER .. '.timestamp',
- date * (S('tT \t') * time * zone^-1)^-1) * scalar_end)
+local T = S(' \t')^1 + S('tT')
+local zone = 'Z' + S(' \t')^0 * S('-+') * hours * (':' * minutes)^-1
+lex:add_rule('timestamp', token('timestamp', date * (T * time * zone^-1)^-1))
+lex:add_style('timestamp', lexer.styles.number)
-- Numbers.
+local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
+local hex = '0' * S('xX') * ('_' * lexer.xdigit^1)^1
+local bin = '0' * S('bB') * S('01')^1 * ('_' * S('01')^1)^0
+local integer = S('+-')^-1 * (hex + bin + dec)
+local float = S('+-')^-1 *
+ ((dec^-1 * '.' * dec + dec * '.' * dec^-1 * -P('.')) * (S('eE') * S('+-')^-1 * dec)^-1 +
+ (dec * S('eE') * S('+-')^-1 * dec))
local special_num = S('+-')^-1 * '.' * word_match('inf nan', true)
-lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number + special_num) * scalar_end)
+lex:add_rule('number', B(lexer.space) * token(lexer.NUMBER, special_num + float + integer))
--- Scalars.
-local block_indicator = S('|>') * (S('-+') * lexer.digit^-1 + lexer.digit * S('-+')^-1)^-1
-local block = lpeg.Cmt(lpeg.C(block_indicator * lexer.newline), function(input, index, indicator)
- local indent = lexer.indent_amount[lexer.line_from_position(index - #indicator)]
- for s, i, j in input:gmatch('()\n()[ \t]*()[^ \t\r\n]', index) do -- ignore blank lines
- if s >= index then -- compatibility for Lua < 5.4, which doesn't have init for string.gmatch()
- if j - i <= indent then return s end
- end
- end
- return #input + 1
-end)
-local seq = B('- ') * lexer.nonnewline^1
-local csv = B(', ') * (lexer.nonnewline - S(',]}'))^1
-local stop_chars, LF = {[string.byte('{')] = true, [string.byte('\n')] = true}, string.byte('\n')
-local map = B(': ') * lexer.nonnewline * P(function(input, index)
- local pos = index
- while pos > 1 and not stop_chars[input:byte(pos)] do pos = pos - 1 end
- local s = input:find(input:byte(pos) ~= LF and '[\n,}]' or '\n', index)
- return s or #input + 1
-end)
-lex:add_rule('scalar', lex:tag(lexer.DEFAULT, block + seq + csv + map))
+-- Types.
+lex:add_rule('type', token(lexer.TYPE, '!!' * word_match({
+ -- Collection types.
+ 'map', 'omap', 'pairs', 'set', 'seq',
+ -- Scalar types.
+ 'binary', 'bool', 'float', 'int', 'merge', 'null', 'str', 'timestamp', 'value', 'yaml'
+}, true) + '!' * lexer.range('<', '>', true)))
+
+-- Document boundaries.
+lex:add_rule('doc_bounds', token('document', lexer.starts_line(P('---') + '...')))
+lex:add_style('document', lexer.styles.constant)
-- Directives
-lex:add_rule('directive', lex:tag(lexer.PREPROCESSOR, lexer.starts_line(lexer.to_eol('%'))))
+lex:add_rule('directive', token('directive', lexer.starts_line(lexer.to_eol('%'))))
+lex:add_style('directive', lexer.styles.preprocessor)
-lexer.property['scintillua.comment'] = '#'
+-- Indicators.
+local anchor = B(lexer.space) * token(lexer.LABEL, '&' * word)
+local alias = token(lexer.VARIABLE, '*' * word)
+local tag = token('tag', '!' * word * P('!')^-1)
+local reserved = token(lexer.ERROR, S('@`') * word)
+local indicator_chars = token(lexer.OPERATOR, S('-?:,>|[]{}!'))
+lex:add_rule('indicator', tag + indicator_chars + alias + anchor + reserved)
+lex:add_style('tag', lexer.styles.class)
return lex
diff -uNr /home/matej/repos/tmp/scintillua/lexers/zig.lua lexers/zig.lua
--- /home/matej/repos/tmp/scintillua/lexers/zig.lua 2022-11-30 11:15:03.689971057 +0100
+++ lexers/zig.lua 2022-11-29 23:51:43.338329111 +0100
@@ -75,9 +75,9 @@
lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
-- Comments.
-local doc_comment = lexer.to_eol('///', true)
-local comment = lexer.to_eol('//', true)
-lex:add_rule('comment', token(lexer.COMMENT, doc_comment + comment))
+lex:add_rule('doc_comment', token('doc_comment', lexer.to_eol('///', true)))
+lex:add_style('doc_comment', lexer.styles.comment)
+lex:add_rule('comment', token(lexer.COMMENT, lexer.to_eol('//', true)))
-- Numbers.
lex:add_rule('number', token(lexer.NUMBER, lexer.number))
@@ -87,7 +87,7 @@
-- Fold points.
lex:add_fold_point(lexer.OPERATOR, '{', '}')
-
-lexer.property['scintillua.comment'] = '//'
+lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
+lex:add_fold_point(lexer.PREPROCESSOR, lexer.fold_consecutive_lines('///'))
return lex
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment