1*94cba803SRyan Moeller-- From lua-resty-template (modified to remove external dependencies) 2*94cba803SRyan Moeller--[[ 3*94cba803SRyan MoellerCopyright (c) 2014 - 2020 Aapo Talvensaari 4*94cba803SRyan MoellerAll rights reserved. 5*94cba803SRyan Moeller 6*94cba803SRyan MoellerRedistribution and use in source and binary forms, with or without modification, 7*94cba803SRyan Moellerare permitted provided that the following conditions are met: 8*94cba803SRyan Moeller 9*94cba803SRyan Moeller* Redistributions of source code must retain the above copyright notice, this 10*94cba803SRyan Moeller list of conditions and the following disclaimer. 11*94cba803SRyan Moeller 12*94cba803SRyan Moeller* Redistributions in binary form must reproduce the above copyright notice, this 13*94cba803SRyan Moeller list of conditions and the following disclaimer in the documentation and/or 14*94cba803SRyan Moeller other materials provided with the distribution. 15*94cba803SRyan Moeller 16*94cba803SRyan Moeller* Neither the name of the {organization} nor the names of its 17*94cba803SRyan Moeller contributors may be used to endorse or promote products derived from 18*94cba803SRyan Moeller this software without specific prior written permission. 19*94cba803SRyan Moeller 20*94cba803SRyan MoellerTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21*94cba803SRyan MoellerANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22*94cba803SRyan MoellerWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23*94cba803SRyan MoellerDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24*94cba803SRyan MoellerANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25*94cba803SRyan Moeller(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26*94cba803SRyan MoellerLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27*94cba803SRyan MoellerANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28*94cba803SRyan Moeller(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29*94cba803SRyan MoellerSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*94cba803SRyan Moeller]]-- 31*94cba803SRyan Moeller 32*94cba803SRyan Moellerlocal setmetatable = setmetatable 33*94cba803SRyan Moellerlocal loadstring = loadstring 34*94cba803SRyan Moellerlocal tostring = tostring 35*94cba803SRyan Moellerlocal setfenv = setfenv 36*94cba803SRyan Moellerlocal require = require 37*94cba803SRyan Moellerlocal concat = table.concat 38*94cba803SRyan Moellerlocal assert = assert 39*94cba803SRyan Moellerlocal write = io.write 40*94cba803SRyan Moellerlocal pcall = pcall 41*94cba803SRyan Moellerlocal phase 42*94cba803SRyan Moellerlocal open = io.open 43*94cba803SRyan Moellerlocal load = load 44*94cba803SRyan Moellerlocal type = type 45*94cba803SRyan Moellerlocal dump = string.dump 46*94cba803SRyan Moellerlocal find = string.find 47*94cba803SRyan Moellerlocal gsub = string.gsub 48*94cba803SRyan Moellerlocal byte = string.byte 49*94cba803SRyan Moellerlocal null 50*94cba803SRyan Moellerlocal sub = string.sub 51*94cba803SRyan Moellerlocal var 52*94cba803SRyan Moeller 53*94cba803SRyan Moellerlocal _VERSION = _VERSION 54*94cba803SRyan Moellerlocal _ENV = _ENV -- luacheck: globals _ENV 55*94cba803SRyan Moellerlocal _G = _G 56*94cba803SRyan Moeller 57*94cba803SRyan Moellerlocal HTML_ENTITIES = { 58*94cba803SRyan Moeller ["&"] = "&", 59*94cba803SRyan Moeller ["<"] = "<", 60*94cba803SRyan Moeller [">"] = ">", 61*94cba803SRyan Moeller ['"'] = """, 62*94cba803SRyan Moeller ["'"] = "'", 63*94cba803SRyan Moeller ["/"] = "/" 64*94cba803SRyan Moeller} 65*94cba803SRyan Moeller 66*94cba803SRyan Moellerlocal CODE_ENTITIES = { 67*94cba803SRyan Moeller ["{"] = "{", 68*94cba803SRyan Moeller ["}"] = "}", 69*94cba803SRyan Moeller ["&"] = "&", 70*94cba803SRyan Moeller ["<"] = "<", 71*94cba803SRyan Moeller [">"] = ">", 72*94cba803SRyan Moeller ['"'] = """, 73*94cba803SRyan Moeller ["'"] = "'", 74*94cba803SRyan Moeller ["/"] = "/" 75*94cba803SRyan Moeller} 76*94cba803SRyan Moeller 77*94cba803SRyan Moellerlocal VAR_PHASES 78*94cba803SRyan Moeller 79*94cba803SRyan Moellerlocal ESC = byte("\27") 80*94cba803SRyan Moellerlocal NUL = byte("\0") 81*94cba803SRyan Moellerlocal HT = byte("\t") 82*94cba803SRyan Moellerlocal VT = byte("\v") 83*94cba803SRyan Moellerlocal LF = byte("\n") 84*94cba803SRyan Moellerlocal SOL = byte("/") 85*94cba803SRyan Moellerlocal BSOL = byte("\\") 86*94cba803SRyan Moellerlocal SP = byte(" ") 87*94cba803SRyan Moellerlocal AST = byte("*") 88*94cba803SRyan Moellerlocal NUM = byte("#") 89*94cba803SRyan Moellerlocal LPAR = byte("(") 90*94cba803SRyan Moellerlocal LSQB = byte("[") 91*94cba803SRyan Moellerlocal LCUB = byte("{") 92*94cba803SRyan Moellerlocal MINUS = byte("-") 93*94cba803SRyan Moellerlocal PERCNT = byte("%") 94*94cba803SRyan Moeller 95*94cba803SRyan Moellerlocal EMPTY = "" 96*94cba803SRyan Moeller 97*94cba803SRyan Moellerlocal VIEW_ENV 98*94cba803SRyan Moellerif _VERSION == "Lua 5.1" then 99*94cba803SRyan Moeller VIEW_ENV = { __index = function(t, k) 100*94cba803SRyan Moeller return t.context[k] or t.template[k] or _G[k] 101*94cba803SRyan Moeller end } 102*94cba803SRyan Moellerelse 103*94cba803SRyan Moeller VIEW_ENV = { __index = function(t, k) 104*94cba803SRyan Moeller return t.context[k] or t.template[k] or _ENV[k] 105*94cba803SRyan Moeller end } 106*94cba803SRyan Moellerend 107*94cba803SRyan Moeller 108*94cba803SRyan Moellerlocal newtab 109*94cba803SRyan Moellerdo 110*94cba803SRyan Moeller local ok 111*94cba803SRyan Moeller ok, newtab = pcall(require, "table.new") 112*94cba803SRyan Moeller if not ok then newtab = function() return {} end end 113*94cba803SRyan Moellerend 114*94cba803SRyan Moeller 115*94cba803SRyan Moellerlocal function enabled(val) 116*94cba803SRyan Moeller if val == nil then return true end 117*94cba803SRyan Moeller return val == true or (val == "1" or val == "true" or val == "on") 118*94cba803SRyan Moellerend 119*94cba803SRyan Moeller 120*94cba803SRyan Moellerlocal function trim(s) 121*94cba803SRyan Moeller return gsub(gsub(s, "^%s+", EMPTY), "%s+$", EMPTY) 122*94cba803SRyan Moellerend 123*94cba803SRyan Moeller 124*94cba803SRyan Moellerlocal function rpos(view, s) 125*94cba803SRyan Moeller while s > 0 do 126*94cba803SRyan Moeller local c = byte(view, s, s) 127*94cba803SRyan Moeller if c == SP or c == HT or c == VT or c == NUL then 128*94cba803SRyan Moeller s = s - 1 129*94cba803SRyan Moeller else 130*94cba803SRyan Moeller break 131*94cba803SRyan Moeller end 132*94cba803SRyan Moeller end 133*94cba803SRyan Moeller return s 134*94cba803SRyan Moellerend 135*94cba803SRyan Moeller 136*94cba803SRyan Moellerlocal function escaped(view, s) 137*94cba803SRyan Moeller if s > 1 and byte(view, s - 1, s - 1) == BSOL then 138*94cba803SRyan Moeller if s > 2 and byte(view, s - 2, s - 2) == BSOL then 139*94cba803SRyan Moeller return false, 1 140*94cba803SRyan Moeller else 141*94cba803SRyan Moeller return true, 1 142*94cba803SRyan Moeller end 143*94cba803SRyan Moeller end 144*94cba803SRyan Moeller return false, 0 145*94cba803SRyan Moellerend 146*94cba803SRyan Moeller 147*94cba803SRyan Moellerlocal function read_file(path) 148*94cba803SRyan Moeller local file, err = open(path, "rb") 149*94cba803SRyan Moeller if not file then return nil, err end 150*94cba803SRyan Moeller local content 151*94cba803SRyan Moeller content, err = file:read "*a" 152*94cba803SRyan Moeller file:close() 153*94cba803SRyan Moeller return content, err 154*94cba803SRyan Moellerend 155*94cba803SRyan Moeller 156*94cba803SRyan Moellerlocal function load_view(template) 157*94cba803SRyan Moeller return function(view, plain) 158*94cba803SRyan Moeller if plain == true then return view end 159*94cba803SRyan Moeller local path, root = view, template.root 160*94cba803SRyan Moeller if root and root ~= EMPTY then 161*94cba803SRyan Moeller if byte(root, -1) == SOL then root = sub(root, 1, -2) end 162*94cba803SRyan Moeller if byte(view, 1) == SOL then path = sub(view, 2) end 163*94cba803SRyan Moeller path = root .. "/" .. path 164*94cba803SRyan Moeller end 165*94cba803SRyan Moeller return plain == false and assert(read_file(path)) or read_file(path) or view 166*94cba803SRyan Moeller end 167*94cba803SRyan Moellerend 168*94cba803SRyan Moeller 169*94cba803SRyan Moellerlocal function load_file(func) 170*94cba803SRyan Moeller return function(view) return func(view, false) end 171*94cba803SRyan Moellerend 172*94cba803SRyan Moeller 173*94cba803SRyan Moellerlocal function load_string(func) 174*94cba803SRyan Moeller return function(view) return func(view, true) end 175*94cba803SRyan Moellerend 176*94cba803SRyan Moeller 177*94cba803SRyan Moellerlocal function loader(template) 178*94cba803SRyan Moeller return function(view) 179*94cba803SRyan Moeller return assert(load(view, nil, nil, setmetatable({ template = template }, VIEW_ENV))) 180*94cba803SRyan Moeller end 181*94cba803SRyan Moellerend 182*94cba803SRyan Moeller 183*94cba803SRyan Moellerlocal function visit(visitors, content, tag, name) 184*94cba803SRyan Moeller if not visitors then 185*94cba803SRyan Moeller return content 186*94cba803SRyan Moeller end 187*94cba803SRyan Moeller 188*94cba803SRyan Moeller for i = 1, visitors.n do 189*94cba803SRyan Moeller content = visitors[i](content, tag, name) 190*94cba803SRyan Moeller end 191*94cba803SRyan Moeller 192*94cba803SRyan Moeller return content 193*94cba803SRyan Moellerend 194*94cba803SRyan Moeller 195*94cba803SRyan Moellerlocal function new(template, safe) 196*94cba803SRyan Moeller template = template or newtab(0, 26) 197*94cba803SRyan Moeller 198*94cba803SRyan Moeller template._VERSION = "2.0" 199*94cba803SRyan Moeller template.cache = {} 200*94cba803SRyan Moeller template.load = load_view(template) 201*94cba803SRyan Moeller template.load_file = load_file(template.load) 202*94cba803SRyan Moeller template.load_string = load_string(template.load) 203*94cba803SRyan Moeller template.print = write 204*94cba803SRyan Moeller 205*94cba803SRyan Moeller local load_chunk = loader(template) 206*94cba803SRyan Moeller 207*94cba803SRyan Moeller local caching 208*94cba803SRyan Moeller if VAR_PHASES and VAR_PHASES[phase()] then 209*94cba803SRyan Moeller caching = enabled(var.template_cache) 210*94cba803SRyan Moeller else 211*94cba803SRyan Moeller caching = true 212*94cba803SRyan Moeller end 213*94cba803SRyan Moeller 214*94cba803SRyan Moeller local visitors 215*94cba803SRyan Moeller function template.visit(func) 216*94cba803SRyan Moeller if not visitors then 217*94cba803SRyan Moeller visitors = { func, n = 1 } 218*94cba803SRyan Moeller return 219*94cba803SRyan Moeller end 220*94cba803SRyan Moeller visitors.n = visitors.n + 1 221*94cba803SRyan Moeller visitors[visitors.n] = func 222*94cba803SRyan Moeller end 223*94cba803SRyan Moeller 224*94cba803SRyan Moeller function template.caching(enable) 225*94cba803SRyan Moeller if enable ~= nil then caching = enable == true end 226*94cba803SRyan Moeller return caching 227*94cba803SRyan Moeller end 228*94cba803SRyan Moeller 229*94cba803SRyan Moeller function template.output(s) 230*94cba803SRyan Moeller if s == nil or s == null then return EMPTY end 231*94cba803SRyan Moeller if type(s) == "function" then return template.output(s()) end 232*94cba803SRyan Moeller return tostring(s) 233*94cba803SRyan Moeller end 234*94cba803SRyan Moeller 235*94cba803SRyan Moeller function template.escape(s, c) 236*94cba803SRyan Moeller if type(s) == "string" then 237*94cba803SRyan Moeller if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end 238*94cba803SRyan Moeller return gsub(s, "[\">/<'&]", HTML_ENTITIES) 239*94cba803SRyan Moeller end 240*94cba803SRyan Moeller return template.output(s) 241*94cba803SRyan Moeller end 242*94cba803SRyan Moeller 243*94cba803SRyan Moeller function template.new(view, layout) 244*94cba803SRyan Moeller local vt = type(view) 245*94cba803SRyan Moeller 246*94cba803SRyan Moeller if vt == "boolean" then return new(nil, view) end 247*94cba803SRyan Moeller if vt == "table" then return new(view, safe) end 248*94cba803SRyan Moeller if vt == "nil" then return new(nil, safe) end 249*94cba803SRyan Moeller 250*94cba803SRyan Moeller local render 251*94cba803SRyan Moeller local process 252*94cba803SRyan Moeller if layout then 253*94cba803SRyan Moeller if type(layout) == "table" then 254*94cba803SRyan Moeller render = function(self, context) 255*94cba803SRyan Moeller context = context or self 256*94cba803SRyan Moeller context.blocks = context.blocks or {} 257*94cba803SRyan Moeller context.view = template.process(view, context) 258*94cba803SRyan Moeller layout.blocks = context.blocks or {} 259*94cba803SRyan Moeller layout.view = context.view or EMPTY 260*94cba803SRyan Moeller layout:render() 261*94cba803SRyan Moeller end 262*94cba803SRyan Moeller process = function(self, context) 263*94cba803SRyan Moeller context = context or self 264*94cba803SRyan Moeller context.blocks = context.blocks or {} 265*94cba803SRyan Moeller context.view = template.process(view, context) 266*94cba803SRyan Moeller layout.blocks = context.blocks or {} 267*94cba803SRyan Moeller layout.view = context.view 268*94cba803SRyan Moeller return tostring(layout) 269*94cba803SRyan Moeller end 270*94cba803SRyan Moeller else 271*94cba803SRyan Moeller render = function(self, context) 272*94cba803SRyan Moeller context = context or self 273*94cba803SRyan Moeller context.blocks = context.blocks or {} 274*94cba803SRyan Moeller context.view = template.process(view, context) 275*94cba803SRyan Moeller template.render(layout, context) 276*94cba803SRyan Moeller end 277*94cba803SRyan Moeller process = function(self, context) 278*94cba803SRyan Moeller context = context or self 279*94cba803SRyan Moeller context.blocks = context.blocks or {} 280*94cba803SRyan Moeller context.view = template.process(view, context) 281*94cba803SRyan Moeller return template.process(layout, context) 282*94cba803SRyan Moeller end 283*94cba803SRyan Moeller end 284*94cba803SRyan Moeller else 285*94cba803SRyan Moeller render = function(self, context) 286*94cba803SRyan Moeller return template.render(view, context or self) 287*94cba803SRyan Moeller end 288*94cba803SRyan Moeller process = function(self, context) 289*94cba803SRyan Moeller return template.process(view, context or self) 290*94cba803SRyan Moeller end 291*94cba803SRyan Moeller end 292*94cba803SRyan Moeller 293*94cba803SRyan Moeller if safe then 294*94cba803SRyan Moeller return setmetatable({ 295*94cba803SRyan Moeller render = function(...) 296*94cba803SRyan Moeller local ok, err = pcall(render, ...) 297*94cba803SRyan Moeller if not ok then 298*94cba803SRyan Moeller return nil, err 299*94cba803SRyan Moeller end 300*94cba803SRyan Moeller end, 301*94cba803SRyan Moeller process = function(...) 302*94cba803SRyan Moeller local ok, output = pcall(process, ...) 303*94cba803SRyan Moeller if not ok then 304*94cba803SRyan Moeller return nil, output 305*94cba803SRyan Moeller end 306*94cba803SRyan Moeller return output 307*94cba803SRyan Moeller end, 308*94cba803SRyan Moeller }, { 309*94cba803SRyan Moeller __tostring = function(...) 310*94cba803SRyan Moeller local ok, output = pcall(process, ...) 311*94cba803SRyan Moeller if not ok then 312*94cba803SRyan Moeller return "" 313*94cba803SRyan Moeller end 314*94cba803SRyan Moeller return output 315*94cba803SRyan Moeller end }) 316*94cba803SRyan Moeller end 317*94cba803SRyan Moeller 318*94cba803SRyan Moeller return setmetatable({ 319*94cba803SRyan Moeller render = render, 320*94cba803SRyan Moeller process = process 321*94cba803SRyan Moeller }, { 322*94cba803SRyan Moeller __tostring = process 323*94cba803SRyan Moeller }) 324*94cba803SRyan Moeller end 325*94cba803SRyan Moeller 326*94cba803SRyan Moeller function template.precompile(view, path, strip, plain) 327*94cba803SRyan Moeller local chunk = dump(template.compile(view, nil, plain), strip ~= false) 328*94cba803SRyan Moeller if path then 329*94cba803SRyan Moeller local file = open(path, "wb") 330*94cba803SRyan Moeller file:write(chunk) 331*94cba803SRyan Moeller file:close() 332*94cba803SRyan Moeller end 333*94cba803SRyan Moeller return chunk 334*94cba803SRyan Moeller end 335*94cba803SRyan Moeller 336*94cba803SRyan Moeller function template.precompile_string(view, path, strip) 337*94cba803SRyan Moeller return template.precompile(view, path, strip, true) 338*94cba803SRyan Moeller end 339*94cba803SRyan Moeller 340*94cba803SRyan Moeller function template.precompile_file(view, path, strip) 341*94cba803SRyan Moeller return template.precompile(view, path, strip, false) 342*94cba803SRyan Moeller end 343*94cba803SRyan Moeller 344*94cba803SRyan Moeller function template.compile(view, cache_key, plain) 345*94cba803SRyan Moeller assert(view, "view was not provided for template.compile(view, cache_key, plain)") 346*94cba803SRyan Moeller if cache_key == "no-cache" then 347*94cba803SRyan Moeller return load_chunk(template.parse(view, plain)), false 348*94cba803SRyan Moeller end 349*94cba803SRyan Moeller cache_key = cache_key or view 350*94cba803SRyan Moeller local cache = template.cache 351*94cba803SRyan Moeller if cache[cache_key] then return cache[cache_key], true end 352*94cba803SRyan Moeller local func = load_chunk(template.parse(view, plain)) 353*94cba803SRyan Moeller if caching then cache[cache_key] = func end 354*94cba803SRyan Moeller return func, false 355*94cba803SRyan Moeller end 356*94cba803SRyan Moeller 357*94cba803SRyan Moeller function template.compile_file(view, cache_key) 358*94cba803SRyan Moeller return template.compile(view, cache_key, false) 359*94cba803SRyan Moeller end 360*94cba803SRyan Moeller 361*94cba803SRyan Moeller function template.compile_string(view, cache_key) 362*94cba803SRyan Moeller return template.compile(view, cache_key, true) 363*94cba803SRyan Moeller end 364*94cba803SRyan Moeller 365*94cba803SRyan Moeller function template.parse(view, plain) 366*94cba803SRyan Moeller assert(view, "view was not provided for template.parse(view, plain)") 367*94cba803SRyan Moeller if plain ~= true then 368*94cba803SRyan Moeller view = template.load(view, plain) 369*94cba803SRyan Moeller if byte(view, 1, 1) == ESC then return view end 370*94cba803SRyan Moeller end 371*94cba803SRyan Moeller local j = 2 372*94cba803SRyan Moeller local c = {[[ 373*94cba803SRyan Moellercontext=... or {} 374*94cba803SRyan Moellerlocal ___,blocks,layout={},blocks or {} 375*94cba803SRyan Moellerlocal function include(v, c) return template.process(v, c or context) end 376*94cba803SRyan Moellerlocal function echo(...) for i=1,select("#", ...) do ___[#___+1] = tostring(select(i, ...)) end end 377*94cba803SRyan Moeller]] } 378*94cba803SRyan Moeller local i, s = 1, find(view, "{", 1, true) 379*94cba803SRyan Moeller while s do 380*94cba803SRyan Moeller local t, p = byte(view, s + 1, s + 1), s + 2 381*94cba803SRyan Moeller if t == LCUB then 382*94cba803SRyan Moeller local e = find(view, "}}", p, true) 383*94cba803SRyan Moeller if e then 384*94cba803SRyan Moeller local z, w = escaped(view, s) 385*94cba803SRyan Moeller if i < s - w then 386*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 387*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 388*94cba803SRyan Moeller c[j+2] = "]=]\n" 389*94cba803SRyan Moeller j=j+3 390*94cba803SRyan Moeller end 391*94cba803SRyan Moeller if z then 392*94cba803SRyan Moeller i = s 393*94cba803SRyan Moeller else 394*94cba803SRyan Moeller c[j] = "___[#___+1]=template.escape(" 395*94cba803SRyan Moeller c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "{") 396*94cba803SRyan Moeller c[j+2] = ")\n" 397*94cba803SRyan Moeller j=j+3 398*94cba803SRyan Moeller s, i = e + 1, e + 2 399*94cba803SRyan Moeller end 400*94cba803SRyan Moeller end 401*94cba803SRyan Moeller elseif t == AST then 402*94cba803SRyan Moeller local e = find(view, "*}", p, true) 403*94cba803SRyan Moeller if e then 404*94cba803SRyan Moeller local z, w = escaped(view, s) 405*94cba803SRyan Moeller if i < s - w then 406*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 407*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 408*94cba803SRyan Moeller c[j+2] = "]=]\n" 409*94cba803SRyan Moeller j=j+3 410*94cba803SRyan Moeller end 411*94cba803SRyan Moeller if z then 412*94cba803SRyan Moeller i = s 413*94cba803SRyan Moeller else 414*94cba803SRyan Moeller c[j] = "___[#___+1]=template.output(" 415*94cba803SRyan Moeller c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "*") 416*94cba803SRyan Moeller c[j+2] = ")\n" 417*94cba803SRyan Moeller j=j+3 418*94cba803SRyan Moeller s, i = e + 1, e + 2 419*94cba803SRyan Moeller end 420*94cba803SRyan Moeller end 421*94cba803SRyan Moeller elseif t == PERCNT then 422*94cba803SRyan Moeller local e = find(view, "%}", p, true) 423*94cba803SRyan Moeller if e then 424*94cba803SRyan Moeller local z, w = escaped(view, s) 425*94cba803SRyan Moeller if z then 426*94cba803SRyan Moeller if i < s - w then 427*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 428*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 429*94cba803SRyan Moeller c[j+2] = "]=]\n" 430*94cba803SRyan Moeller j=j+3 431*94cba803SRyan Moeller end 432*94cba803SRyan Moeller i = s 433*94cba803SRyan Moeller else 434*94cba803SRyan Moeller local n = e + 2 435*94cba803SRyan Moeller if byte(view, n, n) == LF then 436*94cba803SRyan Moeller n = n + 1 437*94cba803SRyan Moeller end 438*94cba803SRyan Moeller local r = rpos(view, s - 1) 439*94cba803SRyan Moeller if i <= r then 440*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 441*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, r)) 442*94cba803SRyan Moeller c[j+2] = "]=]\n" 443*94cba803SRyan Moeller j=j+3 444*94cba803SRyan Moeller end 445*94cba803SRyan Moeller c[j] = visit(visitors, trim(sub(view, p, e - 1)), "%") 446*94cba803SRyan Moeller c[j+1] = "\n" 447*94cba803SRyan Moeller j=j+2 448*94cba803SRyan Moeller s, i = n - 1, n 449*94cba803SRyan Moeller end 450*94cba803SRyan Moeller end 451*94cba803SRyan Moeller elseif t == LPAR then 452*94cba803SRyan Moeller local e = find(view, ")}", p, true) 453*94cba803SRyan Moeller if e then 454*94cba803SRyan Moeller local z, w = escaped(view, s) 455*94cba803SRyan Moeller if i < s - w then 456*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 457*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 458*94cba803SRyan Moeller c[j+2] = "]=]\n" 459*94cba803SRyan Moeller j=j+3 460*94cba803SRyan Moeller end 461*94cba803SRyan Moeller if z then 462*94cba803SRyan Moeller i = s 463*94cba803SRyan Moeller else 464*94cba803SRyan Moeller local f = visit(visitors, sub(view, p, e - 1), "(") 465*94cba803SRyan Moeller local x = find(f, ",", 2, true) 466*94cba803SRyan Moeller if x then 467*94cba803SRyan Moeller c[j] = "___[#___+1]=include([=[" 468*94cba803SRyan Moeller c[j+1] = trim(sub(f, 1, x - 1)) 469*94cba803SRyan Moeller c[j+2] = "]=]," 470*94cba803SRyan Moeller c[j+3] = trim(sub(f, x + 1)) 471*94cba803SRyan Moeller c[j+4] = ")\n" 472*94cba803SRyan Moeller j=j+5 473*94cba803SRyan Moeller else 474*94cba803SRyan Moeller c[j] = "___[#___+1]=include([=[" 475*94cba803SRyan Moeller c[j+1] = trim(f) 476*94cba803SRyan Moeller c[j+2] = "]=])\n" 477*94cba803SRyan Moeller j=j+3 478*94cba803SRyan Moeller end 479*94cba803SRyan Moeller s, i = e + 1, e + 2 480*94cba803SRyan Moeller end 481*94cba803SRyan Moeller end 482*94cba803SRyan Moeller elseif t == LSQB then 483*94cba803SRyan Moeller local e = find(view, "]}", p, true) 484*94cba803SRyan Moeller if e then 485*94cba803SRyan Moeller local z, w = escaped(view, s) 486*94cba803SRyan Moeller if i < s - w then 487*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 488*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 489*94cba803SRyan Moeller c[j+2] = "]=]\n" 490*94cba803SRyan Moeller j=j+3 491*94cba803SRyan Moeller end 492*94cba803SRyan Moeller if z then 493*94cba803SRyan Moeller i = s 494*94cba803SRyan Moeller else 495*94cba803SRyan Moeller c[j] = "___[#___+1]=include(" 496*94cba803SRyan Moeller c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "[") 497*94cba803SRyan Moeller c[j+2] = ")\n" 498*94cba803SRyan Moeller j=j+3 499*94cba803SRyan Moeller s, i = e + 1, e + 2 500*94cba803SRyan Moeller end 501*94cba803SRyan Moeller end 502*94cba803SRyan Moeller elseif t == MINUS then 503*94cba803SRyan Moeller local e = find(view, "-}", p, true) 504*94cba803SRyan Moeller if e then 505*94cba803SRyan Moeller local x, y = find(view, sub(view, s, e + 1), e + 2, true) 506*94cba803SRyan Moeller if x then 507*94cba803SRyan Moeller local z, w = escaped(view, s) 508*94cba803SRyan Moeller if z then 509*94cba803SRyan Moeller if i < s - w then 510*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 511*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 512*94cba803SRyan Moeller c[j+2] = "]=]\n" 513*94cba803SRyan Moeller j=j+3 514*94cba803SRyan Moeller end 515*94cba803SRyan Moeller i = s 516*94cba803SRyan Moeller else 517*94cba803SRyan Moeller y = y + 1 518*94cba803SRyan Moeller x = x - 1 519*94cba803SRyan Moeller if byte(view, y, y) == LF then 520*94cba803SRyan Moeller y = y + 1 521*94cba803SRyan Moeller end 522*94cba803SRyan Moeller local b = trim(sub(view, p, e - 1)) 523*94cba803SRyan Moeller if b == "verbatim" or b == "raw" then 524*94cba803SRyan Moeller if i < s - w then 525*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 526*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 527*94cba803SRyan Moeller c[j+2] = "]=]\n" 528*94cba803SRyan Moeller j=j+3 529*94cba803SRyan Moeller end 530*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[" 531*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, e + 2, x)) 532*94cba803SRyan Moeller c[j+2] = "]=]\n" 533*94cba803SRyan Moeller j=j+3 534*94cba803SRyan Moeller else 535*94cba803SRyan Moeller if byte(view, x, x) == LF then 536*94cba803SRyan Moeller x = x - 1 537*94cba803SRyan Moeller end 538*94cba803SRyan Moeller local r = rpos(view, s - 1) 539*94cba803SRyan Moeller if i <= r then 540*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 541*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, r)) 542*94cba803SRyan Moeller c[j+2] = "]=]\n" 543*94cba803SRyan Moeller j=j+3 544*94cba803SRyan Moeller end 545*94cba803SRyan Moeller c[j] = 'blocks["' 546*94cba803SRyan Moeller c[j+1] = b 547*94cba803SRyan Moeller c[j+2] = '"]=include[=[' 548*94cba803SRyan Moeller c[j+3] = visit(visitors, sub(view, e + 2, x), "-", b) 549*94cba803SRyan Moeller c[j+4] = "]=]\n" 550*94cba803SRyan Moeller j=j+5 551*94cba803SRyan Moeller end 552*94cba803SRyan Moeller s, i = y - 1, y 553*94cba803SRyan Moeller end 554*94cba803SRyan Moeller end 555*94cba803SRyan Moeller end 556*94cba803SRyan Moeller elseif t == NUM then 557*94cba803SRyan Moeller local e = find(view, "#}", p, true) 558*94cba803SRyan Moeller if e then 559*94cba803SRyan Moeller local z, w = escaped(view, s) 560*94cba803SRyan Moeller if i < s - w then 561*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 562*94cba803SRyan Moeller c[j+1] = visit(visitors, sub(view, i, s - 1 - w)) 563*94cba803SRyan Moeller c[j+2] = "]=]\n" 564*94cba803SRyan Moeller j=j+3 565*94cba803SRyan Moeller end 566*94cba803SRyan Moeller if z then 567*94cba803SRyan Moeller i = s 568*94cba803SRyan Moeller else 569*94cba803SRyan Moeller e = e + 2 570*94cba803SRyan Moeller if byte(view, e, e) == LF then 571*94cba803SRyan Moeller e = e + 1 572*94cba803SRyan Moeller end 573*94cba803SRyan Moeller s, i = e - 1, e 574*94cba803SRyan Moeller end 575*94cba803SRyan Moeller end 576*94cba803SRyan Moeller end 577*94cba803SRyan Moeller s = find(view, "{", s + 1, true) 578*94cba803SRyan Moeller end 579*94cba803SRyan Moeller s = sub(view, i) 580*94cba803SRyan Moeller if s and s ~= EMPTY then 581*94cba803SRyan Moeller c[j] = "___[#___+1]=[=[\n" 582*94cba803SRyan Moeller c[j+1] = visit(visitors, s) 583*94cba803SRyan Moeller c[j+2] = "]=]\n" 584*94cba803SRyan Moeller j=j+3 585*94cba803SRyan Moeller end 586*94cba803SRyan Moeller c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" -- luacheck: ignore 587*94cba803SRyan Moeller return concat(c) 588*94cba803SRyan Moeller end 589*94cba803SRyan Moeller 590*94cba803SRyan Moeller function template.parse_file(view) 591*94cba803SRyan Moeller return template.parse(view, false) 592*94cba803SRyan Moeller end 593*94cba803SRyan Moeller 594*94cba803SRyan Moeller function template.parse_string(view) 595*94cba803SRyan Moeller return template.parse(view, true) 596*94cba803SRyan Moeller end 597*94cba803SRyan Moeller 598*94cba803SRyan Moeller function template.process(view, context, cache_key, plain) 599*94cba803SRyan Moeller assert(view, "view was not provided for template.process(view, context, cache_key, plain)") 600*94cba803SRyan Moeller return template.compile(view, cache_key, plain)(context) 601*94cba803SRyan Moeller end 602*94cba803SRyan Moeller 603*94cba803SRyan Moeller function template.process_file(view, context, cache_key) 604*94cba803SRyan Moeller assert(view, "view was not provided for template.process_file(view, context, cache_key)") 605*94cba803SRyan Moeller return template.compile(view, cache_key, false)(context) 606*94cba803SRyan Moeller end 607*94cba803SRyan Moeller 608*94cba803SRyan Moeller function template.process_string(view, context, cache_key) 609*94cba803SRyan Moeller assert(view, "view was not provided for template.process_string(view, context, cache_key)") 610*94cba803SRyan Moeller return template.compile(view, cache_key, true)(context) 611*94cba803SRyan Moeller end 612*94cba803SRyan Moeller 613*94cba803SRyan Moeller function template.render(view, context, cache_key, plain) 614*94cba803SRyan Moeller assert(view, "view was not provided for template.render(view, context, cache_key, plain)") 615*94cba803SRyan Moeller template.print(template.process(view, context, cache_key, plain)) 616*94cba803SRyan Moeller end 617*94cba803SRyan Moeller 618*94cba803SRyan Moeller function template.render_file(view, context, cache_key) 619*94cba803SRyan Moeller assert(view, "view was not provided for template.render_file(view, context, cache_key)") 620*94cba803SRyan Moeller template.render(view, context, cache_key, false) 621*94cba803SRyan Moeller end 622*94cba803SRyan Moeller 623*94cba803SRyan Moeller function template.render_string(view, context, cache_key) 624*94cba803SRyan Moeller assert(view, "view was not provided for template.render_string(view, context, cache_key)") 625*94cba803SRyan Moeller template.render(view, context, cache_key, true) 626*94cba803SRyan Moeller end 627*94cba803SRyan Moeller 628*94cba803SRyan Moeller if safe then 629*94cba803SRyan Moeller return setmetatable({}, { 630*94cba803SRyan Moeller __index = function(_, k) 631*94cba803SRyan Moeller if type(template[k]) == "function" then 632*94cba803SRyan Moeller return function(...) 633*94cba803SRyan Moeller local ok, a, b = pcall(template[k], ...) 634*94cba803SRyan Moeller if not ok then 635*94cba803SRyan Moeller return nil, a 636*94cba803SRyan Moeller end 637*94cba803SRyan Moeller return a, b 638*94cba803SRyan Moeller end 639*94cba803SRyan Moeller end 640*94cba803SRyan Moeller return template[k] 641*94cba803SRyan Moeller end, 642*94cba803SRyan Moeller __new_index = function(_, k, v) 643*94cba803SRyan Moeller template[k] = v 644*94cba803SRyan Moeller end, 645*94cba803SRyan Moeller }) 646*94cba803SRyan Moeller end 647*94cba803SRyan Moeller 648*94cba803SRyan Moeller return template 649*94cba803SRyan Moellerend 650*94cba803SRyan Moeller 651*94cba803SRyan Moellerreturn new() 652