Skip to content

Instantly share code, notes, and snippets.

@max1220
Created April 11, 2024 05:15
Show Gist options
  • Save max1220/320829badfb885562c3f5bae4efbc898 to your computer and use it in GitHub Desktop.
Save max1220/320829badfb885562c3f5bae4efbc898 to your computer and use it in GitHub Desktop.
Configurable Lua table ANSI pretty printer/serializer. Public domain.
local function pretty_print_table(tbl, file, indent, num_fmt, no_ansi, style, seen)
-- default parameters
file = file or io.stdout
indent = indent or 0
num_fmt = tbl.__print_table_number_format or num_fmt or "%.2f"
style = tbl.__print_table_colors or style or {}
seen = seen or {}
-- calculate ANSI color codes
local key_code = no_ansi and "" or style.key or "\027[1;36m"
local tbl_code = no_ansi and "" or style.tbl or "\027[35m"
local comt_code = no_ansi and "" or style.comt or "\027[33m"
local str_code = no_ansi and "" or style.str or "\027[32m"
local num_code = no_ansi and "" or style.num or "\027[34m"
local func_code = no_ansi and "" or style.func or "\027[91m"
local bool_on_code = no_ansi and "" or style.bool_on or "\027[92m"
local bool_off_code = no_ansi and "" or style.bool_off or "\027[91m"
local reset_code = no_ansi and "" or style.reset or "\027[0m"
-- from key-value hash format to list of {k,v} tuples
local itbl = {}
for k, v in pairs(tbl) do
table.insert(itbl, { k, v })
end
-- sort list of tuples by keys
table.sort(itbl, function(a,b)
if type(a[1]) == "number" and type(b[1]) == "number" then
return a[1] < b[1]
else
return tostring(a[1]) < tostring(b[1])
end
end)
-- iterate over tuples, print recursively using ANSI escape sequences for colors
local id = (style.indent_chars or "\t"):rep(indent)
for i,t in ipairs(itbl) do
local k,v = unpack(t)
local ls = (i==#itbl) and "" or ","
local ke = tostring(k) .. " = "
if type(k) == "string" and (("%q"):format(k) ~= "\""..k.."\"") then
ke = ("[%q] = "):format(k):gsub("\\\n", "\\n")
elseif (type(k)=="number") and (k==i) then
ke = ""
elseif type(k)=="number" then
ke = "[" .. num_code .. k .. reset_code .. key_code .. "] = "
end
file:write(id .. key_code .. ke .. reset_code)
if type(v) == "table" then
if seen[v] then
file:write(tbl_code .. "{}" .. ls .. comt_code .. " -- repeat: <" .. tostring(v) .. ">" ..reset_code .. "\n")
else
seen[v] = true
file:write(tbl_code .. "{ " .. comt_code .. "-- <" .. tostring(v) .. ">" .. reset_code .. "\n")
print_table(v, file, indent+1, num_fmt, no_ansi, style, seen)
file:write(id .. tbl_code .. "}" .. reset_code .. ls .. "\n")
end
elseif type(v) == "string" then
file:write(str_code .. ("%q"):format(v):gsub("\\\n", "\\n") .. reset_code .. ls .. "\n")
elseif type(v) == "function" then
file:write(func_code .. "nil" .. ls .. " -- <" .. tostring(v) .. ">" .. reset_code .. "\n")
elseif type(v) == "number" then
file:write(num_code .. num_fmt:format(v) .. reset_code .. ls .. "\n")
elseif type(v) == "boolean" then
file:write((v and (bool_on_code .. "true") or (bool_off_code .. "false")) .. reset_code .. ls .. "\n")
else
file:write(tostring(v) .. ls .. "\n")
end
end
end
local t = {"foo", "bar"}
local test = {
"First",
"Second",
"Third",
44,55,66,
[222] = "is 222",
[999] = "Almost 1000",
["Hello\nWorld!"] = "Foo Bar!",
[false] = true,
print = print,
hex = {
__print_table_number_format = "0x%.1x",
[0]=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
},
colors = {
__print_table_colors = { str = "\027[91m" },
red_str = "This string is red!"
},
t_copy_a = t,
t_copy_b = t,
}
print_table(test)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment