1
0

Fixed docstring

This commit is contained in:
Jon Michael Aanes 2024-07-10 20:38:18 +02:00
parent fd03c384f6
commit 748fe7835e
Signed by: Jmaa
SSH Key Fingerprint: SHA256:Ab0GfHGCblESJx7JRE4fj4bFy/KRpeLhi41y4pF3sNA

View File

@ -1,205 +1,206 @@
--- Pretty --[[--
--
-- `pretty` is an advanced pretty printer for [Lua](lua.org). It's primarily a # Pretty
-- debugging tool, aiming for human readability, by detecting pattern in the input
-- data, and creating an output string utilizing and highlighting those patterns. `pretty` is an advanced pretty printer for [Lua](https://lua.org). It's primarily a
-- debugging tool, aiming for human readability, by detecting pattern in the input
-- ## Code Example data, and creating an output string utilizing and highlighting those patterns.
--
-- Setup is simple, use `pretty = require 'pretty'`, and you're good to go. ## Code Example
--
-- ```lua Setup is simple, use `pretty = require 'pretty'`, and you're good to go.
-- > print(pretty( { 1, 2, 3 } ))
-- { 1, 2, 3 } ```lua
-- $ print(pretty( { 1, 2, 3 } ))
-- > print(pretty( { hello = 'world', num = 42 } )) { 1, 2, 3 }
-- {
-- num = 42 > print(pretty( { hello = 'world', num = 42 } ))
-- hello = 'world' {
-- } num = 42
-- hello = 'world'
-- > print(pretty( { abs = math.abs, max = math.max, some = function() end } )) }
-- {
-- abs = builtin function (x) ... end > print(pretty( { abs = math.abs, max = math.max, some = function() end } ))
-- max = builtin function (x, ...) ... end {
-- 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 > print(pretty( math.abs ))
-- -- Returns the absolute value of x builtin function (x)
-- -- math.abs
-- ... -- Returns the absolute value of x
-- end
-- ``` ...
-- end
-- ## Motivation ```
--
-- This project is the outcome of my frustration with existing pretty printers, and ## Motivation
-- a desire to expand upon the pretty printer I developed for
-- [Xenoterm](https://gitfub.space/takunomi/Xenoterm). The original Xenoterm pretty This project is the outcome of my frustration with existing pretty printers, and
-- printer was much simpler than `pretty` - and the current is even simpler - but a desire to expand upon the pretty printer I developed for
-- the enhancements I make, when compared to other pretty printers, inspired me to [Xenoterm](https://gitfub.space/takunomi/Xenoterm). The original Xenoterm pretty
-- create `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
-- `pretty` sorts it's priorities like so: create `pretty`.
--
-- 1. Human readability. `pretty` sorts it's priorities like so:
-- 2. Lua-compatible output.
-- 3. Customization. 1. Human readability.
-- 2. Lua-compatible output.
-- I'd rather have good defaults than provide a ton of customization options. If an 3. Customization.
-- structure avoids easy representation in Lua, I'd rather extend the syntax, than
-- lose the info. 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
-- Another aspect where `pretty` shines is in exploratory programming, when lose the info.
-- attempting to avoid reliance on outside documentation. The amount of information
-- `pretty` exposes varies by the data you are inspecting. If you're inspecting Another aspect where `pretty` shines is in exploratory programming, when
-- a list of functions, their function signatures are visible, but if you're attempting to avoid reliance on outside documentation. The amount of information
-- inspecting a single function, documentation and source location may appear if `pretty` exposes varies by the data you are inspecting. If you're inspecting
-- available. a list of functions, their function signatures are visible, but if you're
-- inspecting a single function, documentation and source location may appear if
-- ## Features available.
--
-- - Written in good-old pureblood Lua, with support for PUC Lua 5.0+ and ## Features
-- LuaJIT 2.0+.
-- - Redefining what it means to be "human readable": - Written in good-old pure-blood Lua, with support for PUC Lua 5.0+ and LuaJIT 2.0+.
-- * Is multi-line centric, to aid readablitiy. - Redefining what it means to be "human readable":
-- * Indention and alignment of keys-value pairs. * Is multi-line centric, to aid readability.
-- * Keys-value pairs are [properly](http://www.davekoelle.com/alphanum.html) * Indention and alignment of keys-value pairs.
-- sorted by key type and thereafter alphabetically. * Keys-value pairs are
-- * The format and structure of output changes depending upon the input. [alpha-numerically](http://www.davekoelle.com/alphanum.html) sorted by key
-- Maps appear differently to deeply nested tables to long sequences type and thereafter alphabetically.
-- with short strings to short lists. * The format and structure of output changes depending upon the input. Maps
-- * Uses the standard `debug` library to gain information about functions appear differently to deeply nested tables to long sequences with short
-- and other advanced structures. strings to short lists.
-- * Uses the standard `debug` library to gain information about functions and
-- ## Installation other advanced structures.
--
-- `pretty` is loadable directly with `require`. Either clone or download this ## Installation
-- repository. Where you place it, depends upon what you want to do:
-- `pretty` is loadable directly with `require`. Either clone or download this
-- 1. **You want `pretty` in a specific project**: Place the `pretty` folder repository. Where you place it, depends upon what you want to do:
-- 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 1. **You want `pretty` in a specific project**: Place the `pretty` folder
-- it's visible from your Lua-path. On my system this might be somewhere in your project, and `require` it from one of your project files.
-- `/usr/local/share/lua/5.1/`. Now you can `require` it from anywhere. 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
-- ## API Documentation `/usr/local/share/lua/5.1/`. Now you can `require` it from anywhere.
--
-- `pretty` exposes a single function, the `pretty` function itself. It's function ## API Documentation
-- signature is `pretty(value, options)`. `value` can be any Lua value. `options`
-- must be a table. `pretty` exposes a single function, the `pretty` function itself. It's function
-- signature is `pretty(value, options)`. `value` can be any Lua value. `options`
-- ### List of options must be a table.
--
-- `pretty` is sure to complain if you give it an unknown option, or if you give an ### List of options
-- option a bad value.
-- `pretty` is sure to complain if you give it an unknown option, or if you give an
-- - `indent: string`: The string to indent with. Four spaces by default. option a bad value.
--
-- ## TODO - `indent: string`: The string to indent with. Four spaces by default.
--
-- Tasks to be done before `pretty` can be called version 1.0.0, in order of ## TODO
-- priority:
-- Tasks to be done before `pretty` can be called version 1.0.0, in order of
-- - Add a dedicated unicode submodule, to handle some minor alignment and priority:
-- character escaping issues. `pretty` should escape all malformed unicode
-- sequences. - [ ] Add dedicated unicode submodule, to handle some minor alignment and
-- - Align numbers towards right for tabular views. character escaping issues. `pretty` should escape all malformed unicode
-- - Add support for `setmetatable`, and exploring values in metatables. sequences.
-- - Provide nice formatting for `cdata` datatype in LuaJIT. - [ ] Align numbers towards right for tabular views.
-- - Find a better name than `pretty`. - [ ] Add support for `setmetatable`, and exploring values in metatables.
-- - Enhance internal structure some amount. See `TODO` markers in files. - [ ] Provide nice formatting for `cdata` datatype in LuaJIT.
-- - [ ] Find a better name than `pretty`.
-- It would be nice to have the following, but these are secondary: - [ ] Enhance internal structure some amount. See `TODO` markers in files.
--
-- - Add option for colored output. Primarily syntax highlighting, but also It would be nice to have the following, but these are secondary:
-- [BlueJ-style](www.bluej.org/about.html) scope highlighting, with some faint
-- background colors. - [ ] Add option for colored output. Primarily syntax highlighting, but also
-- - Expand on the comment output in output, for `__tostring` methods, and global [BlueJ-style](www.bluej.org/about.html) scope highlighting, with some faint
-- namespaces like `io` or `math`. background colors.
-- - Fit output within a predefined width limit. Default to 80. - [ ] Expand on the comment output in output, for `__tostring` methods, and
-- - Look into tool for understanding complex structures with recursive global namespaces like `io` or `math`.
-- definitions. Whatever modes are thought up, they should be automatic modes, - [ ] Fit output within a predefined width limit. Default to 80.
-- not an options. Should at least include modes for self-referential tables - [ ] Look into tool for understanding complex structures with recursive
-- and Directed-Acyclic-Graphs. definitions. Whatever modes are thought up, they should be automatic modes, not
-- an options. Should at least include modes for self-referential tables and
-- ## Alternative pretty printers Directed-Acyclic-Graphs.
--
-- `pretty` is large, slow, and requires the debug library to work. It's not ## Alternative pretty printers
-- designed for serialization purposes, nor is it concerned with offering the same
-- level of customization as other libraries do. `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
-- If you want a sleek, fast, customizable or embeddable library, there are level of customization as other libraries do.
-- thankfully other options.
-- If you want a sleek, fast, customizable or embeddable library, there are
-- - [inspect.lua](github.com/kikito/inspect.lua): One of the classic debugging thankfully other options.
-- pretty printers.
-- - [pprint.lua](github.com/jagt/pprint.lua): Reimplementation of `inspect.lua` - [inspect.lua](github.com/kikito/inspect.lua): One of the classic debugging pretty printers.
-- - [serpent](github.com/pkulchenko/serpent): Advanced and fast pretty printer. - [pprint.lua](github.com/jagt/pprint.lua): Reimplementation of `inspect.lua`
-- - [pluto](lua-users.org/wiki/PlutoLibrary): Can serialize arbitrary parts of - [serpent](github.com/pkulchenko/serpent): Advanced and fast pretty printer.
-- Lua, including functions, upvalues, and proper lexical scoping. Not written - [pluto](lua-users.org/wiki/PlutoLibrary): Can serialize arbitrary parts of
-- in native Lua. Lua, including functions, upvalues, and proper lexical scoping. Not written in
-- - [binser](github.com/bakpakin/binser): Library for special purpose native Lua.
-- serialization. - [binser](github.com/bakpakin/binser): Library for special purpose serialization.
--
-- Even more are available at [the lua-users wiki](lua-users.org/wiki/TableSerialization). Even more are available at [the lua-users wiki](lua-users.org/wiki/TableSerialization).
--
-- ## Thoughts on displaying tables in an intuitive way. ## Thoughts on displaying tables in an intuitive way.
--
-- Lua's table data-structure is likely to be the most concise data structure ever 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, invented. (If not, please send me a link!) Lists, maps, objects, classes,
-- proxies, etc. This obviously brings about it some difficulty when attempting to 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 represent these tables. What do we want to highlight, and what do we choose to
-- avoid? avoid?
--
-- One notable issue is whether to show every key that a table answers (to lift 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 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 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 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 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 have a better idea, but it would be cluttered to display both types of keys side
-- by side. by side.
--
-- 1. Native representation: Lua's native representation includes the type and 1. Native representation: Lua's native representation includes the type and
-- address of the table. It allows for distinguishing between unique tables, address of the table. It allows for distinguishing between unique tables,
-- but won't tell us anything about the contents. but won't tell us anything about the contents.
-- 2. Omission: By representing tables as the pseudo-parsable `{...}`, it's 2. Omission: By representing tables as the pseudo-parsable `{...}`, it's
-- clear we are talking about a table. We disregard the ability to clear we are talking about a table. We disregard the ability to
-- distinguish between tables. distinguish between tables.
-- 2A. If the table is empty, we could represent it as `{}`. But what if the table 2. 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 has a metatable with `__index` defined? We could continue to represent it as
-- `{}`, but `{...}` would be more "honest". `{}`, but `{...}` would be more "honest".
-- 3. Single-line: TODO 3. Single-line: TODO
-- 4. Multi-line: TODO 4. Multi-line: TODO
-- 5. Columns: For some highly-regular structures, like lists of short strings, 5. 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 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 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 classic `ls` unix tool, and place the output into columns, to help guide
-- the eyes. the eyes.
-- 6. Tabular: Other structures are formatted like actual tables of data, e.g. a 6. 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 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. structures it's an obvious choice to align them based on the keys.
-- 7. Pseudo-Tabular: Some structures are almost tabular, e.g. they are sequences 7. 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 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 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 do this we should sort the key order descending by the number of tuples with
-- the key. the key.
-- But what do we do about the the outlier keys? We can either justify the 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 entire table, and give specific spots for the outlier keys, thereby
-- significantly increasing the size of the table, or we can leave the table significantly increasing the size of the table, or we can leave the table
-- unjustified, abandoning it's eye-guiding attributes. unjustified, abandoning it's eye-guiding attributes.
-- 8. Special cases: (Array-tree, Table-Tree, Linked-List, Predictive Sequences) TODO 8. Special cases: (Array-tree, Table-Tree, Linked-List, Predictive Sequences) TODO
--]]
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Import files -- Import files
local import local import
do do
local thispath = ... and select('1', ...):match('.+%.') or '' local this_path = ... and select('1', ...):match('.+%.') or ''
import = function (name, ignore_failure) return require(thispath..name) end import = function (name, ignore_failure) return require(this_path..name) end
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -421,10 +422,10 @@ local function attempt_to_align_into_columns (l, start_i, stop_i, nr_items_pr_ro
assert(type(stop_i) == 'number') assert(type(stop_i) == 'number')
assert(type(nr_items_pr_row) == 'number') assert(type(nr_items_pr_row) == 'number')
local column = {} local column = {}
--- ---
local start_of_item_i, item_nr = nil, 0 local start_of_item_i, item_nr = nil, 0
for i = start_i, stop_i do for i = start_i, stop_i do
if type(l[i]) == 'table' and (l[i][1] == 'indent' or l[i][1] == 'seperator' or l[i][1] == 'unindent') then if type(l[i]) == 'table' and (l[i][1] == 'indent' or l[i][1] == 'seperator' or l[i][1] == 'unindent') then
if start_of_item_i then if start_of_item_i then
local width_of_item = width_of_strings_in_l(l, start_of_item_i, i-1) local width_of_item = width_of_strings_in_l(l, start_of_item_i, i-1)
@ -433,12 +434,12 @@ local function attempt_to_align_into_columns (l, start_i, stop_i, nr_items_pr_ro
end end
start_of_item_i, item_nr = i + 1, item_nr + 1 start_of_item_i, item_nr = i + 1, item_nr + 1
end end
end end
--- ---
local width = nr_items_pr_row * 2 - 1 -- FIXME: Magic numbers: 2 = #', ', 1 = #' ' local width = nr_items_pr_row * 2 - 1 -- FIXME: Magic numbers: 2 = #', ', 1 = #' '
for i = 1, #column do width = width + column[i] end for i = 1, #column do width = width + column[i] end
-- --
return width, column return width, column
end end
local function align_into_columns (l, start_i, stop_i) local function align_into_columns (l, start_i, stop_i)
@ -448,8 +449,8 @@ local function align_into_columns (l, start_i, stop_i)
local start_i, stop_i = start_i or 1, stop_i or #l local start_i, stop_i = start_i or 1, stop_i or #l
assert(type(start_i) == 'number') assert(type(start_i) == 'number')
assert(type(stop_i) == 'number') assert(type(stop_i) == 'number')
insert_alignment_estimations(l, start_i, stop_i) insert_alignment_estimations(l, start_i, stop_i)
@ -480,7 +481,7 @@ local function align_into_columns (l, start_i, stop_i)
-- Fit into columns. -- Fit into columns.
local start_of_item_i, item_nr = nil, 0 local start_of_item_i, item_nr = nil, 0
for i = start_i, stop_i do for i = start_i, stop_i do
if type(l[i]) ~= 'table' then if type(l[i]) ~= 'table' then
-- Do nothing -- Do nothing
elseif (l[i][1] == 'indent' or l[i][1] == 'seperator' or l[i][1] == 'unindent') then elseif (l[i][1] == 'indent' or l[i][1] == 'seperator' or l[i][1] == 'unindent') then
@ -493,47 +494,47 @@ local function align_into_columns (l, start_i, stop_i)
end end
start_of_item_i, item_nr = i + 1, item_nr + 1 start_of_item_i, item_nr = i + 1, item_nr + 1
end end
end end
end end
local function align_into_tabular_style (l, start_i, stop_i) local function align_into_tabular_style (l, start_i, stop_i)
-- Adds alignment after separators, to create nicely aligned tabular-format. -- Adds alignment after separators, to create nicely aligned tabular-format.
-- Argument fixing and Error Checking -- Argument fixing and Error Checking
local start_i, stop_i = start_i or 1, stop_i or #l local start_i, stop_i = start_i or 1, stop_i or #l
assert(type(l) == 'table') assert(type(l) == 'table')
assert(type(start_i) == 'number') assert(type(start_i) == 'number')
assert(type(stop_i) == 'number') assert(type(stop_i) == 'number')
assert(type(l[start_i]) == 'table' and l[start_i][1] == 'indent') assert(type(l[start_i]) == 'table' and l[start_i][1] == 'indent')
assert(type(l[stop_i]) == 'table' and l[stop_i][1] == 'unindent') assert(type(l[stop_i]) == 'table' and l[stop_i][1] == 'unindent')
-- Calculate where to insert new alignment. -- Calculate where to insert new alignment.
local indent, key_nr, index_of_last_meta, insert_later = 0, 0, 1, {} local indent, key_nr, index_of_last_meta, insert_later = 0, 0, 1, {}
for i = start_i + 1, stop_i - 1 do for i = start_i + 1, stop_i - 1 do
if type(l[i]) ~= 'table' then if type(l[i]) ~= 'table' then
-- Do nothing -- Do nothing
elseif l[i][1] == 'indent' then elseif l[i][1] == 'indent' then
indent = indent + 1 indent = indent + 1
if indent == 1 then key_nr = 1 end if indent == 1 then key_nr = 1 end
index_of_last_meta = i index_of_last_meta = i
elseif l[i][1] == 'unindent' then elseif l[i][1] == 'unindent' then
insert_later[#insert_later+1] = {'align', 'end_subtable_'..key_nr, width_of_strings_in_l(l, index_of_last_meta+1, i), i} insert_later[#insert_later+1] = {'align', 'end_subtable_'..key_nr, width_of_strings_in_l(l, index_of_last_meta+1, i), i}
index_of_last_meta, key_nr = i, key_nr + 1 index_of_last_meta, key_nr = i, key_nr + 1
indent = indent - 1 indent = indent - 1
elseif l[i][1] == 'seperator' and indent ~= 0 then elseif l[i][1] == 'seperator' and indent ~= 0 then
insert_later[#insert_later+1] = {'align', 'key_'..key_nr, width_of_strings_in_l(l, index_of_last_meta+1, i), i+1} insert_later[#insert_later+1] = {'align', 'key_'..key_nr, width_of_strings_in_l(l, index_of_last_meta+1, i), i+1}
index_of_last_meta, key_nr = i, key_nr + 1 index_of_last_meta, key_nr = i, key_nr + 1
end end
end end
-- Insert new alignment. -- Insert new alignment.
for i = #insert_later, 1, -1 do for i = #insert_later, 1, -1 do
local dat = insert_later[i] local dat = insert_later[i]
table.insert(l, dat[#dat], dat) table.insert(l, dat[#dat], dat)
dat[#dat] = nil dat[#dat] = nil
end end
-- Fix that alignemnt -- Fix that alignemnt
return fix_alignment(l, start_i) return fix_alignment(l, start_i)
end end
local function fix_seperator_info (l, indent_char) local function fix_seperator_info (l, indent_char)
@ -562,9 +563,9 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local analyze_structure = import 'analyze_structure' local analyze_structure = import 'analyze_structure'
local TABLE_TYPE = import 'common' . TABLE_TYPE local TABLE_TYPE = import 'common' . TABLE_TYPE
local DISPLAY = import 'common' . DISPLAY local DISPLAY = import 'common' . DISPLAY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Key-value pair formatting. -- Key-value pair formatting.
@ -657,8 +658,8 @@ local function format_table (t, display, l, format_value)
-- NOTE: Currently we only allow leaf-nodes to format into columns, due -- NOTE: Currently we only allow leaf-nodes to format into columns, due
-- to issues with table alignment. -- to issues with table alignment.
align_into_columns(l, start_of_table_i) align_into_columns(l, start_of_table_i)
elseif table_info.is_tabular then elseif table_info.is_tabular then
align_into_tabular_style(l, start_of_table_i, #l) align_into_tabular_style(l, start_of_table_i, #l)
else else
-- Is long table: Fix whitespace alignment -- Is long table: Fix whitespace alignment
fix_alignment(l, start_of_table_i) fix_alignment(l, start_of_table_i)