author | Kim Alvefur <zash@zash.se> |
Sat, 02 Mar 2024 14:14:27 +0100 | |
changeset 13459 | 2a001cd7f99a |
parent 11311 | f2e276bb4ef8 |
permissions | -rw-r--r-- |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
1 |
-- Simple template language |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
2 |
-- |
6774
60957dd5b41b
util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents:
6723
diff
changeset
|
3 |
-- The new() function takes a pattern and an escape function and returns |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
4 |
-- a render() function. Both are required. |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
5 |
-- |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
6 |
-- The function render() takes a string template and a table of values. |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
7 |
-- Sequences like {name} in the template string are substituted |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
8 |
-- with values from the table, optionally depending on a modifier |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
9 |
-- symbol. |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
10 |
-- |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
11 |
-- Variants are: |
6774
60957dd5b41b
util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents:
6723
diff
changeset
|
12 |
-- {name} is substituted for values["name"] and is escaped using the |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
13 |
-- second argument to new_render(). To disable the escaping, use {name!}. |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
14 |
-- {name.item} can be used to access table items. |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
15 |
-- To renter lists of items: {name# item number {idx} is {item} } |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
16 |
-- Or key-value pairs: {name% t[ {idx} ] = {item} } |
6774
60957dd5b41b
util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents:
6723
diff
changeset
|
17 |
-- To show a defaults for missing values {name? sub-template } can be used, |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
18 |
-- which renders a sub-template if values["name"] is false-ish. |
6774
60957dd5b41b
util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents:
6723
diff
changeset
|
19 |
-- {name& sub-template } does the opposite, the sub-template is rendered |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
20 |
-- if the selected value is anything but false or nil. |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
21 |
|
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
22 |
local type, tostring = type, tostring; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
23 |
local pairs, ipairs = pairs, ipairs; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
24 |
local s_sub, s_gsub, s_match = string.sub, string.gsub, string.match; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
25 |
local t_concat = table.concat; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
26 |
|
6775
805baeca56b6
util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents:
6774
diff
changeset
|
27 |
local function new_render(pat, escape, funcs) |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
28 |
-- assert(type(pat) == "string", "bad argument #1 to 'new_render' (string expected)"); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
29 |
-- assert(type(escape) == "function", "bad argument #2 to 'new_render' (function expected)"); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
30 |
local function render(template, values) |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
31 |
-- assert(type(template) == "string", "bad argument #1 to 'render' (string expected)"); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
32 |
-- assert(type(values) == "table", "bad argument #2 to 'render' (table expected)"); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
33 |
return (s_gsub(template, pat, function (block) |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
34 |
block = s_sub(block, 2, -2); |
10352
3852fc91b2fc
util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents:
6775
diff
changeset
|
35 |
local name, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()"); |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
36 |
if not name then return end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
37 |
local value = values[name]; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
38 |
if not value and name:find(".", 2, true) then |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
39 |
value = values; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
40 |
for word in name:gmatch"[^.]+" do |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
41 |
value = value[word]; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
42 |
if not value then break; end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
43 |
end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
44 |
end |
6775
805baeca56b6
util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents:
6774
diff
changeset
|
45 |
if funcs then |
11310
5798ab735619
util.interpolation: Fix combination of filters and fallback values #1623
Kim Alvefur <zash@zash.se>
parents:
10352
diff
changeset
|
46 |
while opt == '|' do |
6775
805baeca56b6
util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents:
6774
diff
changeset
|
47 |
local f; |
10352
3852fc91b2fc
util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents:
6775
diff
changeset
|
48 |
f, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()", e); |
6775
805baeca56b6
util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents:
6774
diff
changeset
|
49 |
f = funcs[f]; |
11310
5798ab735619
util.interpolation: Fix combination of filters and fallback values #1623
Kim Alvefur <zash@zash.se>
parents:
10352
diff
changeset
|
50 |
if value ~= nil and f then value = f(value); end |
6775
805baeca56b6
util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents:
6774
diff
changeset
|
51 |
end |
805baeca56b6
util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents:
6774
diff
changeset
|
52 |
end |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
53 |
if opt == '#' or opt == '%' then |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
54 |
if type(value) ~= "table" then return ""; end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
55 |
local iter = opt == '#' and ipairs or pairs; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
56 |
local out, i, subtpl = {}, 1, s_sub(block, e); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
57 |
local subvalues = setmetatable({}, { __index = values }); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
58 |
for idx, item in iter(value) do |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
59 |
subvalues.idx = idx; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
60 |
subvalues.item = item; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
61 |
out[i], i = render(subtpl, subvalues), i+1; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
62 |
end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
63 |
return t_concat(out); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
64 |
elseif opt == '&' then |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
65 |
if not value then return ""; end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
66 |
return render(s_sub(block, e), values); |
11068
af1e3b7d9ea3
util.interpolation: Add '~' as the opposite of '&' (render sub-block if falsy)
Matthew Wild <mwild1@gmail.com>
parents:
10352
diff
changeset
|
67 |
elseif opt == '~' then |
af1e3b7d9ea3
util.interpolation: Add '~' as the opposite of '&' (render sub-block if falsy)
Matthew Wild <mwild1@gmail.com>
parents:
10352
diff
changeset
|
68 |
if value then return ""; end |
af1e3b7d9ea3
util.interpolation: Add '~' as the opposite of '&' (render sub-block if falsy)
Matthew Wild <mwild1@gmail.com>
parents:
10352
diff
changeset
|
69 |
return render(s_sub(block, e), values); |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
70 |
elseif opt == '?' and not value then |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
71 |
return render(s_sub(block, e), values); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
72 |
elseif value ~= nil then |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
73 |
if type(value) ~= "string" then |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
74 |
value = tostring(value); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
75 |
end |
10352
3852fc91b2fc
util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents:
6775
diff
changeset
|
76 |
if raw ~= '!' then |
6723
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
77 |
return escape(value); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
78 |
end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
79 |
return value; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
80 |
end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
81 |
end)); |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
82 |
end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
83 |
return render; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
84 |
end |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
85 |
|
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
86 |
return { |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
87 |
new = new_render; |
936cf2f7531f
util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
88 |
}; |