Skip to content

Commit

Permalink
Minimum table width parm for shrinkwrap!
Browse files Browse the repository at this point in the history
  • Loading branch information
hutou committed Nov 25, 2019
1 parent e8fa1ef commit e77a6ca
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 12 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Most features of Tabulo are found in Tablo
- Set fixed column widths, then either wrap or truncate the overflow.
- Alternatively, shrinkwrap the table so that each column is just wide enough for its contents.
- Put an upper limit on total table width when shrinkwrapping, to stop it overflowing your terminal horizontally.
- Put a lower limit on total table width when shrinkwrapping, to keep table
width from being too small.
- Alignment of cell content is configurable, but has helpful content-based defaults (numbers right, strings left).
- Headers are repeatable.
- Newlines within cell content are correctly handled.
Expand Down Expand Up @@ -411,7 +413,10 @@ _Take care, however, because the width of columns is then adjusted to their
content, regardless of their width (fixed or default): so columns may be
narrowed or widened!_

If table width gets too wide, there is fortunately a workaround : just pass an argument to _shrinkwrap!_ to limit the total width of the table.
If table width gets too wide, there is fortunately a workaround : just pass an
argument to _shrinkwrap!_ to limit the total width of the table (or, if table
width is too small, pass this argument as a negative value to force a minimum
table width).

```crystal
21: table.shrinkwrap!
Expand Down
19 changes: 18 additions & 1 deletion spec/table_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -764,9 +764,26 @@ describe "Tablo::Table" do
+---+-------+------+-------+-------+------+------+).gsub(/^ +/m, "")
end

t22b = add_columns_7m(mktable_5i32(default_header_alignment: Tablo::Justify::Center, default_column_width: 8))
it "honors the minimum table width (negative value) passed to shrinkwrap!" do
t22b.shrinkwrap!(-80)

t22b.to_s.should eq \
%q(+----------+----------+----------+----------+----------+------------+----------+
| N | Double | to_s | Is it | dec | word | cool |
| | | | even? | | yep | |
+----------+----------+----------+----------+----------+------------+----------+
| 1 | 2 | 1 | false | 1.0 | ww | |
| 2 | 4 | 2 | true | 2.00 | wwww | |
| 3 | 6 | 3 | false | 3.000 | wwwwww | two |
| | | | | | | lines |
| 4 | 8 | 4 | true | 4.0000 | wwwwwwww | |
| 5 | 10 | 5 | false | 5.00000 | wwwwwwwwww | |
+----------+----------+----------+----------+----------+------------+----------+).gsub(/^ +/m, "")
end
t23a = add_columns_7m(mktable_5i32(default_header_alignment: Tablo::Justify::Center, default_column_width: 8))
it "returns the Table itself" do
t23a.shrinkwrap!(max_table_width: [nil, 54, 47].sample).to_s.should eq(t23a.to_s)
t23a.shrinkwrap!(max_min_width: [0, 54, 47].sample).to_s.should eq(t23a.to_s)
end
end

Expand Down
104 changes: 95 additions & 9 deletions src/table.cr
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ module Tablo
# Note that calling this method will cause the entire source to
# be traversed and all the column extractors and formatters to be applied in order
# to calculate the required widths.
def shrinkwrap!(max_table_width = nil)
def shrinkwrap!(max_min_width = 0)
return self if column_registry.none?

columns = column_registry.values

# Adjust column header width to its minimum by calling the `wrapped_with`
Expand All @@ -141,26 +142,111 @@ module Tablo
end
end

if max_table_width
# specific adjustments
if max_min_width != 0
total_columns_width = columns.reduce(0) { |sum, column| sum + column.width }
total_padding = column_registry.size * @column_padding * 2
total_borders = column_registry.size + 1
unadjusted_table_width = total_columns_width + total_padding + total_borders

# Ensure max table width is at least wide enough to accommodate table borders and padding
# and one character of content.
min_table_width = total_padding + total_borders + column_registry.size
max_table_width = min_table_width if min_table_width > max_table_width
if max_min_width < 0
# Minimum width required
min_table_width = [total_padding + total_borders + column_registry.size, max_min_width.abs].max
max_table_width = [unadjusted_table_width, min_table_width].max
else
# Maximum width required
min_table_width = total_padding + total_borders + column_registry.size
max_table_width = [unadjusted_table_width, max_min_width].min
end

required_reduction = [unadjusted_table_width - max_table_width, 0].max
# max_table_width = unadjusted_table_width if max_table_width == 0
# min_table_width = [total_padding + total_borders + column_registry.size, min_table_width].max
# max_table_width = [max_table_width, min_table_width].max

required_reduction.times do
widest_column = columns.reduce(columns.first) do |widest, column|
column.width >= widest.width ? column : widest
if unadjusted_table_width > max_table_width
required_adjustment = [unadjusted_table_width - max_table_width, 0].max
required_adjustment.times do
widest_column = columns.reduce(columns.first) do |widest, column|
column.width >= widest.width ? column : widest
end
widest_column.width -= 1
end
elsif unadjusted_table_width < min_table_width
required_adjustment = [min_table_width - unadjusted_table_width, 0].max
required_adjustment.times do
narrowest_column = columns.reduce(columns.first) do |narrowest, column|
column.width <= narrowest.width ? column : narrowest
end
narrowest_column.width += 1
end
else
# nothoing to do
end

# required_reduction = [unadjusted_table_width - max_table_width, 0].max

end

self
end

def zzz_shrinkwrap!(max_table_width = 0, min_table_width = 0)
return self if column_registry.none?

columns = column_registry.values

# Adjust column header width to its minimum by calling the `wrapped_with`
# method
columns.each do |column|
column.width = wrapped_width(column.header)
end

widest_column.width -= 1
# Adjust column data width to its minimum by calling the `wrapped_with`
# on each source row
@sources.each do |source|
columns.each do |column|
width = wrapped_width(column.formatted_cell_content(source))
column.width = width if width > column.width
end
end

# specific adjustments
if max_table_width != 0 || min_table_width != 0
total_columns_width = columns.reduce(0) { |sum, column| sum + column.width }
total_padding = column_registry.size * @column_padding * 2
total_borders = column_registry.size + 1
unadjusted_table_width = total_columns_width + total_padding + total_borders

# Ensure max table width is at least wide enough to accommodate table borders and padding
# and one character of content.
max_table_width = unadjusted_table_width if max_table_width == 0
min_table_width = [total_padding + total_borders + column_registry.size, min_table_width].max
max_table_width = [max_table_width, min_table_width].max

if unadjusted_table_width > max_table_width
required_adjustment = [unadjusted_table_width - max_table_width, 0].max
required_adjustment.times do
widest_column = columns.reduce(columns.first) do |widest, column|
column.width >= widest.width ? column : widest
end
widest_column.width -= 1
end
elsif unadjusted_table_width < min_table_width
required_adjustment = [min_table_width - unadjusted_table_width, 0].max
required_adjustment.times do
narrowest_column = columns.reduce(columns.first) do |narrowest, column|
column.width <= narrowest.width ? column : narrowest
end
narrowest_column.width += 1
end
else
# nothoing to do
end

# required_reduction = [unadjusted_table_width - max_table_width, 0].max

end

self
Expand Down
2 changes: 1 addition & 1 deletion src/tablo.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ require "./table.cr"
require "./column.cr"

module Tablo
VERSION = "0.9.2"
VERSION = "0.9.3"
extend self
end

0 comments on commit e77a6ca

Please sign in to comment.