2016-12-28 23:51:07 +00:00
2017-01-05 12:37:44 +00:00
-- Ensure loading library, if it exists, no matter where pretty.lua was loaded from.
-- Load the library component
2017-04-03 09:55:49 +00:00
local format_number , format_function , analyze_structure , TABLE_TYPE
2017-01-05 12:37:44 +00:00
do
local thispath = ... and select ( ' 1 ' , ... ) : match ( ' .+%. ' ) or ' '
2017-01-16 15:10:10 +00:00
2017-04-03 09:55:49 +00:00
-- Load number and function formatting
format_number = select ( 2 , pcall ( require , thispath .. ' number ' ) )
format_function = select ( 2 , pcall ( require , thispath .. ' function ' ) )
2017-01-16 15:10:10 +00:00
2017-04-03 09:55:49 +00:00
-- Load other stuff
local was_loaded
2017-04-03 09:24:51 +00:00
was_loaded , analyze_structure = pcall ( require , thispath .. ' analyze_structure ' )
2017-04-05 10:21:43 +00:00
print ( was_loaded , analyze_structure )
assert ( was_loaded , ' [pretty]: Could not load vital library: analyze_structure ' )
2017-04-03 09:55:49 +00:00
was_loaded , TABLE_TYPE = pcall ( require , thispath .. ' table_type ' )
2017-04-05 10:21:43 +00:00
assert ( was_loaded , ' [pretty]: Could not load vital library: table_type ' )
2017-01-05 12:37:44 +00:00
end
--
2016-12-29 17:40:30 +00:00
2016-12-29 14:33:43 +00:00
local ERROR_UNKNOWN_TYPE = [ [
[ pretty ] : Attempting to format unsupported value of type " %s " .
A native formatting of the value is : % s
2017-04-03 09:24:51 +00:00
We are attempting to cover all Lua features , so please report this bug , so we can improve .
] ]
2016-12-29 11:11:48 +00:00
local SINGLE_LINE_TABLE_TYPES = {
2017-04-03 09:24:51 +00:00
[ TABLE_TYPE.SEQUENCE ] = true ,
[ TABLE_TYPE.PURE_MAP ] = true ,
[ TABLE_TYPE.STRING_MAP ] = true ,
2016-12-29 11:11:48 +00:00
}
2016-12-28 23:51:07 +00:00
local SINGLE_LINE_SEQ_MAX_ELEMENTS = 10
local SINGLE_LINE_MAP_MAX_ELEMENTS = 5
local NR_CHARS_IN_LONG_STRING = 40
local TYPE_SORT_ORDER = {
[ ' nil ' ] = 0 ,
[ ' boolean ' ] = 1 ,
[ ' number ' ] = 2 ,
[ ' string ' ] = 3 ,
[ ' table ' ] = 4 ,
[ ' userdata ' ] = 5 ,
[ ' thread ' ] = 6 ,
[ ' function ' ] = 7 ,
}
local RESERVED_LUA_WORDS = {
[ ' and ' ] = true ,
[ ' break ' ] = true ,
[ ' do ' ] = true ,
[ ' else ' ] = true ,
[ ' elseif ' ] = true ,
[ ' end ' ] = true ,
[ ' false ' ] = true ,
[ ' for ' ] = true ,
[ ' function ' ] = true ,
[ ' if ' ] = true ,
[ ' in ' ] = true ,
[ ' local ' ] = true ,
[ ' nil ' ] = true ,
[ ' not ' ] = true ,
[ ' or ' ] = true ,
[ ' repeat ' ] = true ,
[ ' return ' ] = true ,
[ ' then ' ] = true ,
[ ' true ' ] = true ,
[ ' until ' ] = true ,
[ ' while ' ] = true ,
}
local CHAR_TO_STR_REPR = { }
do
for i = 00 , 031 do CHAR_TO_STR_REPR [ i ] = ' \\ 0 ' .. ( i < 10 and ' 0 ' or ' ' ) .. i end
for i = 32 , 255 do CHAR_TO_STR_REPR [ i ] = string.char ( i ) end
CHAR_TO_STR_REPR [ 7 ] = ' \\ a '
CHAR_TO_STR_REPR [ 8 ] = ' \\ b '
CHAR_TO_STR_REPR [ 9 ] = ' \t '
CHAR_TO_STR_REPR [ 10 ] = ' \n '
CHAR_TO_STR_REPR [ 11 ] = ' \\ v '
CHAR_TO_STR_REPR [ 12 ] = ' \\ f '
CHAR_TO_STR_REPR [ 13 ] = ' \\ r '
CHAR_TO_STR_REPR [ 92 ] = ' \\ \\ '
CHAR_TO_STR_REPR [ 127 ] = ' \\ 127 '
end
--------------------------------------------------------------------------------
-- Util
local function padnum ( d )
local dec , n = string.match ( d , " (%.?)0*(.+) " )
return # dec > 0 and ( " %.12f " ) : format ( d ) or ( " %s%03d%s " ) : format ( dec , # n , n )
end
local function alphanum_compare_strings ( a , b )
return tostring ( a ) : gsub ( " %.?%d+ " , padnum ) .. ( " %3d " ) : format ( # b )
< tostring ( b ) : gsub ( " %.?%d+ " , padnum ) .. ( " %3d " ) : format ( # a )
end
local function smallest_secure_longform_string_level ( str )
-- Determines the level a longform string needs to use, to avoid "code"
-- injection. For example, if we want to use longform on the string
-- 'Hello ]] World', we cannot use level-0 as this would result in
-- '[[Hello ]] World]]', which could be an issue in certain applications.
local levels = { [ 1 ] = 1 }
str : gsub ( ' %]=*%] ' , function ( m ) levels [ m : len ( ) ] = true end )
return # levels - 1
end
local function compare_key_value_pairs ( a , b )
-- Get types
local type_key_a , type_key_b = type ( a [ 1 ] ) , type ( b [ 1 ] )
local type_value_a , type_value_b = type ( a [ 2 ] ) , type ( b [ 2 ] )
-- Tons of compare
2017-01-16 15:10:10 +00:00
if ( type_key_a == ' string ' and type_key_b == ' string ' ) then
2016-12-28 23:51:07 +00:00
return alphanum_compare_strings ( a [ 1 ] , b [ 1 ] )
2017-01-16 15:10:10 +00:00
elseif ( type_key_a == ' number ' and type_key_b == ' number ' ) then
return a [ 1 ] < b [ 1 ]
2016-12-28 23:51:07 +00:00
else
return TYPE_SORT_ORDER [ type_value_a ] < TYPE_SORT_ORDER [ type_value_b ]
end
end
local function get_key_value_pairs_in_proper_order ( t )
-- Generates a sequence of key value pairs, in proper order.
-- Proper order is:
-- 1. By value type: as defined by the TYPE_SORT_ORDER in the top.
-- 2. By key type: TODO: Implement this.
-- 2.1. Numbers
-- 2.2. Strings in alphanumeric order
-- 2.3. Other wierdness.
local key_value_pairs = { }
for key , value in pairs ( t ) do
key_value_pairs [ # key_value_pairs + 1 ] = { key , value }
end
table.sort ( key_value_pairs , compare_key_value_pairs )
return key_value_pairs
end
local function nr_elements_in_map ( t )
local k , count = nil , - 1
repeat
k , count = next ( t , k ) , count + 1
until not k
return count
end
local function is_identifier ( str )
-- An identier is defined in the lua reference guide
return str : match ( ' ^[_%a][_%w]*$ ' ) and not RESERVED_LUA_WORDS [ str ]
end
local function contains_only_nice_string_keys ( t )
-- A "nice" string is here defined is one following the rules of lua
-- identifiers.
for k , _ in pairs ( t ) do
if type ( k ) ~= ' string ' or not is_identifier ( k ) then
return false
end
end
return true
end
2016-12-29 11:11:48 +00:00
local function contains_only_nice_number_indexes ( t )
-- A "nice" index is here defined as one which would be visited when using
-- ipairs: An integer larger than 1 and less than #t
local max_index = # t
for k , v in pairs ( t ) do
if type ( k ) ~= ' number ' or k < 1 or max_index < k or k ~= math.floor ( k ) then
return false
end
end
return true
end
2016-12-28 23:51:07 +00:00
local function escape_string ( str )
local l = { }
for i = 1 , # str do
l [ # l + 1 ] = CHAR_TO_STR_REPR [ str : byte ( i ) ]
end
return table.concat ( l , ' ' )
end
2017-01-05 12:44:47 +00:00
local function width_of_strings_in_l ( l , start_i , end_i )
local width = 0
for i = start_i or 1 , ( end_i or # l ) do
width = width + # l [ i ]
end
return width
end
2017-01-05 13:28:31 +00:00
local function ignore_alignment_info ( l , start_i , stop_i )
for i = start_i or 1 , stop_i or # l do
if type ( l [ i ] ) == ' table ' then
l [ i ] = ' '
end
end
end
local function fix_alignment ( l , start_i , stop_i )
-- Find maximums
local max = { }
for i = start_i or 1 , stop_i or # l do
if type ( l [ i ] ) == ' table ' then
max [ l [ i ] [ 2 ] ] = math.max ( l [ i ] [ 1 ] , max [ l [ i ] [ 2 ] ] or 0 )
end
end
-- Insert the proper whitespace
for i = start_i , stop_i do
if type ( l [ i ] ) == ' table ' then
l [ i ] = string.rep ( ' ' , max [ l [ i ] [ 2 ] ] - l [ i ] [ 1 ] )
end
end
end
2016-12-29 15:54:31 +00:00
2016-12-28 23:51:07 +00:00
--------------------------------------------------------------------------------
-- Identifyer stuff
local SIMPLE_VALUE_TYPES = {
[ ' nil ' ] = true ,
[ ' boolean ' ] = true ,
[ ' number ' ] = true ,
[ ' string ' ] = true ,
}
local function is_empty_table ( value )
2017-04-05 10:21:43 +00:00
if type ( value ) ~= ' table ' then
error ( ( ' [pretty/internal]: Only tables allowed in function pretty.is_empty_table, but was given %s (%s) ' ) : format ( value , type ( value ) ) , 2 )
end
2016-12-28 23:51:07 +00:00
return next ( value ) == nil
end
local function is_short_table ( value )
-- In this context, a short table is either an empty table, or one with a
-- single element.
2017-04-05 10:21:43 +00:00
if type ( value ) ~= ' table ' then
error ( ( ' [pretty/internal]: Only tables allowed in function pretty.is_short_table, but was given %s (%s) ' ) : format ( value , type ( value ) ) , 2 )
end
2016-12-28 23:51:07 +00:00
local first_key = next ( value )
return ( not first_key or SIMPLE_VALUE_TYPES [ type ( value [ first_key ] ) ] )
and ( next ( value , first_key ) == nil )
end
local function is_simple_value ( value )
-- In this context, a simple value is a either nil, a boolean, a number,
-- a string or a short table.
-- TODO: Add clause about long strings. (Maybe >7 chars?)
--if type(value) == 'table' then print(value, is_short_table(value)) end
return SIMPLE_VALUE_TYPES [ type ( value ) ]
or type ( value ) == ' table ' and is_short_table ( value )
end
local function contains_non_simple_key_or_value ( t )
for k , v in pairs ( t ) do
if not is_simple_value ( k ) or not is_simple_value ( v ) then
return true
end
end
return false
end
local function get_table_type ( value )
-- Determines table type:
-- * Sequence: All keys are integer in the range 1..#value
-- * Pure Map: #value == 0
-- * Mixed: Any other
2017-04-03 09:24:51 +00:00
if is_empty_table ( value ) then return TABLE_TYPE.EMPTY end
2016-12-28 23:51:07 +00:00
2016-12-29 11:11:48 +00:00
local is_sequence = contains_only_nice_number_indexes ( value )
local only_string_keys = contains_only_nice_string_keys ( value )
local is_pure_map = ( # value == 0 )
2016-12-28 23:51:07 +00:00
-- Return type
2017-04-03 09:24:51 +00:00
if is_sequence then return TABLE_TYPE.SEQUENCE
elseif only_string_keys then return TABLE_TYPE.STRING_MAP
elseif is_pure_map then return TABLE_TYPE.PURE_MAP
else return TABLE_TYPE.MIXED
2016-12-28 23:51:07 +00:00
end
end
local function is_single_line_table ( value )
-- In this context, a single-line table, is:
-- A) Either a sequence or a pure map.
-- B) Has no non-simple keys or values
-- C 1) If sequence, has at most SINGLE_LINE_SEQ_MAX_ELEMENTS elements.
-- C 2) If map, has at most SINGLE_LINE_MAP_MAX_ELEMENTS elements.
local table_type = get_table_type ( value )
return not contains_non_simple_key_or_value ( value )
2016-12-29 11:11:48 +00:00
and SINGLE_LINE_TABLE_TYPES [ table_type ]
and # value <= SINGLE_LINE_SEQ_MAX_ELEMENTS
and nr_elements_in_map ( value ) <= SINGLE_LINE_MAP_MAX_ELEMENTS
2016-12-28 23:51:07 +00:00
end
--------------------------------------------------------------------------------
-- Formatting stuff
local format_table , format_value
-- Ways to format keys
2016-12-29 04:34:44 +00:00
local function format_key_and_value_string_map ( l , key , value , options , depth )
l [ # l + 1 ] = key
2017-01-05 13:28:31 +00:00
l [ # l + 1 ] = { # key , ' key ' }
2016-12-29 04:34:44 +00:00
l [ # l + 1 ] = ' = '
2017-01-05 14:50:44 +00:00
return format_value ( value , options , depth , l )
2016-12-28 23:51:07 +00:00
end
2016-12-29 04:34:44 +00:00
local function format_key_and_value_arbitr_map ( l , key , value , options , depth )
2017-01-05 12:44:47 +00:00
local index_before_key = # l + 1
2016-12-29 04:34:44 +00:00
l [ # l + 1 ] = ' [ '
2017-01-05 12:37:44 +00:00
format_value ( key , options , ' max ' , l )
2016-12-29 04:34:44 +00:00
l [ # l + 1 ] = ' ] '
2017-01-05 13:28:31 +00:00
l [ # l + 1 ] = { width_of_strings_in_l ( l , index_before_key ) , ' key ' }
2016-12-29 04:34:44 +00:00
l [ # l + 1 ] = ' = '
2017-01-05 14:50:44 +00:00
return format_value ( value , options , depth , l )
2016-12-28 23:51:07 +00:00
end
2016-12-29 10:37:31 +00:00
local function format_key_and_value_sequence ( l , key , value , options , depth )
2017-01-05 14:50:44 +00:00
return format_value ( value , options , depth , l )
2016-12-29 10:37:31 +00:00
end
2016-12-28 23:51:07 +00:00
2016-12-29 11:11:48 +00:00
local TABLE_TYPE_TO_PAIR_FORMAT = {
2017-04-03 09:24:51 +00:00
[ TABLE_TYPE.SEQUENCE ] = format_key_and_value_sequence ,
[ TABLE_TYPE.STRING_MAP ] = format_key_and_value_string_map ,
[ TABLE_TYPE.PURE_MAP ] = format_key_and_value_arbitr_map ,
[ TABLE_TYPE.MIXED ] = format_key_and_value_arbitr_map ,
2016-12-29 11:11:48 +00:00
}
2016-12-28 23:51:07 +00:00
2016-12-29 10:37:31 +00:00
-- Formatting tables
2017-01-05 12:37:44 +00:00
local function format_single_line_map ( t , options , l )
2016-12-28 23:51:07 +00:00
-- NOTE: Assumes that the input table was pre-checked with `is_single_line_table()`
2016-12-29 11:11:48 +00:00
local key_value_pairs = get_key_value_pairs_in_proper_order ( t )
local table_type = get_table_type ( t )
local pair_format_func = TABLE_TYPE_TO_PAIR_FORMAT [ table_type ]
2016-12-29 10:37:31 +00:00
2017-01-05 12:37:44 +00:00
l [ # l + 1 ] = ' { '
2016-12-29 10:37:31 +00:00
local top_before = # l
2016-12-28 23:51:07 +00:00
for _ , pair in ipairs ( key_value_pairs ) do
2016-12-29 04:34:44 +00:00
pair_format_func ( l , pair [ 1 ] , pair [ 2 ] , options , ' max ' )
2016-12-28 23:51:07 +00:00
l [ # l + 1 ] = ' , '
end
2016-12-29 10:37:31 +00:00
-- Ignore the "width of key"-shit
2017-01-05 13:28:31 +00:00
ignore_alignment_info ( l , top_before , # l )
2016-12-28 23:51:07 +00:00
2016-12-29 10:37:31 +00:00
if l [ # l ] == ' , ' then l [ # l ] = nil end
l [ # l + 1 ] = ' } '
2016-12-28 23:51:07 +00:00
end
2017-01-05 12:37:44 +00:00
local function format_map ( t , options , depth , l )
-- TODO: l.
2016-12-28 23:51:07 +00:00
2016-12-29 11:11:48 +00:00
local key_value_pairs = get_key_value_pairs_in_proper_order ( t )
local table_type = get_table_type ( t )
local pair_format_func = TABLE_TYPE_TO_PAIR_FORMAT [ table_type ]
2017-01-05 12:37:44 +00:00
l [ # l + 1 ] = ' { \n '
2016-12-29 04:34:44 +00:00
local top_before = # l
for _ , pair in pairs ( key_value_pairs ) do
2016-12-28 23:51:07 +00:00
l [ # l + 1 ] = options.indent : rep ( depth + 1 )
2016-12-29 04:34:44 +00:00
pair_format_func ( l , pair [ 1 ] , pair [ 2 ] , options , depth + 1 )
2016-12-28 23:51:07 +00:00
l [ # l + 1 ] = ' , \n '
end
2016-12-29 04:34:44 +00:00
2017-01-05 13:28:31 +00:00
-- Fix whitespace alignment
fix_alignment ( l , top_before , # l )
-- Fix and cleanup
2016-12-29 11:11:48 +00:00
if l [ # l ] == ' , \n ' then l [ # l ] = nil end
l [ # l + 1 ] = ' \n '
2016-12-28 23:51:07 +00:00
l [ # l + 1 ] = options.indent : rep ( depth )
l [ # l + 1 ] = ' } '
2017-01-05 12:37:44 +00:00
2016-12-28 23:51:07 +00:00
end
2017-01-05 12:37:44 +00:00
function format_table ( t , options , depth , l )
2017-04-03 09:24:51 +00:00
local info = l.info [ t ] or { }
--local table_type = get_table_type(t)
if options.recursion == ' marked ' and info.marker then
l [ # l + 1 ] , l [ # l + 2 ] , l [ # l + 3 ] = ' < ' , info.marker , ' > '
end
2016-12-28 23:51:07 +00:00
2016-12-29 10:37:31 +00:00
-- Empty or exteeding max-depth?
2017-04-03 09:24:51 +00:00
if info.type == TABLE_TYPE.EMPTY then l [ # l + 1 ] = ' {} ' ; return
2017-01-16 15:22:46 +00:00
elseif depth ~= ' max ' and depth >= options.max_depth or l.visited [ t ] then l [ # l + 1 ] = ' {...} ' ; return
2016-12-28 23:51:07 +00:00
end
2016-12-29 10:37:31 +00:00
2017-01-16 15:22:46 +00:00
l.visited [ t ] = true
2016-12-29 10:37:31 +00:00
-- Single line?
2017-01-05 12:37:44 +00:00
if is_single_line_table ( t ) then format_single_line_map ( t , options , l ) ; return end
2016-12-29 10:37:31 +00:00
2017-01-05 12:37:44 +00:00
if depth == ' max ' then l [ # l + 1 ] = ' {...} ' ; return end
2016-12-29 10:37:31 +00:00
-- Normal table
2017-01-05 12:37:44 +00:00
format_map ( t , options , depth , l )
2016-12-28 23:51:07 +00:00
end
2017-01-05 12:37:44 +00:00
local function format_string ( str , options , depth , l )
2016-12-28 23:51:07 +00:00
-- TODO: Add option for escaping unicode characters.
local is_long_string = ( str : len ( ) >= NR_CHARS_IN_LONG_STRING )
local newline_or_tab_index = str : find ( ' [ \n \t ] ' )
local single_quote_index = str : find ( ' \' ' )
local double_quote_index = str : find ( ' \" ' )
2017-01-16 15:10:10 +00:00
-- ...
local chance_of_longform = is_long_string and ( ( newline_or_tab_index or math.huge ) <= NR_CHARS_IN_LONG_STRING ) or double_quote_index and single_quote_index
2016-12-28 23:51:07 +00:00
local cut_string_index = options.cut_strings and ( is_long_string or chance_of_longform )
and math.min ( NR_CHARS_IN_LONG_STRING - 3 , newline_or_tab_index or 1 / 0 , double_quote_index or 1 / 0 , single_quote_index or 1 / 0 )
local longform = chance_of_longform and ( ( not cut_string_index ) or cut_string_index < math.min ( newline_or_tab_index or 1 / 0 , double_quote_index or 1 / 0 , single_quote_index or 1 / 0 ) )
local escape_newline_and_tab = not longform and newline_or_tab_index
-- Determine string delimiters
local left , right
if longform then
local level = smallest_secure_longform_string_level ( str )
left , right = ' [ ' .. string.rep ( ' = ' , level ) .. ' [ ' , ' ] ' .. string.rep ( ' = ' , level ) .. ' ] '
if newline_or_tab_index then str = ' \n ' .. str end
elseif not single_quote_index then
left , right = ' \' ' , ' \' '
else
left , right = ' \" ' , ' \" '
end
-- Cut string
if cut_string_index then str = str : sub ( 1 , cut_string_index ) end
str = escape_string ( str )
-- Escape newline and tab
if escape_newline_and_tab then str = str : gsub ( ' \n ' , ' \\ n ' ) : gsub ( ' \t ' , ' \\ t ' ) end
2017-01-05 12:37:44 +00:00
l [ # l + 1 ] = left
l [ # l + 1 ] = str
l [ # l + 1 ] = right
2016-12-28 23:51:07 +00:00
end
2017-01-16 15:10:10 +00:00
if not format_number then
2017-04-03 09:55:49 +00:00
-- Very simple number formatting, if number.lua is not available.
format_number = function ( value , _ , _ , l )
l [ # l + 1 ] = tostring ( value )
2016-12-28 23:51:07 +00:00
end
end
2017-01-05 12:37:44 +00:00
local function format_coroutine ( value , options , depth , l )
l [ # l + 1 ] = coroutine.status ( value )
l [ # l + 1 ] = ' coroutine: '
l [ # l + 1 ] = tostring ( value ) : sub ( 9 )
2016-12-29 14:33:43 +00:00
end
2017-01-05 12:37:44 +00:00
local function format_primitive ( value , options , depth , l )
l [ # l + 1 ] = tostring ( value )
2016-12-29 14:33:43 +00:00
end
2017-04-03 09:55:49 +00:00
if not format_function then
-- Very simple function formatting, if function.lua is not available.
format_function = function ( value , _ , _ , l )
l [ # l + 1 ] = ' function (...) --[[ ' .. tostring ( value ) : sub ( 11 ) .. ' ]] end '
2016-12-29 15:17:58 +00:00
end
2016-12-29 14:33:43 +00:00
end
local TYPE_TO_FORMAT_FUNC = {
[ ' nil ' ] = format_primitive ,
[ ' boolean ' ] = format_primitive ,
[ ' number ' ] = format_number ,
[ ' string ' ] = format_string ,
[ ' thread ' ] = format_coroutine ,
[ ' table ' ] = format_table ,
-- TODO
[ ' function ' ] = format_function ,
[ ' userdata ' ] = format_primitive ,
[ ' cdata ' ] = format_primitive , -- Luajit exclusive ?
}
2017-04-03 09:24:51 +00:00
function format_value ( value , _ , depth , l )
2016-12-29 14:33:43 +00:00
local format_func = TYPE_TO_FORMAT_FUNC [ type ( value ) ]
if format_func then
2017-04-03 09:55:49 +00:00
format_func ( value , l.options , depth , l , format_value )
2016-12-29 14:33:43 +00:00
else
2017-01-05 12:44:47 +00:00
error ( ERROR_UNKNOWN_TYPE : format ( type ( value ) , tostring ( value ) ) , 2 )
2016-12-28 23:51:07 +00:00
end
end
--------------------------------------------------------------------------------
2017-04-03 14:39:19 +00:00
local KNOWN_OPTIONS = {
_all_function_info = ' boolean ' ,
cut_strings = ' boolean ' ,
include_closure = ' boolean ' ,
indent = ' string ' ,
math_shorthand = ' boolean ' ,
max_depth = ' number ' ,
more_function_info = ' boolean ' ,
recursion = ' string ' ,
short_builtins = ' boolean ' ,
}
local function ensure_that_all_options_are_known ( options )
for option_name , option_value in pairs ( options ) do
if not KNOWN_OPTIONS [ option_name ] then
error ( ( ' [pretty]: Unknown option: %s. Was given value %s (%s) ' ) : format ( option_name , option_value , type ( option_value ) ) , 2 )
elseif type ( option_value ) ~= KNOWN_OPTIONS [ option_name ] then
error ( ( ' [pretty]: Bad value given to option %s: %s (%s). Expected value of type %s ' ) : format ( option_name , option_value , type ( option_value ) , KNOWN_OPTIONS [ option_name ] ) , 2 )
end
end
end
2016-12-28 23:51:07 +00:00
local function pretty_format ( value , options )
2017-01-16 15:22:46 +00:00
local l = { visited = { next_mark = 1 } }
2017-04-03 09:24:51 +00:00
l.options = options or { }
l.options . max_depth = l.options . max_depth or math.huge
l.options . indent = l.options . indent or ' \t '
2017-04-03 14:39:19 +00:00
ensure_that_all_options_are_known ( l.options )
2017-04-03 09:24:51 +00:00
l.info = ( type ( value ) == ' table ' ) and analyze_structure ( value ) or { }
format_value ( value , nil , 0 , l )
2017-01-05 13:28:31 +00:00
-- If any alignment info still exists, ignore it
ignore_alignment_info ( l )
2017-01-05 12:37:44 +00:00
return table.concat ( l , ' ' )
2016-12-28 23:51:07 +00:00
end
return pretty_format