|
""" |
|
pygments.lexers.typst |
|
~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
Lexers for Typst language. |
|
|
|
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS. |
|
:license: BSD, see LICENSE for details. |
|
""" |
|
|
|
from pygments.lexer import RegexLexer, words, bygroups, include |
|
from pygments.token import Comment, Keyword, Name, String, Punctuation, \ |
|
Whitespace, Generic, Operator, Number, Text |
|
from pygments.util import get_choice_opt |
|
|
|
__all__ = ['TypstLexer'] |
|
|
|
|
|
class TypstLexer(RegexLexer): |
|
""" |
|
For Typst code. |
|
|
|
Additional options accepted: |
|
|
|
`start` |
|
Specifies the starting state of the lexer (one of 'markup', 'math', |
|
'code'). The default is 'markup'. |
|
""" |
|
|
|
name = 'Typst' |
|
aliases = ['typst'] |
|
filenames = ['*.typ'] |
|
mimetypes = ['text/x-typst'] |
|
url = 'https://typst.app' |
|
version_added = '2.18' |
|
|
|
MATH_SHORTHANDS = ( |
|
'[|', '|]', '||', '*', ':=', '::=', '...', '\'', '-', '=:', '!=', '>>', |
|
'>=', '>>>', '<<', '<=', '<<<', '->', '|->', '=>', '|=>', '==>', |
|
'-->', '~~>', '~>', '>->', '->>', '<-', '<==', '<--', '<~~', '<~', |
|
'<-<','<<-','<->','<=>','<==>','<-->', '>', '<', '~', ':', '|' |
|
) |
|
|
|
tokens = { |
|
'root': [ |
|
include('markup'), |
|
], |
|
|
|
'into_code': [ |
|
(words(('#let', '#set', '#show'), suffix=r'\b'), Keyword.Declaration, 'inline_code'), |
|
(words(('#import', '#include'), suffix=r'\b'), Keyword.Namespace, 'inline_code'), |
|
(words(('#if', '#for', '#while', '#export'), suffix=r'\b'), Keyword.Reserved, 'inline_code'), |
|
(r'#\{', Punctuation, 'code'), |
|
(r'#\(', Punctuation, 'code'), |
|
(r'(#[a-zA-Z_][a-zA-Z0-9_-]*)(\[)', bygroups(Name.Function, Punctuation), 'markup'), |
|
(r'(#[a-zA-Z_][a-zA-Z0-9_-]*)(\()', bygroups(Name.Function, Punctuation), 'code'), |
|
(words(('#true', '#false', '#none', '#auto'), suffix=r'\b'), Keyword.Constant), |
|
(r'#[a-zA-Z_][a-zA-Z0-9_]*', Name.Variable), |
|
(r'#0x[0-9a-fA-F]+', Number.Hex), |
|
(r'#0b[01]+', Number.Bin), |
|
(r'#0o[0-7]+', Number.Oct), |
|
(r'#[0-9]+[\.e][0-9]+', Number.Float), |
|
(r'#[0-9]+', Number.Integer), |
|
], |
|
'markup': [ |
|
include('comment'), |
|
(r'^\s*=+.*$', Generic.Heading), |
|
(r'[*][^*]*[*]', Generic.Strong), |
|
(r'_[^_]*_', Generic.Emph), |
|
(r'\$', Punctuation, 'math'), |
|
(r'`[^`]*`', String.Backtick), |
|
(r'^(\s*)(-)(\s+)', bygroups(Whitespace, Punctuation, Whitespace)), |
|
(r'^(\s*)(\+)(\s+)', bygroups(Whitespace, Punctuation, Whitespace)), |
|
(r'^(\s*)([0-9]+\.)', bygroups(Whitespace, Punctuation)), |
|
(r'^(\s*)(/)(\s+)([^:]+)(:)', bygroups(Whitespace, Punctuation, Whitespace, Name.Variable, Punctuation)), |
|
(r'<[a-zA-Z_][a-zA-Z0-9_-]*>', Name.Label), |
|
(r'@[a-zA-Z_][a-zA-Z0-9_-]*', Name.Label), |
|
(r'\\#', Text), |
|
include('into_code'), |
|
(r'```(?:.|\n)*?```', String.Backtick), |
|
(r'https?://[0-9a-zA-Z~/%#&=\',;.+?]*', Generic.Emph), |
|
(words(('---', '\\', '~', '--', '...'), suffix=r'\B'), Punctuation), |
|
(r'\\\[', Punctuation), |
|
(r'\\\]', Punctuation), |
|
(r'\[', Punctuation, '#push'), |
|
(r'\]', Punctuation, '#pop'), |
|
(r'[ \t]+\n?|\n', Whitespace), |
|
(r'((?![*_$`<@\\#\] ]|https?://).)+', Text), |
|
], |
|
'math': [ |
|
include('comment'), |
|
(words(('\\_', '\\^', '\\&')), Text), |
|
(words(('_', '^', '&', ';')), Punctuation), |
|
(words(('+', '/', '=') + MATH_SHORTHANDS), Operator), |
|
(r'\\', Punctuation), |
|
(r'\\\$', Punctuation), |
|
(r'\$', Punctuation, '#pop'), |
|
include('into_code'), |
|
(r'([a-zA-Z][a-zA-Z0-9-]*)(\s*)(\()', bygroups(Name.Function, Whitespace, Punctuation)), |
|
(r'([a-zA-Z][a-zA-Z0-9-]*)(:)', bygroups(Name.Variable, Punctuation)), |
|
(r'([a-zA-Z][a-zA-Z0-9-]*)', Name.Variable), |
|
(r'[0-9]+(\.[0-9]+)?', Number), |
|
(r'\.{1,3}|\(|\)|,|\{|\}', Punctuation), |
|
(r'"[^"]*"', String.Double), |
|
(r'[ \t\n]+', Whitespace), |
|
], |
|
'comment': [ |
|
(r'//.*$', Comment.Single), |
|
(r'/[*](.|\n)*?[*]/', Comment.Multiline), |
|
], |
|
'code': [ |
|
include('comment'), |
|
(r'\[', Punctuation, 'markup'), |
|
(r'\(|\{', Punctuation, 'code'), |
|
(r'\)|\}', Punctuation, '#pop'), |
|
(r'"[^"]*"', String.Double), |
|
(r',|\.{1,2}', Punctuation), |
|
(r'=', Operator), |
|
(words(('and', 'or', 'not'), suffix=r'\b'), Operator.Word), |
|
(r'=>|<=|==|!=|>|<|-=|\+=|\*=|/=|\+|-|\\|\*', Operator), |
|
(r'([a-zA-Z_][a-zA-Z0-9_-]*)(:)', bygroups(Name.Variable, Punctuation)), |
|
(r'([a-zA-Z_][a-zA-Z0-9_-]*)(\()', bygroups(Name.Function, Punctuation), 'code'), |
|
(words(('as', 'break', 'export', 'continue', 'else', 'for', 'if', |
|
'in', 'return', 'while'), suffix=r'\b'), |
|
Keyword.Reserved), |
|
(words(('import', 'include'), suffix=r'\b'), Keyword.Namespace), |
|
(words(('auto', 'none', 'true', 'false'), suffix=r'\b'), Keyword.Constant), |
|
(r'([0-9.]+)(mm|pt|cm|in|em|fr|%)', bygroups(Number, Keyword.Reserved)), |
|
(r'0x[0-9a-fA-F]+', Number.Hex), |
|
(r'0b[01]+', Number.Bin), |
|
(r'0o[0-7]+', Number.Oct), |
|
(r'[0-9]+[\.e][0-9]+', Number.Float), |
|
(r'[0-9]+', Number.Integer), |
|
(words(('let', 'set', 'show'), suffix=r'\b'), Keyword.Declaration), |
|
|
|
|
|
|
|
(r'([a-zA-Z_][a-zA-Z0-9_-]*)', Name.Variable), |
|
(r'[ \t\n]+', Whitespace), |
|
(r':', Punctuation), |
|
], |
|
'inline_code': [ |
|
(r';\b', Punctuation, '#pop'), |
|
(r'\n', Whitespace, '#pop'), |
|
include('code'), |
|
], |
|
} |
|
|
|
def __init__(self, **options): |
|
self.start_state = get_choice_opt( |
|
options, 'start', ['markup', 'code', 'math'], 'markup', True) |
|
|
|
RegexLexer.__init__(self, **options) |
|
|
|
def get_tokens_unprocessed(self, text): |
|
stack = ['root'] |
|
if self.start_state != 'markup': |
|
stack.append(self.start_state) |
|
|
|
yield from RegexLexer.get_tokens_unprocessed(self, text, stack) |
|
|