My avatar. Arnaught A pride flag.

Picotron pretty_printh and ANSI Codes for Colored Logs

October 16, 2024 | Tags: picotron programming


This isn’t a Picotron specific thing, but you can use ANSI escape codes inside printh to make your logs colorful, which can be helpful with debugging.

A demo of Pretty Printh
A demo of Pretty Printh

To set the color, typically you do \033[38;5;<COLOR>m or \033[38;2;<RED>;<GREEN>;<BLUE>m. This sets the foreground color to a color from this chart or an RGB color code (if your terminal supports truecolor).

This just works in Picotron, but you have to do \27 instead of \033. (This is the escape code for ESC, which is 27 in decimal and 033 in octal.)

However, writing ANSI codes by hand is a pain, so I wrote a function to make inserting these codes easier, using a bbcode-like syntax.

function pretty_printh(s)
	s = s
		:gsub("%[fg=(#?%w+)]", function (c)
			if c:find("^%d+$") then
				return string.format("\27[38;5;%sm", c)
			end

			if c:find("^#[%da-fA-F][%da-fA-F][%da-fA-F][%da-fA-F][%da-fA-F][%da-fA-F]$") then
				return string.format(
					"\27[38;2;%d;%d;%dm",
					tonum("0x" .. c:sub(2, 3)),
					tonum("0x" .. c:sub(4, 5)),
					tonum("0x" .. c:sub(6, 7))
				)
			end
		end)
		:gsub("%[/fg]", "\27[39m")
		:gsub("%[bg=(#?%w+)]", function (c)
			if c:find("^%d+$") then
				return string.format("\27[48;5;%sm", c)
			end

			if c:find("^#[%da-fA-F][%da-fA-F][%da-fA-F][%da-fA-F][%da-fA-F][%da-fA-F]$") then
				return string.format(
					"\27[48;2;%d;%d;%dm",
					tonum("0x" .. c:sub(2, 3)),
					tonum("0x" .. c:sub(4, 5)),
					tonum("0x" .. c:sub(6, 7))
				)
			end
		end)
		:gsub("%[/bg]", "\27[49m")
		:gsub("%[u]", "\27[4m")
		:gsub("%[/u]", "\27[24m")
		:gsub("%[b]", "\27[1m")
		:gsub("%[/b]", "\27[22m")
		:gsub("%[i]", "\27[3m")
		:gsub("%[/i]", "\27[23m")

	printh(s .. "\27[0m")
end

function error(msg)
	pretty_printh("[fg=1][b][ERROR][/b][/fg]: " .. msg)
end

function warn(msg)
	pretty_printh("[fg=3][b][WARNING][/b][/fg]: " .. msg)
end

function info(msg)
	pretty_printh("[fg=4][b][INFO][/b][/fg]: " .. msg)
end

Here’s the code that I used to get the example in the screenshot:

function left_pad(s, ch, len)
	while #s < len do
		s = ch .. s
	end

	return s
end

function _init()
	pretty_printh("[fg=6][b][u]Pretty Printh Demo[/u][/b][/fg]")

	for i = 0, 15, 4 do
		str = string.format(
			"[fg=%d]color %s[/fg]\t[fg=%d]color %s[/fg]\t[fg=%d]color %s[/fg]\t[fg=%d]color %s[/fg]",
			i, left_pad(tostr(i), "0", 2),
			i + 1, left_pad(tostr(i + 1), "0", 2),
			i + 2, left_pad(tostr(i + 2), "0", 2),
			i + 3, left_pad(tostr(i + 3), "0", 2)
		)

		pretty_printh(str)
	end

	error("this is an error")
	warn("this is a warning")
	info("this is informative")

	pretty_printh("this is a line with [b]bold[/b], [i]italics[/i], and [u]underlines[/u]")

	pretty_printh("[bg=#ffffff][fg=#241f31]this is a line with hex colors[/fg][/bg]")
end

This post was originally posted on the Picotron BBS. The code for pretty_printh can also be found at this gist.