-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, []).