Anonymous avatar Anonymous committed 24f298a

Support indentation-based Haml blocks.

Comments (0)

Files changed (1)

pygments/lexers/web.py

 except NameError:
     from sets import Set as set
 
-from pygments.lexer import RegexLexer, bygroups, using, include, this
+from pygments.lexer import RegexLexer, ExtendedRegexLexer, bygroups, using, include, this
 from pygments.token import \
      Text, Comment, Operator, Keyword, Name, String, Number, Other, Punctuation
 from pygments.util import get_bool_opt, get_list_opt, looks_like_xml, \
         if re.match(r'\w+\s*:\s*\w', text): return 0.3
 
 
-class HamlLexer(RegexLexer):
+class HamlLexer(ExtendedRegexLexer):
     """
     For Haml markup.
     """
     mimetypes = ['text/x-haml']
 
     flags = re.IGNORECASE
+
+    def indentation(lexer, match, ctx):
+        indentation = match.group(0)
+        yield match.start(), Text, indentation
+        ctx.last_indentation = indentation
+        ctx.pos = match.end()
+
+        if hasattr(ctx, 'block_state') and ctx.block_state and \
+                indentation.startswith(ctx.block_indentation) and \
+                indentation != ctx.block_indentation:
+            ctx.stack.append(ctx.block_state)
+        else:
+            ctx.block_state = None
+            ctx.block_indentation = None
+            ctx.stack.append('content')
+
+    def starts_block(token, state):
+        def callback(lexer, match, ctx):
+            yield match.start(), token, match.group(0)
+
+            if hasattr(ctx, 'last_indentation'):
+                ctx.block_indentation = ctx.last_indentation
+            else:
+                ctx.block_indentation = ''
+
+            ctx.block_state = state
+            ctx.pos = match.end()
+
+        return callback
+
     tokens = {
         'root': [
             (r'[ \t]*\n', Text),
-            (r'[ \t]*', Text, 'content'),
+            (r'[ \t]*', indentation),
         ],
 
         'css': [
             (r'(/)(\[.*?\])(.*\n)',
              bygroups(Comment, Comment.Special, Comment),
              '#pop'),
-            (r'/.*\n', Comment, '#pop'),
-            (r'-#.*\n', Comment.Preproc, '#pop'),
+            (r'/.*\n', starts_block(Comment, 'html-comment-block'), '#pop'),
+            (r'-#.*\n', starts_block(Comment.Preproc, 'haml-comment-block'), '#pop'),
             (r'(-)(.*\n)',
              bygroups(Punctuation, using(RubyLexer)),
              '#pop'),
-            (r':.*\n', Name.Decorator, '#pop'),
+            (r':.*\n', starts_block(Name.Decorator, 'filter-block'), '#pop'),
             include('eval-or-plain'),
         ],
 
             (r"'(\\\\|\\'|[^'\n])*'", String, '#pop'),
             (r'"(\\\\|\\"|[^"\n])*"', String, '#pop'),
         ],
+
+        'html-comment-block': [
+            (r'.+', Comment),
+            (r'\n', Text, 'root'),
+        ],
+
+        'haml-comment-block': [
+            (r'.+', Comment.Preproc),
+            (r'\n', Text, 'root'),
+        ],
+
+        'filter-block': [
+            (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Name.Decorator),
+            (r'(#\{)(.*?)(\})',
+             bygroups(String.Interpol, using(RubyLexer), String.Interpol)),
+            (r'\n', Text, 'root'),
+        ],
     }
 
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.