1
0

Finally implemented column alignment

It's currently a bit limited in scope, but looks great when active.
This commit is contained in:
Jon Michael Aanes 2017-07-20 12:01:26 +02:00
parent 0b0c2330ec
commit 93beb4bd1e
5 changed files with 136 additions and 38 deletions

View File

@ -101,8 +101,6 @@ printers specified below.
I'm looking into implementing following features:
- Improve display of medium-long lists with short elements. One option is
something analog to the default results of `ls` on Linux.
- Add support for `setmetatable`, and exploring the values accessible through
it.
- Provide nice formatting for `cdata` datatype in LuaJIT.

View File

@ -36,10 +36,11 @@ local RESERVED_LUA_WORDS = {
['goto'] = true,
}
local SIMPLE_VALUE_TYPES = {
local LEAF_VALUE_TYPES = {
['nil'] = true,
['boolean'] = true,
['number'] = true,
['string'] = true,
['boolean'] = true,
}
local SHORT_STRING_MAX_LEN = 7
@ -186,6 +187,20 @@ local function has_uniform_structure (t)
return true
end
local function is_leaf_node (t)
-- Predicate: Returns true if table only contains elements of type nil,
-- number, string or boolean
assert(type(t) == 'table')
for k,v in pairs(t) do
if not LEAF_VALUE_TYPES[type(k)] or not LEAF_VALUE_TYPES[type(v)] then
return false
end
end
return true
end
--------------------------------------------------------------------------------
local function get_table_info (t)
@ -201,6 +216,7 @@ local function get_table_info (t)
info.is_set = is_set(t) and info.nr_elems >= MINIMUM_NUMBER_OF_SET_ELEMENTS
info.is_tabular = is_tabular(t)
info.is_uniform = has_uniform_structure(t)
info.is_leaf_node = is_leaf_node(t)
-- Determine type of table
if not info.has_seq and not info.has_map then info.type = TABLE_TYPE.EMPTY

View File

@ -30,7 +30,7 @@ a table, we have a better idea, but then the output would be cluttered.
continue to represent it as `{}`, but `{...}` would be more "honest".
4. Single-line: TODO
5. Multi-line: TODO
6. ls style: TODO
6. Format into columns: (like ls) TODO
7. Tabular: TODO
8. Special cases: (Array-tree, Table-Tree, Linked-List) TODO
@ -268,7 +268,6 @@ local function fix_alignment (l, start_i, stop_i)
assert(type(start_i) == 'number')
assert(type(start_i) == 'number')
-- Do stuff
-- Find maximums
local max = {}
@ -286,6 +285,85 @@ local function fix_alignment (l, start_i, stop_i)
end
end
local function attempt_to_align_into_columns (l, start_i, stop_i, nr_items_pr_row)
assert(type(l) == 'table')
assert(type(start_i) == 'number')
assert(type(stop_i) == 'number')
assert(type(nr_items_pr_row) == 'number')
local column = {}
---
local start_of_item_i, item_nr = nil, 0
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 start_of_item_i then
local width_of_item = width_of_strings_in_l(l, start_of_item_i, i-1)
local column_i = (item_nr-1)%nr_items_pr_row+1
column[column_i] = math.max(column[column_i] or 0, width_of_item)
end
start_of_item_i, item_nr = i + 1, item_nr + 1
end
end
---
local width = nr_items_pr_row * 2 - 1 -- FIXME: Magic numbers: 2 = #', ', 1 = #' '
for i = 1, #column do width = width + column[i] end
--
return width, column
end
local function align_into_columns (l, start_i, stop_i)
-- Argument fixing and Error Checking
assert(type(l) == 'table')
local start_i, stop_i = start_i or 1, stop_i or #l
assert(type(start_i) == 'number')
assert(type(start_i) == 'number')
-- Find columns
local columns = nil
for nr_items_pr_row = 10, 1, -1 do -- TODO: Do this more intelligently.
local column_width
column_width, columns = attempt_to_align_into_columns(l, start_i, stop_i, nr_items_pr_row)
if column_width <= MAX_WIDTH_FOR_SINGLE_LINE_TABLE then break end
end
-- Change alignment of columns
local start_of_item_i, item_nr = nil, 0
for i = start_i, stop_i do
if type(l[i]) == 'table' and l[i][1] == 'align' then
local column_i = (item_nr-1)%#columns+1
l[i][2] = l[i][2] .. '_column_'..column_i
elseif (l[i][1] == 'indent' or l[i][1] == 'seperator' or l[i][1] == 'unindent') then
start_of_item_i, item_nr = i + 1, item_nr + 1
end
end
-- Fix newly changed alignment
fix_alignment(l, start_i, stop_i)
-- Quick-exit on only a single column
if #columns == 1 then return end
-- Fit into columns.
local start_of_item_i, item_nr = nil, 0
for i = start_i, stop_i do
if type(l[i]) ~= 'table' then
-- Do nothing
elseif (l[i][1] == 'indent' or l[i][1] == 'seperator' or l[i][1] == 'unindent') then
if start_of_item_i and l[i][1] == 'seperator' then
local column_i = (item_nr-1)%#columns+1
if column_i ~= #columns then
local width_of_item = width_of_strings_in_l(l, start_of_item_i, i-1)
l[i] = l[i][2] .. ' ' .. (' '):rep(columns[column_i]-width_of_item)
end
end
start_of_item_i, item_nr = i + 1, item_nr + 1
end
end
end
local function fix_seperator_info (l, indent_char, max_depth)
-- Error Checking
@ -404,6 +482,11 @@ local function format_table (t, depth, l)
-- Is short table: Ignore the "width of key"-shit
l[start_of_table_i][3] = 'inline'
ignore_alignment_info(l, start_of_table_i)
elseif table_info.is_leaf_node then
-- Is leaf node: Can format into columns.
-- NOTE: Currently we only allow leaf-nodes to format into columns, due
-- to issues with table alignment.
align_into_columns(l, start_of_table_i)
else
-- Is long table: Fix whitespace alignment
fix_alignment(l, start_of_table_i)

View File

@ -316,6 +316,18 @@ format_test {
expect = '{\n djævle = \'dyr?\',\n europa = \'måne\',\n øå = \'en å på en ø?\'\n}',
}
format_test {
name = 'Format table into columns, if leaf node',
input = {
'hello', 'world', 'how',
'is', 'it', 'going?',
'Im', 'doing great', 'thanks',
'that', 'was', 'what',
'I', 'were', 'expecting'
},
expect = '{\n \'hello\', \'world\', \'how\',\n \'is\', \'it\', \'going?\',\n \'Im\', \'doing great\', \'thanks\',\n \'that\', \'was\', \'what\',\n \'I\', \'were\', \'expecting\'\n}',
}
--------------------------------------------------------------------------------
-- Table recursion

View File

@ -50,7 +50,7 @@ format_test {
format_test {
name = 'Keys should be sorted such that uppercase and lowercase lies near each other',
input = { Dave = 1, dave = 2, mary = 3, Mary = 4, Adam = 5, adam = 6 },
expect = '{\n Adam = 5,\n adam = 6,\n Dave = 1,\n dave = 2,\n Mary = 4,\n mary = 3\n}',
expect = '{\n Adam = 5, adam = 6, Dave = 1,\n dave = 2, Mary = 4, mary = 3\n}',
}
format_test {
@ -118,28 +118,17 @@ local EXAMPLE_1_INPUT = {
}
local EXAMPLE_1_OUTPUT = ([[{
['z1.doc'] = 1,
['z2.doc'] = 1,
['z3.doc'] = 1,
['z4.doc'] = 1,
['z5.doc'] = 1,
['z6.doc'] = 1,
['z7.doc'] = 1,
['z8.doc'] = 1,
['z9.doc'] = 1,
['z10.doc'] = 1,
['z11.doc'] = 1,
['z12.doc'] = 1,
['z13.doc'] = 1,
['z14.doc'] = 1,
['z15.doc'] = 1,
['z16.doc'] = 1,
['z17.doc'] = 1,
['z18.doc'] = 1,
['z19.doc'] = 1,
['z20.doc'] = 1,
['z100.doc'] = 1,
['z101.doc'] = 1,
['z1.doc'] = 1, ['z2.doc'] = 1,
['z3.doc'] = 1, ['z4.doc'] = 1,
['z5.doc'] = 1, ['z6.doc'] = 1,
['z7.doc'] = 1, ['z8.doc'] = 1,
['z9.doc'] = 1, ['z10.doc'] = 1,
['z11.doc'] = 1, ['z12.doc'] = 1,
['z13.doc'] = 1, ['z14.doc'] = 1,
['z15.doc'] = 1, ['z16.doc'] = 1,
['z17.doc'] = 1, ['z18.doc'] = 1,
['z19.doc'] = 1, ['z20.doc'] = 1,
['z100.doc'] = 1, ['z101.doc'] = 1,
['z102.doc'] = 1
}]]):gsub('\t', ' ')
@ -238,7 +227,7 @@ end)
SUITE:addTest('alphanum algorithm extension 1', function ()
-- This is a test-case taken from http://www.davekoelle.com/alphanum.html
local OUTPUT = "{\n ['z2'] = 1,\n ['z2.'] = 1,\n ['z2.z'] = 1,\n ['z2.0'] = 1\n}"
local OUTPUT = "{\n ['z2'] = 1, ['z2.'] = 1,\n ['z2.z'] = 1, ['z2.0'] = 1\n}"
assert_equal(OUTPUT, pretty { ['z2.z'] = 1, ['z2.0'] = 1, ['z2.'] = 1, ['z2'] = 1 })
end)