Image
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************

ScriptName = "HS_Globals"

-- **************************************************
-- General information about this script
-- **************************************************

HS_Globals = {}

function HS_Globals:Name()
	return "Print Globals"
end

function HS_Globals:Version()
	return "3.93"
end

function HS_Globals:Description()
	return "Print global variables tables"
end

function HS_Globals:Creator()
	return "HayaSidist"
end

function HS_Globals:UILabel()
	return("Print Globals to HTML file")
end

local thisUUT = "E"

-->> Live run **** vvv
local HS_Test_harness = {}
HS_Test_harness.tracePrint = function () end
HS_Test_harness.diagnosePrint = function () end
HS_Test_harness.diagnoseModifierKeys = function () end
--<< ***** ^^^^^^
--[[]]

-- **************************************************
-- The guts of this script
-- **************************************************

function HS_Globals:Run(moho)

	HS_Globals:Execute (moho, _G, "")

end



function HS_Globals:Execute (moho, what, tag)

--
-- show all global variables (recursive traverse of tables)
--
	local seen={}
	local strg, k, v
	local deep = 1
	local qualName = {}	-- the elements of a qualified name
	local header = {}	-- the header last at each level (saves rebuilding it)
	local t0

	local num, str, boo, uDat = "number", "string", "boolean", "userdata"

--	local cAPI1 = "tolua_ubox"
	local cAPI2 = ".collector"
	local cAPI3 = ".set"
	local cAPI4 = ".get"

	local showSystem = false
--	local showSystem = true

	local showNonAlpha = false
--	local showNonAlpha = true


	local doAscii = 1
	local doNotCaseSensitive = 2

	local function strictAscii (a,b)
		return (a<b)
	end

	local function notCaseSensitive (a,b)
		local la, lb
		la = a:lower()
		lb = b:lower()
		return (la<lb)
	end

	local keySort = {strictAscii, notCaseSensitive}

	local sortOpt = doAscii
--	local sortOpt = doNotCaseSensitive


	local function filePath (s, opt) -- opt = true => ensure s is of form <path>file.ext; otherwise return just file.ext

		local i, j, k, n, p, q
		local prefix = "globals"
		local dot = "."
		local suffix ="htm"

		local inStr


		local path = moho:UserAppDir()
		local pc = string.find(path,"\\")
		local mac = string.find(path,"/")
		local delim = ""
		if mac ~= nil then
			inStr = "^(%w*%.*%w*)(/.*)"
		end

		if pc ~= nil then
			inStr = "^(%w*%.*%w*)(\\.*)"
		end


		p = string.reverse (s)

		q, n = string.gsub (p, inStr, "%1")
		q = string.reverse (q)

		if opt then
			i, j = string.find (q, ".", 1, true)

			if #q == 0 then
					s = s .. prefix .. dot .. suffix
			HS_Test_harness:diagnosePrint (thisUUT, "add whole file name")
			elseif #q == i then
				s = s .. suffix
				HS_Test_harness:diagnosePrint (thisUUT, "add suffix")
			elseif #q > 0 and not i then
				s = s .. dot .. suffix
				HS_Test_harness:diagnosePrint (thisUUT, "add <dot> suffix")
			else
				HS_Test_harness:diagnosePrint (thisUUT, "ok???!")
			end
		else
			s = q
		end	

		return s
		
	end





--
-- ** line-by-line output
--


	local function Fitem (type, string, f) -- format a string with attribute
		local err, strg
		strg = "<" .. type .. ">" .. string .. "</" .. type .. ">"
		return (strg)
	end


	local function Fwrite (type, string, f) -- write a line
		local err, strg
		strg = Fitem (type, string, f)
		err = f:write(strg .. "\n")
		return err
	end

	local function Bwrite (type, string, f)	-- begin a type
		local err, strg
		strg = "<" .. type .. ">\n" 
		err = f:write(strg)
		return (err)
	end

	local function Ewrite (type, string, f)	-- end a type
		local err, strg
		strg = "</" .. type .. ">\n" 
		err = f:write(strg)
		return (err)
	end

	local function fmtVal (v2)
		local varType = type(v2)
		local varVal = nil
		local varDisp = nil

		if varType == num then
			varVal = (string.format ("%.6g", v2))
		elseif (varType == str) or (varType == boo) then
			varVal = tostring (v2)
		elseif varType == uDat then
			varVal = HS_formatUserData (v2)
		end

		if varVal then
			varVal = Fitem ("i", varVal) 		-- italic the value
			varDisp = varType ..  "   " ..  varVal
		else
			varDisp = varType	-- varType includes the type tag and an internal address
		end

		return varDisp

	end


--
--
--
--	********************************* identify the output
--

	local function fileId (f)
		local err
		local vers
		local date = os.date ("%d %b %Y %H:%M:%S")  -- see http://pubs.opengroup.org/onlinepubs/007908799/xsh/strftime.html 


		err = Bwrite ("p", "", f)
		err = Fwrite ("li", self:Description() .. "  Version " .. self:Version() .. "<br>", f) -- identfy this program
		err = Fwrite ("li", "Print created: " .. date .. "<br>", f) 			-- timestamp 

 
		if type (MOHO.ScriptInterface.AppVersion) == "function" then  		-- identfy Moho version (if there)


			local MohoVers = 0
			MohoVers = tonumber((string.gsub(MOHO.ScriptInterface.AppVersion(), "^(%d+)(%.%d+)(%..+)", "%1%2")))

			if MohoVers < 12 then 
				vers = "Anime Studio Version  "
			else
				vers = "Moho Version  "
			end
			vers = vers .. Fitem ("b", moho:AppVersion(), f)
			err = Fwrite("li", vers, f) 			-- identfy
		end

		err = Ewrite ("p", "", f)

		return err
	end

--
--	********************************* the main table / entry print routine
--
	local function dump(t, level, f)
--
--	t is the table to dump; level is the table level (1 = outermost), f is the file identifier
--

		deep = deep +1
		local simple = {}			-- place to store simple data types
		local tables = {}			-- place to store tables ... 
		local systems = {}			-- place to store system type data ...
		local nonAlpha = {}			-- and the non-stringy keys (e.g. functions)
		local ns, nt, nx, nq = 0, 0, 0, 0	-- TABLES START AT _ONE_ not zero!!!! Increment index BEFORE store!!
		local j=0


 		seen[t]=true			-- we've done this table
		nx, nq = 0, 0
		for k, v in pairs(t) do		-- take the keys and values from table t

			HS_Test_harness:diagnosePrint (thisUUT, k, type(k))

			if type(k) == "string" then
				if (string.sub(k,1,1) ~= "_") 
--				and (k ~= cAPI1)
				and (k ~= cAPI2)
				and (k ~= cAPI3) then
					if type(t[k]) == "table" then
						nt = nt + 1
						tables[nt] = k
					else
						ns = ns + 1
						simple[ns] = k
					end
				else
					nx = nx +1 		-- count of "systems-y" keys
					systems[nx] = k
				end
			else
--
-- 	other key type (e.g. function)
--
				HS_Test_harness:diagnosePrint (thisUUT, strg, "has key of type", type(k))
				nq = nq +1			-- count of non-string keys
				nonAlpha[nq] = k
			end
		end



		table.sort(simple, keySort[sortOpt])		-- sort the keys (table s has a list of keys; the "v in s" is the "k of t")
		table.sort(tables, keySort[sortOpt])		
		table.sort(systems, keySort[sortOpt])		
		table.sort(nonAlpha, keySort[sortOpt])		

--
--	report the tables
--
		if showNonAlpha then 

			for k,v in ipairs(nonAlpha) do
				HS_Test_harness:diagnosePrint (thisUUT, type(t[k]), tostring(t[k]), tostring(t[v]))

--				qualName[deep] = v

				v = "key " .. type(t[k])
				local varDisp = tostring(t[k])

				v = Fitem ("b", v)	-- format the tag as bold

				strg = v .. "   " .. varDisp 
				err = Fwrite("li", strg, f)

			end


		else
			if nq > 0 then
				strg = "table has " .. tostring (nq) .. " non-alphanumeric keys"
				strg = Fitem ("b", strg) 		-- bold the value
				err = Fwrite("li", strg, f)
			end
		end


		if showSystem then 
			for k,v in ipairs(systems) do
				HS_Test_harness:diagnosePrint (thisUUT, k, v, type(t[v]), t[v])

				qualName[deep] = v

				local varDisp = fmtVal (t[v])

				v = Fitem ("b", v)	-- format the tag as bold

				strg = v .. "   " .. varDisp
				err = Fwrite("li", strg, f)
			end
		else
			if nx > 0 then
				strg = "table has " .. tostring (nx) .. " hidden keys"
				strg = Fitem ("b", strg) 		-- bold the value
				err = Fwrite("li", strg, f)
			end
 		end

			


		for k,v in ipairs(simple) do
			HS_Test_harness:diagnosePrint (thisUUT, k, v, type(t[v]), t[v])

			qualName[deep] = v


			local varDisp = fmtVal (t[v])

			v = Fitem ("b", v)	-- format the tag as bold

			strg = v .. "   " .. varDisp
			err = Fwrite("li", strg, f)

 		end

		for k,v in ipairs(tables) do
			HS_Test_harness:diagnosePrint (thisUUT, k, v, type(t[v]), t[v])

			qualName[deep] = v


			local varDisp = ""
			local v2 = t[v]
			local varType = type(v2)
			local varVal = tostring (v2)


	  		if not seen[v2] then
				HS_Test_harness:diagnosePrint (thisUUT, "Deep=", deep, qualName[deep])

				if qualName[1] == "" then
					strg = ""
				else
					strg = qualName[1] .. "."
				end
				for j = 2, deep-1 do
					strg = strg .. qualName[j] .. "."
				end

				if v == cAPI4 then
					header [level+1] = strg .. "[" .. cAPI4 .. "]"
					strg = strg .. "   Attributes:"
				else
					strg = strg .. qualName[deep]
					header [level+1] = strg
					strg = strg .. " Table begin"
				end

				err = Fwrite("h"..tostring(level+1), strg, f)
				err = Bwrite("ul", "", f)


 	  			dump(v2, level+1, f)

			end

 		end



--
-- show end of indented table details
--

		err = Ewrite("ul","", f)
		strg = "end"
		err = Fwrite("h"..tostring(level), strg, f) -->> level not checked -- assumed less than the 6 supported in html5

		deep = deep - 1

	end




--
-- ********************* Run code starts here
--
	local thisUUT = "A"
	HS_Test_harness:tracePrint (thisUUT, self:Name(), self:Version())
	HS_Test_harness:diagnosePrint (thisUUT, type(what), tag)


	if type(what) == "table" then
		t0 = what
	elseif type(what) == "nil" then
		t0 = _G
	elseif type(what) == "function" or type(what) == "thread" then
		t0 = nil
	elseif type(what) == num then
		t0 = (string.format ("%.6g", what))
	elseif (type(what) == str) or (type(what) == boo) then
		t0 = tostring (what)
	elseif type(what) == uDat then
		t0 = HS_formatUserData (v2)
	end



	if type (tag) ~= str then
		if type(t0) ~= str then
			qualName[1] = ""
		else
			qualName[1] = type(what)
		end
	else
		qualName[1] = tag
	end

	strg = qualName[1]

	HS_Test_harness:diagnosePrint (thisUUT, "validated inputs", type(t0), strg)

	
	if type(t0) == "table" then

--
-- ** open file for write and recursively dump the tables...
--

	local path = LM.GUI.SaveFile("save globals to file?")

		if path == "" then
			return false		-- cancel pressed
		end

		path = filePath(path, true) -- fill in filename and extension if necessary

		local f, err = io.open(path, "w")
		if (f == nil) then
			err = "file open error: " .. err
			LM.GUI.Alert (LM.GUI.ALERT_WARNING, 
				err, nil, nil, 
				"OK", nil, nil)
			return
		end

		err = Bwrite("!DOCTYPE html", "", f)
		err = Bwrite("html", "", f)
		err = Bwrite("body", "", f)

		if strg == "" then
			strg =  "Global Table (_G)"
		end


		err = fileId (f) -- identify the output


		local level = 1
		header[level] = strg
		strg = strg .. " begin"


		err = Fwrite("h1", strg, f)
		err = Bwrite("ul", "", f)


		dump(t0, level, f) -- level 1 to start -- but level and deep NEED NOT be the same (but usually are!)

		err = Ewrite("ul", "", f)
		err = Ewrite("body", "", f)
		err = Ewrite("html", "", f)
		f:close()

		if os.execute () then -- check for os shell and throw the output file at it if the "open" button is pressed

			local openOutput = 0
			local doWhat = LM.GUI.Alert (LM.GUI.ALERT_INFO, 
				"output is in " .. path, nil, nil, 
				"Open", "OK", nil)

			if doWhat == openOutput then
				path = filePath(path, false)
				local ok, err = os.execute (path)
				if not ok then
					LM.GUI.Alert (LM.GUI.ALERT_INFO, 
					"Could not execute " .. path, "System returned " .. err, nil, 
					"OK", nil, nil)
					HS_Test_harness:diagnosePrint (thisUUT, "execute failed ", err)
				end
			end
		else

			LM.GUI.Alert (LM.GUI.ALERT_INFO, 
				"output is in " .. path, nil, nil, 
				"OK", nil, nil)
		end

	elseif type(t0) == "string" then

		LM.GUI.Alert (LM.GUI.ALERT_INFO, 
			strg, t0, nil, 
			"OK", nil, nil)

	else

		LM.GUI.Alert (LM.GUI.ALERT_INFO, 
			"Cannot display value of " .. tag,
			"it is of type " .. type(what),
			nil, 
			"OK", nil, nil)

	end


	return true

end

Print Globals to HTML
Listed

Script type: Button/Menu

Uploaded: Jul 15 2022, 03:30

Last modified: May 12 2023, 04:49

Script Version: 3.93

Outputs a snapshot of the whole Global table to an HTML file
HS_Globals – version 3.93
==========================
This script scans the list of global variables used within Moho and creates a list of these and, for variables, their instantaneous values in an html file.

Minor changes  from 3.83 (last published version) in the output formatting. Minor code re-structuring for future enhancement. 

Installation
=============
Copy the script file to
   \scripts\menu\Script Writing
(or any other directory as required)


Requires:
========
HS_formatUserData.lua - this need to be in the utilities folder.



Operation
==========
Navigate to
>> Scripts / Script writing / Print Globals to HTML file

When prompted, enter a valid path and file name. The script will add “.html” as a suffix if not entered.
Press “save”. (Pressing “cancel” abandons the operation.)
If the file already exists confirm that it is OK to overwrite.

When the script has run an information pop-up will be presented giving the full path of the created file. If the operating system supports commands from LUA, there will be two buttons:
>> “Open” will invoke the browser and open the output file. If this operation fails it will do so without issuing any diagnostic, but the output file will still be saved.
>> “OK” to acknowledge the message and exit without opening the file.

If the operating system does not support commands from LUA, only the “OK” button will be presented.


(note that the standard Moho utility is in the same menu list as simply “Print Globals” – this lists the globals on the LUA console).


Known Issues
==============
None.

Installation Options:

This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 606