Colored console debug and development tools with various inspection features and customizations available. Its purpose is to quickly throw relevant info about what you're working on right into the console during runtime.
As of the above date the latest version I use in my engine has been pushed which is a big refactor. Some of the data in the below readme may be outdated. The following is the latest implementation guideline for consolecandy:
ccandy:export(n)- export the whole thing into the global namespace with n prefix (_c_is defaulted if n is nil) <-- personally I've stopped using this and have been doing:_G.console = require 'consolecandy'thus commands in my codebase look likeconsole.debug(t)for instance
ccandy.debug(t)- This is the bread and butter of this library and may be all anyone wants to use. This has been worked on ad nauseum to become a powerful tableprinter. This will print an entire table to the console, tabbed for formatting, detecting recursion (kind of) and collapsing nested tables further than one layer. Checks tables for keys and considers them when it determines size. Collapsed tables are instead printed like this:TABLENAME = (table) [ addr:0x0119d9fb10 #len:0 keys:3 depth: > LIMIT (9) ],.Lenis the index length,keysis how many non-indexed values are in the table,depthis how deep the table goes. There are still some problems with recursion detection (I think after a certain self-referencing depth it fails to detect that it's recursing) sotableDepthLimitclamps the depth testing -- if you see> LIMIT (#)then it probably got looped into recursion.- Also useful: with the exception of some userdata stuff and metatables, this will also specify the primitive types of all values found in a table
level,parseStart,depthAre tweaks that you could go without using, but if you want to,levelspecifies a limit on how far back the filename prepend will print,parseStartindicates where to start on the call line, anddepthis the table dive depth limit which will override the default.
ccandy.title(t)- prints a==============================================Dirty Separator==============================================- For quick and dirty console eyeballing. Centering is planned at some point.
todo,warn,error,stop,reminderall work as below in the documentation still. They may be deprecated/removed from the module at some point. There was a reason behind all of them but as I've been developing the engine I use this in more, I've used these features much, much less. The most-used of these for me areccandy.warn()andccandy.todo().todolets you specify a "due by" date at which point it will change color to red.
A quick tl;dr of most features in this library:
- A lot of uses of these features is modular. Except for
debug, most or all of the error message throwing methods accept a string, a table, or a function and will adapt to each. Thus you can pass complicated messages to the outputs. - All the colors are configurable. A lot of things like tabs are configurable. Please make an issue if any configurations don't work, because it's likely they were changed but the documentation not fixed.
- All methods print the filenames they came from, as well as the lines they were called from in code. They trace back so you can see how far back they go - using the stack to indicate the trace they were called from. This is configurable globally or per-call.
For generating this text, see Example 1
- Installation
- Latest Features - updated 01/04/2025
- Functions
- Arguments
- Customizing
- Examples
- Some Notes
- ToDo List
require "debugcandy.lua"will put theccandynamespace into Global, putting all tools there.require ("path.debugcandy.lua"):export(n)will export all of the functions into the Global namespace with the optionalnprefix.- Leaving
nblank will use the prefix_c_to avoid overwriting common Lua and Löve names likeerror
Last updated 01/04/2025
- Sequential files are now collapsed into a "line path" so
[update.lua:100][update.lua:55][update.lua:2]becomes[update.lua:100:55:2]. - New Customizations! All globals are now local to the library now too. (see Customizations )
- New Optional argument:
parseStartthat modifies how many lines of the stacktrace are ignored - Most commands can now call a function if they find them in the
msg(orreminderList) table. See Example 2 for an example of how to do this. - Background colors are now an option, although I have yet to play around with them to figure out what looks good as defaults. The default bgs I set are eyesores, so they are turned off by default.
debug(msg,level,parseStart)Default BluePrints detailed information on every value including variable type and, if it finds a nested table, it will show how many indices, keys, the memory address, and the depth (recursion is still an issue for me, so it stops at 9 for now). Will not call functions, but instead show that the function is there and the addresss. See Example 3 for an example ofdebug()printing a table.
warn(msg,level,parseStart)Default Yellow. Takes a string or indiced table, will call functions as it finds them.
error(msg,level,parseStart)Default Red. Takes a string or indiced table, will call functions as it finds them.
stop(msg,level,parseStart)Default Red. Callsccandy.error()and then uses Löve's inbuilterror()to stop the game completely. Lets you use the library's ownccandy.error()function, while retaining Löve's program-stopping feature of the builtinerror()
todo(msg)Default Cyan. Generates a ToDo[ ]list from the indiced table. Does not acceptfunctions. If it finds a date in format of01/01/2025it will compare it withos.time(). If the number of days is>= toDoExpirationit will throw a warning. The warning iswarning colorat first, thenerror coloratdays x 3. Will interpret capitalXat the beginning of a string as a checkmark on the item[X]. Note: will parse the first date it finds then treat subsequent datestrings as todolist items. It will otherwise discard the first date it finds after evaluating the expiration status.- Since it basically is meant to be called with a table only, it is more Lua-esque to call it like this:
todo{"01/01/2025","todo1","todo2","Xtodo3"}
- Since it basically is meant to be called with a table only, it is more Lua-esque to call it like this:
remind(setDate,remindDate,reminderList)Default Yellow. Liketodo{}it usesos.time()to check the dates. Checks againstremindDateand, if that date has passed, will print how many days it's been sincesetDateand then print the indiced items ofreminderList. Will call both indiced and non-indiced functions, first calling the indiced ones then the non-indiced ones. It also prints a visually distinct header and footer, which can be set per Customization below.
blank(msg,lines)- Prints blank newlines to the console, with an optional message. Can be called as
blank(),blank(lines), orblank(msg,lines). Iflinesis empty, will default to 10 newlines.
- Prints blank newlines to the console, with an optional message. Can be called as
- Helper functions that can be used directly:
printC(ANSI, ...)- Where
ANSIis either an ansi code or a string of color names, and...must be a string. It can accept two formats of color string:"yellow"will make the text color (FG) yellow, while"yellow|blue"will make the FG yellow and the BG blue. The library uses this function internally passing direct ANSI escape codes constructed at the time the other tools are called, but this function is also available for direct access.
- Where
printCTable(cTable, sTable)- Calls
printCin sequence according to the index values ofsTable, matching them with the corresponding indices incTable. If you pass a string for the first argument it will use that for every call, instead.
- Calls
All arguments are optional. Using any function with no arguments will result in defaults being used no message being printed.
msg- An indiced table or a string which gets printed.
debug()will print non-indiced keys, as well. Default just prints blank. If a function is found, most tools will call that function (see the functions list for details)
- An indiced table or a string which gets printed.
level- The level of files to parse back in the stacktrace. E.g.
[data.lua:10][src.lua:10]. It attempts to avoid showing its own filename for obvious reasons. Default isCANDYDEBUGBASELEVELbelow.
- The level of files to parse back in the stacktrace. E.g.
parseStart- How many files of the traceback are omitted in the output. You can usually leave this alone, as the code has been generally tweaked to avoid unnecessary info (such as showing that every function comes from
debugcandy.lua. However, if you are including the library nested further than one or two additional files, you might want to use this. The default starts at4so tweak accordingly.
- How many files of the traceback are omitted in the output. You can usually leave this alone, as the code has been generally tweaked to avoid unnecessary info (such as showing that every function comes from
All of these have default values that produce the results you see in the screenshots.
- Data Output Customizations:
ccandy.colorsOff: turns all colors off. Will not affect already-printed outputs. False by default.ccandy.debugOn: Used to activatedebug(),todo(), andremind()ccandy.baseLevel: For iflevelis not passedccandy.pathDepth: If>0, this will add paths to the parsed stacktrace itself, e.g.:[src/states/game.lua:100]ccandy.tabledepthlimit: how fardebug()will parse a nested table before stopping.ccandy.toDoExpiration: How many days can pass beforetodo()shows warnings
- Visual Customizations:
ccandy.reminderheaderandccandy.reminderfooter: are printed before and after reminders to make them standout. They look like the screenshots by default.ccandy.todotab: how far indented the todolist isccandy.backgrounds: defaults to false. If true, will useccandy.backgroundsto print background colors to all options. Can be set individually, seeccandy.bgcolorsccandy.colors: are the colors printed by different functions. These are strings. Can also use ANSI escape codes, ex:warn = "\x1B[31m"this will make warnings print red instead of yellow. If you're familiar with these escape codes you can add things like underlines, bold, italics etc. to the output.warn = "yellow"error = "red"debug = "blue"todo = "cyan"remind = "yellow"success = "green"
ccandy.bgcolors: Only used ifccandy.backgroundsis on. These are off by default. Set to nil or "" to turn off individual ones instead. NOTE: These defaults are probably eyesores. Your dev is actually partially colorblind, so matching colors is not my strong suit. I do not use backgrounds. As a personal recommendation, background colors with plain white or black text looks nice though, so probably tweak both if you're going to turn backgrounds on.warn = "red"error = "white"debug = "magenta"todo = "magenta"remind = "black"success = "white"
_c_warn("A new console library is in town!")
_c_blank(0)
_c_debug{sup = "sup","you can debug a table and print it with a bunch of data",x=10,y=20,sheesh = "sheesh",isTrue=false}
_c_blank(0)
_c_todo{"02/02/2024","Make an old todo list","todo() can throw a warning if it's been too long since you've updated","Show off features"}
_c_blank(0)
_c_remind("01/03/2025","02/03/2025",{"Clean up _g^crash deprecations",f = function() _c_todo{"Evaluate deprecation stubs","Evaluate namespace stubs","Do the dishes","XMake a todo list","XPost something in time for Vornmas"}end})
_c_blank(0)
_c_error("this is an error, jack",2)
_c_blank(0)
_c_success("successful something or other", 3)
_c_blank(0)
_c_success()
_c_blank("Also I thought it'd be nice to be able to blank the console (blank(n) just prints n or 10 blank lines")This type of function usage is called functional programming:
local function throwDebugError(bad_thing,level,parseLevel)
return function _c_debug(bad_thing,level,parseLevel) end
end
---somewhere in your code where you need a hard assertion:
if bad_thing then
_c_stop{"bad_thing happened! Debug Output", throwDebugError(bad_thing,level,parseLevel)}
endAn example of debug() printing a table:
- File parsing will remove spaces because the stack trace produces a lot of formatting, and debugcandy removes that in favor of its own. That said, if the filename has a space in it, that space will be removed. I don't personally plan to tweak this to "fix" this situation, because spaces are a pain in code files anyway so I never use them, and it's generally not recommended.
- Most of the time, I am attempting to follow Lua style recommendations for cleaner code. Please leave feedback if you use this and find any issues with the formatting!
- This is not a "live updating" debug tool, nor is it a visual GUI debug tool. There aren't plans for one either. It outputs a static console output, and is meant for during-development stages. Heavy use of these tools will affect game performance, so be sure to erase and comment out your uses of these tools when you're not needing them! (and turn off
debugOn) - This library probably won't dig into memory profiling. If and until it does, pick something from the Awesome Löve repo instead.
Planned for the future
- Example images or code for features that don't have examples
- Play with background settings to produce defaults that look nice.
- On that note, it seems reasonable that an optional "swap" flag could be passed to flip bg/fg situationally
- Dig deeper into ANSI escape sequences to provide more shortcuts to those features.
- Improve recursion detection by
debug()sotableDepthLimitcan be expanded safely (I'm not sure the lib is doing it right). - Memory usage statistics of tables in
debug()? This might be out of scope for this library. Maybe just use a memory module from