Packages

A simple Gleam library for pretty printing tabular data!

Current section

Files

Jump to
trellis src trellis.erl
Raw

src/trellis.erl

-module(trellis).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([table/1, param/1, with/4, to_string/1]).
-export_type([table/1, column/1, align/0]).
-type table(EZQ) :: {table, list(column(EZQ)), list(EZQ)}.
-type column(EZR) :: {column, binary(), align(), fun((EZR) -> binary())}.
-type align() :: left | right | center.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 60).
-spec table(list(EZS)) -> table(EZS).
table(Rows) ->
{table, [], Rows}.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 68).
-spec param(fun((EZV) -> EZW)) -> fun((EZV) -> EZW).
param(F) ->
F.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 73).
-spec with(table(EZX), binary(), align(), fun((EZX) -> binary())) -> table(EZX).
with(Builder, Header, Align, Getter) ->
{table, Columns, Rows} = Builder,
{table, [{column, Header, Align, Getter} | Columns], Rows}.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 87).
-spec calculate_widths(list(binary()), list(binary())) -> list(integer()).
calculate_widths(Headers, Values) ->
Lengths = gleam@list:sized_chunk(Values, erlang:length(Headers)),
gleam@list:map2(
Headers,
gleam@list:transpose(Lengths),
fun(Header, Col_values) ->
Max_value_length = gleam@list:fold(
Col_values,
0,
fun(Acc, Val) -> gleam@int:max(Acc, string:length(Val)) end
),
gleam@int:max(string:length(Header), Max_value_length)
end
).
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 193).
-spec pad_left(binary(), integer()) -> binary().
pad_left(Text, Width) ->
Padding = Width - string:length(Text),
<<(gleam@string:repeat(<<" "/utf8>>, Padding))/binary, Text/binary>>.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 199).
-spec pad_right(binary(), integer()) -> binary().
pad_right(Text, Width) ->
Padding = Width - string:length(Text),
<<Text/binary, (gleam@string:repeat(<<" "/utf8>>, Padding))/binary>>.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 205).
-spec pad_center(binary(), integer()) -> binary().
pad_center(Text, Width) ->
Padding = Width - string:length(Text),
Left = Padding div 2,
Right = Padding - Left,
<<<<(gleam@string:repeat(<<" "/utf8>>, Left))/binary, Text/binary>>/binary,
(gleam@string:repeat(<<" "/utf8>>, Right))/binary>>.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 166).
-spec make_row(list(align()), list(integer()), list(binary())) -> binary().
make_row(Aligns, Widths, Values) ->
Row = begin
_pipe = begin
gleam@list:map2(
begin
gleam@list:map2(
Aligns,
Widths,
fun(Align, Width) -> {Align, Width} end
)
end,
Values,
fun(_use0, Value) ->
{Align@1, Width@1} = _use0,
Padded = case Align@1 of
left ->
pad_right(Value, Width@1);
right ->
pad_left(Value, Width@1);
center ->
pad_center(Value, Width@1)
end,
<<<<" "/utf8, Padded/binary>>/binary, " "/utf8>>
end
)
end,
gleam@string:join(_pipe, <<"│"/utf8>>)
end,
<<<<"│"/utf8, Row/binary>>/binary, "│"/utf8>>.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 138).
-spec make_separator(list(integer()), boolean(), boolean()) -> binary().
make_separator(Columns, Is_header, Is_top) ->
Start = case {Is_top, Is_header} of
{true, _} ->
<<"┌"/utf8>>;
{false, true} ->
<<"├"/utf8>>;
{false, false} ->
<<"└"/utf8>>
end,
End = case {Is_top, Is_header} of
{true, _} ->
<<"┐"/utf8>>;
{false, true} ->
<<"┤"/utf8>>;
{false, false} ->
<<"┘"/utf8>>
end,
Middle = case {Is_top, Is_header} of
{true, _} ->
<<"┬"/utf8>>;
{false, true} ->
<<"┼"/utf8>>;
{false, false} ->
<<"┴"/utf8>>
end,
Line = gleam@list:fold(
Columns,
Start,
fun(Acc, Col) ->
<<<<Acc/binary,
(gleam@string:repeat(<<"─"/utf8>>, Col + 2))/binary>>/binary,
Middle/binary>>
end
),
<<(gleam@string:slice(Line, 0, string:length(Line) - 1))/binary,
End/binary>>.
-file("/home/ethanthoma/projects/trellis/src/trellis.gleam", 102).
-spec to_string(table(any())) -> binary().
to_string(Table) ->
{table, Columns, Rows} = Table,
Columns@1 = lists:reverse(Columns),
Headers = gleam@list:map(Columns@1, fun(Col) -> erlang:element(2, Col) end),
Aligns = gleam@list:map(
Columns@1,
fun(Col@1) -> erlang:element(3, Col@1) end
),
Values = gleam@list:flat_map(
Rows,
fun(Row) ->
gleam@list:map(
Columns@1,
fun(Col@2) -> (erlang:element(4, Col@2))(Row) end
)
end
),
Widths = calculate_widths(Headers, Values),
Separator_top = make_separator(Widths, true, true),
Header_row = make_row(
gleam@list:map(
gleam@list:range(1, erlang:length(Columns@1)),
fun(_) -> center end
),
Widths,
Headers
),
Separator_header = make_separator(Widths, true, false),
Body_rows = gleam@list:map(
Rows,
fun(Row@1) ->
Row_values = gleam@list:map(
Columns@1,
fun(Col@3) -> (erlang:element(4, Col@3))(Row@1) end
),
make_row(Aligns, Widths, Row_values)
end
),
Separator_bottom = make_separator(Widths, false, false),
_pipe = [Separator_top, Header_row, Separator_header],
_pipe@1 = lists:append(_pipe, Body_rows),
_pipe@2 = lists:append(_pipe@1, [Separator_bottom]),
gleam@string:join(_pipe@2, <<"\n"/utf8>>).