From 3e7e65885a51a7846f4b81b276e28181623428de Mon Sep 17 00:00:00 2001
From: ShadowNinja <shadowninja@minetest.net>
Date: Sat, 19 Jul 2014 23:39:23 -0400
Subject: [PATCH] Make dump's output prettier

Changes:
  * Indentation with tabs by default.
  * Array keys dumped without "[i] = " prefix.
  * String keys that are valid identifiers aren't enclosed in '[""]'.
  * Basic support for multiple references (as specified in the comment).
---
 builtin/common/misc_helpers.lua | 97 ++++++++++++++++++++++++++-------
 1 file changed, 76 insertions(+), 21 deletions(-)

diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua
index f57efc138..2e2eac925 100644
--- a/builtin/common/misc_helpers.lua
+++ b/builtin/common/misc_helpers.lua
@@ -21,6 +21,37 @@ function basic_dump(o)
 	end
 end
 
+local keywords = {
+	["and"] = true,
+	["break"] = true,
+	["do"] = true,
+	["else"] = true,
+	["elseif"] = true,
+	["end"] = true,
+	["false"] = true,
+	["for"] = true,
+	["function"] = true,
+	["goto"] = true,  -- Lua 5.2
+	["if"] = true,
+	["in"] = true,
+	["local"] = true,
+	["nil"] = true,
+	["not"] = true,
+	["or"] = true,
+	["repeat"] = true,
+	["return"] = true,
+	["then"] = true,
+	["true"] = true,
+	["until"] = true,
+	["while"] = true,
+}
+local function is_valid_identifier(str)
+	if not str:find("^[a-zA-Z_][a-zA-Z0-9_]*$") or keywords[str] then
+		return false
+	end
+	return true
+end
+
 --------------------------------------------------------------------------------
 -- Dumps values in a line-per-value format.
 -- For example, {test = {"Testing..."}} becomes:
@@ -70,33 +101,57 @@ function dump2(o, name, dumped)
 end
 
 --------------------------------------------------------------------------------
--- This dumps values in a one-line format, like serialize().
--- For example, {test = {"Testing..."}} becomes {["test"] = {[1] = "Testing..."}}
+-- This dumps values in a one-statement format.
+-- For example, {test = {"Testing..."}} becomes:
+-- [[{
+-- 	test = {
+-- 		"Testing..."
+-- 	}
+-- }]]
 -- This supports tables as keys, but not circular references.
 -- It performs poorly with multiple references as it writes out the full
 -- table each time.
--- The dumped argument is internal-only.
+-- The indent field specifies a indentation string, it defaults to a tab.
+-- Use the empty string to disable indentation.
+-- The dumped and level arguments are internal-only.
 
-function dump(o, dumped)
-	-- Same as "dumped" in dump2.  The difference is that here it can only
-	-- contain boolean (and nil) values since multiple references aren't
-	-- handled properly.
-	dumped = dumped or {}
-	if type(o) == "table" then
-		if dumped[o] then
-			return "<circular reference>"
-		end
-		dumped[o] = true
-		local t = {}
-		for k, v in pairs(o) do
-			k = dump(k, dumped)
-			v = dump(v, dumped)
-			table.insert(t, string.format("[%s] = %s", k, v))
-		end
-		return string.format("{%s}", table.concat(t, ", "))
-	else
+function dump(o, indent, nested, level)
+	if type(o) ~= "table" then
 		return basic_dump(o)
 	end
+	-- Contains table -> true/nil of currently nested tables
+	nested = nested or {}
+	if nested[o] then
+		return "<circular reference>"
+	end
+	nested[o] = true
+	indent = indent or "\t"
+	level = level or 1
+	local t = {}
+	local dumped_indexes = {}
+	for i, v in ipairs(o) do
+		table.insert(t, dump(v, indent, nested, level + 1))
+		dumped_indexes[i] = true
+	end
+	for k, v in pairs(o) do
+		if not dumped_indexes[k] then
+			if type(k) ~= "string" or not is_valid_identifier(k) then
+				k = "["..dump(k, indent, nested, level + 1).."]"
+			end
+			v = dump(v, indent, nested, level + 1)
+			table.insert(t, k.." = "..v)
+		end
+	end
+	nested[o] = nil
+	if indent ~= "" then
+		local indent_str = "\n"..string.rep(indent, level)
+		local end_indent_str = "\n"..string.rep("\t", level - 1)
+		return string.format("{%s%s%s}",
+				indent_str,
+				table.concat(t, ","..indent_str),
+				end_indent_str)
+	end
+	return "{"..table.concat(t, ", ").."}"
 end
 
 --------------------------------------------------------------------------------
-- 
GitLab