Skip to content

Instantly share code, notes, and snippets.

@pcarrier
Last active June 24, 2024 21:30
Show Gist options
  • Save pcarrier/b17b78e756d2457d3514c87ba17901c0 to your computer and use it in GitHub Desktop.
Save pcarrier/b17b78e756d2457d3514c87ba17901c0 to your computer and use it in GitHub Desktop.
HTML markup DSL for Lua
local m = require('markup')
print('<!doctype html>', m.html{
lang = 'en',
m.head{
m.title 'markup.lua',
m.meta{ charset = 'utf-8' },
m.meta{ name = 'viewport', content = 'width=device-width, initial-scale=1' },
},
m.body {
m.h1 'markup.lua makes <html/>',
m.p{ "It\'s super ", m.b 'easy', '!' },
}
})
--[[
$ lua marked.lua
<!doctype html> <html lang="en"><head><title>markup.lua</title><meta charset="utf-8"/><meta content="width=device-width, initial-scale=1" name="viewport"/></head><body><h1>markup.lua makes &lt;html/&gt;</h1><p>It's super <b>easy</b>!</p></body></html>
$
]]
--[[
Copyright © 2024 Pierre Carrier
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
]]
local M, name_ = {}, {}
local replacements = { ["&"] = "&amp;", ["<"] = "&lt;", [">"] = "&gt;", ['"'] = "&quot;", }
local function escape(s)
return s:gsub("[&<>]", replacements)
end
local function qescape(s)
return s:gsub('[&<>"]', replacements)
end
local mt = {
__tostring = function(t)
local attrs, children = {}, {}
for k, v in next, t do
if type(k) == "number" then
children[k] = v
else
attrs[k] = v
end
end
local parts = { "<", t[name_] }
for k, v in next, attrs do
if k ~= name_ then
parts[#parts + 1] = " " .. tostring(k) .. '="' .. qescape(v) .. '"'
end
end
if #children == 0 then
parts[#parts + 1] = "/>"
else
parts[#parts + 1] = ">"
for _, v in ipairs(children) do
parts[#parts + 1] = type(v) == "string" and escape(v) or tostring(v)
end
parts[#parts + 1] = "</" .. t[name_] .. ">"
end
return table.concat(parts)
end
}
setmetatable(M, {
__index = function(_, name)
return function(arg)
if type(arg) ~= "table" then
arg = { arg }
end
setmetatable(arg, mt)
arg[name_] = name
return arg
end
end
})
return M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment