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