scansion.pretty: Utility lib for XML pretty-printing, borrowed from Prosody

Mon, 10 Sep 2018 13:46:33 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Mon, 10 Sep 2018 13:46:33 +0100
changeset 112
bbb49227c174
parent 111
25530dccf696
child 113
f5c1ccc58b48

scansion.pretty: Utility lib for XML pretty-printing, borrowed from Prosody

scansion/pretty.lua file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scansion/pretty.lua	Mon Sep 10 13:46:33 2018 +0100
@@ -0,0 +1,76 @@
+require "verse"
+local xml = require "scansion.xml";
+local s_format, s_gsub = string.format, string.gsub;
+
+local escape_table = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
+local function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end
+
+-- Dummy functions compatible with util.termcolours,
+-- just in case we add colour in the future
+local function getstyle() return "" end
+local function getstring(style, text)
+	if not style then
+		text = style;
+	end
+	return text;
+end
+
+local default_config = {
+	indent = 2;
+	preserve_whitespace = false;
+};
+
+local function new(user_config)
+	local config = setmetatable({}, { __index = function (_, k) return user_config[k] or default_config[k]; end });
+	local style_attrk = getstyle("yellow");
+	local style_attrv = getstyle("red");
+	local style_tagname = getstyle("red");
+	local style_punc = getstyle("magenta");
+
+	local attr_format = " "..getstring(style_attrk, "%s")..getstring(style_punc, "=")..getstring(style_attrv, "'%s'");
+	local open_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">");
+	local close_tag_format = getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">");
+	local tag_format = open_tag_format.."%s"..close_tag_format;
+	local short_close_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, "/>");
+	local function pretty_print(t, ind)
+		ind = ind or config.indent;
+		local children_text = "";
+		for i, child in ipairs(t) do
+			if type(child) == "string" then
+				if config.preserve_whitespace or child:match("%S") then
+					children_text = children_text .. "\n"..string.rep(" ", ind) .. xml_escape(child);
+				end
+			else
+				children_text = children_text .. "\n" .. pretty_print(child, ind+config.indent);
+			end
+		end
+
+		local attr_string = "";
+		if t.attr then
+			for k, v in pairs(t.attr) do
+				if type(k) == "string" then
+					attr_string = attr_string .. s_format(attr_format, k, tostring(v));
+				end
+			end
+		end
+
+		local use_tag_format = tag_format;
+		if #t == 0 then
+			use_tag_format = short_close_tag_format;
+		end
+		if children_text ~= "" then
+			children_text = children_text .. "\n" .. string.rep(" ", ind);
+		end
+
+		return string.rep(" ", ind)..s_format(use_tag_format, t.name, attr_string, children_text, t.name);
+	end
+
+	return function (s, ind)
+		local doc = assert(xml.parse(s));
+		return pretty_print(doc, ind);
+	end
+end
+
+return {
+	new = new;
+}

mercurial