Skip to content

Commit

Permalink
Add some more
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorthurlow committed Jun 26, 2020
1 parent dae011a commit cc573e0
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 124 deletions.
204 changes: 204 additions & 0 deletions src/thicket/column.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
class Column
property :string_list

enum Layout
Plain
Column
Row
end

enum Enable
Always
Never
Auto
end

def initialize(
@string_list : Array(String),
@column_options : ColumnOptions,
@rows : UInt32,
@cols : UInt32,
@cell_length : Array(UInt32), # len
@width : Array(UInt16), # index to longest row in column
@layout : Layout,
@enable : Enable,
@dense : Bool
)
end

private def compute_column_width
@cols.each_with_index do |col, x|
@width[x] = x_y_to_linear(x, 0)
@rows.each_with_index do |row, y|
i = x_y_to_linear(x, y)
@width[x] = i if i < @string_list.size && @cell_length[@width[x]] < @cell_length[i]
end
end
end

# Shrink all columns by shortening them one row each time (and adding more
# columns along the way). Hopefully the longest cell will be moved to the
# next column, column is shrunk so we have more space for new columns. The
# process ends when the whole thing no longer fits in total_width.
def shrink_columns
while @rows > 1
rows = @rows
cols = @cols
@rows -= 1
@cols = (@string_list.size + @rows - 1) / @rows

compute_column_width if @cols != cols

total_width = @column_options.indent

@cols.each_with_index do |col, x|
total_width += @cell_length[@width[x]]
total_width += @column_options.padding
end

if total_width > @column_options.width
@rows = rows
@cols = cols
break
end
end

compute_column_width
end

def print_columns(string_list : Array(String), column_options : ColumnOptions)
return if string_list.empty?

# raise "fail" unless col_auto_enabled

nopts = ColumnOptions.new(
indent: column_options.indent || "",
newline: column_options.newline || "\n",
padding: column_options.padding || 1,
width: column_options.width || (term_columns - 1),
)

if @enable == Enable::Always
display_plain(string_list, "", "\n")
return
end

case @layout
when Layout::Plain
display_plain(list, nopts.indent, nopts.newline)
when Layout::Row, Layout::Column
display_table(list, nopts)
else
raise "Invalid layout mode: #{@layout}"
end
end

private def display_plain(string_list : Array(String), indent : String, newline : String)
string_list.each do |s|
STDOUT.printf(
"%s%s%s",
indent,
string_list[i],
newline
)
end
end

# Print a cell to STDOUT with all necessary leading/trailing space
private def display_cell(initial_width : UInt16, empty_cell : String, x : UInt32, y : UInt32) : Bool
i = x_y_to_linear(x, y)
return false if i >= @string_list.size

length = @cell_length[i]
if (@width && @cell_length[width[x]]) < initial_width
length += initial_width - @cell_length[width[x]]
length -= @column_options.padding
end

newline = if @column_options.cols_before_rows?
i + @rows >= @string_list.size
else
x == @cols - 1 || i == @string_list.size - 1
end

STDOUT.printf(
"%s%s%s",
x == 0 ? @column_options.indent : "",
@string_list[i],
newline ? @column_options.newline : empty_cell + length
)

return true
end

private def display_table(string_list : Array(String), column_options : ColumnOptions)
column = Column.new(
string_list: string_list,
column_options: column_options,
cell_length: string_list.map { |s| self.string_length_without_ansi(s) },
)

initial_width = 0
layout(column, initial_width)

# if COL_DENSE then shrink_columns(column)

@rows.each_with_index do |row, y|
@cols.each do |col, x|
break if display_cell(column, initial_width, " ", x, y)
end
end
end

# Calculate cell width, rows, and columns for a table of equal cells, given
# table width and how many spaces between the cells.
private def layout(width : UInt16 = 0)
width = @cell_length.max
width += @column_options.padding

@cols = (@column_options.width - @column_options.indent.size) / width
@cols = 1 if @cols == 0

@rows = (@string_list.size + @cols - 1) / @cols
end

private def x_y_to_linear(x : UInt32, y : UInt32) : UInt32
if @column_options.cols_before_rows?
x * @rows + y
else
y * @cols + x
end
end

COL_LAYOUT_MASK = 0x000F
COL_COLUMN = 0 # fill columns before rows
COL_ROW = 1 # fill rows before columns
COL_PLAIN = 15 # one column

ANSI_ESCAPE_REGEX = /(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/

private def self.string_length_without_ansi(string : String) : UInt32
string.gsub(ANSI_ESCAPE_REGEX, "").size
end

struct ColumnOptions
property :width, :padding, :indent, :newline, :rows_before_cols

def initialize(
@width : UInt8,
@padding : UInt8,
@indent : String,
@newline : String,
@rows_before_cols : Bool
)
end

def rows_before_cols? : Bool
@rows_before_cols
end

def cols_before_rows? : Bool
!rows_before_cols?
end
end
end
125 changes: 1 addition & 124 deletions src/thicket/graph.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module Thicket
end

def initialize(revs)
@commit = nil
@commit : Commit # the commit currently being processed
@revs = revs
@num_parents = 0
@expansion_row = 0
Expand All @@ -28,127 +28,4 @@ module Thicket
@columns = Array(Column)
end
end

class Column
property :string_list

def initialize(
@string_list : Array(String),
@column_options : ColumnOptions,
@rows : UInt32,
@cols : UInt32,
@cell_length : Array(UInt32), # len
@width : Array(UInt16) # index to longest row in column
)
end

private def display_plain(string_list : Array(String), indent : String, newline : String)
string_list.each do |s|
STDOUT.printf(
"%s%s%s",
indent,
string_list[i],
newline
)
end
end

# Print a cell to STDOUT with all necessary leading/trailing space
private def display_cell(initial_width : UInt16, empty_cell : String, x : UInt32, y : UInt32) : Boolean
i = x_y_to_linear(x, y)
return false if i >= @string_list.size

length = @cell_length[i]
if (@width && @cell_length[width[x]]) < initial_width
length += initial_width - @cell_length[width[x]]
length -= @column_options.padding
end

newline = if @column_options.cols_before_rows?
i + @rows >= @string_list.size
else
x == @cols - 1 || i == @string_list.size - 1
end

STDOUT.printf(
"%s%s%s",
x == 0 ? @column_options.indent : "",
@string_list[i],
newline ? @column_options.newline : empty_cell + length
)

return true
end

private def display_table(string_list : Array(String), column_options : ColumnOptions)
column = Column.new(
string_list: string_list,
column_options: column_options,
cell_length: string_list.map { |s| self.string_length_without_ansi(s) },
)

initial_width = 0
layout(column, initial_width)

# if COL_DENSE then shrink_columns(column)

@rows.each_with_index do |row, y|
@cols.each do |col, x|
break if display_cell(column, initial_width, " ", x, y)
end
end
end

# Calculate cell width, rows, and columns for a table of equal cells, given
# table width and how many spaces between the cells.
private def layout(width : UInt16 = 0)
width = @cell_length.max
width += @column_options.padding

@cols = (@column_options.width - @column_options.indent.size) / width
@cols = 1 if @cols == 0

@rows = (@string_list.size + @cols - 1) / @cols
end

private def x_y_to_linear(x : UInt32, y : UInt32) : UInt32
if @column_options.cols_before_rows?
x * @rows + y
else
y * @cols + x
end
end

COL_LAYOUT_MASK = 0x000F
COL_COLUMN = 0 # fill columns before rows
COL_ROW = 1 # fill rows before columns
COL_PLAIN = 15 # one column

ANSI_ESCAPE_REGEX = /(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/

private def self.string_length_without_ansi(string : String) : UInt32
string.gsub(ANSI_ESCAPE_REGEX, "").size
end

struct ColumnOptions
property :width, :padding, :indent, :newline, :rows_before_cols

def initialize(
@width : UInt8,
@padding : UInt8,
@indent : String,
@newline : String,
@rows_before_cols : Boolean
)
end

def rows_before_cols? : Boolean
@rows_before_cols
end

def cols_before_rows? : Boolean
!rows_before_cols?
end
end
end
end

0 comments on commit cc573e0

Please sign in to comment.