1# ext/pygmentplugin.py 
    2# Copyright 2006-2025 the Mako authors and contributors <see AUTHORS file> 
    3# 
    4# This module is part of Mako and is released under 
    5# the MIT License: http://www.opensource.org/licenses/mit-license.php 
    6 
    7from pygments import highlight 
    8from pygments.formatters.html import HtmlFormatter 
    9from pygments.lexer import bygroups 
    10from pygments.lexer import DelegatingLexer 
    11from pygments.lexer import include 
    12from pygments.lexer import RegexLexer 
    13from pygments.lexer import using 
    14from pygments.lexers.agile import Python3Lexer 
    15from pygments.lexers.agile import PythonLexer 
    16from pygments.lexers.web import CssLexer 
    17from pygments.lexers.web import HtmlLexer 
    18from pygments.lexers.web import JavascriptLexer 
    19from pygments.lexers.web import XmlLexer 
    20from pygments.token import Comment 
    21from pygments.token import Keyword 
    22from pygments.token import Name 
    23from pygments.token import Operator 
    24from pygments.token import Other 
    25from pygments.token import String 
    26from pygments.token import Text 
    27 
    28 
    29class MakoLexer(RegexLexer): 
    30    name = "Mako" 
    31    aliases = ["mako"] 
    32    filenames = ["*.mao"] 
    33 
    34    tokens = { 
    35        "root": [ 
    36            ( 
    37                r"(\s*)(\%)(\s*end(?:\w+))(\n|\Z)", 
    38                bygroups(Text, Comment.Preproc, Keyword, Other), 
    39            ), 
    40            ( 
    41                r"(\s*)(\%(?!%))([^\n]*)(\n|\Z)", 
    42                bygroups(Text, Comment.Preproc, using(PythonLexer), Other), 
    43            ), 
    44            ( 
    45                r"(\s*)(##[^\n]*)(\n|\Z)", 
    46                bygroups(Text, Comment.Preproc, Other), 
    47            ), 
    48            (r"""(?s)<%doc>.*?</%doc>""", Comment.Preproc), 
    49            ( 
    50                r"(<%)([\w\.\:]+)", 
    51                bygroups(Comment.Preproc, Name.Builtin), 
    52                "tag", 
    53            ), 
    54            ( 
    55                r"(</%)([\w\.\:]+)(>)", 
    56                bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc), 
    57            ), 
    58            (r"<%(?=([\w\.\:]+))", Comment.Preproc, "ondeftags"), 
    59            ( 
    60                r"(?s)(<%(?:!?))(.*?)(%>)", 
    61                bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc), 
    62            ), 
    63            ( 
    64                r"(\$\{)(.*?)(\})", 
    65                bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc), 
    66            ), 
    67            ( 
    68                r"""(?sx) 
    69                (.+?)               # anything, followed by: 
    70                (?: 
    71                 (?<=\n)(?=%(?!%)|\#\#) |  # an eval or comment line 
    72                 (?=\#\*) |          # multiline comment 
    73                 (?=</?%) |         # a python block 
    74                                    # call start or end 
    75                 (?=\$\{) |         # a substitution 
    76                 (?<=\n)(?=\s*%) | 
    77                                    # - don't consume 
    78                 (\\\n) |           # an escaped newline 
    79                 \Z                 # end of string 
    80                ) 
    81            """, 
    82                bygroups(Other, Operator), 
    83            ), 
    84            (r"\s+", Text), 
    85        ], 
    86        "ondeftags": [ 
    87            (r"<%", Comment.Preproc), 
    88            (r"(?<=<%)(include|inherit|namespace|page)", Name.Builtin), 
    89            include("tag"), 
    90        ], 
    91        "tag": [ 
    92            (r'((?:\w+)\s*=)\s*(".*?")', bygroups(Name.Attribute, String)), 
    93            (r"/?\s*>", Comment.Preproc, "#pop"), 
    94            (r"\s+", Text), 
    95        ], 
    96        "attr": [ 
    97            ('".*?"', String, "#pop"), 
    98            ("'.*?'", String, "#pop"), 
    99            (r"[^\s>]+", String, "#pop"), 
    100        ], 
    101    } 
    102 
    103 
    104class MakoHtmlLexer(DelegatingLexer): 
    105    name = "HTML+Mako" 
    106    aliases = ["html+mako"] 
    107 
    108    def __init__(self, **options): 
    109        super().__init__(HtmlLexer, MakoLexer, **options) 
    110 
    111 
    112class MakoXmlLexer(DelegatingLexer): 
    113    name = "XML+Mako" 
    114    aliases = ["xml+mako"] 
    115 
    116    def __init__(self, **options): 
    117        super().__init__(XmlLexer, MakoLexer, **options) 
    118 
    119 
    120class MakoJavascriptLexer(DelegatingLexer): 
    121    name = "JavaScript+Mako" 
    122    aliases = ["js+mako", "javascript+mako"] 
    123 
    124    def __init__(self, **options): 
    125        super().__init__(JavascriptLexer, MakoLexer, **options) 
    126 
    127 
    128class MakoCssLexer(DelegatingLexer): 
    129    name = "CSS+Mako" 
    130    aliases = ["css+mako"] 
    131 
    132    def __init__(self, **options): 
    133        super().__init__(CssLexer, MakoLexer, **options) 
    134 
    135 
    136pygments_html_formatter = HtmlFormatter( 
    137    cssclass="syntax-highlighted", linenos=True 
    138) 
    139 
    140 
    141def syntax_highlight(filename="", language=None): 
    142    mako_lexer = MakoLexer() 
    143    python_lexer = Python3Lexer() 
    144    if filename.startswith("memory:") or language == "mako": 
    145        return lambda string: highlight( 
    146            string, mako_lexer, pygments_html_formatter 
    147        ) 
    148    return lambda string: highlight( 
    149        string, python_lexer, pygments_html_formatter 
    150    )