PageRenderTime 75ms CodeModel.GetById 19ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/syntaxhighlight/pygments/lexers/templates.py

http://github.com/plushcms/PlushCMS
Python | 1583 lines | 1206 code | 162 blank | 215 comment | 58 complexity | 5c679c887905ece216cec7825aa53d90 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1# -*- coding: utf-8 -*-
   2"""
   3    plushcms.syntaxhighlight.pygments.lexers.templates
   4    ~~~~~~~~~~~~~~~~~~~~~~~~~
   5
   6    Lexers for various template engines' markup.
   7
   8    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
   9    :license: BSD, see LICENSE for details.
  10"""
  11
  12import re
  13
  14from plushcms.syntaxhighlight.pygments.lexers.web import \
  15     PhpLexer, HtmlLexer, XmlLexer, JavascriptLexer, CssLexer
  16from plushcms.syntaxhighlight.pygments.lexers.agile import PythonLexer, PerlLexer
  17from plushcms.syntaxhighlight.pygments.lexers.compiled import JavaLexer
  18from plushcms.syntaxhighlight.pygments.lexer import Lexer, DelegatingLexer, RegexLexer, bygroups, \
  19     include, using, this
  20from plushcms.syntaxhighlight.pygments.token import Error, Punctuation, \
  21     Text, Comment, Operator, Keyword, Name, String, Number, Other, Token
  22from plushcms.syntaxhighlight.pygments.util import html_doctype_matches, looks_like_xml
  23
  24__all__ = ['HtmlPhpLexer', 'XmlPhpLexer', 'CssPhpLexer',
  25           'JavascriptPhpLexer', 'ErbLexer', 'RhtmlLexer',
  26           'XmlErbLexer', 'CssErbLexer', 'JavascriptErbLexer',
  27           'SmartyLexer', 'HtmlSmartyLexer', 'XmlSmartyLexer',
  28           'CssSmartyLexer', 'JavascriptSmartyLexer', 'DjangoLexer',
  29           'HtmlDjangoLexer', 'CssDjangoLexer', 'XmlDjangoLexer',
  30           'JavascriptDjangoLexer', 'GenshiLexer', 'HtmlGenshiLexer',
  31           'GenshiTextLexer', 'CssGenshiLexer', 'JavascriptGenshiLexer',
  32           'MyghtyLexer', 'MyghtyHtmlLexer', 'MyghtyXmlLexer',
  33           'MyghtyCssLexer', 'MyghtyJavascriptLexer', 'MasonLexer', 'MakoLexer',
  34           'MakoHtmlLexer', 'MakoXmlLexer', 'MakoJavascriptLexer',
  35           'MakoCssLexer', 'JspLexer', 'CheetahLexer', 'CheetahHtmlLexer',
  36           'CheetahXmlLexer', 'CheetahJavascriptLexer',
  37           'EvoqueLexer', 'EvoqueHtmlLexer', 'EvoqueXmlLexer',
  38           'ColdfusionLexer', 'ColdfusionHtmlLexer',
  39           'VelocityLexer', 'VelocityHtmlLexer', 'VelocityXmlLexer',
  40           'SspLexer']
  41
  42
  43class ErbLexer(Lexer):
  44    """
  45    Generic `ERB <http://ruby-doc.org/core/classes/ERB.html>`_ (Ruby Templating)
  46    lexer.
  47
  48    Just highlights ruby code between the preprocessor directives, other data
  49    is left untouched by the lexer.
  50
  51    All options are also forwarded to the `RubyLexer`.
  52    """
  53
  54    name = 'ERB'
  55    aliases = ['erb']
  56    mimetypes = ['application/x-ruby-templating']
  57
  58    _block_re = re.compile(r'(<%%|%%>|<%=|<%#|<%-|<%|-%>|%>|^%[^%].*?$)', re.M)
  59
  60    def __init__(self, **options):
  61        from plushcms.syntaxhighlight.pygments.lexers.agile import RubyLexer
  62        self.ruby_lexer = RubyLexer(**options)
  63        Lexer.__init__(self, **options)
  64
  65    def get_tokens_unprocessed(self, text):
  66        """
  67        Since ERB doesn't allow "<%" and other tags inside of ruby
  68        blocks we have to use a split approach here that fails for
  69        that too.
  70        """
  71        tokens = self._block_re.split(text)
  72        tokens.reverse()
  73        state = idx = 0
  74        try:
  75            while True:
  76                # text
  77                if state == 0:
  78                    val = tokens.pop()
  79                    yield idx, Other, val
  80                    idx += len(val)
  81                    state = 1
  82                # block starts
  83                elif state == 1:
  84                    tag = tokens.pop()
  85                    # literals
  86                    if tag in ('<%%', '%%>'):
  87                        yield idx, Other, tag
  88                        idx += 3
  89                        state = 0
  90                    # comment
  91                    elif tag == '<%#':
  92                        yield idx, Comment.Preproc, tag
  93                        val = tokens.pop()
  94                        yield idx + 3, Comment, val
  95                        idx += 3 + len(val)
  96                        state = 2
  97                    # blocks or output
  98                    elif tag in ('<%', '<%=', '<%-'):
  99                        yield idx, Comment.Preproc, tag
 100                        idx += len(tag)
 101                        data = tokens.pop()
 102                        r_idx = 0
 103                        for r_idx, r_token, r_value in \
 104                            self.ruby_lexer.get_tokens_unprocessed(data):
 105                            yield r_idx + idx, r_token, r_value
 106                        idx += len(data)
 107                        state = 2
 108                    elif tag in ('%>', '-%>'):
 109                        yield idx, Error, tag
 110                        idx += len(tag)
 111                        state = 0
 112                    # % raw ruby statements
 113                    else:
 114                        yield idx, Comment.Preproc, tag[0]
 115                        r_idx = 0
 116                        for r_idx, r_token, r_value in \
 117                            self.ruby_lexer.get_tokens_unprocessed(tag[1:]):
 118                            yield idx + 1 + r_idx, r_token, r_value
 119                        idx += len(tag)
 120                        state = 0
 121                # block ends
 122                elif state == 2:
 123                    tag = tokens.pop()
 124                    if tag not in ('%>', '-%>'):
 125                        yield idx, Other, tag
 126                    else:
 127                        yield idx, Comment.Preproc, tag
 128                    idx += len(tag)
 129                    state = 0
 130        except IndexError:
 131            return
 132
 133    def analyse_text(text):
 134        if '<%' in text and '%>' in text:
 135            return 0.4
 136
 137
 138class SmartyLexer(RegexLexer):
 139    """
 140    Generic `Smarty <http://smarty.php.net/>`_ template lexer.
 141
 142    Just highlights smarty code between the preprocessor directives, other
 143    data is left untouched by the lexer.
 144    """
 145
 146    name = 'Smarty'
 147    aliases = ['smarty']
 148    filenames = ['*.tpl']
 149    mimetypes = ['application/x-smarty']
 150
 151    flags = re.MULTILINE | re.DOTALL
 152
 153    tokens = {
 154        'root': [
 155            (r'[^{]+', Other),
 156            (r'(\{)(\*.*?\*)(\})',
 157             bygroups(Comment.Preproc, Comment, Comment.Preproc)),
 158            (r'(\{php\})(.*?)(\{/php\})',
 159             bygroups(Comment.Preproc, using(PhpLexer, startinline=True),
 160                      Comment.Preproc)),
 161            (r'(\{)(/?[a-zA-Z_][a-zA-Z0-9_]*)(\s*)',
 162             bygroups(Comment.Preproc, Name.Function, Text), 'smarty'),
 163            (r'\{', Comment.Preproc, 'smarty')
 164        ],
 165        'smarty': [
 166            (r'\s+', Text),
 167            (r'\}', Comment.Preproc, '#pop'),
 168            (r'#[a-zA-Z_][a-zA-Z0-9_]*#', Name.Variable),
 169            (r'\$[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z0-9_]+)*', Name.Variable),
 170            (r'[~!%^&*()+=|\[\]:;,.<>/?{}@-]', Operator),
 171            ('(true|false|null)\b', Keyword.Constant),
 172            (r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|"
 173             r"0[xX][0-9a-fA-F]+[Ll]?", Number),
 174            (r'"(\\\\|\\"|[^"])*"', String.Double),
 175            (r"'(\\\\|\\'|[^'])*'", String.Single),
 176            (r'[a-zA-Z_][a-zA-Z0-9_]*', Name.Attribute)
 177        ]
 178    }
 179
 180    def analyse_text(text):
 181        rv = 0.0
 182        if re.search('\{if\s+.*?\}.*?\{/if\}', text):
 183            rv += 0.15
 184        if re.search('\{include\s+file=.*?\}', text):
 185            rv += 0.15
 186        if re.search('\{foreach\s+.*?\}.*?\{/foreach\}', text):
 187            rv += 0.15
 188        if re.search('\{\$.*?\}', text):
 189            rv += 0.01
 190        return rv
 191
 192
 193class VelocityLexer(RegexLexer):
 194    """
 195    Generic `Velocity <http://velocity.apache.org/>`_ template lexer.
 196
 197    Just highlights velocity directives and variable references, other
 198    data is left untouched by the lexer.
 199    """
 200
 201    name = 'Velocity'
 202    aliases = ['velocity']
 203    filenames = ['*.vm','*.fhtml']
 204
 205    flags = re.MULTILINE | re.DOTALL
 206
 207    identifier = r'[a-zA-Z_][a-zA-Z0-9_]*'
 208
 209    tokens = {
 210        'root': [
 211            (r'[^{#$]+', Other),
 212            (r'(#)(\*.*?\*)(#)',
 213             bygroups(Comment.Preproc, Comment, Comment.Preproc)),
 214            (r'(##)(.*?$)',
 215             bygroups(Comment.Preproc, Comment)),
 216            (r'(#\{?)(' + identifier + r')(\}?)(\s?\()',
 217             bygroups(Comment.Preproc, Name.Function, Comment.Preproc, Punctuation),
 218             'directiveparams'),
 219            (r'(#\{?)(' + identifier + r')(\}|\b)',
 220             bygroups(Comment.Preproc, Name.Function, Comment.Preproc)),
 221            (r'\$\{?', Punctuation, 'variable')
 222        ],
 223        'variable': [
 224            (identifier, Name.Variable),
 225            (r'\(', Punctuation, 'funcparams'),
 226            (r'(\.)(' + identifier + r')', bygroups(Punctuation, Name.Variable), '#push'),
 227            (r'\}', Punctuation, '#pop'),
 228            (r'', Other, '#pop')
 229        ],
 230        'directiveparams': [
 231            (r'(&&|\|\||==?|!=?|[-<>+*%&\|\^/])|\b(eq|ne|gt|lt|ge|le|not|in)\b', Operator),
 232            (r'\[', Operator, 'rangeoperator'),
 233            (r'\b' + identifier + r'\b', Name.Function),
 234            include('funcparams')
 235        ],
 236        'rangeoperator': [
 237            (r'\.\.', Operator),
 238            include('funcparams'),
 239            (r'\]', Operator, '#pop')
 240        ],
 241        'funcparams': [
 242            (r'\$\{?', Punctuation, 'variable'),
 243            (r'\s+', Text),
 244            (r',', Punctuation),
 245            (r'"(\\\\|\\"|[^"])*"', String.Double),
 246            (r"'(\\\\|\\'|[^'])*'", String.Single),
 247            (r"0[xX][0-9a-fA-F]+[Ll]?", Number),
 248            (r"\b[0-9]+\b", Number),
 249            (r'(true|false|null)\b', Keyword.Constant),
 250            (r'\(', Punctuation, '#push'),
 251            (r'\)', Punctuation, '#pop')
 252        ]
 253    }
 254
 255    def analyse_text(text):
 256        rv = 0.0
 257        if re.search(r'#\{?macro\}?\(.*?\).*?#\{?end\}?', text):
 258            rv += 0.25
 259        if re.search(r'#\{?if\}?\(.+?\).*?#\{?end\}?', text):
 260            rv += 0.15
 261        if re.search(r'#\{?foreach\}?\(.+?\).*?#\{?end\}?', text):
 262            rv += 0.15
 263        if re.search(r'\$\{?[a-zA-Z_][a-zA-Z0-9_]*(\([^)]*\))?(\.[a-zA-Z0-9_]+(\([^)]*\))?)*\}?', text):
 264            rv += 0.01
 265        return rv
 266
 267
 268class VelocityHtmlLexer(DelegatingLexer):
 269    """
 270    Subclass of the `VelocityLexer` that highlights unlexer data
 271    with the `HtmlLexer`.
 272
 273    """
 274
 275    name = 'HTML+Velocity'
 276    aliases = ['html+velocity']
 277    alias_filenames = ['*.html','*.fhtml']
 278    mimetypes = ['text/html+velocity']
 279
 280    def __init__(self, **options):
 281        super(VelocityHtmlLexer, self).__init__(HtmlLexer, VelocityLexer,
 282                                              **options)
 283
 284
 285class VelocityXmlLexer(DelegatingLexer):
 286    """
 287    Subclass of the `VelocityLexer` that highlights unlexer data
 288    with the `XmlLexer`.
 289
 290    """
 291
 292    name = 'XML+Velocity'
 293    aliases = ['xml+velocity']
 294    alias_filenames = ['*.xml','*.vm']
 295    mimetypes = ['application/xml+velocity']
 296
 297    def __init__(self, **options):
 298        super(VelocityXmlLexer, self).__init__(XmlLexer, VelocityLexer,
 299                                               **options)
 300
 301    def analyse_text(text):
 302        rv = VelocityLexer.analyse_text(text) - 0.01
 303        if looks_like_xml(text):
 304            rv += 0.5
 305        return rv
 306
 307
 308class DjangoLexer(RegexLexer):
 309    """
 310    Generic `django <http://www.djangoproject.com/documentation/templates/>`_
 311    and `jinja <http://wsgiarea.pocoo.org/jinja/>`_ template lexer.
 312
 313    It just highlights django/jinja code between the preprocessor directives,
 314    other data is left untouched by the lexer.
 315    """
 316
 317    name = 'Django/Jinja'
 318    aliases = ['django', 'jinja']
 319    mimetypes = ['application/x-django-templating', 'application/x-jinja']
 320
 321    flags = re.M | re.S
 322
 323    tokens = {
 324        'root': [
 325            (r'[^{]+', Other),
 326            (r'\{\{', Comment.Preproc, 'var'),
 327            # jinja/django comments
 328            (r'\{[*#].*?[*#]\}', Comment),
 329            # django comments
 330            (r'(\{%)(-?\s*)(comment)(\s*-?)(%\})(.*?)'
 331             r'(\{%)(-?\s*)(endcomment)(\s*-?)(%\})',
 332             bygroups(Comment.Preproc, Text, Keyword, Text, Comment.Preproc,
 333                      Comment, Comment.Preproc, Text, Keyword, Text,
 334                      Comment.Preproc)),
 335            # raw jinja blocks
 336            (r'(\{%)(-?\s*)(raw)(\s*-?)(%\})(.*?)'
 337             r'(\{%)(-?\s*)(endraw)(\s*-?)(%\})',
 338             bygroups(Comment.Preproc, Text, Keyword, Text, Comment.Preproc,
 339                      Text, Comment.Preproc, Text, Keyword, Text,
 340                      Comment.Preproc)),
 341            # filter blocks
 342            (r'(\{%)(-?\s*)(filter)(\s+)([a-zA-Z_][a-zA-Z0-9_]*)',
 343             bygroups(Comment.Preproc, Text, Keyword, Text, Name.Function),
 344             'block'),
 345            (r'(\{%)(-?\s*)([a-zA-Z_][a-zA-Z0-9_]*)',
 346             bygroups(Comment.Preproc, Text, Keyword), 'block'),
 347            (r'\{', Other)
 348        ],
 349        'varnames': [
 350            (r'(\|)(\s*)([a-zA-Z_][a-zA-Z0-9_]*)',
 351             bygroups(Operator, Text, Name.Function)),
 352            (r'(is)(\s+)(not)?(\s+)?([a-zA-Z_][a-zA-Z0-9_]*)',
 353             bygroups(Keyword, Text, Keyword, Text, Name.Function)),
 354            (r'(_|true|false|none|True|False|None)\b', Keyword.Pseudo),
 355            (r'(in|as|reversed|recursive|not|and|or|is|if|else|import|'
 356             r'with(?:(?:out)?\s*context)?|scoped|ignore\s+missing)\b',
 357             Keyword),
 358            (r'(loop|block|super|forloop)\b', Name.Builtin),
 359            (r'[a-zA-Z][a-zA-Z0-9_-]*', Name.Variable),
 360            (r'\.[a-zA-Z0-9_]+', Name.Variable),
 361            (r':?"(\\\\|\\"|[^"])*"', String.Double),
 362            (r":?'(\\\\|\\'|[^'])*'", String.Single),
 363            (r'([{}()\[\]+\-*/,:~]|[><=]=?)', Operator),
 364            (r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|"
 365             r"0[xX][0-9a-fA-F]+[Ll]?", Number),
 366        ],
 367        'var': [
 368            (r'\s+', Text),
 369            (r'(-?)(\}\})', bygroups(Text, Comment.Preproc), '#pop'),
 370            include('varnames')
 371        ],
 372        'block': [
 373            (r'\s+', Text),
 374            (r'(-?)(%\})', bygroups(Text, Comment.Preproc), '#pop'),
 375            include('varnames'),
 376            (r'.', Punctuation)
 377        ]
 378    }
 379
 380    def analyse_text(text):
 381        rv = 0.0
 382        if re.search(r'\{%\s*(block|extends)', text) is not None:
 383            rv += 0.4
 384        if re.search(r'\{%\s*if\s*.*?%\}', text) is not None:
 385            rv += 0.1
 386        if re.search(r'\{\{.*?\}\}', text) is not None:
 387            rv += 0.1
 388        return rv
 389
 390
 391class MyghtyLexer(RegexLexer):
 392    """
 393    Generic `myghty templates`_ lexer. Code that isn't Myghty
 394    markup is yielded as `Token.Other`.
 395
 396    *New in Pygments 0.6.*
 397
 398    .. _myghty templates: http://www.myghty.org/
 399    """
 400
 401    name = 'Myghty'
 402    aliases = ['myghty']
 403    filenames = ['*.myt', 'autodelegate']
 404    mimetypes = ['application/x-myghty']
 405
 406    tokens = {
 407        'root': [
 408            (r'\s+', Text),
 409            (r'(<%(def|method))(\s*)(.*?)(>)(.*?)(</%\2\s*>)(?s)',
 410             bygroups(Name.Tag, None, Text, Name.Function, Name.Tag,
 411                      using(this), Name.Tag)),
 412            (r'(<%(\w+))(.*?)(>)(.*?)(</%\2\s*>)(?s)',
 413             bygroups(Name.Tag, None, Name.Function, Name.Tag,
 414                      using(PythonLexer), Name.Tag)),
 415            (r'(<&[^|])(.*?)(,.*?)?(&>)',
 416             bygroups(Name.Tag, Name.Function, using(PythonLexer), Name.Tag)),
 417            (r'(<&\|)(.*?)(,.*?)?(&>)(?s)',
 418             bygroups(Name.Tag, Name.Function, using(PythonLexer), Name.Tag)),
 419            (r'</&>', Name.Tag),
 420            (r'(<%!?)(.*?)(%>)(?s)',
 421             bygroups(Name.Tag, using(PythonLexer), Name.Tag)),
 422            (r'(?<=^)#[^\n]*(\n|\Z)', Comment),
 423            (r'(?<=^)(%)([^\n]*)(\n|\Z)',
 424             bygroups(Name.Tag, using(PythonLexer), Other)),
 425            (r"""(?sx)
 426                 (.+?)               # anything, followed by:
 427                 (?:
 428                  (?<=\n)(?=[%#]) |  # an eval or comment line
 429                  (?=</?[%&]) |      # a substitution or block or
 430                                     # call start or end
 431                                     # - don't consume
 432                  (\\\n) |           # an escaped newline
 433                  \Z                 # end of string
 434                 )""", bygroups(Other, Operator)),
 435        ]
 436    }
 437
 438
 439class MyghtyHtmlLexer(DelegatingLexer):
 440    """
 441    Subclass of the `MyghtyLexer` that highlights unlexer data
 442    with the `HtmlLexer`.
 443
 444    *New in Pygments 0.6.*
 445    """
 446
 447    name = 'HTML+Myghty'
 448    aliases = ['html+myghty']
 449    mimetypes = ['text/html+myghty']
 450
 451    def __init__(self, **options):
 452        super(MyghtyHtmlLexer, self).__init__(HtmlLexer, MyghtyLexer,
 453                                              **options)
 454
 455
 456class MyghtyXmlLexer(DelegatingLexer):
 457    """
 458    Subclass of the `MyghtyLexer` that highlights unlexer data
 459    with the `XmlLexer`.
 460
 461    *New in Pygments 0.6.*
 462    """
 463
 464    name = 'XML+Myghty'
 465    aliases = ['xml+myghty']
 466    mimetypes = ['application/xml+myghty']
 467
 468    def __init__(self, **options):
 469        super(MyghtyXmlLexer, self).__init__(XmlLexer, MyghtyLexer,
 470                                             **options)
 471
 472
 473class MyghtyJavascriptLexer(DelegatingLexer):
 474    """
 475    Subclass of the `MyghtyLexer` that highlights unlexer data
 476    with the `JavascriptLexer`.
 477
 478    *New in Pygments 0.6.*
 479    """
 480
 481    name = 'JavaScript+Myghty'
 482    aliases = ['js+myghty', 'javascript+myghty']
 483    mimetypes = ['application/x-javascript+myghty',
 484                 'text/x-javascript+myghty',
 485                 'text/javascript+mygthy']
 486
 487    def __init__(self, **options):
 488        super(MyghtyJavascriptLexer, self).__init__(JavascriptLexer,
 489                                                    MyghtyLexer, **options)
 490
 491
 492class MyghtyCssLexer(DelegatingLexer):
 493    """
 494    Subclass of the `MyghtyLexer` that highlights unlexer data
 495    with the `CssLexer`.
 496
 497    *New in Pygments 0.6.*
 498    """
 499
 500    name = 'CSS+Myghty'
 501    aliases = ['css+myghty']
 502    mimetypes = ['text/css+myghty']
 503
 504    def __init__(self, **options):
 505        super(MyghtyCssLexer, self).__init__(CssLexer, MyghtyLexer,
 506                                             **options)
 507
 508
 509class MasonLexer(RegexLexer):
 510    """
 511    Generic `mason templates`_ lexer. Stolen from Myghty lexer. Code that isn't
 512    Mason markup is HTML.
 513
 514    .. _mason templates: http://www.masonhq.com/
 515
 516    *New in Pygments 1.4.*
 517    """
 518    name = 'Mason'
 519    aliases = ['mason']
 520    filenames = ['*.m', '*.mhtml', '*.mc', '*.mi', 'autohandler', 'dhandler']
 521    mimetypes = ['application/x-mason']
 522
 523    tokens = {
 524        'root': [
 525            (r'\s+', Text),
 526            (r'(<%doc>)(.*?)(</%doc>)(?s)',
 527             bygroups(Name.Tag, Comment.Multiline, Name.Tag)),
 528            (r'(<%(def|method))(\s*)(.*?)(>)(.*?)(</%\2\s*>)(?s)',
 529             bygroups(Name.Tag, None, Text, Name.Function, Name.Tag,
 530                      using(this), Name.Tag)),
 531            (r'(<%(\w+))(.*?)(>)(.*?)(</%\2\s*>)(?s)',
 532             bygroups(Name.Tag, None, Name.Function, Name.Tag,
 533                      using(PerlLexer), Name.Tag)),
 534            (r'(<&[^|])(.*?)(,.*?)?(&>)(?s)',
 535             bygroups(Name.Tag, Name.Function, using(PerlLexer), Name.Tag)),
 536            (r'(<&\|)(.*?)(,.*?)?(&>)(?s)',
 537             bygroups(Name.Tag, Name.Function, using(PerlLexer), Name.Tag)),
 538            (r'</&>', Name.Tag),
 539            (r'(<%!?)(.*?)(%>)(?s)',
 540             bygroups(Name.Tag, using(PerlLexer), Name.Tag)),
 541            (r'(?<=^)#[^\n]*(\n|\Z)', Comment),
 542            (r'(?<=^)(%)([^\n]*)(\n|\Z)',
 543             bygroups(Name.Tag, using(PerlLexer), Other)),
 544            (r"""(?sx)
 545                 (.+?)               # anything, followed by:
 546                 (?:
 547                  (?<=\n)(?=[%#]) |  # an eval or comment line
 548                  (?=</?[%&]) |      # a substitution or block or
 549                                     # call start or end
 550                                     # - don't consume
 551                  (\\\n) |           # an escaped newline
 552                  \Z                 # end of string
 553                 )""", bygroups(using(HtmlLexer), Operator)),
 554        ]
 555    }
 556
 557    def analyse_text(text):
 558        rv = 0.0
 559        if re.search('<&', text) is not None:
 560            rv = 1.0
 561        return rv
 562
 563
 564class MakoLexer(RegexLexer):
 565    """
 566    Generic `mako templates`_ lexer. Code that isn't Mako
 567    markup is yielded as `Token.Other`.
 568
 569    *New in Pygments 0.7.*
 570
 571    .. _mako templates: http://www.makotemplates.org/
 572    """
 573
 574    name = 'Mako'
 575    aliases = ['mako']
 576    filenames = ['*.mao']
 577    mimetypes = ['application/x-mako']
 578
 579    tokens = {
 580        'root': [
 581            (r'(\s*)(%)(\s*end(?:\w+))(\n|\Z)',
 582             bygroups(Text, Comment.Preproc, Keyword, Other)),
 583            (r'(\s*)(%)([^\n]*)(\n|\Z)',
 584             bygroups(Text, Comment.Preproc, using(PythonLexer), Other)),
 585            (r'(\s*)(##[^\n]*)(\n|\Z)',
 586             bygroups(Text, Comment.Preproc, Other)),
 587            (r'(?s)<%doc>.*?</%doc>', Comment.Preproc),
 588            (r'(<%)([\w\.\:]+)',
 589             bygroups(Comment.Preproc, Name.Builtin), 'tag'),
 590            (r'(</%)([\w\.\:]+)(>)',
 591             bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc)),
 592            (r'<%(?=([\w\.\:]+))', Comment.Preproc, 'ondeftags'),
 593            (r'(<%(?:!?))(.*?)(%>)(?s)',
 594             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
 595            (r'(\$\{)(.*?)(\})',
 596             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
 597            (r'''(?sx)
 598                (.+?)                # anything, followed by:
 599                (?:
 600                 (?<=\n)(?=%|\#\#) | # an eval or comment line
 601                 (?=\#\*) |          # multiline comment
 602                 (?=</?%) |          # a python block
 603                                     # call start or end
 604                 (?=\$\{) |          # a substitution
 605                 (?<=\n)(?=\s*%) |
 606                                     # - don't consume
 607                 (\\\n) |            # an escaped newline
 608                 \Z                  # end of string
 609                )
 610            ''', bygroups(Other, Operator)),
 611            (r'\s+', Text),
 612        ],
 613        'ondeftags': [
 614            (r'<%', Comment.Preproc),
 615            (r'(?<=<%)(include|inherit|namespace|page)', Name.Builtin),
 616            include('tag'),
 617        ],
 618        'tag': [
 619            (r'((?:\w+)\s*=)\s*(".*?")',
 620             bygroups(Name.Attribute, String)),
 621            (r'/?\s*>', Comment.Preproc, '#pop'),
 622            (r'\s+', Text),
 623        ],
 624        'attr': [
 625            ('".*?"', String, '#pop'),
 626            ("'.*?'", String, '#pop'),
 627            (r'[^\s>]+', String, '#pop'),
 628        ],
 629    }
 630
 631
 632class MakoHtmlLexer(DelegatingLexer):
 633    """
 634    Subclass of the `MakoLexer` that highlights unlexed data
 635    with the `HtmlLexer`.
 636
 637    *New in Pygments 0.7.*
 638    """
 639
 640    name = 'HTML+Mako'
 641    aliases = ['html+mako']
 642    mimetypes = ['text/html+mako']
 643
 644    def __init__(self, **options):
 645        super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer,
 646                                              **options)
 647
 648class MakoXmlLexer(DelegatingLexer):
 649    """
 650    Subclass of the `MakoLexer` that highlights unlexer data
 651    with the `XmlLexer`.
 652
 653    *New in Pygments 0.7.*
 654    """
 655
 656    name = 'XML+Mako'
 657    aliases = ['xml+mako']
 658    mimetypes = ['application/xml+mako']
 659
 660    def __init__(self, **options):
 661        super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer,
 662                                             **options)
 663
 664class MakoJavascriptLexer(DelegatingLexer):
 665    """
 666    Subclass of the `MakoLexer` that highlights unlexer data
 667    with the `JavascriptLexer`.
 668
 669    *New in Pygments 0.7.*
 670    """
 671
 672    name = 'JavaScript+Mako'
 673    aliases = ['js+mako', 'javascript+mako']
 674    mimetypes = ['application/x-javascript+mako',
 675                 'text/x-javascript+mako',
 676                 'text/javascript+mako']
 677
 678    def __init__(self, **options):
 679        super(MakoJavascriptLexer, self).__init__(JavascriptLexer,
 680                                                    MakoLexer, **options)
 681
 682class MakoCssLexer(DelegatingLexer):
 683    """
 684    Subclass of the `MakoLexer` that highlights unlexer data
 685    with the `CssLexer`.
 686
 687    *New in Pygments 0.7.*
 688    """
 689
 690    name = 'CSS+Mako'
 691    aliases = ['css+mako']
 692    mimetypes = ['text/css+mako']
 693
 694    def __init__(self, **options):
 695        super(MakoCssLexer, self).__init__(CssLexer, MakoLexer,
 696                                             **options)
 697
 698
 699# Genshi and Cheetah lexers courtesy of Matt Good.
 700
 701class CheetahPythonLexer(Lexer):
 702    """
 703    Lexer for handling Cheetah's special $ tokens in Python syntax.
 704    """
 705
 706    def get_tokens_unprocessed(self, text):
 707        pylexer = PythonLexer(**self.options)
 708        for pos, type_, value in pylexer.get_tokens_unprocessed(text):
 709            if type_ == Token.Error and value == '$':
 710                type_ = Comment.Preproc
 711            yield pos, type_, value
 712
 713
 714class CheetahLexer(RegexLexer):
 715    """
 716    Generic `cheetah templates`_ lexer. Code that isn't Cheetah
 717    markup is yielded as `Token.Other`.  This also works for
 718    `spitfire templates`_ which use the same syntax.
 719
 720    .. _cheetah templates: http://www.cheetahtemplate.org/
 721    .. _spitfire templates: http://code.google.com/p/spitfire/
 722    """
 723
 724    name = 'Cheetah'
 725    aliases = ['cheetah', 'spitfire']
 726    filenames = ['*.tmpl', '*.spt']
 727    mimetypes = ['application/x-cheetah', 'application/x-spitfire']
 728
 729    tokens = {
 730        'root': [
 731            (r'(##[^\n]*)$',
 732             (bygroups(Comment))),
 733            (r'#[*](.|\n)*?[*]#', Comment),
 734            (r'#end[^#\n]*(?:#|$)', Comment.Preproc),
 735            (r'#slurp$', Comment.Preproc),
 736            (r'(#[a-zA-Z]+)([^#\n]*)(#|$)',
 737             (bygroups(Comment.Preproc, using(CheetahPythonLexer),
 738                       Comment.Preproc))),
 739            # TODO support other Python syntax like $foo['bar']
 740            (r'(\$)([a-zA-Z_][a-zA-Z0-9_\.]*[a-zA-Z0-9_])',
 741             bygroups(Comment.Preproc, using(CheetahPythonLexer))),
 742            (r'(\$\{!?)(.*?)(\})(?s)',
 743             bygroups(Comment.Preproc, using(CheetahPythonLexer),
 744                      Comment.Preproc)),
 745            (r'''(?sx)
 746                (.+?)               # anything, followed by:
 747                (?:
 748                 (?=[#][#a-zA-Z]*) |   # an eval comment
 749                 (?=\$[a-zA-Z_{]) | # a substitution
 750                 \Z                 # end of string
 751                )
 752            ''', Other),
 753            (r'\s+', Text),
 754        ],
 755    }
 756
 757
 758class CheetahHtmlLexer(DelegatingLexer):
 759    """
 760    Subclass of the `CheetahLexer` that highlights unlexer data
 761    with the `HtmlLexer`.
 762    """
 763
 764    name = 'HTML+Cheetah'
 765    aliases = ['html+cheetah', 'html+spitfire']
 766    mimetypes = ['text/html+cheetah', 'text/html+spitfire']
 767
 768    def __init__(self, **options):
 769        super(CheetahHtmlLexer, self).__init__(HtmlLexer, CheetahLexer,
 770                                               **options)
 771
 772
 773class CheetahXmlLexer(DelegatingLexer):
 774    """
 775    Subclass of the `CheetahLexer` that highlights unlexer data
 776    with the `XmlLexer`.
 777    """
 778
 779    name = 'XML+Cheetah'
 780    aliases = ['xml+cheetah', 'xml+spitfire']
 781    mimetypes = ['application/xml+cheetah', 'application/xml+spitfire']
 782
 783    def __init__(self, **options):
 784        super(CheetahXmlLexer, self).__init__(XmlLexer, CheetahLexer,
 785                                              **options)
 786
 787
 788class CheetahJavascriptLexer(DelegatingLexer):
 789    """
 790    Subclass of the `CheetahLexer` that highlights unlexer data
 791    with the `JavascriptLexer`.
 792    """
 793
 794    name = 'JavaScript+Cheetah'
 795    aliases = ['js+cheetah', 'javascript+cheetah',
 796               'js+spitfire', 'javascript+spitfire']
 797    mimetypes = ['application/x-javascript+cheetah',
 798                 'text/x-javascript+cheetah',
 799                 'text/javascript+cheetah',
 800                 'application/x-javascript+spitfire',
 801                 'text/x-javascript+spitfire',
 802                 'text/javascript+spitfire']
 803
 804    def __init__(self, **options):
 805        super(CheetahJavascriptLexer, self).__init__(JavascriptLexer,
 806                                                     CheetahLexer, **options)
 807
 808
 809class GenshiTextLexer(RegexLexer):
 810    """
 811    A lexer that highlights `genshi <http://genshi.edgewall.org/>`_ text
 812    templates.
 813    """
 814
 815    name = 'Genshi Text'
 816    aliases = ['genshitext']
 817    mimetypes = ['application/x-genshi-text', 'text/x-genshi']
 818
 819    tokens = {
 820        'root': [
 821            (r'[^#\$\s]+', Other),
 822            (r'^(\s*)(##.*)$', bygroups(Text, Comment)),
 823            (r'^(\s*)(#)', bygroups(Text, Comment.Preproc), 'directive'),
 824            include('variable'),
 825            (r'[#\$\s]', Other),
 826        ],
 827        'directive': [
 828            (r'\n', Text, '#pop'),
 829            (r'(?:def|for|if)\s+.*', using(PythonLexer), '#pop'),
 830            (r'(choose|when|with)([^\S\n]+)(.*)',
 831             bygroups(Keyword, Text, using(PythonLexer)), '#pop'),
 832            (r'(choose|otherwise)\b', Keyword, '#pop'),
 833            (r'(end\w*)([^\S\n]*)(.*)', bygroups(Keyword, Text, Comment), '#pop'),
 834        ],
 835        'variable': [
 836            (r'(?<!\$)(\$\{)(.+?)(\})',
 837             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
 838            (r'(?<!\$)(\$)([a-zA-Z_][a-zA-Z0-9_\.]*)',
 839             Name.Variable),
 840        ]
 841    }
 842
 843
 844class GenshiMarkupLexer(RegexLexer):
 845    """
 846    Base lexer for Genshi markup, used by `HtmlGenshiLexer` and
 847    `GenshiLexer`.
 848    """
 849
 850    flags = re.DOTALL
 851
 852    tokens = {
 853        'root': [
 854            (r'[^<\$]+', Other),
 855            (r'(<\?python)(.*?)(\?>)',
 856             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
 857            # yield style and script blocks as Other
 858            (r'<\s*(script|style)\s*.*?>.*?<\s*/\1\s*>', Other),
 859            (r'<\s*py:[a-zA-Z0-9]+', Name.Tag, 'pytag'),
 860            (r'<\s*[a-zA-Z0-9:]+', Name.Tag, 'tag'),
 861            include('variable'),
 862            (r'[<\$]', Other),
 863        ],
 864        'pytag': [
 865            (r'\s+', Text),
 866            (r'[a-zA-Z0-9_:-]+\s*=', Name.Attribute, 'pyattr'),
 867            (r'/?\s*>', Name.Tag, '#pop'),
 868        ],
 869        'pyattr': [
 870            ('(")(.*?)(")', bygroups(String, using(PythonLexer), String), '#pop'),
 871            ("(')(.*?)(')", bygroups(String, using(PythonLexer), String), '#pop'),
 872            (r'[^\s>]+', String, '#pop'),
 873        ],
 874        'tag': [
 875            (r'\s+', Text),
 876            (r'py:[a-zA-Z0-9_-]+\s*=', Name.Attribute, 'pyattr'),
 877            (r'[a-zA-Z0-9_:-]+\s*=', Name.Attribute, 'attr'),
 878            (r'/?\s*>', Name.Tag, '#pop'),
 879        ],
 880        'attr': [
 881            ('"', String, 'attr-dstring'),
 882            ("'", String, 'attr-sstring'),
 883            (r'[^\s>]*', String, '#pop')
 884        ],
 885        'attr-dstring': [
 886            ('"', String, '#pop'),
 887            include('strings'),
 888            ("'", String)
 889        ],
 890        'attr-sstring': [
 891            ("'", String, '#pop'),
 892            include('strings'),
 893            ("'", String)
 894        ],
 895        'strings': [
 896            ('[^"\'$]+', String),
 897            include('variable')
 898        ],
 899        'variable': [
 900            (r'(?<!\$)(\$\{)(.+?)(\})',
 901             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
 902            (r'(?<!\$)(\$)([a-zA-Z_][a-zA-Z0-9_\.]*)',
 903             Name.Variable),
 904        ]
 905    }
 906
 907
 908class HtmlGenshiLexer(DelegatingLexer):
 909    """
 910    A lexer that highlights `genshi <http://genshi.edgewall.org/>`_ and
 911    `kid <http://kid-templating.org/>`_ kid HTML templates.
 912    """
 913
 914    name = 'HTML+Genshi'
 915    aliases = ['html+genshi', 'html+kid']
 916    alias_filenames = ['*.html', '*.htm', '*.xhtml']
 917    mimetypes = ['text/html+genshi']
 918
 919    def __init__(self, **options):
 920        super(HtmlGenshiLexer, self).__init__(HtmlLexer, GenshiMarkupLexer,
 921                                              **options)
 922
 923    def analyse_text(text):
 924        rv = 0.0
 925        if re.search('\$\{.*?\}', text) is not None:
 926            rv += 0.2
 927        if re.search('py:(.*?)=["\']', text) is not None:
 928            rv += 0.2
 929        return rv + HtmlLexer.analyse_text(text) - 0.01
 930
 931
 932class GenshiLexer(DelegatingLexer):
 933    """
 934    A lexer that highlights `genshi <http://genshi.edgewall.org/>`_ and
 935    `kid <http://kid-templating.org/>`_ kid XML templates.
 936    """
 937
 938    name = 'Genshi'
 939    aliases = ['genshi', 'kid', 'xml+genshi', 'xml+kid']
 940    filenames = ['*.kid']
 941    alias_filenames = ['*.xml']
 942    mimetypes = ['application/x-genshi', 'application/x-kid']
 943
 944    def __init__(self, **options):
 945        super(GenshiLexer, self).__init__(XmlLexer, GenshiMarkupLexer,
 946                                          **options)
 947
 948    def analyse_text(text):
 949        rv = 0.0
 950        if re.search('\$\{.*?\}', text) is not None:
 951            rv += 0.2
 952        if re.search('py:(.*?)=["\']', text) is not None:
 953            rv += 0.2
 954        return rv + XmlLexer.analyse_text(text) - 0.01
 955
 956
 957class JavascriptGenshiLexer(DelegatingLexer):
 958    """
 959    A lexer that highlights javascript code in genshi text templates.
 960    """
 961
 962    name = 'JavaScript+Genshi Text'
 963    aliases = ['js+genshitext', 'js+genshi', 'javascript+genshitext',
 964               'javascript+genshi']
 965    alias_filenames = ['*.js']
 966    mimetypes = ['application/x-javascript+genshi',
 967                 'text/x-javascript+genshi',
 968                 'text/javascript+genshi']
 969
 970    def __init__(self, **options):
 971        super(JavascriptGenshiLexer, self).__init__(JavascriptLexer,
 972                                                    GenshiTextLexer,
 973                                                    **options)
 974
 975    def analyse_text(text):
 976        return GenshiLexer.analyse_text(text) - 0.05
 977
 978
 979class CssGenshiLexer(DelegatingLexer):
 980    """
 981    A lexer that highlights CSS definitions in genshi text templates.
 982    """
 983
 984    name = 'CSS+Genshi Text'
 985    aliases = ['css+genshitext', 'css+genshi']
 986    alias_filenames = ['*.css']
 987    mimetypes = ['text/css+genshi']
 988
 989    def __init__(self, **options):
 990        super(CssGenshiLexer, self).__init__(CssLexer, GenshiTextLexer,
 991                                             **options)
 992
 993    def analyse_text(text):
 994        return GenshiLexer.analyse_text(text) - 0.05
 995
 996
 997class RhtmlLexer(DelegatingLexer):
 998    """
 999    Subclass of the ERB lexer that highlights the unlexed data with the
1000    html lexer.
1001
1002    Nested Javascript and CSS is highlighted too.
1003    """
1004
1005    name = 'RHTML'
1006    aliases = ['rhtml', 'html+erb', 'html+ruby']
1007    filenames = ['*.rhtml']
1008    alias_filenames = ['*.html', '*.htm', '*.xhtml']
1009    mimetypes = ['text/html+ruby']
1010
1011    def __init__(self, **options):
1012        super(RhtmlLexer, self).__init__(HtmlLexer, ErbLexer, **options)
1013
1014    def analyse_text(text):
1015        rv = ErbLexer.analyse_text(text) - 0.01
1016        if html_doctype_matches(text):
1017            # one more than the XmlErbLexer returns
1018            rv += 0.5
1019        return rv
1020
1021
1022class XmlErbLexer(DelegatingLexer):
1023    """
1024    Subclass of `ErbLexer` which highlights data outside preprocessor
1025    directives with the `XmlLexer`.
1026    """
1027
1028    name = 'XML+Ruby'
1029    aliases = ['xml+erb', 'xml+ruby']
1030    alias_filenames = ['*.xml']
1031    mimetypes = ['application/xml+ruby']
1032
1033    def __init__(self, **options):
1034        super(XmlErbLexer, self).__init__(XmlLexer, ErbLexer, **options)
1035
1036    def analyse_text(text):
1037        rv = ErbLexer.analyse_text(text) - 0.01
1038        if looks_like_xml(text):
1039            rv += 0.4
1040        return rv
1041
1042
1043class CssErbLexer(DelegatingLexer):
1044    """
1045    Subclass of `ErbLexer` which highlights unlexed data with the `CssLexer`.
1046    """
1047
1048    name = 'CSS+Ruby'
1049    aliases = ['css+erb', 'css+ruby']
1050    alias_filenames = ['*.css']
1051    mimetypes = ['text/css+ruby']
1052
1053    def __init__(self, **options):
1054        super(CssErbLexer, self).__init__(CssLexer, ErbLexer, **options)
1055
1056    def analyse_text(text):
1057        return ErbLexer.analyse_text(text) - 0.05
1058
1059
1060class JavascriptErbLexer(DelegatingLexer):
1061    """
1062    Subclass of `ErbLexer` which highlights unlexed data with the
1063    `JavascriptLexer`.
1064    """
1065
1066    name = 'JavaScript+Ruby'
1067    aliases = ['js+erb', 'javascript+erb', 'js+ruby', 'javascript+ruby']
1068    alias_filenames = ['*.js']
1069    mimetypes = ['application/x-javascript+ruby',
1070                 'text/x-javascript+ruby',
1071                 'text/javascript+ruby']
1072
1073    def __init__(self, **options):
1074        super(JavascriptErbLexer, self).__init__(JavascriptLexer, ErbLexer,
1075                                                 **options)
1076
1077    def analyse_text(text):
1078        return ErbLexer.analyse_text(text) - 0.05
1079
1080
1081class HtmlPhpLexer(DelegatingLexer):
1082    """
1083    Subclass of `PhpLexer` that highlights unhandled data with the `HtmlLexer`.
1084
1085    Nested Javascript and CSS is highlighted too.
1086    """
1087
1088    name = 'HTML+PHP'
1089    aliases = ['html+php']
1090    filenames = ['*.phtml']
1091    alias_filenames = ['*.php', '*.html', '*.htm', '*.xhtml',
1092                       '*.php[345]']
1093    mimetypes = ['application/x-php',
1094                 'application/x-httpd-php', 'application/x-httpd-php3',
1095                 'application/x-httpd-php4', 'application/x-httpd-php5']
1096
1097    def __init__(self, **options):
1098        super(HtmlPhpLexer, self).__init__(HtmlLexer, PhpLexer, **options)
1099
1100    def analyse_text(text):
1101        rv = PhpLexer.analyse_text(text) - 0.01
1102        if html_doctype_matches(text):
1103            rv += 0.5
1104        return rv
1105
1106
1107class XmlPhpLexer(DelegatingLexer):
1108    """
1109    Subclass of `PhpLexer` that higlights unhandled data with the `XmlLexer`.
1110    """
1111
1112    name = 'XML+PHP'
1113    aliases = ['xml+php']
1114    alias_filenames = ['*.xml', '*.php', '*.php[345]']
1115    mimetypes = ['application/xml+php']
1116
1117    def __init__(self, **options):
1118        super(XmlPhpLexer, self).__init__(XmlLexer, PhpLexer, **options)
1119
1120    def analyse_text(text):
1121        rv = PhpLexer.analyse_text(text) - 0.01
1122        if looks_like_xml(text):
1123            rv += 0.4
1124        return rv
1125
1126
1127class CssPhpLexer(DelegatingLexer):
1128    """
1129    Subclass of `PhpLexer` which highlights unmatched data with the `CssLexer`.
1130    """
1131
1132    name = 'CSS+PHP'
1133    aliases = ['css+php']
1134    alias_filenames = ['*.css']
1135    mimetypes = ['text/css+php']
1136
1137    def __init__(self, **options):
1138        super(CssPhpLexer, self).__init__(CssLexer, PhpLexer, **options)
1139
1140    def analyse_text(text):
1141        return PhpLexer.analyse_text(text) - 0.05
1142
1143
1144class JavascriptPhpLexer(DelegatingLexer):
1145    """
1146    Subclass of `PhpLexer` which highlights unmatched data with the
1147    `JavascriptLexer`.
1148    """
1149
1150    name = 'JavaScript+PHP'
1151    aliases = ['js+php', 'javascript+php']
1152    alias_filenames = ['*.js']
1153    mimetypes = ['application/x-javascript+php',
1154                 'text/x-javascript+php',
1155                 'text/javascript+php']
1156
1157    def __init__(self, **options):
1158        super(JavascriptPhpLexer, self).__init__(JavascriptLexer, PhpLexer,
1159                                                 **options)
1160
1161    def analyse_text(text):
1162        return PhpLexer.analyse_text(text)
1163
1164
1165class HtmlSmartyLexer(DelegatingLexer):
1166    """
1167    Subclass of the `SmartyLexer` that highighlights unlexed data with the
1168    `HtmlLexer`.
1169
1170    Nested Javascript and CSS is highlighted too.
1171    """
1172
1173    name = 'HTML+Smarty'
1174    aliases = ['html+smarty']
1175    alias_filenames = ['*.html', '*.htm', '*.xhtml', '*.tpl']
1176    mimetypes = ['text/html+smarty']
1177
1178    def __init__(self, **options):
1179        super(HtmlSmartyLexer, self).__init__(HtmlLexer, SmartyLexer, **options)
1180
1181    def analyse_text(text):
1182        rv = SmartyLexer.analyse_text(text) - 0.01
1183        if html_doctype_matches(text):
1184            rv += 0.5
1185        return rv
1186
1187
1188class XmlSmartyLexer(DelegatingLexer):
1189    """
1190    Subclass of the `SmartyLexer` that highlights unlexed data with the
1191    `XmlLexer`.
1192    """
1193
1194    name = 'XML+Smarty'
1195    aliases = ['xml+smarty']
1196    alias_filenames = ['*.xml', '*.tpl']
1197    mimetypes = ['application/xml+smarty']
1198
1199    def __init__(self, **options):
1200        super(XmlSmartyLexer, self).__init__(XmlLexer, SmartyLexer, **options)
1201
1202    def analyse_text(text):
1203        rv = SmartyLexer.analyse_text(text) - 0.01
1204        if looks_like_xml(text):
1205            rv += 0.4
1206        return rv
1207
1208
1209class CssSmartyLexer(DelegatingLexer):
1210    """
1211    Subclass of the `SmartyLexer` that highlights unlexed data with the
1212    `CssLexer`.
1213    """
1214
1215    name = 'CSS+Smarty'
1216    aliases = ['css+smarty']
1217    alias_filenames = ['*.css', '*.tpl']
1218    mimetypes = ['text/css+smarty']
1219
1220    def __init__(self, **options):
1221        super(CssSmartyLexer, self).__init__(CssLexer, SmartyLexer, **options)
1222
1223    def analyse_text(text):
1224        return SmartyLexer.analyse_text(text) - 0.05
1225
1226
1227class JavascriptSmartyLexer(DelegatingLexer):
1228    """
1229    Subclass of the `SmartyLexer` that highlights unlexed data with the
1230    `JavascriptLexer`.
1231    """
1232
1233    name = 'JavaScript+Smarty'
1234    aliases = ['js+smarty', 'javascript+smarty']
1235    alias_filenames = ['*.js', '*.tpl']
1236    mimetypes = ['application/x-javascript+smarty',
1237                 'text/x-javascript+smarty',
1238                 'text/javascript+smarty']
1239
1240    def __init__(self, **options):
1241        super(JavascriptSmartyLexer, self).__init__(JavascriptLexer, SmartyLexer,
1242                                                    **options)
1243
1244    def analyse_text(text):
1245        return SmartyLexer.analyse_text(text) - 0.05
1246
1247
1248class HtmlDjangoLexer(DelegatingLexer):
1249    """
1250    Subclass of the `DjangoLexer` that highighlights unlexed data with the
1251    `HtmlLexer`.
1252
1253    Nested Javascript and CSS is highlighted too.
1254    """
1255
1256    name = 'HTML+Django/Jinja'
1257    aliases = ['html+django', 'html+jinja']
1258    alias_filenames = ['*.html', '*.htm', '*.xhtml']
1259    mimetypes = ['text/html+django', 'text/html+jinja']
1260
1261    def __init__(self, **options):
1262        super(HtmlDjangoLexer, self).__init__(HtmlLexer, DjangoLexer, **options)
1263
1264    def analyse_text(text):
1265        rv = DjangoLexer.analyse_text(text) - 0.01
1266        if html_doctype_matches(text):
1267            rv += 0.5
1268        return rv
1269
1270
1271class XmlDjangoLexer(DelegatingLexer):
1272    """
1273    Subclass of the `DjangoLexer` that highlights unlexed data with the
1274    `XmlLexer`.
1275    """
1276
1277    name = 'XML+Django/Jinja'
1278    aliases = ['xml+django', 'xml+jinja']
1279    alias_filenames = ['*.xml']
1280    mimetypes = ['application/xml+django', 'application/xml+jinja']
1281
1282    def __init__(self, **options):
1283        super(XmlDjangoLexer, self).__init__(XmlLexer, DjangoLexer, **options)
1284
1285    def analyse_text(text):
1286        rv = DjangoLexer.analyse_text(text) - 0.01
1287        if looks_like_xml(text):
1288            rv += 0.4
1289        return rv
1290
1291
1292class CssDjangoLexer(DelegatingLexer):
1293    """
1294    Subclass of the `DjangoLexer` that highlights unlexed data with the
1295    `CssLexer`.
1296    """
1297
1298    name = 'CSS+Django/Jinja'
1299    aliases = ['css+django', 'css+jinja']
1300    alias_filenames = ['*.css']
1301    mimetypes = ['text/css+django', 'text/css+jinja']
1302
1303    def __init__(self, **options):
1304        super(CssDjangoLexer, self).__init__(CssLexer, DjangoLexer, **options)
1305
1306    def analyse_text(text):
1307        return DjangoLexer.analyse_text(text) - 0.05
1308
1309
1310class JavascriptDjangoLexer(DelegatingLexer):
1311    """
1312    Subclass of the `DjangoLexer` that highlights unlexed data with the
1313    `JavascriptLexer`.
1314    """
1315
1316    name = 'JavaScript+Django/Jinja'
1317    aliases = ['js+django', 'javascript+django',
1318               'js+jinja', 'javascript+jinja']
1319    alias_filenames = ['*.js']
1320    mimetypes = ['application/x-javascript+django',
1321                 'application/x-javascript+jinja',
1322                 'text/x-javascript+django',
1323                 'text/x-javascript+jinja',
1324                 'text/javascript+django',
1325                 'text/javascript+jinja']
1326
1327    def __init__(self, **options):
1328        super(JavascriptDjangoLexer, self).__init__(JavascriptLexer, DjangoLexer,
1329                                                    **options)
1330
1331    def analyse_text(text):
1332        return DjangoLexer.analyse_text(text) - 0.05
1333
1334
1335class JspRootLexer(RegexLexer):
1336    """
1337    Base for the `JspLexer`. Yields `Token.Other` for area outside of
1338    JSP tags.
1339
1340    *New in Pygments 0.7.*
1341    """
1342
1343    tokens = {
1344        'root': [
1345            (r'<%\S?', Keyword, 'sec'),
1346            # FIXME: I want to make these keywords but still parse attributes.
1347            (r'</?jsp:(forward|getProperty|include|plugin|setProperty|useBean).*?>',
1348             Keyword),
1349            (r'[^<]+', Other),
1350            (r'<', Other),
1351        ],
1352        'sec': [
1353            (r'%>', Keyword, '#pop'),
1354            # note: '\w\W' != '.' without DOTALL.
1355            (r'[\w\W]+?(?=%>|\Z)', using(JavaLexer)),
1356        ],
1357    }
1358
1359
1360class JspLexer(DelegatingLexer):
1361    """
1362    Lexer for Java Server Pages.
1363
1364    *New in Pygments 0.7.*
1365    """
1366    name = 'Java Server Page'
1367    aliases = ['jsp']
1368    filenames = ['*.jsp']
1369    mimetypes = ['application/x-jsp']
1370
1371    def __init__(self, **options):
1372        super(JspLexer, self).__init__(XmlLexer, JspRootLexer, **options)
1373
1374    def analyse_text(text):
1375        rv = JavaLexer.analyse_text(text) - 0.01
1376        if looks_like_xml(text):
1377            rv += 0.4
1378        if '<%' in text and '%>' in text:
1379            rv += 0.1
1380        return rv
1381
1382
1383class EvoqueLexer(RegexLexer):
1384    """
1385    For files using the Evoque templating system.
1386
1387    *New in Pygments 1.1.*
1388    """
1389    name = 'Evoque'
1390    aliases = ['evoque']
1391    filenames = ['*.evoque']
1392    mimetypes = ['application/x-evoque']
1393
1394    flags = re.DOTALL
1395
1396    tokens = {
1397        'root': [
1398            (r'[^#$]+', Other),
1399            (r'#\[', Comment.Multiline, 'comment'),
1400            (r'\$\$', Other),
1401            # svn keywords
1402            (r'\$\w+:[^$\n]*\$', Comment.Multiline),
1403            # directives: begin, end
1404            (r'(\$)(begin|end)(\{(%)?)(.*?)((?(4)%)\})',
1405             bygroups(Punctuation, Name.Builtin, Punctuation, None,
1406                      String, Punctuation, None)),
1407            # directives: evoque, overlay
1408            # see doc for handling first name arg: /directives/evoque/
1409            #+ minor inconsistency: the "name" in e.g. $overlay{name=site_base}
1410            # should be using(PythonLexer), not passed out as String
1411            (r'(\$)(evoque|overlay)(\{(%)?)(\s*[#\w\-"\'.]+[^=,%}]+?)?'
1412             r'(.*?)((?(4)%)\})',
1413             bygroups(Punctuation, Name.Builtin, Punctuation, None,
1414                      String, using(PythonLexer), Punctuation, None)),
1415            # directives: if, for, prefer, test
1416            (r'(\$)(\w+)(\{(%)?)(.*?)((?(4)%)\})',
1417             bygroups(Punctuation, Name.Builtin, Punctuation, None,
1418                      using(PythonLexer), Punctuation, None)),
1419            # directive clauses (no {} expression)
1420            (r'(\$)(else|rof|fi)', bygroups(Punctuation, Name.Builtin)),
1421            # expressions
1422            (r'(\$\{(%)?)(.*?)((!)(.*?))?((?(2)%)\})',
1423             bygroups(Punctuation, None, using(PythonLexer),
1424                      Name.Builtin, None, None, Punctuation, None)),
1425            (r'#', Other),
1426        ],
1427        'comment': [
1428            (r'[^\]#]', Comment.Multiline),
1429            (r'#\[', Comment.Multiline, '#push'),
1430            (r'\]#', Comment.Multiline, '#pop'),
1431            (r'[\]#]', Comment.Multiline)
1432        ],
1433    }
1434
1435class EvoqueHtmlLexer(DelegatingLexer):
1436    """
1437    Subclass of the `EvoqueLexer` that highlights unlexed data with the
1438    `HtmlLexer`.
1439
1440    *New in Pygments 1.1.*
1441    """
1442    name = 'HTML+Evoque'
1443    aliases = ['html+evoque']
1444    filenames = ['*.html']
1445    mimetypes = ['text/html+evoque']
1446
1447    def __init__(self, **options):
1448        super(EvoqueHtmlLexer, self).__init__(HtmlLexer, EvoqueLexer,
1449                                              **options)
1450
1451class EvoqueXmlLexer(DelegatingLexer):
1452    """
1453    Subclass of the `EvoqueLexer` that highlights unlexed data with the
1454    `XmlLexer`.
1455
1456    *New in Pygments 1.1.*
1457    """
1458    name = 'XML+Evoque'
1459    aliases = ['xml+evoque']
1460    filenames = ['*.xml']
1461    mimetypes = ['application/xml+evoque']
1462
1463    def __init__(self, **options):
1464        super(EvoqueXmlLexer, self).__init__(XmlLexer, EvoqueLexer,
1465                                             **options)
1466
1467class ColdfusionLexer(RegexLexer):
1468    """
1469    Coldfusion statements
1470    """
1471    name = 'cfstatement'
1472    aliases = ['cfs']
1473    filenames = []
1474    mimetypes = []
1475    flags = re.IGNORECASE | re.MULTILINE
1476
1477    tokens = {
1478        'root': [
1479            (r'//.*', Comment),
1480            (r'\+\+|--', Operator),
1481            (r'[-+*/^&=!]', Operator),
1482            (r'<=|>=|<|>', Operator),
1483            (r'mod\b', Operator),
1484            (r'(eq|lt|gt|lte|gte|not|is|and|or)\b', Operator),
1485            (r'\|\||&&', Operator),
1486            (r'"', String.Double, 'string'),
1487            # There is a special rule for allowing html in single quoted
1488            # strings, evidently.
1489            (r"'.*?'", String.Single),
1490            (r'\d+', Number),
1491            (r'(if|else|len|var|case|default|break|switch)\b', Keyword),
1492            (r'([A-Za-z_$][A-Za-z0-9_.]*)\s*(\()', bygroups(Name.Function, Punctuation)),
1493            (r'[A-Za-z_$][A-Za-z0-9_.]*', Name.Variable),
1494            (r'[()\[\]{};:,.\\]', Punctuation),
1495            (r'\s+', Text),
1496        ],
1497        'string': [
1498            (r'""', String.Double),
1499            (r'#.+?#', String.Interp),
1500            (r'[^"#]+', String.Double),
1501            (r'#', String.Double),
1502            (r'"', String.Double, '#pop'),
1503        ],
1504    }
1505
1506class ColdfusionMarkupLexer(RegexLexer):
1507    """
1508    Coldfusion markup only
1509    """
1510    name = 'Coldfusion'
1511    aliases = ['cf']
1512    filenames = []
1513    mimetypes = []
1514
1515    tokens = {
1516        'root': [
1517            (r'[^<]+', Other),
1518            include('tags'),
1519            (r'<[^<>]*', Other),
1520        ],
1521        'tags': [
1522            (r'(?s)<!---.*?--->', Comment.Multiline),
1523            (r'(?s)<!--.*?-->', Comment),
1524            (r'<cfoutput.*?>', Name.Builtin, 'cfoutput'),
1525            (r'(?s)(<cfscript.*?>)(.+?)(</cfscript.*?>)',
1526             bygroups(Name.Builtin, using(ColdfusionLexer), Name.Builtin)),
1527            # neg…

Large files files are truncated, but you can click here to view the full file