Last active
December 23, 2015 14:59
-
-
Save maul-esel/6652045 to your computer and use it in GitHub Desktop.
a WIP pygments lexer for the liquid templating language
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is an example file. Process it with `./pygmentize -O full -f html -o /liquid-example.html example.liquid`. | |
{% raw %} | |
some {{raw}} liquid syntax | |
{% raw %} | |
{% endraw %} | |
Just regular text - what happens? | |
{% comment %}My lovely {{comment}} {% comment %}{% endcomment %} | |
{% custom_tag params: true %} | |
{% custom_block my="abc" c = false %} | |
Just usual {{liquid}}. | |
{% endcustom_block %} | |
{% another_tag "my string param" %} | |
{{ variable | upcase }} | |
{{ var.field | textilize | markdownify }} | |
{{ var.field.property | textilize | markdownify }} | |
{{ 'string' | truncate: 100 param='df"g' }} | |
{% cycle '1', 2, var %} | |
{% cycle 'group1': '1', var, 2 %} | |
{% cycle group2: '1', var, 2 %} | |
{% if a == 'B' %} | |
{% elsif a == 'C%}' %} | |
{% else %} | |
{% endif %} | |
{% unless not a %} | |
{% else %} | |
{% endunless %} | |
{% case a %} | |
{% when 'B' %} | |
{% when 'C' %} | |
{% else %} | |
{% endcase %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a non-completed pygments lexer for the liquid templating language. | |
# | |
# To use this, you must: | |
# 1. download the pygments-main source code | |
# 2. include the code below in the pygments/lexers/template.py file | |
# 3. modify __all__ in the same file to include 'LiquidLexer' | |
# 4. execute 'make mapfiles' | |
from pygments.lexers import combined | |
from pygments.token import Whitespace | |
class LiquidLexer(RegexLexer): | |
name = 'liquid' | |
aliases = ['liquid'] | |
filenames = ['*.liquid'] | |
tokens = { | |
'root': [ | |
(r'[^\{]+', Text), | |
(r'(\{%)(\s*)', bygroups(Punctuation, Whitespace), 'tag-or-block'), # tags and block tags | |
(r'(\{\{)(\s*)([^\s(\}\})]+)', bygroups(Punctuation, Whitespace, using(this, state = 'generic')), 'output'), # output tags | |
(r'\{', Text) | |
], | |
'tag-or-block': [ | |
# builtin logic blocks | |
(r'(if|unless|elsif|case)(?=\s+)', Keyword.Reserved, 'condition'), | |
(r'(when)(\s+)', bygroups(Keyword.Reserved, Whitespace), combined('end-of-block', 'whitespace', 'generic')), | |
(r'(else)(\s*)(%\})', bygroups(Keyword.Reserved, Whitespace, Punctuation), '#pop'), | |
# other builtin blocks | |
(r'(capture)(\s+)([^\s%]+)(\s*)(%\})', bygroups(Name.Tag, Whitespace, using(this, state = 'variable'), Whitespace, Punctuation), '#pop'), | |
(r'(comment)(\s*)(%\})', bygroups(Name.Tag, Whitespace, Punctuation), 'comment'), | |
(r'(raw)(\s*)(%\})', bygroups(Name.Tag, Whitespace, Punctuation), 'raw'), | |
# end of block | |
(r'(end(case|unless|if))(\s*)(%\})', bygroups(Keyword.Reserved, None, Whitespace, Punctuation), '#pop'), | |
(r'(end([^\s%]+))(\s*)(%\})', bygroups(Name.Tag, None, Whitespace, Punctuation), '#pop'), | |
# builtin tags (assign and include are handled together with usual tags) | |
(r'(cycle)(\s+)(([^\s:]*)(:))?(\s*)', bygroups(Name.Tag, Whitespace, None, using(this, state = 'generic'), Punctuation, Whitespace), 'variable-tag-markup'), | |
# other tags or blocks | |
(r'([^\s%]+)(\s*)', bygroups(Name.Tag, Whitespace), 'tag-markup') | |
], | |
'output': [ | |
include('whitespace'), | |
('\}\}', Punctuation, '#pop'), # end of output | |
(r'\|', Punctuation, 'filters') | |
], | |
'filters': [ | |
include('whitespace'), | |
(r'\}\}', Punctuation, ('#pop', '#pop')), # end of filters and output | |
(r'([^\s\|:]+)(:?)(\s*)', bygroups(Name.Function, Punctuation, Whitespace), 'filter-markup') | |
], | |
'filter-markup': [ | |
(r'\|', Punctuation, '#pop'), | |
include('end-of-tag'), | |
include('default-param-markup') | |
], | |
'condition': [ | |
include('end-of-block'), | |
include('whitespace'), | |
(r'([^\s=!><]+)(\s*)([=!><]=?)(\s*)([^\s]+)(\s*)(%\})', bygroups(using(this, state = 'generic'), Whitespace, Operator, Whitespace, using(this, state = 'generic'), Whitespace, Punctuation)), | |
(r'\b((!)|(not\b))', bygroups(None, Operator, Operator.Word)), | |
(r'([\w\.\'"]+)(\s+)(contains)(\s+)([\w\.\'"]+)', bygroups(using(this, state = 'generic'), Whitespace, Operator.Word, Whitespace, using(this, state = 'generic'))), | |
include('generic'), | |
include('whitespace') | |
], | |
'generic-value': [ | |
include('generic'), | |
include('end-at-whitespace') | |
], | |
'operator': [ | |
(r'(\s*)((=|!|>|<)=?)(\s*)', bygroups(Whitespace, Operator, None, Whitespace), '#pop'), | |
(r'(\s*)(\bcontains\b)(\s*)', bygroups(Whitespace, Operator.Word, Whitespace), '#pop'), | |
], | |
'end-of-tag': [ | |
(r'\}\}', Punctuation, '#pop') | |
], | |
'end-of-block': [ | |
(r'%\}', Punctuation, ('#pop', '#pop')) | |
], | |
'end-at-whitespace': [ | |
(r'\s+', Whitespace, '#pop') | |
], | |
# states for unknown markup | |
'param-markup': [ | |
include('whitespace'), | |
(r'([^\s=:]+)(\s*)(=|:)', bygroups(Name.Attribute, Whitespace, Operator)), # params with colons or equals | |
(r'(\{\{)(\s*)([^\s\}])(\s*)(\}\})', bygroups(Punctuation, Whitespace, using(this, state = 'variable'), Whitespace, Punctuation)), # explicit variables | |
include('string'), | |
include('number'), | |
include('keyword'), | |
(r',', Punctuation) | |
], | |
'default-param-markup': [ | |
include('param-markup'), | |
(r'.', Text) # fallback for switches / variables / un-quoted strings / ... | |
], | |
'variable-param-markup': [ | |
include('param-markup'), | |
include('variable'), | |
(r'.', Text) # fallback | |
], | |
'tag-markup': [ | |
(r'%\}', Punctuation, ('#pop', '#pop')), # end of tag | |
include('default-param-markup') | |
], | |
'variable-tag-markup': [ | |
(r'%\}', Punctuation, ('#pop', '#pop')), # end of tag | |
include('variable-param-markup') | |
], | |
# states for different values types | |
'keyword': [ | |
(r'\b(false|true)\b', Keyword.Constant) | |
], | |
'variable': [ | |
(r'[a-zA-Z_]\w*', Name.Variable), | |
(r'(?<=\w)\.(?=\w)', Punctuation) | |
], | |
'string': [ | |
(r"'[^']*'", String.Single), | |
(r'"[^"]*"', String.Double) | |
], | |
'number': [ | |
(r'\d+\.\d+', Number.Float), | |
(r'\d+', Number.Integer) | |
], | |
'generic': [ # decides for variable, string, keyword or number | |
include('keyword'), | |
include('string'), | |
include('number'), | |
include('variable') | |
], | |
'whitespace': [ | |
(r'[ \t]+', Whitespace) | |
], | |
# states for builtin blocks | |
'comment': [ | |
(r'(\{%)(\s*)(endcomment)(\s*)(%\})', bygroups(Punctuation, Whitespace, Name.Tag, Whitespace, Punctuation), ('#pop', '#pop')), | |
(r'.', Comment) | |
], | |
'raw': [ | |
(r'[^\{]+', Text), | |
(r'(\{%)(\s*)(endraw)(\s*)(%\})', bygroups(Punctuation, Whitespace, Name.Tag, Whitespace, Punctuation), '#pop'), | |
(r'\{', Text) | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
NICE!