Skip to content

Instantly share code, notes, and snippets.

@pingbird
Last active October 2, 2019 05:51
Show Gist options
  • Save pingbird/974e3fb00b9064371981 to your computer and use it in GitHub Desktop.
Save pingbird/974e3fb00b9064371981 to your computer and use it in GitHub Desktop.
Fancy lua serialization
--[[
Fancy lua serialization by PixelToast, public domain
serializes a value into a fancy and human readable format
example:
> cserialize({key="value",table={list={1,2,"three"},d="alphabetical order",c=1,b=2,a=3}})
┌─────────────────────────────────────────┐
│"key" = "value" │
│ ┌─────────────────────────────┐│
│ │"a" = 3 ││
│ │"b" = 2 ││
│ │"c" = 1 ││
│ │"d" = "alphabetical order"││
│"table" = │ ┌───────┐ ││
│ │ │1 │ ││
│ │"list" = │2 │ ││
│ │ │"three"│ ││
│ │ └───────┘ ││
│ └─────────────────────────────┘│
└─────────────────────────────────────────┘
]]
local box={
ud="│",
lr="─",
ur="└",
rd="┌",
ld="┐",
lu="┘",
e="[]"
}
--[[local box={
ud="|",
lr="-",
ur="\\",
rd="/",
ld="\\",
lu="/",
e="[]"
}]]
local function utf8len(s)
local t=0
for l1=1,#s do
local c=s:byte(l1)
if bit.band(c,0xC0)~=0x80 then
t=t+1
end
end
return t
end
local function txtbl(s,mx)
local o={}
for c in s:gmatch("[^\r\n]+") do
table.insert(o,c)
end
mx=mx or 0
for l1=1,#o do
mx=math.max(mx,utf8len(o[l1]))
end
for l1=1,#o do
o[l1]=o[l1]..(" "):rep(mx-utf8len(o[l1]))
end
return o,mx
end
local function consoleBox(s)
if s=="" then
s=" "
end
local t,l=txtbl(s)
for l1=1,#t do
t[l1]=box.ud..t[l1]..box.ud
end
table.insert(t,1,box.rd..(box.lr:rep(l))..box.ld)
table.insert(t,box.ur..(box.lr:rep(l))..box.lu)
return table.concat(t,"\n")
end
local function consoleCat(a,b,al,bl)
local at,al=txtbl(a,al)
local bt,bl=txtbl(b,bl)
if #at==#bt then
for l1=1,#bt do
bt[l1]=at[l1]..bt[l1]
end
return table.concat(bt,"\n")
end
if al==0 then
return table.concat(bt,"\n")
elseif bl==0 then
return table.concat(at,"\n")
end
local ml=math.max(#at,#bt)
for l1=1,math.floor((#bt-#at)/2) do
table.insert(at,1,(" "):rep(al))
end
for l1=#at+1,ml do
table.insert(at,(" "):rep(al))
end
for l1=1,math.floor((#at-#bt)/2) do
table.insert(bt,1,(" "):rep(bl))
end
for l1=#bt+1,ml do
table.insert(bt,(" "):rep(bl))
end
for l1=1,ml do
at[l1]=at[l1]..bt[l1]
end
return table.concat(at,"\n")
end
local function _cserialize(t,r)
r=r or {}
if r[t] then
return tostring(t)
end
local tpe=type(t)
if tpe=="table" then
local err,res=pcall(function()
local ok={}
local ov={}
local u={}
local n=1
r[t]=true
while t[n]~=nil do
u[n]=true
table.insert(ok," ")
table.insert(ov,consoleCat(" ",_cserialize(t[n],r)))
n=n+1
end
local oi={}
for k,v in pairs(t) do
if not u[k] then
table.insert(oi,{k,v})
end
end
if #oi==0 then
for l1=1,#ov do
ov[l1]=ov[l1]:sub(4)
end
end
table.sort(oi,function(a,b)
return tostring(a[1])<tostring(b[1])
end)
for k,v in ipairs(oi) do
table.insert(ok,_cserialize(v[1],r))
table.insert(ov,consoleCat(" = ",_cserialize(v[2],r)))
end
if #ok==0 then
return box.e
end
local _
local kl=0
for k,v in pairs(ok) do
if v~=" " then
_,kl=txtbl(v,kl)
end
end
if kl==0 then
return consoleBox(table.concat(ov,"\n"))
end
local vl=0
for k,v in pairs(ov) do
_,vl=txtbl(v,vl)
end
local o=""
for l1=1,#ok do
o=o..consoleCat(ok[l1],ov[l1],kl,vl).."\n"
end
r[t]=nil
return consoleBox(o)
end)
return err and res or tostring(t)
elseif tpe=="number" then
if t~=t then
return "nan"
elseif t==math.huge then
return "inf"
elseif t==-math.huge then
return "-inf"
end
return tostring(t)
elseif tpe=="string" then
local o=string.format("%q",t):gsub("\\\n","\\n"):gsub("%z","\\z")
return o
else
return tostring(t)
end
end
function cserialize(t)
return _cserialize(t)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment