Commits

tboyt committed 25d37b3

Added Handlebars lexer

Comments (0)

Files changed (4)

pygments/lexers/_mapping.py

     'GroffLexer': ('pygments.lexers.text', 'Groff', ('groff', 'nroff', 'man'), ('*.[1234567]', '*.man'), ('application/x-troff', 'text/troff')),
     'GroovyLexer': ('pygments.lexers.jvm', 'Groovy', ('groovy',), ('*.groovy',), ('text/x-groovy',)),
     'HamlLexer': ('pygments.lexers.web', 'Haml', ('haml', 'HAML'), ('*.haml',), ('text/x-haml',)),
+    'HandlebarsHtmlLexer': ('pygments.lexers.templates', 'HTML+Handlebars', ('html+handlebars',), ('*.handlebars', '*.hbs'), ('text/html+handlebars', 'text/x-handlebars-template')),
+    'HandlebarsLexer': ('pygments.lexers.templates', 'Handlebars', ('handlebars',), (), ()),
     'HaskellLexer': ('pygments.lexers.functional', 'Haskell', ('haskell', 'hs'), ('*.hs',), ('text/x-haskell',)),
     'HaxeLexer': ('pygments.lexers.web', 'haXe', ('hx', 'haXe'), ('*.hx',), ('text/haxe',)),
     'HtmlDjangoLexer': ('pygments.lexers.templates', 'HTML+Django/Jinja', ('html+django', 'html+jinja'), (), ('text/html+django', 'text/html+jinja')),

pygments/lexers/templates.py

            'EvoqueHtmlLexer', 'EvoqueXmlLexer', 'ColdfusionLexer',
            'ColdfusionHtmlLexer', 'VelocityLexer', 'VelocityHtmlLexer',
            'VelocityXmlLexer', 'SspLexer', 'TeaTemplateLexer', 'LassoHtmlLexer',
-           'LassoXmlLexer', 'LassoCssLexer', 'LassoJavascriptLexer']
+           'LassoXmlLexer', 'LassoCssLexer', 'LassoJavascriptLexer', 
+           'HandlebarsLexer', 'HandlebarsHtmlLexer']
 
 
 class ErbLexer(Lexer):
         if 'function' in text:
             rv += 0.2
         return rv
+
+class HandlebarsLexer(RegexLexer):
+    """
+    Generic `handlebars <http://handlebarsjs.com/>` template lexer.
+
+    Highlights only the Handlebars template tags (stuff between `{{` and `}}`).
+    Everything else is left for a delegating lexer.
+    """
+
+    name = "Handlebars"
+    aliases = ['handlebars']
+
+    tokens = {
+        'root': [
+            (r'[^{]+', Other),
+
+            (r'{{!.*}}', Comment),
+
+            (r'({{{)(\s*)', bygroups(Comment.Special, Text), 'tag'),
+            (r'({{)(\s*)', bygroups(Comment.Preproc, Text), 'tag'),
+        ],
+
+        'tag': [
+            (r'\s+', Text),
+            (r'\}\}\}', Comment.Special, '#pop'),
+            (r'\}\}', Comment.Preproc, '#pop'),
+
+            # Handlebars
+            (r'([\#/]*)(each|if|unless|else|with|log|in)', bygroups(Keyword, 
+             Keyword)),
+
+            # General {{#block}}
+            (r'([\#/])(\w+)', bygroups(Name.Function, Name.Function)),
+
+            # {{opt=something}}
+            (r'(\w+)(=)', bygroups(Name.Attribute, Operator)),
+
+            # borrowed from DjangoLexer
+            (r':?"(\\\\|\\"|[^"])*"', String.Double),
+            (r":?'(\\\\|\\'|[^'])*'", String.Single),
+            (r'[a-zA-Z][a-zA-Z0-9_-]*', Name.Variable),
+            (r'\.[a-zA-Z0-9_]+', Name.Variable),
+            (r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|"
+             r"0[xX][0-9a-fA-F]+[Ll]?", Number),
+        ]
+    }
+
+
+class HandlebarsHtmlLexer(DelegatingLexer):
+    """
+    Subclass of the `HandlebarsLexer` that highlights unlexed data with the 
+    `HtmlLexer`.
+    """
+
+    name = "HTML+Handlebars"
+    aliases = ["html+handlebars"]
+    filenames = ['*.handlebars', '*.hbs']
+    mimetypes = ['text/html+handlebars', 'text/x-handlebars-template']
+
+    def __init__(self, **options):
+        super(HandlebarsHtmlLexer, self).__init__(HtmlLexer, HandlebarsLexer, **options)

tests/examplefiles/demo.hbs

+<!-- post.handlebars -->
+
+<div class='intro'>
+  {{intro}}
+</div>
+
+{{#if isExpanded}}
+  <div class='body'>{{body}}</div>
+  <button {{action contract}}>Contract</button>
+{{else}}
+  <button {{action expand}}>Show More...</button>
+{{/if}}

tests/examplefiles/ember.handlebars

+{{#view EmberFirebaseChat.ChatView class="chat-container"}}
+  <div class="chat-messages-container">
+    <ul class="chat-messages">
+      {{#each message in content}}
+      <li>
+        [{{formatTimestamp "message.timestamp" fmtString="h:mm:ss A"}}] 
+        <strong>{{message.sender}}</strong>: {{message.content}}
+      </li>
+      {{/each}}
+    </ul>
+  </div>
+
+  {{! Comment }}
+  {{{unescaped value}}}
+
+  {{#view EmberFirebaseChat.InputView class="chat-input-container"}}
+    <form class="form-inline">
+      {{#if "auth.authed"}}
+        {{#if "auth.hasName"}}
+          <input type="text" id="message" placeholder="Message">
+          <button {{action "postMessage" target="view"}} class="btn">Send</button>
+        {{else}}
+          <input type="text" id="username" placeholder="Enter your username...">
+          <button {{action "pickName" target="view"}} class="btn">Send</button>
+        {{/if}}
+      {{else}}
+        <input type="text" placeholder="Log in with Persona to chat!" disabled="disabled">
+        <button {{action "login"}} class="btn">Login</button>
+      {{/if}}
+    </form>
+  {{/view}}
+{{/view}}
+