1
0
An advanced pretty printer, aiming for human readability.
Go to file
takunomi-build-bot 72475b05bd
Some checks failed
LÖVE/Lua Library / Lua-Testing (push) Failing after 8s
LÖVE/Lua Library / Static-Analysis (push) Failing after 4s
🤖 Bumped version to 0.5.7
This commit was automatically generated by [a script](https://gitfub.space/Jmaa/repo-manager)
2025-04-17 17:05:03 +02:00
.gitea/workflows 🤖 Repository layout updated to latest version 2025-04-17 16:30:39 +02:00
test Minoir changes 2017-12-11 11:04:11 +01:00
.gitignore 🤖 Repository layout updated to latest version 2025-04-17 17:04:38 +02:00
.luacheckrc 🤖 Repository layout updated to latest version 2025-04-17 16:30:39 +02:00
analyze_byte_string.lua Cdata is now being tested against again, and some unicode stuff has been implemented. 2017-10-22 14:26:19 +02:00
analyze_structure.lua Better has_uniform_structure. 2017-10-22 12:29:43 +02:00
cdata.lua Merged cdata into master, and added some tests. 2017-08-07 10:39:45 +02:00
common.lua Minoir changes 2017-12-11 11:04:11 +01:00
function.lua Fixed alignment issue for certain tables. 2017-11-18 13:23:43 +01:00
init.lua 🤖 Repository layout updated to latest version 2025-04-17 16:30:39 +02:00
library.lua Some utf8 tests and fixing minor library issues. 2017-07-31 16:29:56 +02:00
LICENSE 🤖 Repository layout updated to latest version 2025-04-17 16:30:39 +02:00
number.lua Added new common file, where DISPLAY variable has been moved to. 2017-10-09 13:54:56 +02:00
pretty.lua 🤖 Bumped version to 0.5.7 2025-04-17 17:05:03 +02:00
pstring.lua Implemented shortening of decimal escaped charaters, when at end of cut-strings. 2017-10-23 14:40:30 +02:00
README.md 🤖 Repository layout updated to latest version 2025-04-17 16:30:39 +02:00

Pretty

pretty is an advanced pretty printer for Lua.

It's primarily a debugging tool, aiming for human readability, by detecting pattern in the input data, and creating an output string utilizing and highlighting those patterns.

Code Example

Setup is simple, use pretty = require 'pretty', and you're good to go.

$ print(pretty( { 1, 2, 3 } ))
{ 1, 2, 3 }

$ print(pretty( { hello = 'world', num = 42 } ))
{
    num   = 42
    hello = 'world'
}

$ print(pretty( { abs = math.abs, max = math.max, some = function() end } ))
{
    abs  = builtin function (x)      ... end
    max  = builtin function (x, ...) ... end
    some =         function ()       ... end
}

$ print(pretty( math.abs ))
builtin function (x)
    -- math.abs
    -- Returns the absolute value of x

    ...
end

Motivation

This project is the outcome of my frustration with existing pretty printers, and a desire to expand upon the pretty printer I developed for Xenoterm. The original Xenoterm pretty printer was much simpler than pretty - and the current is even simpler - but the enhancements I make, when compared to other pretty printers, inspired me to create pretty.

pretty sorts it's priorities like so:

  1. Human readability.
  2. Lua-compatible output.
  3. Customization.

I'd rather have good defaults than provide a ton of customization options. If an structure avoids easy representation in Lua, I'd rather extend the syntax, than lose the info.

Another aspect where pretty shines is in exploratory programming, when attempting to avoid reliance on outside documentation. The amount of information pretty exposes varies by the data you are inspecting. If you're inspecting a list of functions, their function signatures are visible, but if you're inspecting a single function, documentation and source location may appear if available.

Features

  • Written in good-old pure-blood Lua, with support for PUC Lua 5.0+ and LuaJIT 2.0+.
  • Redefining what it means to be "human readable":
  • Is multi-line centric, to aid readability.
  • Indention and alignment of keys-value pairs.
  • Keys-value pairs are alpha-numerically sorted by key type and thereafter alphabetically.
  • The format and structure of output changes depending upon the input. Maps appear differently to deeply nested tables to long sequences with short strings to short lists.
  • Uses the standard debug library to gain information about functions and other advanced structures.

Installation

pretty is loadable directly with require. Either clone or download this repository. Where you place it, depends upon what you want to do:

  1. You want pretty in a specific project: Place the pretty folder somewhere in your project, and require it from one of your project files.
  2. You want pretty on your system: Place the pretty folder such that it's visible from your Lua-path. On my system this might be /usr/local/share/lua/5.1/. Now you can require it from anywhere.

API Documentation

pretty exposes a single function, the pretty function itself. It's function signature is pretty(value, options). value can be any Lua value. options must be a table.

pretty is sure to complain if you give it an unknown option, or if you give an option a bad value.

  • indent: string: The string to indent with. Four spaces by default.

TODO

Tasks to be done before pretty can be called version 1.0.0, in order of priority:

  • Add dedicated unicode submodule, to handle some minor alignment and character escaping issues. pretty should escape all malformed unicode sequences.
  • Align numbers towards right for tabular views.
  • Add support for setmetatable, and exploring values in metatables.
  • Provide nice formatting for cdata datatype in LuaJIT.
  • Find a better name than pretty.
  • Enhance internal structure some amount. See TODO markers in files.

It would be nice to have the following, but these are secondary:

  • Add option for colored output. Primarily syntax highlighting, but also BlueJ-style scope highlighting, with some faint background colors.
  • Expand on the comment output in output, for __tostring methods, and global namespaces like io or math.
  • Fit output within a predefined width limit. Default to 80.
  • Look into tool for understanding complex structures with recursive definitions. Whatever modes are thought up, they should be automatic modes, not an options. Should at least include modes for self-referential tables and Directed-Acyclic-Graphs.

Alternative pretty printers

pretty is large, slow, and requires the debug library to work. It's not designed for serialization purposes, nor is it concerned with offering the same level of customization as other libraries do.

If you want a sleek, fast, customizable or embeddable library, there are thankfully other options.

  • inspect.lua: One of the classic debugging pretty printers.
  • pprint.lua: Reimplementation of inspect.lua
  • serpent: Advanced and fast pretty printer.
  • pluto: Can serialize arbitrary parts of Lua, including functions, upvalues, and proper lexical scoping. Not written in native Lua.
  • binser: Library for special purpose serialization.

Even more are available at the lua-users wiki.

Thoughts on displaying tables in an intuitive way.

Lua's table data-structure is likely to be the most concise data structure ever invented. (If not, please send me a link!) Lists, maps, objects, classes, proxies, etc. This obviously brings about it some difficulty when attempting to represent these tables. What do we want to highlight, and what do we choose to avoid?

One notable issue is whether to show every key that a table answers (to lift some Smalltalk terms) to, or to just display those it contains. That is, do we think about __index in the table's metatable and what it returns, or do we ignore __index? For cases where __index is a function, we cannot say anything about the keys that the table answers to. If __index is a table, we have a better idea, but it would be cluttered to display both types of keys side by side.

  1. Native representation: Lua's native representation includes the type and address of the table. It allows for distinguishing between unique tables, but won't tell us anything about the contents.
  2. Omission: By representing tables as the pseudo-parsable {...}, it's clear we are talking about a table. We disregard the ability to distinguish between tables.
  3. If the table is empty, we could represent it as {}. But what if the table has a metatable with __index defined? We could continue to represent it as {}, but {...} would be more "honest".
  4. Single-line: TODO
  5. Multi-line: TODO
  6. Columns: For some highly-regular structures, like lists of short strings, giving each string it's own line would be too long, but formatting them as a single-line list would be too cluttered. Thus we can take inspiration from the classic ls unix tool, and place the output into columns, to help guide the eyes.
  7. Tabular: Other structures are formatted like actual tables of data, e.g. a sequence of tuples, like one would see in an SQL database. For these structures it's an obvious choice to align them based on the keys.
  8. Pseudo-Tabular: Some structures are almost tabular, e.g. they are sequences of tuples, but some of the tuples differ in their structure. For these structures it's still useful to tabulate the keys that all tuples share. To do this we should sort the key order descending by the number of tuples with the key. But what do we do about the the outlier keys? We can either justify the entire table, and give specific spots for the outlier keys, thereby significantly increasing the size of the table, or we can leave the table unjustified, abandoning it's eye-guiding attributes.
  9. Special cases: (Array-tree, Table-Tree, Linked-List, Predictive Sequences) TODO

Dependencies

This project requires PUC Lua 5.1 or LuaJIT. Newer versions of PUC Lua are not supported.

This project does not have any library requirements 😎

Contributing

Feel free to submit pull requests. Please follow the Code Conventions when doing so.

License

MIT License

Copyright (c) 2016-2025 Jon Michael Aanes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.