# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
class Liquid < RegexLexer
title "Liquid"
desc 'Liquid is a templating engine for Ruby (liquidmarkup.org)'
tag 'liquid'
filenames '*.liquid'
mimetypes 'text/html+liquid'
state :root do
rule %r/[^\{]+/, Text
rule %r/(\{%-?)(\s*)/ do
groups Comment::Preproc, Text::Whitespace
push :logic
end
rule %r/(\{\{-?)(\s*)/ do
groups Comment::Preproc, Text::Whitespace
push :output
end
rule %r/\{/, Text
end
state :end_logic do
rule(/(\s*)(-?%\})/) do
groups Text::Whitespace, Comment::Preproc
reset_stack
end
rule(/\n\s*/) do
token Text::Whitespace
if in_state? :liquid
pop! until state? :liquid
end
end
mixin :whitespace
end
state :end_output do
rule(/(\s*)(-?\}\})/) do
groups Text::Whitespace, Comment::Preproc
reset_stack
end
end
state :liquid do
mixin :end_logic
mixin :logic
end
state :logic do
rule %r/(liquid)\b/, Name::Tag, :liquid
# builtin logic blocks
rule %r/(if|elsif|unless|case)\b/, Name::Tag, :condition
rule %r/(when)\b/, Name::Tag, :value
rule %r/(else|ifchanged|end\w+)\b/, Name::Tag, :end_logic
rule %r/(break|continue)\b/, Keyword::Reserved, :end_logic
# builtin iteration blocks
rule %r/(for|tablerow)(\s+)(\S+)(\s+)(in)(\s+)/ do
groups Name::Tag, Text::Whitespace, Name::Variable, Text::Whitespace,
Name::Tag, Text::Whitespace
push :iteration_args
end
# other builtin blocks
rule %r/(capture|(?:in|de)crement)(\s+)([a-zA-Z_](?:\w|-(?!%))*)/ do
groups Name::Tag, Text::Whitespace, Name::Variable
push :end_logic
end
rule %r/(comment)(\s*)(-?%\})/ do
groups Name::Tag, Text::Whitespace, Comment::Preproc
push :comment
end
rule %r/(raw)(\s*)(-?%\})/ do
groups Name::Tag, Text::Whitespace, Comment::Preproc
push :raw
end
# builtin tags
rule %r/(assign|echo)\b/, Name::Tag, :assign
rule %r/(include|render)(\s+)([\/\w-]+(?:\.[\w-]+)+\b)?/ do
groups Name::Tag, Text::Whitespace, Text
push :include
end
rule %r/(cycle)(\s+)(?:([\w-]+|'[^']*'|"[^"]*")(\s*)(:))?(\s*)/ do |m|
token_class = case m[3]
when %r/'[^']*'/ then Str::Single
when %r/"[^"]*"/ then Str::Double
else
Name::Attribute
end
groups Name::Tag, Text::Whitespace, token_class,
Text::Whitespace, Punctuation, Text::Whitespace
push :tag_args
end
# custom tags or blocks
rule %r/(\w+)\b/, Name::Tag, :block_args
mixin :end_logic
end
state :output do
rule %r/(\|)(\s*)/ do
groups Punctuation, Text::Whitespace
push :filters
push :filter
end
mixin :end_output
mixin :static
mixin :variable
end
state :condition do
rule %r/([=!]=|[<>]=?)/, Operator
rule %r/(and|or|contains)\b/, Operator::Word
mixin :value
end
state :value do
mixin :end_logic
mixin :static
mixin :variable
end
state :iteration_args do
rule %r/(reversed|continue)\b/, Name::Attribute
rule %r/\(/, Punctuation, :range
mixin :tag_args
end
state :block_args do
rule %r/(\{\{-?)/, Comment::Preproc, :output_embed
rule %r/(\|)(\s*)/ do
groups Punctuation, Text::Whitespace
push :filters
push :filter
end
mixin :tag_args
end
state :tag_args do
mixin :end_logic
mixin :args
end
state :comment do
rule %r/[^\{]+/, Comment
rule %r/(\{%-?)(\s*)(endcomment)(\s*)(-?%\})/ do
groups Comment::Preproc, Text::Whitespace, Name::Tag, Text::Whitespace, Comment::Preproc
reset_stack
end
rule %r/\{/, Comment
end
state :raw do
rule %r/[^\{]+/, Text
rule %r/(\{%-?)(\s*)(endraw)(\s*)(-?%\})/ do
groups Comment::Preproc, Text::Whitespace, Name::Tag, Text::Whitespace, Comment::Preproc
reset_stack
end
rule %r/\{/, Text
end
state :assign do
rule %r/=/, Operator
rule %r/\(/, Punctuation, :range
rule %r/(\|)(\s*)/ do
groups Punctuation, Text::Whitespace
push :filters
push :filter
end
mixin :value
end
state :include do
rule %r/(\{\{-?)/, Comment::Preproc, :output_embed
rule %r/(with|for|as)\b/, Keyword::Reserved
mixin :tag_args
end
state :output_embed do
rule %r/(\|)(\s*)([a-zA-Z_](?:\w|-(?!}))*)/ do
groups Punctuation, Text::Whitespace, Name::Function
end
rule %r/-?\}\}/, Comment::Preproc, :pop!
mixin :args
end
state :range do
rule %r/\.\./, Punctuation
rule %r/\)/, Punctuation, :pop!
mixin :whitespace
mixin :number
mixin :variable
end
state :filters do
rule %r/(\|)(\s*)/ do
groups Punctuation, Text::Whitespace
push :filter
end
mixin :end_logic
mixin :end_output
mixin :args
end
state :filter do
rule %r/[a-zA-Z_](?:\w|-(?![%}]))*/, Name::Function, :pop!
mixin :whitespace
end
state :args do
mixin :static
rule %r/([a-zA-Z_][\w-]*)(\s*)(=|:)/ do
groups Name::Attribute, Text::Whitespace, Operator
end
mixin :variable
end
state :static do
rule %r/(false|true|nil)\b/, Keyword::Constant
rule %r/'[^']*'/, Str::Single
rule %r/"[^"]*"/, Str::Double
rule %r/[,:]/, Punctuation
mixin :whitespace
mixin :number
end
state :whitespace do
rule %r/\s+/, Text::Whitespace
rule %r/#.*?(?=$|-?[}%]})/, Comment
end
state :number do
rule %r/-/, Operator
rule %r/\d+\.\d+/, Num::Float
rule %r/\d+/, Num::Integer
end
state :variable do
rule %r/(\.)(\s*)(first|last|size)\b(?![?!\/])/ do
groups Punctuation, Text::Whitespace, Name::Function
end
rule %r/\.(?= *\w)|\[|\]/, Punctuation
rule %r/(empty|blank|(for|tablerow)loop\.(parentloop\.)*\w+)\b(?![?!\/])/, Name::Builtin
rule %r/[a-zA-Z_][\w-]*\b-?(?![?!\/])/, Name::Variable
rule %r/\S+/, Text
end
end
end
end