From 213036b1ede66e7f6496054c6e70d404ab64099d Mon Sep 17 00:00:00 2001 From: LordOfSpelunky <147883041+LordOfSpelunky@users.noreply.github.com> Date: Mon, 20 May 2024 12:51:37 -0700 Subject: [PATCH] Initial draft --- docs/pretty-tables.md | 142 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 docs/pretty-tables.md diff --git a/docs/pretty-tables.md b/docs/pretty-tables.md new file mode 100644 index 0000000..3d65876 --- /dev/null +++ b/docs/pretty-tables.md @@ -0,0 +1,142 @@ +# `table.pretty` and changes to printing tables + +## Summary + +We will add a function to display a pretty version of a table for debugging purposes. We will use this function as the backbone to changing the default implementation of `print(table)` in CLI contexts. + +## Motivation + +In Roblox Studio, printing out a table with "Log mode" off will display an interactive table. In roblox-cli, Lune, and luau.exe, it will print the memory address, which is faintly useful, and makes debugging tables a massive chore. Making tables pretty print is a clear win in this regard. + +Adding a function to create these pretty forms and using that as the underlying implementation behind `print` is useful for custom loggers that do not use print and go to file, or for something like debug commands. + +## Design + +### `table.pretty` + +The following function will be added to the standard library: + +`table.pretty(input: { [any]: any }, indentation: number?): string` + +`indentation` defaults to 2. + +For a non-empty table, this will perform the following behavior: + +1. The initial opening and ending brace will be on their own line +2. Form the string `[$key]: $value,` for every key and value, based on the same behavior as generalized iteration, even using `__iter` if it exists. + - `$key` and `$value` will be pretty printed if it is both a table and if it would be acceptable to do so (no `__metatable`). This will be indented `indentation` number of spaces. + - If `$value` is a string, it will be wrapped in quotes. + - Otherwise, `$key` and `$value` will be the result of `tostring(value)`. + - The comma is always included. + - `$key` is not included if it is a number part of a sequence of keys starting with `1`. +3. In the event of a cyclic table with no tostring implementation, the literal string `""` will be put in its place. + +If indentation is 0, then it will all be put onto a single line, with spaces being used in place of new lines. In this case, trailing commas will not be present. + +#### Examples + +```lua +print(table.pretty({ + width = 12, + toppings = { + "pepperoni", + "sausage", + }, +})) +``` + +--> + +``` +{ + width = 12, + toppings = { + "pepperoni", + "sausage", + } +} +``` + +--- + +```lua +print(table.pretty({ + "my cool", + "mixed table", + + key = "value", + [150] = "awesome", +})) +``` + +--> + +``` +{ + "my cool", + "mixed table", + key = "value", + [150] = "awesome", +} +``` + +--- + +```lua +print(table.pretty({ + "my", + "table", + { + x = 1, + y = 2, + } +}, 0)) +``` + +--> + +``` +{ "my", "table", { x = 1, y = 2 } } +``` + +--- + +```lua +local t = { x = 1 } +t.y = t +print(table.pretty(t)) +``` + +--> + +``` +{ + x = 1, + y = , +} +``` + +#### Caveats +An empty table will always produce "{}". + +Calling `table.pretty` on an input table with a custom `__metatable` will throw an error. + +### Changes to printing tables + +The default behavior of printing will change from calling `__tostring` to instead using `__tostring` if it exists, and `table.pretty(t)` if it does not. The existing behavior of printing a memory address will still be available through `print(tostring(t))`, which is already useful in a context like Roblox when working with Log mode. + +#### Roblox +While Luau is not Roblox specific, it is nevertheless useful to clarify the expected behavior in that environment. Roblox Studio is expected to work the same way as it does now when "Log mode" is disabled--an interactive table expansion. When "Log mode" is enabled, the new printing behavior will take effect. + +## Drawbacks +TODO: +- LogService breaking change + +## Alternatives +TODO: +- implement one and not the other +- use tabs +- more configuration like spaces/tabs/column width (Python pprint) +- implement nothing, only change in roblox-cli +- custom metamethod for printing/pretty +- no trailing comma