# HG changeset patch # User Matthew Wild # Date 1536583593 -3600 # Node ID bbb49227c1744041948c376e5162efb610843350 # Parent 25530dccf6962e1d816e4b1a8bdda4196ea25161 scansion.pretty: Utility lib for XML pretty-printing, borrowed from Prosody diff -r 25530dccf696 -r bbb49227c174 scansion/pretty.lua --- /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 = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; +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, ""); + 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; +}