"""
pygments.lexers.ul4
~~~~~~~~~~~~~~~~~~~
Lexer for the UL4 templating language.
More information: https://python.livinglogic.de/UL4.html
:copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re
from pygments.lexer import RegexLexer, DelegatingLexer, bygroups, words, include
from pygments.token import Comment, Text, Keyword, String, Number, Literal, \
Name, Other, Operator
from pygments.lexers.web import HtmlLexer, XmlLexer, CssLexer, JavascriptLexer
from pygments.lexers.python import PythonLexer
__all__ = ['UL4Lexer', 'HTMLUL4Lexer', 'XMLUL4Lexer', 'CSSUL4Lexer',
'JavascriptUL4Lexer', 'PythonUL4Lexer']
class UL4Lexer(RegexLexer):
"""
Generic lexer for UL4.
.. versionadded:: 2.12
"""
flags = re.MULTILINE | re.DOTALL
name = 'UL4'
aliases = ['ul4']
filenames = ['*.ul4']
tokens = {
"root": [
(
# Template header without name:
# ``<?ul4?>``
r"(<\?)(\s*)(ul4)(\s*)(\?>)",
bygroups(Comment.Preproc, Text.Whitespace, Keyword,
Text.Whitespace, Comment.Preproc),
),
(
# Template header with name (potentially followed by the signature):
# ``<?ul4 foo(bar=42)?>``
r"(<\?)(\s*)(ul4)(\s*)([a-zA-Z_][a-zA-Z_0-9]*)?",
bygroups(Comment.Preproc, Text.Whitespace, Keyword,
Text.Whitespace, Name.Function),
"ul4", # Switch to "expression" mode
),
(
# Comment:
# ``<?note foobar?>``
r"<\?\s*note\s.*?\?>",
Comment,
),
(
# Template documentation:
# ``<?doc foobar?>``
r"<\?\s*doc\s.*?\?>",
String.Doc,
),
(
# ``<?ignore?>`` tag for commenting out code:
# ``<?ignore?>...<?end ignore?>``
r"<\?\s*ignore\s*\?>",
Comment,
"ignore", # Switch to "ignore" mode
),
(
# ``<?def?>`` tag for defining local templates
# ``<?def foo(bar=42)?>...<?end def?>``
r"(<\?)(\s*)(def)(\s*)([a-zA-Z_][a-zA-Z_0-9]*)?",
bygroups(Comment.Preproc, Text.Whitespace, Keyword,
Text.Whitespace, Name.Function),
"ul4", # Switch to "expression" mode
),
(
# The rest of the supported tags
r"(<\?)(\s*)(printx|print|for|if|elif|else|while|code|renderblocks?|render)\b",
bygroups(Comment.Preproc, Text.Whitespace, Keyword),
"ul4", # Switch to "expression" mode
),
(
# ``<?end?>`` tag for ending ``<?def?>``, ``<?for?>``,
# ``<?if?>``, ``<?while?>``, ``<?renderblock?>`` and
# ``<?renderblocks?>`` blocks.
r"(<\?)(\s*)(end)\b",
bygroups(Comment.Preproc, Text.Whitespace, Keyword),
"end", # Switch to "end tag" mode
),
(
# ``<?whitespace?>`` tag for configuring whitespace handlng
r"(<\?)(\s*)(whitespace)\b",
bygroups(Comment.Preproc, Text.Whitespace, Keyword),
"whitespace", # Switch to "whitespace" mode
),
# Plain text
(r"[^<]+", Other),
(r"<", Other),
],
# Ignore mode ignores everything upto the matching ``<?end ignore?>`` tag
"ignore": [
# Nested ``<?ignore?>`` tag
(r"<\?\s*ignore\s*\?>", Comment, "#push"),
# ``<?end ignore?>`` tag
(r"<\?\s*end\s+ignore\s*\?>", Comment, "#pop"),
# Everything else
(r"[^<]+", Comment),
(r".", Comment),
],
# UL4 expressions
"ul4": [
# End the tag
(r"\?>", Comment.Preproc, "#pop"),
# Start triple quoted string constant
("'''", String, "string13"),
('"""', String, "string23"),
# Start single quoted string constant
("'", String, "string1"),
('"', String, "string2"),
# Floating point number
(r"\d+\.\d*([eE][+-]?\d+)?", Number.Float),
(r"\.\d+([eE][+-]?\d+)?", Number.Float),
(r"\d+[eE][+-]?\d+", Number.Float),
# Binary integer: ``0b101010``
(r"0[bB][01]+", Number.Bin),
# Octal integer: ``0o52``
(r"0[oO][0-7]+", Number.Oct),
# Hexadecimal integer: ``0x2a``
(r"0[xX][0-9a-fA-F]+", Number.Hex),
# Date or datetime: ``@(2000-02-29)``/``@(2000-02-29T12:34:56.987654)``
(r"@\(\d\d\d\d-\d\d-\d\d(T(\d\d:\d\d(:\d\d(\.\d{6})?)?)?)?\)", Literal.Date),
# Color: ``#fff``, ``#fff8f0`` etc.
(r"#[0-9a-fA-F]{8}", Literal.Color),
(r"#[0-9a-fA-F]{6}", Literal.Color),
(r"#[0-9a-fA-F]{3,4}", Literal.Color),
# Decimal integer: ``42``
(r"\d+", Number.Integer),
# Operators
(r"//|==|!=|>=|<=|<<|>>|\+=|-=|\*=|/=|//=|<<=|>>=|&=|\|=|^=|=|[\[\]{},:*/().~%&|<>^+-]", Operator),
# Keywords
(words(("for", "in", "if", "else", "not", "is", "and", "or"), suffix=r"\b"), Keyword),
# Builtin constants
(words(("None", "False", "True"), suffix=r"\b"), Keyword.Constant),
# Variable names
(r"[a-zA-Z_][a-zA-Z0-9_]*", Name),
# Whitespace
(r"\s+", Text.Whitespace),
],
# ``<?end ...?>`` tag for closing the last open block
"end": [
(r"\?>", Comment.Preproc, "#pop"),
(words(("for", "if", "def", "while", "renderblock", "renderblocks"), suffix=r"\b"), Keyword),
(r"\s+", Text),
],
# Content of the ``<?whitespace ...?>`` tag:
# ``keep``, ``strip`` or ``smart``
"whitespace": [
(r"\?>", Comment.Preproc, "#pop"),
(words(("keep", "strip", "smart"), suffix=r"\b"), Comment.Preproc),
(r"\s+", Text.Whitespace),
],
# Inside a string constant
"stringescapes": [
(r"""\\[\\'"abtnfr]""", String.Escape),
(r"\\x[0-9a-fA-F]{2}", String.Escape),
(r"\\u[0-9a-fA-F]{4}", String.Escape),
(r"\\U[0-9a-fA-F]{8}", String.Escape),
],
# Inside a triple quoted string started with ``'''``
"string13": [
(r"'''", String, "#pop"),
include("stringescapes"),
(r"[^\\']+", String),
(r'.', String),
],
# Inside a triple quoted string started with ``"""``
"string23": [
(r'"""', String, "#pop"),
include("stringescapes"),
(r'[^\\"]+', String),
(r'.', String),
],
# Inside a single quoted string started with ``'``
"string1": [
(r"'", String, "#pop"),
include("stringescapes"),
(r"[^\\']+", String),
(r'.', String),
],
# Inside a single quoted string started with ``"``
"string2": [
(r'"', String, "#pop"),
include("stringescapes"),
(r'[^\\"]+', String),
(r'.', String),
],
}
class HTMLUL4Lexer(DelegatingLexer):
"""
Lexer for UL4 embedded in HTML.
"""
name = 'HTML+UL4'
aliases = ['html+ul4']
filenames = ['*.htmlul4']
def __init__(self, **options):
super().__init__(HtmlLexer, UL4Lexer, **options)
class XMLUL4Lexer(DelegatingLexer):
"""
Lexer for UL4 embedded in XML.
"""
name = 'XML+UL4'
aliases = ['xml+ul4']
filenames = ['*.xmlul4']
def __init__(self, **options):
super().__init__(XmlLexer, UL4Lexer, **options)
class CSSUL4Lexer(DelegatingLexer):
"""
Lexer for UL4 embedded in CSS.
"""
name = 'CSS+UL4'
aliases = ['css+ul4']
filenames = ['*.cssul4']
def __init__(self, **options):
super().__init__(CssLexer, UL4Lexer, **options)
class JavascriptUL4Lexer(DelegatingLexer):
"""
Lexer for UL4 embedded in Javascript.
"""
name = 'Javascript+UL4'
aliases = ['js+ul4']
filenames = ['*.jsul4']
def __init__(self, **options):
super().__init__(JavascriptLexer, UL4Lexer, **options)
class PythonUL4Lexer(DelegatingLexer):
"""
Lexer for UL4 embedded in Python.
"""
name = 'Python+UL4'
aliases = ['py+ul4']
filenames = ['*.pyul4']
def __init__(self, **options):
super().__init__(PythonLexer, UL4Lexer, **options)