Skip to content

Instantly share code, notes, and snippets.

@mevansam
Last active October 12, 2015 21:57
Show Gist options
  • Save mevansam/4092474 to your computer and use it in GitHub Desktop.
Save mevansam/4092474 to your computer and use it in GitHub Desktop.
Ruby method to format a text table that resizes to the screen width
require "set"
require "highline"
#
# Prints a 2-d array as a table formatted to terminal size
#
def print_table(table, format = true, cols = nil)
# Apply column filter
unless cols.nil?
headings = cols.split(",").to_set
cols_to_delete = [ ]
i = 0
table[0].each do |col|
cols_to_delete << i unless headings.include?(col)
i = i + 1
end
table.each do |row|
cols_to_delete.reverse_each { |j| row.delete_at(j) }
end
end
if format
# Calculate widths
widths = []
table.each do |line|
c = 0
line.each do |col|
len = col.length
widths[c] = (widths[c] && widths[c] > len) ? widths[c] : len
c += 1
end
end
max_scr_cols = HighLine::SystemExtensions.terminal_size[0] - (widths.length * 3) - 1
max_tbl_cols = 0
width_map = {}
c = 0
widths.each do |n|
max_tbl_cols += n
width_map[c] = n
c += 1
end
c = nil
# Shrink columns that have too much space to try and fit table into visible console
if max_tbl_cols > max_scr_cols
width_map = width_map.sort_by { |col,width| -width }
last_col = widths.length - 1
c = 0
while max_tbl_cols > max_scr_cols && c < last_col
while width_map[c][1] > width_map[c + 1][1]
i = c
while i >= 0
width_map[i][1] -= 1
widths[width_map[i][0]] -= 1
max_tbl_cols -= 1
i -= 1
break if max_tbl_cols == max_scr_cols
end
break if max_tbl_cols == max_scr_cols
end
c += 1
end
end
border1 = ""
border2 = ""
format = ""
widths.each do |n|
border1 += "+#{'-' * (n + 2)}"
border2 += "+#{'=' * (n + 2)}"
format += "| %#{n}s "
end
border1 += "+\n"
border2 += "+\n"
format += "|\n"
else
c = nil
border1 = nil
border2 = nil
format = Array.new(table[0].size, "%s,").join.chop! + "\n"
# Delete column headings for unformatted output
table.delete_at(0)
end
# Print each line.
write_header_border = !border2.nil?
printf border1 if border1
table.each do |line|
if c
# Check if cell needs to be truncated
i = 0
while i < c
j = width_map[i][0]
width = width_map[i][1]
cell = line[j]
len = cell.length
if len > width
line[j] = cell[0, width - 2] + ".."
end
i += 1
end
end
printf format, *line
if write_header_border
printf border2
write_header_border = false
end
end
printf border1 if border1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment