diff options
Diffstat (limited to 'html.lua')
-rw-r--r-- | html.lua | 124 |
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 = { + ["<"] = "<", + [">"] = ">", + ['"'] = """ +} +local function escape(x) + local escaped = tostring(x) + escaped = escaped:gsub("&", "&") + + 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 + |