194cba803SRyan Moeller-- From lua-resty-template (modified to remove external dependencies) 294cba803SRyan Moeller--[[ 394cba803SRyan MoellerCopyright (c) 2014 - 2020 Aapo Talvensaari 494cba803SRyan MoellerAll rights reserved. 594cba803SRyan Moeller 694cba803SRyan MoellerRedistribution and use in source and binary forms, with or without modification, 794cba803SRyan Moellerare permitted provided that the following conditions are met: 894cba803SRyan Moeller 994cba803SRyan Moeller* Redistributions of source code must retain the above copyright notice, this 1094cba803SRyan Moeller list of conditions and the following disclaimer. 1194cba803SRyan Moeller 1294cba803SRyan Moeller* Redistributions in binary form must reproduce the above copyright notice, this 1394cba803SRyan Moeller list of conditions and the following disclaimer in the documentation and/or 1494cba803SRyan Moeller other materials provided with the distribution. 1594cba803SRyan Moeller 1694cba803SRyan Moeller* Neither the name of the {organization} nor the names of its 1794cba803SRyan Moeller contributors may be used to endorse or promote products derived from 1894cba803SRyan Moeller this software without specific prior written permission. 1994cba803SRyan Moeller 2094cba803SRyan MoellerTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 2194cba803SRyan MoellerANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2294cba803SRyan MoellerWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2394cba803SRyan MoellerDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 2494cba803SRyan MoellerANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2594cba803SRyan Moeller(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2694cba803SRyan MoellerLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 2794cba803SRyan MoellerANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2894cba803SRyan Moeller(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2994cba803SRyan MoellerSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3094cba803SRyan Moeller]]-- 3194cba803SRyan Moeller 3294cba803SRyan Moellerlocal setmetatable = setmetatable 3394cba803SRyan Moellerlocal loadstring = loadstring 3494cba803SRyan Moellerlocal tostring = tostring 3594cba803SRyan Moellerlocal setfenv = setfenv 3694cba803SRyan Moellerlocal require = require 3794cba803SRyan Moellerlocal concat = table.concat 3894cba803SRyan Moellerlocal assert = assert 3994cba803SRyan Moellerlocal write = io.write 4094cba803SRyan Moellerlocal pcall = pcall 4194cba803SRyan Moellerlocal phase 4294cba803SRyan Moellerlocal open = io.open 4394cba803SRyan Moellerlocal load = load 4494cba803SRyan Moellerlocal type = type 4594cba803SRyan Moellerlocal dump = string.dump 4694cba803SRyan Moellerlocal find = string.find 4794cba803SRyan Moellerlocal gsub = string.gsub 4894cba803SRyan Moellerlocal byte = string.byte 4994cba803SRyan Moellerlocal null 5094cba803SRyan Moellerlocal sub = string.sub 5194cba803SRyan Moellerlocal var 5294cba803SRyan Moeller 5394cba803SRyan Moellerlocal _VERSION = _VERSION 5494cba803SRyan Moellerlocal _ENV = _ENV -- luacheck: globals _ENV 5594cba803SRyan Moellerlocal _G = _G 5694cba803SRyan Moeller 5794cba803SRyan Moellerlocal HTML_ENTITIES = { 5894cba803SRyan Moeller ["&"] = "&", 5994cba803SRyan Moeller ["<"] = "<", 6094cba803SRyan Moeller [">"] = ">", 6194cba803SRyan Moeller ['"'] = """, 6294cba803SRyan Moeller ["'"] = "'", 6394cba803SRyan Moeller ["/"] = "/" 6494cba803SRyan Moeller} 6594cba803SRyan Moeller 6694cba803SRyan Moellerlocal CODE_ENTITIES = { 6794cba803SRyan Moeller ["{"] = "{", 6894cba803SRyan Moeller ["}"] = "}", 6994cba803SRyan Moeller ["&"] = "&", 7094cba803SRyan Moeller ["<"] = "<", 7194cba803SRyan Moeller [">"] = ">", 7294cba803SRyan Moeller ['"'] = """, 7394cba803SRyan Moeller ["'"] = "'", 7494cba803SRyan Moeller ["/"] = "/" 7594cba803SRyan Moeller} 7694cba803SRyan Moeller 7794cba803SRyan Moellerlocal VAR_PHASES 7894cba803SRyan Moeller 7994cba803SRyan Moellerlocal ESC = byte("\27") 8094cba803SRyan Moellerlocal NUL = byte("\0") 8194cba803SRyan Moellerlocal HT = byte("\t") 8294cba803SRyan Moellerlocal VT = byte("\v") 8394cba803SRyan Moellerlocal LF = byte("\n") 8494cba803SRyan Moellerlocal SOL = byte("/") 8594cba803SRyan Moellerlocal BSOL = byte("\\") 8694cba803SRyan Moellerlocal SP = byte(" ") 8794cba803SRyan Moellerlocal AST = byte("*") 8894cba803SRyan Moellerlocal NUM = byte("#") 8994cba803SRyan Moellerlocal LPAR = byte("(") 9094cba803SRyan Moellerlocal LSQB = byte("[") 9194cba803SRyan Moellerlocal LCUB = byte("{") 9294cba803SRyan Moellerlocal MINUS = byte("-") 9394cba803SRyan Moellerlocal PERCNT = byte("%") 9494cba803SRyan Moeller 9594cba803SRyan Moellerlocal EMPTY = "" 9694cba803SRyan Moeller 9794cba803SRyan Moellerlocal VIEW_ENV 9894cba803SRyan Moellerif _VERSION == "Lua 5.1" then 9994cba803SRyan Moeller VIEW_ENV = { __index = function(t, k) 10094cba803SRyan Moeller return t.context[k] or t.template[k] or _G[k] 10194cba803SRyan Moeller end } 10294cba803SRyan Moellerelse 10394cba803SRyan Moeller VIEW_ENV = { __index = function(t, k) 10494cba803SRyan Moeller return t.context[k] or t.template[k] or _ENV[k] 10594cba803SRyan Moeller end } 10694cba803SRyan Moellerend 10794cba803SRyan Moeller 10894cba803SRyan Moellerlocal newtab 10994cba803SRyan Moellerdo 11094cba803SRyan Moeller local ok 11194cba803SRyan Moeller ok, newtab = pcall(require, "table.new") 11294cba803SRyan Moeller if not ok then newtab = function() return {} end end 11394cba803SRyan Moellerend 11494cba803SRyan Moeller 11594cba803SRyan Moellerlocal function enabled(val) 11694cba803SRyan Moeller if val == nil then return true end 11794cba803SRyan Moeller return val == true or (val == "1" or val == "true" or val == "on") 11894cba803SRyan Moellerend 11994cba803SRyan Moeller 12094cba803SRyan Moellerlocal function trim(s) 12194cba803SRyan Moeller return gsub(gsub(s, "^%s+", EMPTY), "%s+$", EMPTY) 12294cba803SRyan Moellerend 12394cba803SRyan Moeller 12494cba803SRyan Moellerlocal function rpos(view, s) 12594cba803SRyan Moeller while s > 0 do 12694cba803SRyan Moeller local c = byte(view, s, s) 12794cba803SRyan Moeller if c == SP or c == HT or c == VT or c == NUL then 12894cba803SRyan Moeller s = s - 1 12994cba803SRyan Moeller else 13094cba803SRyan Moeller break 13194cba803SRyan Moeller end 13294cba803SRyan Moeller end 13394cba803SRyan Moeller return s 13494cba803SRyan Moellerend 13594cba803SRyan Moeller 13694cba803SRyan Moellerlocal function escaped(view, s) 13794cba803SRyan Moeller if s > 1 and byte(view, s - 1, s - 1) == BSOL then 13894cba803SRyan Moeller if s > 2 and byte(view, s - 2, s - 2) == BSOL then 13994cba803SRyan Moeller return false, 1 14094cba803SRyan Moeller else 14194cba803SRyan Moeller return true, 1 14294cba803SRyan Moeller end 14394cba803SRyan Moeller end 14494cba803SRyan Moeller return false, 0 14594cba803SRyan Moellerend 14694cba803SRyan Moeller 14794cba803SRyan Moellerlocal function read_file(path) 14894cba803SRyan Moeller local file, err = open(path, "rb") 14994cba803SRyan Moeller if not file then return nil, err end 15094cba803SRyan Moeller local content 15194cba803SRyan Moeller content, err = file:read "*a" 15294cba803SRyan Moeller file:close() 15394cba803SRyan Moeller return content, err 15494cba803SRyan Moellerend 15594cba803SRyan Moeller 15694cba803SRyan Moellerlocal function load_view(template) 15794cba803SRyan Moeller return function(view, plain) 15894cba803SRyan Moeller if plain == true then return view end 15994cba803SRyan Moeller local path, root = view, template.root 16094cba803SRyan Moeller if root and root ~= EMPTY then 16194cba803SRyan Moeller if byte(root, -1) == SOL then root = sub(root, 1, -2) end 16294cba803SRyan Moeller if byte(view, 1) == SOL then path = sub(view, 2) end 16394cba803SRyan Moeller path = root .. "/" .. path 16494cba803SRyan Moeller end 16594cba803SRyan Moeller return plain == false and assert(read_file(path)) or read_file(path) or view 16694cba803SRyan Moeller end 16794cba803SRyan Moellerend 16894cba803SRyan Moeller 16994cba803SRyan Moellerlocal function load_file(func) 17094cba803SRyan Moeller return function(view) return func(view, false) end 17194cba803SRyan Moellerend 17294cba803SRyan Moeller 17394cba803SRyan Moellerlocal function load_string(func) 17494cba803SRyan Moeller return function(view) return func(view, true) end 17594cba803SRyan Moellerend 17694cba803SRyan Moeller 17794cba803SRyan Moellerlocal function loader(template) 17894cba803SRyan Moeller return function(view) 17994cba803SRyan Moeller return assert(load(view, nil, nil, setmetatable({ template = template }, VIEW_ENV))) 18094cba803SRyan Moeller end 18194cba803SRyan Moellerend 18294cba803SRyan Moeller 18394cba803SRyan Moellerlocal function visit(visitors, content, tag, name) 18494cba803SRyan Moeller if not visitors then 18594cba803SRyan Moeller return content 18694cba803SRyan Moeller end 18794cba803SRyan Moeller 18894cba803SRyan Moeller for i = 1, visitors.n do 18994cba803SRyan Moeller content = visitors[i](content, tag, name) 19094cba803SRyan Moeller end 19194cba803SRyan Moeller 19294cba803SRyan Moeller return content 19394cba803SRyan Moellerend 19494cba803SRyan Moeller 19594cba803SRyan Moellerlocal function new(template, safe) 19694cba803SRyan Moeller template = template or newtab(0, 26) 19794cba803SRyan Moeller 19894cba803SRyan Moeller template._VERSION = "2.0" 19994cba803SRyan Moeller template.cache = {} 20094cba803SRyan Moeller template.load = load_view(template) 20194cba803SRyan Moeller template.load_file = load_file(template.load) 20294cba803SRyan Moeller template.load_string = load_string(template.load) 20394cba803SRyan Moeller template.print = write 20494cba803SRyan Moeller 20594cba803SRyan Moeller local load_chunk = loader(template) 20694cba803SRyan Moeller 20794cba803SRyan Moeller local caching 20894cba803SRyan Moeller if VAR_PHASES and VAR_PHASES[phase()] then 20994cba803SRyan Moeller caching = enabled(var.template_cache) 21094cba803SRyan Moeller else 21194cba803SRyan Moeller caching = true 21294cba803SRyan Moeller end 21394cba803SRyan Moeller 21494cba803SRyan Moeller local visitors 21594cba803SRyan Moeller function template.visit(func) 21694cba803SRyan Moeller if not visitors then 21794cba803SRyan Moeller visitors = { func, n = 1 } 21894cba803SRyan Moeller return 21994cba803SRyan Moeller end 22094cba803SRyan Moeller visitors.n = visitors.n + 1 22194cba803SRyan Moeller visitors[visitors.n] = func 22294cba803SRyan Moeller end 22394cba803SRyan Moeller 22494cba803SRyan Moeller function template.caching(enable) 22594cba803SRyan Moeller if enable ~= nil then caching = enable == true end 22694cba803SRyan Moeller return caching 22794cba803SRyan Moeller end 22894cba803SRyan Moeller 22994cba803SRyan Moeller function template.output(s) 23094cba803SRyan Moeller if s == nil or s == null then return EMPTY end 23194cba803SRyan Moeller if type(s) == "function" then return template.output(s()) end 23294cba803SRyan Moeller return tostring(s) 23394cba803SRyan Moeller end 23494cba803SRyan Moeller 23594cba803SRyan Moeller function template.escape(s, c) 23694cba803SRyan Moeller if type(s) == "string" then 23794cba803SRyan Moeller if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end 23894cba803SRyan Moeller return gsub(s, "[\">/<'&]", HTML_ENTITIES) 23994cba803SRyan Moeller end 24094cba803SRyan Moeller return template.output(s) 24194cba803SRyan Moeller end 24294cba803SRyan Moeller 24394cba803SRyan Moeller function template.new(view, layout) 24494cba803SRyan Moeller local vt = type(view) 24594cba803SRyan Moeller 24694cba803SRyan Moeller if vt == "boolean" then return new(nil, view) end 24794cba803SRyan Moeller if vt == "table" then return new(view, safe) end 24894cba803SRyan Moeller if vt == "nil" then return new(nil, safe) end 24994cba803SRyan Moeller 25094cba803SRyan Moeller local render 25194cba803SRyan Moeller local process 25294cba803SRyan Moeller if layout then 25394cba803SRyan Moeller if type(layout) == "table" then 25494cba803SRyan Moeller render = function(self, context) 25594cba803SRyan Moeller context = context or self 25694cba803SRyan Moeller context.blocks = context.blocks or {} 25794cba803SRyan Moeller context.view = template.process(view, context) 25894cba803SRyan Moeller layout.blocks = context.blocks or {} 25994cba803SRyan Moeller layout.view = context.view or EMPTY 26094cba803SRyan Moeller layout:render() 26194cba803SRyan Moeller end 26294cba803SRyan Moeller process = function(self, context) 26394cba803SRyan Moeller context = context or self 26494cba803SRyan Moeller context.blocks = context.blocks or {} 26594cba803SRyan Moeller context.view = template.process(view, context) 26694cba803SRyan Moeller layout.blocks = context.blocks or {} 26794cba803SRyan Moeller layout.view = context.view 26894cba803SRyan Moeller return tostring(layout) 26994cba803SRyan Moeller end 27094cba803SRyan Moeller else 27194cba803SRyan Moeller render = function(self, context) 27294cba803SRyan Moeller context = context or self 27394cba803SRyan Moeller context.blocks = context.blocks or {} 27494cba803SRyan Moeller context.view = template.process(view, context) 27594cba803SRyan Moeller template.render(layout, context) 27694cba803SRyan Moeller end 27794cba803SRyan Moeller process = function(self, context) 27894cba803SRyan Moeller context = context or self 27994cba803SRyan Moeller context.blocks = context.blocks or {} 28094cba803SRyan Moeller context.view = template.process(view, context) 28194cba803SRyan Moeller return template.process(layout, context) 28294cba803SRyan Moeller end 28394cba803SRyan Moeller end 28494cba803SRyan Moeller else 28594cba803SRyan Moeller render = function(self, context) 28694cba803SRyan Moeller return template.render(view, context or self) 28794cba803SRyan Moeller end 28894cba803SRyan Moeller process = function(self, context) 28994cba803SRyan Moeller return template.process(view, context or self) 29094cba803SRyan Moeller end 29194cba803SRyan Moeller end 29294cba803SRyan Moeller 29394cba803SRyan Moeller if safe then 29494cba803SRyan Moeller return setmetatable({ 29594cba803SRyan Moeller render = function(...) 29694cba803SRyan Moeller local ok, err = pcall(render, ...) 29794cba803SRyan Moeller if not ok then 29894cba803SRyan Moeller return nil, err 29994cba803SRyan Moeller end 30094cba803SRyan Moeller end, 30194cba803SRyan Moeller process = function(...) 30294cba803SRyan Moeller local ok, output = pcall(process, ...) 30394cba803SRyan Moeller if not ok then 30494cba803SRyan Moeller return nil, output 30594cba803SRyan Moeller end 30694cba803SRyan Moeller return output 30794cba803SRyan Moeller end, 30894cba803SRyan Moeller }, { 30994cba803SRyan Moeller __tostring = function(...) 31094cba803SRyan Moeller local ok, output = pcall(process, ...) 31194cba803SRyan Moeller if not ok then 31294cba803SRyan Moeller return "" 31394cba803SRyan Moeller end 31494cba803SRyan Moeller return output 31594cba803SRyan Moeller end }) 31694cba803SRyan Moeller end 31794cba803SRyan Moeller 31894cba803SRyan Moeller return setmetatable({ 31994cba803SRyan Moeller render = render, 32094cba803SRyan Moeller process = process 32194cba803SRyan Moeller }, { 32294cba803SRyan Moeller __tostring = process 32394cba803SRyan Moeller }) 32494cba803SRyan Moeller end 32594cba803SRyan Moeller 32694cba803SRyan Moeller function template.precompile(view, path, strip, plain) 32794cba803SRyan Moeller local chunk = dump(template.compile(view, nil, plain), strip ~= false) 32894cba803SRyan Moeller if path then 32994cba803SRyan Moeller local file = open(path, "wb") 33094cba803SRyan Moeller file:write(chunk) 33194cba803SRyan Moeller file:close() 33294cba803SRyan Moeller end 33394cba803SRyan Moeller return chunk 33494cba803SRyan Moeller end 33594cba803SRyan Moeller 33694cba803SRyan Moeller function template.precompile_string(view, path, strip) 33794cba803SRyan Moeller return template.precompile(view, path, strip, true) 33894cba803SRyan Moeller end 33994cba803SRyan Moeller 34094cba803SRyan Moeller function template.precompile_file(view, path, strip) 34194cba803SRyan Moeller return template.precompile(view, path, strip, false) 34294cba803SRyan Moeller end 34394cba803SRyan Moeller 34494cba803SRyan Moeller function template.compile(view, cache_key, plain) 34594cba803SRyan Moeller assert(view, "view was not provided for template.compile(view, cache_key, plain)") 34694cba803SRyan Moeller if cache_key == "no-cache" then 34794cba803SRyan Moeller return load_chunk(template.parse(view, plain)), false 34894cba803SRyan Moeller end 34994cba803SRyan Moeller cache_key = cache_key or view 35094cba803SRyan Moeller local cache = template.cache 35194cba803SRyan Moeller if cache[cache_key] then return cache[cache_key], true end 35294cba803SRyan Moeller local func = load_chunk(template.parse(view, plain)) 35394cba803SRyan Moeller if caching then cache[cache_key] = func end 35494cba803SRyan Moeller return func, false 35594cba803SRyan Moeller end 35694cba803SRyan Moeller 35794cba803SRyan Moeller function template.compile_file(view, cache_key) 35894cba803SRyan Moeller return template.compile(view, cache_key, false) 35994cba803SRyan Moeller end 36094cba803SRyan Moeller 36194cba803SRyan Moeller function template.compile_string(view, cache_key) 36294cba803SRyan Moeller return template.compile(view, cache_key, true) 36394cba803SRyan Moeller end 36494cba803SRyan Moeller 36594cba803SRyan Moeller function template.parse(view, plain) 36694cba803SRyan Moeller assert(view, "view was not provided for template.parse(view, plain)") 36794cba803SRyan Moeller if plain ~= true then 36894cba803SRyan Moeller view = template.load(view, plain) 36994cba803SRyan Moeller if byte(view, 1, 1) == ESC then return view end 37094cba803SRyan Moeller end 37194cba803SRyan Moeller local j = 2 37294cba803SRyan Moeller local c = {[[ 37394cba803SRyan Moellercontext=... or {} 37494cba803SRyan Moellerlocal ___,blocks,layout={},blocks or {} 37594cba803SRyan Moellerlocal function include(v, c) return template.process(v, c or context) end 37694cba803SRyan Moellerlocal function echo(...) for i=1,select("#", ...) do ___[#___+1] = tostring(select(i, ...)) end end 37794cba803SRyan Moeller]] } 37894cba803SRyan Moeller local i, s = 1, find(view, "{", 1, true) 37994cba803SRyan Moeller while s do 38094cba803SRyan Moeller local t, p = byte(view, s + 1, s + 1), s + 2 38194cba803SRyan Moeller if t == LCUB then 38294cba803SRyan Moeller local e = find(view, "}}", p, true) 38394cba803SRyan Moeller if e then 38494cba803SRyan Moeller local z, w = escaped(view, s) 38594cba803SRyan Moeller if i < s - w then 38694cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 38794cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 38894cba803SRyan Moeller c[j+2] = "]=]\n" 38994cba803SRyan Moeller j=j+3 39094cba803SRyan Moeller end 39194cba803SRyan Moeller if z then 39294cba803SRyan Moeller i = s 39394cba803SRyan Moeller else 39494cba803SRyan Moeller c[j] = "___[#___+1]=template.escape(" 39594cba803SRyan Moeller c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "{") 39694cba803SRyan Moeller c[j+2] = ")\n" 39794cba803SRyan Moeller j=j+3 39894cba803SRyan Moeller s, i = e + 1, e + 2 39994cba803SRyan Moeller end 40094cba803SRyan Moeller end 40194cba803SRyan Moeller elseif t == AST then 40294cba803SRyan Moeller local e = find(view, "*}", p, true) 40394cba803SRyan Moeller if e then 40494cba803SRyan Moeller local z, w = escaped(view, s) 40594cba803SRyan Moeller if i < s - w then 40694cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 40794cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 40894cba803SRyan Moeller c[j+2] = "]=]\n" 40994cba803SRyan Moeller j=j+3 41094cba803SRyan Moeller end 41194cba803SRyan Moeller if z then 41294cba803SRyan Moeller i = s 41394cba803SRyan Moeller else 41494cba803SRyan Moeller c[j] = "___[#___+1]=template.output(" 41594cba803SRyan Moeller c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "*") 41694cba803SRyan Moeller c[j+2] = ")\n" 41794cba803SRyan Moeller j=j+3 41894cba803SRyan Moeller s, i = e + 1, e + 2 41994cba803SRyan Moeller end 42094cba803SRyan Moeller end 42194cba803SRyan Moeller elseif t == PERCNT then 42294cba803SRyan Moeller local e = find(view, "%}", p, true) 42394cba803SRyan Moeller if e then 42494cba803SRyan Moeller local z, w = escaped(view, s) 42594cba803SRyan Moeller if z then 42694cba803SRyan Moeller if i < s - w then 42794cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 42894cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 42994cba803SRyan Moeller c[j+2] = "]=]\n" 43094cba803SRyan Moeller j=j+3 43194cba803SRyan Moeller end 43294cba803SRyan Moeller i = s 43394cba803SRyan Moeller else 43494cba803SRyan Moeller local n = e + 2 43594cba803SRyan Moeller if byte(view, n, n) == LF then 43694cba803SRyan Moeller n = n + 1 43794cba803SRyan Moeller end 43894cba803SRyan Moeller local r = rpos(view, s - 1) 43994cba803SRyan Moeller if i <= r then 44094cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 44194cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, r)) 44294cba803SRyan Moeller c[j+2] = "]=]\n" 44394cba803SRyan Moeller j=j+3 44494cba803SRyan Moeller end 44594cba803SRyan Moeller c[j] = visit(visitors, trim(sub(view, p, e - 1)), "%") 44694cba803SRyan Moeller c[j+1] = "\n" 44794cba803SRyan Moeller j=j+2 44894cba803SRyan Moeller s, i = n - 1, n 44994cba803SRyan Moeller end 45094cba803SRyan Moeller end 45194cba803SRyan Moeller elseif t == LPAR then 45294cba803SRyan Moeller local e = find(view, ")}", p, true) 45394cba803SRyan Moeller if e then 45494cba803SRyan Moeller local z, w = escaped(view, s) 45594cba803SRyan Moeller if i < s - w then 45694cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 45794cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 45894cba803SRyan Moeller c[j+2] = "]=]\n" 45994cba803SRyan Moeller j=j+3 46094cba803SRyan Moeller end 46194cba803SRyan Moeller if z then 46294cba803SRyan Moeller i = s 46394cba803SRyan Moeller else 46494cba803SRyan Moeller local f = visit(visitors, sub(view, p, e - 1), "(") 46594cba803SRyan Moeller local x = find(f, ",", 2, true) 46694cba803SRyan Moeller if x then 46794cba803SRyan Moeller c[j] = "___[#___+1]=include([=[" 46894cba803SRyan Moeller c[j+1] = trim(sub(f, 1, x - 1)) 46994cba803SRyan Moeller c[j+2] = "]=]," 47094cba803SRyan Moeller c[j+3] = trim(sub(f, x + 1)) 47194cba803SRyan Moeller c[j+4] = ")\n" 47294cba803SRyan Moeller j=j+5 47394cba803SRyan Moeller else 47494cba803SRyan Moeller c[j] = "___[#___+1]=include([=[" 47594cba803SRyan Moeller c[j+1] = trim(f) 47694cba803SRyan Moeller c[j+2] = "]=])\n" 47794cba803SRyan Moeller j=j+3 47894cba803SRyan Moeller end 47994cba803SRyan Moeller s, i = e + 1, e + 2 48094cba803SRyan Moeller end 48194cba803SRyan Moeller end 48294cba803SRyan Moeller elseif t == LSQB then 48394cba803SRyan Moeller local e = find(view, "]}", p, true) 48494cba803SRyan Moeller if e then 48594cba803SRyan Moeller local z, w = escaped(view, s) 48694cba803SRyan Moeller if i < s - w then 48794cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 48894cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 48994cba803SRyan Moeller c[j+2] = "]=]\n" 49094cba803SRyan Moeller j=j+3 49194cba803SRyan Moeller end 49294cba803SRyan Moeller if z then 49394cba803SRyan Moeller i = s 49494cba803SRyan Moeller else 49594cba803SRyan Moeller c[j] = "___[#___+1]=include(" 49694cba803SRyan Moeller c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "[") 49794cba803SRyan Moeller c[j+2] = ")\n" 49894cba803SRyan Moeller j=j+3 49994cba803SRyan Moeller s, i = e + 1, e + 2 50094cba803SRyan Moeller end 50194cba803SRyan Moeller end 50294cba803SRyan Moeller elseif t == MINUS then 50394cba803SRyan Moeller local e = find(view, "-}", p, true) 50494cba803SRyan Moeller if e then 50594cba803SRyan Moeller local x, y = find(view, sub(view, s, e + 1), e + 2, true) 50694cba803SRyan Moeller if x then 50794cba803SRyan Moeller local z, w = escaped(view, s) 50894cba803SRyan Moeller if z then 50994cba803SRyan Moeller if i < s - w then 51094cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 51194cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 51294cba803SRyan Moeller c[j+2] = "]=]\n" 51394cba803SRyan Moeller j=j+3 51494cba803SRyan Moeller end 51594cba803SRyan Moeller i = s 51694cba803SRyan Moeller else 51794cba803SRyan Moeller y = y + 1 51894cba803SRyan Moeller x = x - 1 51994cba803SRyan Moeller if byte(view, y, y) == LF then 52094cba803SRyan Moeller y = y + 1 52194cba803SRyan Moeller end 52294cba803SRyan Moeller local b = trim(sub(view, p, e - 1)) 52394cba803SRyan Moeller if b == "verbatim" or b == "raw" then 52494cba803SRyan Moeller if i < s - w then 52594cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 52694cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 52794cba803SRyan Moeller c[j+2] = "]=]\n" 52894cba803SRyan Moeller j=j+3 52994cba803SRyan Moeller end 53094cba803SRyan Moeller c[j] = "___[#___+1]=[=[" 53194cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, e + 2, x)) 53294cba803SRyan Moeller c[j+2] = "]=]\n" 53394cba803SRyan Moeller j=j+3 53494cba803SRyan Moeller else 53594cba803SRyan Moeller if byte(view, x, x) == LF then 53694cba803SRyan Moeller x = x - 1 53794cba803SRyan Moeller end 53894cba803SRyan Moeller local r = rpos(view, s - 1) 53994cba803SRyan Moeller if i <= r then 54094cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 54194cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, r)) 54294cba803SRyan Moeller c[j+2] = "]=]\n" 54394cba803SRyan Moeller j=j+3 54494cba803SRyan Moeller end 54594cba803SRyan Moeller c[j] = 'blocks["' 54694cba803SRyan Moeller c[j+1] = b 54794cba803SRyan Moeller c[j+2] = '"]=include[=[' 54894cba803SRyan Moeller c[j+3] = visit(visitors, sub(view, e + 2, x), "-", b) 54994cba803SRyan Moeller c[j+4] = "]=]\n" 55094cba803SRyan Moeller j=j+5 55194cba803SRyan Moeller end 55294cba803SRyan Moeller s, i = y - 1, y 55394cba803SRyan Moeller end 55494cba803SRyan Moeller end 55594cba803SRyan Moeller end 55694cba803SRyan Moeller elseif t == NUM then 55794cba803SRyan Moeller local e = find(view, "#}", p, true) 55894cba803SRyan Moeller if e then 55994cba803SRyan Moeller local z, w = escaped(view, s) 56094cba803SRyan Moeller if i < s - w then 56194cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 56294cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 56394cba803SRyan Moeller c[j+2] = "]=]\n" 56494cba803SRyan Moeller j=j+3 56594cba803SRyan Moeller end 56694cba803SRyan Moeller if z then 56794cba803SRyan Moeller i = s 56894cba803SRyan Moeller else 56994cba803SRyan Moeller e = e + 2 57094cba803SRyan Moeller if byte(view, e, e) == LF then 57194cba803SRyan Moeller e = e + 1 57294cba803SRyan Moeller end 57394cba803SRyan Moeller s, i = e - 1, e 57494cba803SRyan Moeller end 57594cba803SRyan Moeller end 57694cba803SRyan Moeller end 57794cba803SRyan Moeller s = find(view, "{", s + 1, true) 57894cba803SRyan Moeller end 57994cba803SRyan Moeller s = sub(view, i) 58094cba803SRyan Moeller if s and s ~= EMPTY then 58194cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 58294cba803SRyan Moeller c[j+1] = visit(visitors, s) 58394cba803SRyan Moeller c[j+2] = "]=]\n" 58494cba803SRyan Moeller j=j+3 58594cba803SRyan Moeller end 58694cba803SRyan Moeller c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" -- luacheck: ignore 58794cba803SRyan Moeller return concat(c) 58894cba803SRyan Moeller end 58994cba803SRyan Moeller 59094cba803SRyan Moeller function template.parse_file(view) 59194cba803SRyan Moeller return template.parse(view, false) 59294cba803SRyan Moeller end 59394cba803SRyan Moeller 59494cba803SRyan Moeller function template.parse_string(view) 59594cba803SRyan Moeller return template.parse(view, true) 59694cba803SRyan Moeller end 59794cba803SRyan Moeller 59894cba803SRyan Moeller function template.process(view, context, cache_key, plain) 59994cba803SRyan Moeller assert(view, "view was not provided for template.process(view, context, cache_key, plain)") 60094cba803SRyan Moeller return template.compile(view, cache_key, plain)(context) 60194cba803SRyan Moeller end 60294cba803SRyan Moeller 60394cba803SRyan Moeller function template.process_file(view, context, cache_key) 60494cba803SRyan Moeller assert(view, "view was not provided for template.process_file(view, context, cache_key)") 60594cba803SRyan Moeller return template.compile(view, cache_key, false)(context) 60694cba803SRyan Moeller end 60794cba803SRyan Moeller 60894cba803SRyan Moeller function template.process_string(view, context, cache_key) 60994cba803SRyan Moeller assert(view, "view was not provided for template.process_string(view, context, cache_key)") 61094cba803SRyan Moeller return template.compile(view, cache_key, true)(context) 61194cba803SRyan Moeller end 61294cba803SRyan Moeller 61394cba803SRyan Moeller function template.render(view, context, cache_key, plain) 61494cba803SRyan Moeller assert(view, "view was not provided for template.render(view, context, cache_key, plain)") 61594cba803SRyan Moeller template.print(template.process(view, context, cache_key, plain)) 61694cba803SRyan Moeller end 61794cba803SRyan Moeller 61894cba803SRyan Moeller function template.render_file(view, context, cache_key) 61994cba803SRyan Moeller assert(view, "view was not provided for template.render_file(view, context, cache_key)") 62094cba803SRyan Moeller template.render(view, context, cache_key, false) 62194cba803SRyan Moeller end 62294cba803SRyan Moeller 62394cba803SRyan Moeller function template.render_string(view, context, cache_key) 62494cba803SRyan Moeller assert(view, "view was not provided for template.render_string(view, context, cache_key)") 62594cba803SRyan Moeller template.render(view, context, cache_key, true) 62694cba803SRyan Moeller end 62794cba803SRyan Moeller 62894cba803SRyan Moeller if safe then 62994cba803SRyan Moeller return setmetatable({}, { 63094cba803SRyan Moeller __index = function(_, k) 63194cba803SRyan Moeller if type(template[k]) == "function" then 63294cba803SRyan Moeller return function(...) 63394cba803SRyan Moeller local ok, a, b = pcall(template[k], ...) 63494cba803SRyan Moeller if not ok then 63594cba803SRyan Moeller return nil, a 63694cba803SRyan Moeller end 63794cba803SRyan Moeller return a, b 63894cba803SRyan Moeller end 63994cba803SRyan Moeller end 64094cba803SRyan Moeller return template[k] 64194cba803SRyan Moeller end, 64294cba803SRyan Moeller __new_index = function(_, k, v) 64394cba803SRyan Moeller template[k] = v 64494cba803SRyan Moeller end, 64594cba803SRyan Moeller }) 64694cba803SRyan Moeller end 64794cba803SRyan Moeller 64894cba803SRyan Moeller return template 64994cba803SRyan Moellerend 65094cba803SRyan Moeller 65194cba803SRyan Moellerreturn new() 652