Current section

Files

Jump to
tobble src tobble.erl
Raw

src/tobble.erl

-module(tobble).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([builder/0, add_row/2, to_list/1, build/1, build_with_internal/1, render_iter/2, render_with_options/2, render/1]).
-export_type([table/0, builder/0, render_option/0, render_line_type/0, builder_error/0, render_context/1, table_element/0, horizontal_rule_position/0, scaled_column_widths/0]).
-opaque table() :: {table, tobble@internal@rows:rows(binary())}.
-opaque builder() :: {builder, tobble@internal@builder:builder()}.
-type render_option() :: {table_width_render_option, integer()} |
{column_width_render_option, integer()} |
{line_type_render_option, render_line_type()}.
-type render_line_type() :: box_drawing_chars_line_type |
box_drawing_chars_with_rounded_corners_line_type |
ascii_line_type.
-type builder_error() :: {inconsistent_column_count_error, integer(), integer()} |
empty_table_error.
-type render_context(OLI) :: {render_context,
list(integer()),
fun((table_element()) -> binary())} |
{gleam_phantom, OLI}.
-type table_element() :: horizontal_line_element |
vertical_line_element |
four_way_junction_element |
start_junction_element |
end_junction_element |
top_junction_element |
bottom_junction_element |
top_start_corner_junction_element |
top_end_corner_junction_element |
bottom_start_corner_junction_element |
bottom_end_corner_junction_element.
-type horizontal_rule_position() :: top_rule_position |
center_rule_position |
bottom_rule_position.
-type scaled_column_widths() :: {scaled_column_widths,
list(integer()),
integer()}.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 158).
-spec builder() -> builder().
builder() ->
{builder, tobble@internal@builder:new()}.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 165).
-spec add_row(builder(), list(binary())) -> builder().
add_row(Builder, Columns) ->
_pipe = erlang:element(2, Builder),
_pipe@1 = tobble@internal@builder:add_row(_pipe, Columns),
{builder, _pipe@1}.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 327).
-spec to_list(table()) -> list(list(binary())).
to_list(Table) ->
tobble@internal@rows:to_lists(erlang:element(2, Table)).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 331).
-spec builder_error_from_internal(tobble@internal@builder:builder_error()) -> builder_error().
builder_error_from_internal(Error) ->
case Error of
{inconsistent_column_count_error, Expected, Got} ->
{inconsistent_column_count_error, Expected, Got};
empty_table_error ->
empty_table_error
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 173).
-spec build(builder()) -> {ok, table()} | {error, builder_error()}.
build(Builder) ->
_pipe = erlang:element(2, Builder),
_pipe@1 = tobble@internal@builder:to_result(_pipe),
_pipe@2 = gleam@result:map(_pipe@1, fun(Rows) -> {table, Rows} end),
gleam@result:map_error(_pipe@2, fun builder_error_from_internal/1).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 181).
-spec build_with_internal(tobble@internal@builder:builder()) -> {ok, table()} |
{error, builder_error()}.
build_with_internal(Builder) ->
build({builder, Builder}).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 361).
-spec render_horizontal_rule(render_context(any()), horizontal_rule_position()) -> binary().
render_horizontal_rule(Context, Position) ->
Start_junction = case Position of
top_rule_position ->
(erlang:element(3, Context))(top_start_corner_junction_element);
center_rule_position ->
(erlang:element(3, Context))(start_junction_element);
bottom_rule_position ->
(erlang:element(3, Context))(bottom_start_corner_junction_element)
end,
Middle_junction = case Position of
top_rule_position ->
(erlang:element(3, Context))(top_junction_element);
center_rule_position ->
(erlang:element(3, Context))(four_way_junction_element);
bottom_rule_position ->
(erlang:element(3, Context))(bottom_junction_element)
end,
End_junction = case Position of
top_rule_position ->
(erlang:element(3, Context))(top_end_corner_junction_element);
center_rule_position ->
(erlang:element(3, Context))(end_junction_element);
bottom_rule_position ->
(erlang:element(3, Context))(bottom_end_corner_junction_element)
end,
Horizontal = (erlang:element(3, Context))(horizontal_line_element),
Rule = begin
_pipe = erlang:element(2, Context),
_pipe@3 = gleam@list:map(_pipe, fun(Width) -> _pipe@1 = Horizontal,
_pipe@2 = gleam@string:repeat(_pipe@1, Width + 2),
gleam_stdlib:identity(_pipe@2) end),
_pipe@4 = gleam@string_tree:join(_pipe@3, Middle_junction),
_pipe@5 = gleam@string_tree:prepend(_pipe@4, Start_junction),
_pipe@6 = gleam@string_tree:append(_pipe@5, End_junction),
unicode:characters_to_binary(_pipe@6)
end,
Rule.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 498).
-spec limit_text_width(binary(), integer()) -> binary().
limit_text_width(Text, Width) ->
string_width:limit(Text, {size, string:length(Text), Width}, <<""/utf8>>).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 508).
-spec pad_end(binary(), integer()) -> binary().
pad_end(Text, Width) ->
string_width:align(Text, Width, left, <<" "/utf8>>).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 492).
-spec column_text_to_width(binary(), integer()) -> binary().
column_text_to_width(Text, Width) ->
_pipe = Text,
_pipe@1 = limit_text_width(_pipe, Width),
pad_end(_pipe@1, Width).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 471).
-spec render_visual_row(render_context(any()), list(binary())) -> binary().
render_visual_row(Context, Column_text) ->
Start_separator = <<((erlang:element(3, Context))(vertical_line_element))/binary,
" "/utf8>>,
Center_separator = <<<<" "/utf8,
((erlang:element(3, Context))(vertical_line_element))/binary>>/binary,
" "/utf8>>,
End_separator = <<" "/utf8,
((erlang:element(3, Context))(vertical_line_element))/binary>>,
_pipe = Column_text,
_pipe@3 = gleam@list:map2(
_pipe,
erlang:element(2, Context),
fun(Column, Width) -> _pipe@1 = Column,
_pipe@2 = column_text_to_width(_pipe@1, Width),
gleam_stdlib:identity(_pipe@2) end
),
_pipe@4 = gleam@string_tree:join(_pipe@3, Center_separator),
_pipe@5 = gleam@string_tree:prepend(_pipe@4, Start_separator),
_pipe@6 = gleam@string_tree:append(_pipe@5, End_separator),
unicode:characters_to_binary(_pipe@6).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 512).
-spec pad_list_end(list(OMU), integer(), OMU) -> list(OMU).
pad_list_end(List, To_length, Filler) ->
Length = erlang:length(List),
case Length >= To_length of
true ->
List;
false ->
gleam@list:flatten(
[List, gleam@list:repeat(Filler, To_length - Length)]
)
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 524).
-spec max_length(list(OMX), fun((OMX) -> integer())) -> {ok, integer()} |
{error, nil}.
max_length(Lists, Get_length) ->
case Lists of
[] ->
{error, nil};
Lists@1 ->
_pipe = Lists@1,
_pipe@1 = gleam@list:fold(
_pipe,
0,
fun(Acc, Lengthable) ->
Length = Get_length(Lengthable),
case Length > Acc of
true ->
Length;
false ->
Acc
end
end
),
{ok, _pipe@1}
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 351).
-spec column_lengths(tobble@internal@rows:rows(binary())) -> list(integer()).
column_lengths(Rows) ->
tobble@internal@rows:columnwise_fold(
Rows,
0,
fun(Max, Column) -> _pipe = Column,
_pipe@1 = gleam@string:split(_pipe, <<"\n"/utf8>>),
_pipe@2 = max_length(_pipe@1, fun string_width:line/1),
_pipe@3 = gleam@result:unwrap(_pipe@2, 0),
gleam@int:max(_pipe@3, Max) end
).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 442).
-spec row_yielder(render_context(any()), list(binary())) -> gleam@yielder:yielder(binary()).
row_yielder(Context, Column_text) ->
Column_lines = gleam@list:map2(
Column_text,
erlang:element(2, Context),
fun(Text, Width) -> _pipe = Text,
_pipe@1 = limit_text_width(_pipe, Width),
gleam@string:split(_pipe@1, <<"\n"/utf8>>) end
),
Height = begin
_pipe@2 = Column_lines,
_pipe@3 = max_length(_pipe@2, fun erlang:length/1),
gleam@result:unwrap(_pipe@3, 1)
end,
Visual_rows = begin
_pipe@4 = Column_lines,
_pipe@5 = gleam@list:map(
_pipe@4,
fun(Column) -> pad_list_end(Column, Height, <<""/utf8>>) end
),
gleam@list:transpose(_pipe@5)
end,
gleam@yielder:unfold(
Visual_rows,
fun(Remaining_rows) -> case Remaining_rows of
[] ->
done;
[Visual_row | Rest_rows] ->
{next, render_visual_row(Context, Visual_row), Rest_rows}
end end
).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 417).
-spec header_yielder(render_context(any()), list(binary())) -> gleam@yielder:yielder(binary()).
header_yielder(Context, Column_text) ->
gleam@yielder:append(
row_yielder(Context, Column_text),
gleam@yielder:once(
fun() -> render_horizontal_rule(Context, center_rule_position) end
)
).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 427).
-spec rows_yielder(render_context(any()), tobble@internal@rows:rows(binary())) -> gleam@yielder:yielder(binary()).
rows_yielder(Context, Rows) ->
_pipe = gleam@yielder:unfold(
Rows,
fun(Remaining_rows) ->
case tobble@internal@rows:pop_row(Remaining_rows) of
{error, nil} ->
done;
{ok, {Row, Rest_rows}} ->
{next, row_yielder(Context, Row), Rest_rows}
end
end
),
gleam@yielder:flatten(_pipe).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 401).
-spec rows_with_header_yielder(
render_context(any()),
tobble@internal@rows:rows(binary())
) -> gleam@yielder:yielder(binary()).
rows_with_header_yielder(Context, Rows) ->
case tobble@internal@rows:pop_row(Rows) of
{error, nil} ->
gleam@yielder:empty();
{ok, {Head_row, Rest_rows}} ->
gleam@yielder:append(
header_yielder(Context, Head_row),
rows_yielder(Context, Rest_rows)
)
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 340).
-spec rendered_yielder(render_context(any()), table()) -> gleam@yielder:yielder(binary()).
rendered_yielder(Context, Table) ->
_pipe = gleam@yielder:once(
fun() -> render_horizontal_rule(Context, top_rule_position) end
),
_pipe@1 = gleam@yielder:append(
_pipe,
rows_with_header_yielder(Context, erlang:element(2, Table))
),
gleam@yielder:append(
_pipe@1,
gleam@yielder:once(
fun() -> render_horizontal_rule(Context, bottom_rule_position) end
)
).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 618).
-spec apply_column_width_render_option(render_context(ONN), integer()) -> render_context(ONN).
apply_column_width_render_option(Context, Desired_width) ->
erlang:setelement(
2,
Context,
gleam@list:map(
erlang:element(2, Context),
fun(_) -> gleam@int:max(1, Desired_width) end
)
).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 632).
-spec column_content_width_for_table_width(integer(), integer()) -> integer().
column_content_width_for_table_width(Num_columns, Desired_width) ->
Decoration_width = (((Num_columns * 2) + (Num_columns - 1)) + 2),
Desired_width@1 = Desired_width - Decoration_width,
case Desired_width@1 =< 0 of
false ->
Desired_width@1;
true ->
Num_columns
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 660).
-spec scale_empty_columns(list(integer()), integer()) -> scaled_column_widths().
scale_empty_columns(Widths, Allowed_extra_width) ->
{Extra_width, New_widths} = gleam@list:map_fold(
Widths,
Allowed_extra_width,
fun(Acc, Width) -> case Acc of
0 ->
{Acc, Width};
Acc@1 when Width =:= 0 ->
{Acc@1 - 1, Width + 1};
Acc@2 ->
{Acc@2, Width}
end end
),
{scaled_column_widths, New_widths, Extra_width}.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 690).
-spec do_redistribute_extra_width(list(integer()), integer()) -> scaled_column_widths().
do_redistribute_extra_width(Widths, Allowed_extra_width) ->
{Extra_width@2, New_widths} = gleam@list:map_fold(
Widths,
Allowed_extra_width,
fun(Extra_width, Width) -> case Extra_width of
0 ->
{Extra_width, Width};
Extra_width@1 ->
{Extra_width@1 - 1, Width + 1}
end end
),
{scaled_column_widths, New_widths, Extra_width@2}.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 676).
-spec redistribute_extra_width(list(integer()), integer()) -> scaled_column_widths().
redistribute_extra_width(Widths, Allowed_extra_width) ->
case Allowed_extra_width of
0 ->
{scaled_column_widths, Widths, 0};
Allowed_extra_width@1 ->
Redistributed = do_redistribute_extra_width(
Widths,
Allowed_extra_width@1
),
redistribute_extra_width(
erlang:element(2, Redistributed),
erlang:element(3, Redistributed)
)
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 581).
-spec apply_table_width_render_option(render_context(ONK), integer()) -> render_context(ONK).
apply_table_width_render_option(Context, Desired_width) ->
Desired_width@1 = column_content_width_for_table_width(
erlang:length(erlang:element(2, Context)),
Desired_width
),
Total_original_width = gleam@int:sum(erlang:element(2, Context)),
Scaled_widths = gleam@list:map(
erlang:element(2, Context),
fun(Column_width) -> case Total_original_width of
0 -> 0;
Gleam@denominator -> Column_width * Desired_width@1 div Gleam@denominator
end end
),
Total_scaled_width = gleam@int:sum(Scaled_widths),
case gleam@int:compare(Total_scaled_width, Total_original_width) of
gt ->
erlang:setelement(2, Context, Scaled_widths);
eq ->
erlang:setelement(2, Context, Scaled_widths);
lt ->
Extra_width = Desired_width@1 - Total_scaled_width,
{scaled_column_widths, Scaled_widths@1, Extra_width@1} = scale_empty_columns(
Scaled_widths,
Extra_width
),
{scaled_column_widths, Scaled_widths@2, _} = redistribute_extra_width(
Scaled_widths@1,
Extra_width@1
),
erlang:setelement(2, Context, Scaled_widths@2)
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 709).
-spec lookup_ascii_table_element(table_element()) -> binary().
lookup_ascii_table_element(Element) ->
case Element of
horizontal_line_element ->
<<"-"/utf8>>;
vertical_line_element ->
<<"|"/utf8>>;
four_way_junction_element ->
<<"+"/utf8>>;
start_junction_element ->
<<"+"/utf8>>;
end_junction_element ->
<<"+"/utf8>>;
top_junction_element ->
<<"+"/utf8>>;
bottom_junction_element ->
<<"+"/utf8>>;
top_start_corner_junction_element ->
<<"+"/utf8>>;
top_end_corner_junction_element ->
<<"+"/utf8>>;
bottom_start_corner_junction_element ->
<<"+"/utf8>>;
bottom_end_corner_junction_element ->
<<"+"/utf8>>
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 541).
-spec default_render_context(table()) -> render_context(any()).
default_render_context(Table) ->
{render_context,
column_lengths(erlang:element(2, Table)),
fun lookup_ascii_table_element/1}.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 725).
-spec lookup_box_drawing_table_element(table_element()) -> binary().
lookup_box_drawing_table_element(Element) ->
case Element of
horizontal_line_element ->
<<"─"/utf8>>;
vertical_line_element ->
<<"│"/utf8>>;
four_way_junction_element ->
<<"┼"/utf8>>;
start_junction_element ->
<<"├"/utf8>>;
end_junction_element ->
<<"┤"/utf8>>;
top_junction_element ->
<<"┬"/utf8>>;
bottom_junction_element ->
<<"┴"/utf8>>;
top_start_corner_junction_element ->
<<"┌"/utf8>>;
top_end_corner_junction_element ->
<<"┐"/utf8>>;
bottom_start_corner_junction_element ->
<<"└"/utf8>>;
bottom_end_corner_junction_element ->
<<"┘"/utf8>>
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 741).
-spec lookup_box_drawing_rounded_corner_table_element(table_element()) -> binary().
lookup_box_drawing_rounded_corner_table_element(Element) ->
case Element of
horizontal_line_element ->
<<"─"/utf8>>;
vertical_line_element ->
<<"│"/utf8>>;
four_way_junction_element ->
<<"┼"/utf8>>;
start_junction_element ->
<<"├"/utf8>>;
end_junction_element ->
<<"┤"/utf8>>;
top_junction_element ->
<<"┬"/utf8>>;
bottom_junction_element ->
<<"┴"/utf8>>;
top_start_corner_junction_element ->
<<"╭"/utf8>>;
top_end_corner_junction_element ->
<<"╮"/utf8>>;
bottom_start_corner_junction_element ->
<<"╰"/utf8>>;
bottom_end_corner_junction_element ->
<<"╯"/utf8>>
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 564).
-spec apply_line_type_render_option(render_context(ONH), render_line_type()) -> render_context(ONH).
apply_line_type_render_option(Context, Line_type) ->
case Line_type of
ascii_line_type ->
erlang:setelement(3, Context, fun lookup_ascii_table_element/1);
box_drawing_chars_line_type ->
erlang:setelement(
3,
Context,
fun lookup_box_drawing_table_element/1
);
box_drawing_chars_with_rounded_corners_line_type ->
erlang:setelement(
3,
Context,
fun lookup_box_drawing_rounded_corner_table_element/1
)
end.
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 548).
-spec apply_options(render_context(OND), list(render_option())) -> render_context(OND).
apply_options(Context, Options) ->
gleam@list:fold(Options, Context, fun(Context@1, Option) -> case Option of
{line_type_render_option, Line_type} ->
apply_line_type_render_option(Context@1, Line_type);
{table_width_render_option, Width} ->
apply_table_width_render_option(Context@1, Width);
{column_width_render_option, Width@1} ->
apply_column_width_render_option(Context@1, Width@1)
end end).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 248).
-spec render_iter(table(), list(render_option())) -> gleam@yielder:yielder(binary()).
render_iter(Table, Options) ->
_pipe = default_render_context(Table),
_pipe@1 = apply_options(_pipe, Options),
rendered_yielder(_pipe@1, Table).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 290).
-spec render_with_options(table(), list(render_option())) -> binary().
render_with_options(Table, Options) ->
_pipe = default_render_context(Table),
_pipe@1 = apply_options(_pipe, Options),
_pipe@2 = rendered_yielder(_pipe@1, Table),
_pipe@3 = gleam@yielder:map(_pipe@2, fun gleam_stdlib:identity/1),
_pipe@4 = gleam@yielder:to_list(_pipe@3),
_pipe@5 = gleam@string_tree:join(_pipe@4, <<"\n"/utf8>>),
unicode:characters_to_binary(_pipe@5).
-file("/home/nick/Documents/code/tobble/src/tobble.gleam", 213).
-spec render(table()) -> binary().
render(Table) ->
render_with_options(Table, []).