aboutsummaryrefslogtreecommitdiff
path: root/html.lua
diff options
context:
space:
mode:
Diffstat (limited to 'html.lua')
-rw-r--r--html.lua124
1 files changed, 124 insertions, 0 deletions
diff --git a/html.lua b/html.lua
new file mode 100644
index 0000000..454eae8
--- /dev/null
+++ b/html.lua
@@ -0,0 +1,124 @@
+-- HTML generator DSL for lua 5.3
+
+-- copyright © 2021 citrons <citrons@mondecitronne.com>
+-- arbitrary copying, distribution, modification, and use is permitted as long
+-- as this copyright notice is retained, and you get in the hole immediately.
+-- go on, get in.
+
+
+local h = {}
+
+local esc_sequences = {
+ ["<"] = "&lt;",
+ [">"] = "&gt;",
+ ['"'] = "&quot;"
+}
+local function escape(x)
+ local escaped = tostring(x)
+ escaped = escaped:gsub("&", "&amp;")
+
+ for char,esc in pairs(esc_sequences) do
+ escaped = string.gsub(escaped, char, esc)
+ end
+ return escaped
+end
+
+local function render(x)
+ local mt = getmetatable(x)
+ if mt.render then return mt.render(x)
+ else return escape(x) end
+end
+
+local function verify_tag(x)
+end
+
+local meta = {}
+function meta.render(self)
+ local attr_strings = {}
+ local i = 1
+ for k,v in pairs(self.attrs) do
+ verify_tag(k)
+ attr_strings[i] = string.format(' %s="%s"', k, escape(v))
+ i = i + 1
+ end
+ local attrs = table.concat(attr_strings)
+
+ local str
+ if self.children then
+ local child_strings = {}
+ for i,c in ipairs(self.children) do
+ child_strings[i] = render(c)
+ end
+ local children = table.concat(child_strings)
+
+ str = string.format('<%s%s>%s</%s>',
+ self.tag, attrs, children, self.tag)
+ else
+ str = string.format('<%s%s />', self.tag, attrs)
+ end
+
+ if self.tag == "html" then
+ str = "<!DOCTYPE html>\n" .. str
+ end
+ return str
+end
+meta.__tostring = meta.render
+
+setmetatable(h, {
+ __index = function(self, tag)
+ verify_tag(tag)
+ return function(...)
+ local attrs, children
+ local args = {...}
+
+ if #args == 2 then
+ attrs = args[1]
+ if type(args[2]) ~= "table" then
+ children = {args[2]}
+ else
+ children = args[2]
+ end
+ elseif #args == 1 then
+ if type(args[1]) ~= "table" then
+ attrs = {} children = {args[1]}
+ elseif args[1][1] ~= nil then
+ attrs = {} children = args[1]
+ else
+ children = {}
+ attrs = {}
+ -- if args[1] is key/value pairs, use it as attributes
+ for _,_ in pairs(args[1]) do
+ children = nil attrs = args[1] break
+ end
+ end
+ else attrs = {} end
+
+ if children then
+ for i,v in ipairs(children) do
+ local mt = getmetatable(v)
+ if mt.tohtml then
+ children[i] = mt.tohtml(v)
+ end
+ end
+ end
+
+ local element = {tag=tag, attrs=attrs, children=children}
+ setmetatable(element, meta)
+ return element
+ end
+ end
+})
+
+local raw_meta = {
+ render = function(self) return self.str end,
+ __tostring = function(self) return self.str end
+}
+
+function h.raw(str)
+ local raw = {str=str}
+ setmetatable(raw, raw_meta)
+ return raw
+end
+
+return h
+