-module(spruce@block). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/spruce/block.gleam"). -export([new/0, foreground/2, background/2, padding/5, margin/5, width/2, height/2, align/3, border/2, border_colors/5, border_sides/5, render/3]). -export_type([block/0, sides/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(" Block styling for multiline terminal text.\n"). -opaque block() :: {block, gleam@option:option(spruce@style:color()), gleam@option:option(spruce@style:color()), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), gleam@option:option(integer()), gleam@option:option(integer()), spruce@layout:pos(), spruce@layout:pos(), gleam@option:option(spruce@box:border()), spruce@style:color(), spruce@style:color(), spruce@style:color(), spruce@style:color(), boolean(), boolean(), boolean(), boolean()}. -type sides() :: {sides, boolean(), boolean(), boolean(), boolean()}. -file("src/spruce/block.gleam", 49). ?DOC(" Build block options with no styling, padding, margin, or border.\n"). -spec new() -> block(). new() -> {block, none, none, 0, 0, 0, 0, 0, 0, 0, 0, none, none, start, start, none, cyan, cyan, cyan, cyan, true, true, true, true}. -file("src/spruce/block.gleam", 78). ?DOC(" Set the foreground color applied to content lines.\n"). -spec foreground(block(), spruce@style:color()) -> block(). foreground(Block, Color) -> {block, {some, Color}, erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 83). ?DOC(" Set the background color applied to content lines.\n"). -spec background(block(), spruce@style:color()) -> block(). background(Block, Color) -> {block, erlang:element(2, Block), {some, Color}, erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 568). -spec non_negative(integer()) -> integer(). non_negative(Value) -> gleam@int:max(0, Value). -file("src/spruce/block.gleam", 88). ?DOC(" Set inner padding as top, right, bottom, left cell counts.\n"). -spec padding(block(), integer(), integer(), integer(), integer()) -> block(). padding(Block, Top, Right, Bottom, Left) -> {block, erlang:element(2, Block), erlang:element(3, Block), non_negative(Top), non_negative(Right), non_negative(Bottom), non_negative(Left), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 105). ?DOC(" Set outer margin as top, right, bottom, left cell counts.\n"). -spec margin(block(), integer(), integer(), integer(), integer()) -> block(). margin(Block, Top, Right, Bottom, Left) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), non_negative(Top), non_negative(Right), non_negative(Bottom), non_negative(Left), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 122). ?DOC(" Constrain content to a visual width and wrap with `spruce/align.wrap`.\n"). -spec width(block(), integer()) -> block(). width(Block, Width) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), {some, non_negative(Width)}, erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 129). ?DOC( " Constrain content to a line count.\n" " Short content is padded with blank lines using vertical alignment; tall\n" " content is truncated from the bottom after wrapping.\n" ). -spec height(block(), integer()) -> block(). height(Block, Height) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), {some, non_negative(Height)}, erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 134). ?DOC(" Align content horizontally within width and vertically within height.\n"). -spec align(block(), spruce@layout:pos(), spruce@layout:pos()) -> block(). align(Block, Horizontal, Vertical) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), Horizontal, Vertical, erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 143). ?DOC(" Draw a border around the padded block.\n"). -spec border(block(), spruce@box:border()) -> block(). border(Block, Border) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), {some, Border}, erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 148). ?DOC(" Set top, right, bottom, and left border colors independently.\n"). -spec border_colors( block(), spruce@style:color(), spruce@style:color(), spruce@style:color(), spruce@style:color() ) -> block(). border_colors(Block, Top, Right, Bottom, Left) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), Top, Right, Bottom, Left, erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}. -file("src/spruce/block.gleam", 165). ?DOC(" Set top, right, bottom, and left border visibility independently.\n"). -spec border_sides(block(), boolean(), boolean(), boolean(), boolean()) -> block(). border_sides(Block, Top, Right, Bottom, Left) -> {block, erlang:element(2, Block), erlang:element(3, Block), erlang:element(4, Block), erlang:element(5, Block), erlang:element(6, Block), erlang:element(7, Block), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block), erlang:element(12, Block), erlang:element(13, Block), erlang:element(14, Block), erlang:element(15, Block), erlang:element(16, Block), erlang:element(17, Block), erlang:element(18, Block), erlang:element(19, Block), erlang:element(20, Block), Top, Right, Bottom, Left}. -file("src/spruce/block.gleam", 557). -spec repeat_line_loop(binary(), integer(), list(binary())) -> list(binary()). repeat_line_loop(Line, Count, Acc) -> case Count of 0 -> Acc; _ -> repeat_line_loop(Line, Count - 1, [Line | Acc]) end. -file("src/spruce/block.gleam", 553). -spec repeat_line(binary(), integer()) -> list(binary()). repeat_line(Line, Count) -> repeat_line_loop(Line, non_negative(Count), []). -file("src/spruce/block.gleam", 530). -spec find_max_width(list(binary()), integer()) -> integer(). find_max_width(Lines, Min_width) -> _pipe = Lines, _pipe@1 = gleam@list:map(_pipe, fun spruce@align:visual_length/1), gleam@list:fold(_pipe@1, Min_width, fun gleam@int:max/2). -file("src/spruce/block.gleam", 498). -spec apply_margin( list(binary()), binary(), integer(), integer(), integer(), integer() ) -> list(binary()). apply_margin(Lines, Prefix, Top, Right, Bottom, Left) -> Line_width = find_max_width(Lines, 0), Blank = gleam@string:repeat(<<" "/utf8>>, (Left + Line_width) + Right), Top_rows = repeat_line(<>, Top), Body = gleam@list:map( Lines, fun(Line) -> <<<<<>, Left))/binary>>/binary, (spruce@align:pad_right(Line, Line_width))/binary>>/binary, (gleam@string:repeat(<<" "/utf8>>, Right))/binary>> end ), _pipe = Top_rows, _pipe@1 = lists:append(_pipe, Body), lists:append(_pipe@1, repeat_line(<>, Bottom)). -file("src/spruce/block.gleam", 414). -spec corner(boolean(), boolean(), binary()) -> binary(). corner(Horizontal, Vertical, Char) -> gleam@bool:guard( Horizontal andalso (Vertical =:= false), <<""/utf8>>, fun() -> Char end ). -file("src/spruce/block.gleam", 383). -spec render_bottom( integer(), sides(), spruce@box:border_chars(), fun((binary()) -> binary()) ) -> binary(). render_bottom(Inner_width, Sides, Chars, Paint_bottom) -> <<<<(Paint_bottom( corner( erlang:element(4, Sides), erlang:element(5, Sides), erlang:element(8, Chars) ) ))/binary, (Paint_bottom( gleam@string:repeat(erlang:element(7, Chars), Inner_width) ))/binary>>/binary, (Paint_bottom( corner( erlang:element(4, Sides), erlang:element(3, Sides), erlang:element(6, Chars) ) ))/binary>>. -file("src/spruce/block.gleam", 360). -spec add_bottom( list(binary()), sides(), integer(), spruce@box:border_chars(), fun((binary()) -> binary()) ) -> list(binary()). add_bottom(Lines, Sides, Inner_width, Chars, Paint_bottom) -> gleam@bool:guard( erlang:element(4, Sides) =:= false, Lines, fun() -> lists:append( Lines, [render_bottom(Inner_width, Sides, Chars, Paint_bottom)] ) end ). -file("src/spruce/block.gleam", 372). -spec render_top( integer(), sides(), spruce@box:border_chars(), fun((binary()) -> binary()) ) -> binary(). render_top(Inner_width, Sides, Chars, Paint_top) -> <<<<(Paint_top( corner( erlang:element(2, Sides), erlang:element(5, Sides), erlang:element(2, Chars) ) ))/binary, (Paint_top( gleam@string:repeat(erlang:element(3, Chars), Inner_width) ))/binary>>/binary, (Paint_top( corner( erlang:element(2, Sides), erlang:element(3, Sides), erlang:element(4, Chars) ) ))/binary>>. -file("src/spruce/block.gleam", 348). -spec add_top( list(binary()), sides(), integer(), spruce@box:border_chars(), fun((binary()) -> binary()) ) -> list(binary()). add_top(Lines, Sides, Inner_width, Chars, Paint_top) -> gleam@bool:guard( erlang:element(2, Sides) =:= false, Lines, fun() -> [render_top(Inner_width, Sides, Chars, Paint_top) | Lines] end ). -file("src/spruce/block.gleam", 404). -spec side_right( sides(), spruce@box:border_chars(), fun((binary()) -> binary()) ) -> binary(). side_right(Sides, Chars, Paint_right) -> gleam@bool:guard( erlang:element(3, Sides) =:= false, <<""/utf8>>, fun() -> Paint_right(erlang:element(5, Chars)) end ). -file("src/spruce/block.gleam", 394). -spec side_left(sides(), spruce@box:border_chars(), fun((binary()) -> binary())) -> binary(). side_left(Sides, Chars, Paint_left) -> gleam@bool:guard( erlang:element(5, Sides) =:= false, <<""/utf8>>, fun() -> Paint_left(erlang:element(9, Chars)) end ). -file("src/spruce/block.gleam", 334). -spec add_vertical_sides( list(binary()), sides(), spruce@box:border_chars(), fun((binary()) -> binary()), fun((binary()) -> binary()) ) -> list(binary()). add_vertical_sides(Lines, Sides, Chars, Paint_left, Paint_right) -> gleam@list:map( Lines, fun(Line) -> <<<<(side_left(Sides, Chars, Paint_left))/binary, Line/binary>>/binary, (side_right(Sides, Chars, Paint_right))/binary>> end ). -file("src/spruce/block.gleam", 420). -spec border_painter(spruce:spruce(), spruce@style:color()) -> fun((binary()) -> binary()). border_painter(Sp, Color) -> Border_style = begin _pipe = spruce@style:new(), spruce@style:fg(_pipe, Color) end, fun(Text) -> spruce@style:render(Sp, Border_style, Text) end. -file("src/spruce/block.gleam", 426). -spec border_chars(spruce@box:border()) -> spruce@box:border_chars(). border_chars(Border) -> case Border of normal -> {border_chars, <<"┌"/utf8>>, <<"─"/utf8>>, <<"┐"/utf8>>, <<"│"/utf8>>, <<"┘"/utf8>>, <<"─"/utf8>>, <<"└"/utf8>>, <<"│"/utf8>>}; rounded -> {border_chars, <<"╭"/utf8>>, <<"─"/utf8>>, <<"╮"/utf8>>, <<"│"/utf8>>, <<"╯"/utf8>>, <<"─"/utf8>>, <<"╰"/utf8>>, <<"│"/utf8>>}; thick -> {border_chars, <<"┏"/utf8>>, <<"━"/utf8>>, <<"┓"/utf8>>, <<"┃"/utf8>>, <<"┛"/utf8>>, <<"━"/utf8>>, <<"┗"/utf8>>, <<"┃"/utf8>>}; double -> {border_chars, <<"╔"/utf8>>, <<"═"/utf8>>, <<"╗"/utf8>>, <<"║"/utf8>>, <<"╝"/utf8>>, <<"═"/utf8>>, <<"╚"/utf8>>, <<"║"/utf8>>}; block -> {border_chars, <<"█"/utf8>>, <<"█"/utf8>>, <<"█"/utf8>>, <<"█"/utf8>>, <<"█"/utf8>>, <<"█"/utf8>>, <<"█"/utf8>>, <<"█"/utf8>>}; hidden -> {border_chars, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>}; {custom, Chars} -> Chars end. -file("src/spruce/block.gleam", 305). -spec apply_border(spruce:spruce(), list(binary()), block()) -> list(binary()). apply_border(Sp, Lines, Block) -> case erlang:element(16, Block) of none -> Lines; {some, hidden} -> Lines; {some, Border} -> Sides = {sides, erlang:element(21, Block), erlang:element(22, Block), erlang:element(23, Block), erlang:element(24, Block)}, Chars = border_chars(Border), Inner_width = find_max_width(Lines, 0), Rows = gleam@list:map( Lines, fun(Line) -> spruce@align:pad_right(Line, Inner_width) end ), Paint_top = border_painter(Sp, erlang:element(17, Block)), Paint_right = border_painter(Sp, erlang:element(18, Block)), Paint_bottom = border_painter(Sp, erlang:element(19, Block)), Paint_left = border_painter(Sp, erlang:element(20, Block)), _pipe = Rows, _pipe@1 = add_vertical_sides( _pipe, Sides, Chars, Paint_left, Paint_right ), _pipe@2 = add_top(_pipe@1, Sides, Inner_width, Chars, Paint_top), add_bottom(_pipe@2, Sides, Inner_width, Chars, Paint_bottom) end. -file("src/spruce/block.gleam", 222). -spec background_style(block()) -> spruce@style:style(). background_style(Block) -> case erlang:element(3, Block) of {some, Color} -> spruce@style:bg(spruce@style:new(), Color); none -> spruce@style:new() end. -file("src/spruce/block.gleam", 284). -spec apply_padding(spruce:spruce(), list(binary()), block()) -> list(binary()). apply_padding(Sp, Lines, Block) -> Content_width = find_max_width(Lines, 0), Padded_width = (Content_width + erlang:element(7, Block)) + erlang:element( 5, Block ), Blank = gleam@string:repeat(<<" "/utf8>>, Padded_width), Body = gleam@list:map( Lines, fun(Line) -> <<<<(gleam@string:repeat(<<" "/utf8>>, erlang:element(7, Block)))/binary, (spruce@align:pad_right(Line, Content_width))/binary>>/binary, (gleam@string:repeat(<<" "/utf8>>, erlang:element(5, Block)))/binary>> end ), _pipe = repeat_line(Blank, erlang:element(4, Block)), _pipe@1 = lists:append(_pipe, Body), _pipe@2 = lists:append( _pipe@1, repeat_line(Blank, erlang:element(6, Block)) ), gleam@list:map( _pipe@2, fun(Line@1) -> spruce@style:render(Sp, background_style(Block), Line@1) end ). -file("src/spruce/block.gleam", 215). -spec foreground_style(block()) -> spruce@style:style(). foreground_style(Block) -> case erlang:element(2, Block) of {some, Color} -> spruce@style:fg(spruce@style:new(), Color); none -> spruce@style:new() end. -file("src/spruce/block.gleam", 273). -spec padding_counts(integer(), spruce@layout:pos()) -> {integer(), integer()}. padding_counts(Extra, Pos) -> case Pos of start -> {0, Extra}; center -> Before = Extra div 2, {Before, Extra - Before}; 'end' -> {Extra, 0} end. -file("src/spruce/block.gleam", 259). -spec pad_height(list(binary()), integer(), integer(), spruce@layout:pos()) -> list(binary()). pad_height(Lines, Width, Extra, Vertical) -> Blank = gleam@string:repeat(<<" "/utf8>>, Width), {Before, After} = padding_counts(Extra, Vertical), _pipe = repeat_line(Blank, Before), _pipe@1 = lists:append(_pipe, Lines), lists:append(_pipe@1, repeat_line(Blank, After)). -file("src/spruce/block.gleam", 541). -spec take_lines_loop(list(binary()), integer(), list(binary())) -> list(binary()). take_lines_loop(Lines, Count, Acc) -> case {Lines, Count} of {_, 0} -> Acc; {[], _} -> Acc; {[Line | Rest], Count@1} -> take_lines_loop(Rest, Count@1 - 1, [Line | Acc]) end. -file("src/spruce/block.gleam", 536). -spec take_lines(list(binary()), integer()) -> list(binary()). take_lines(Lines, Count) -> _pipe = take_lines_loop(Lines, non_negative(Count), []), lists:reverse(_pipe). -file("src/spruce/block.gleam", 241). -spec fit_height(list(binary()), integer(), integer(), spruce@layout:pos()) -> list(binary()). fit_height(Lines, Width, Height, Vertical) -> Current = erlang:length(Lines), case Height =< 0 of true -> []; false -> case Current > Height of true -> take_lines(Lines, Height); false -> pad_height(Lines, Width, Height - Current, Vertical) end end. -file("src/spruce/block.gleam", 229). -spec apply_height( list(binary()), integer(), gleam@option:option(integer()), spruce@layout:pos() ) -> list(binary()). apply_height(Lines, Width, Height, Vertical) -> case Height of {some, Height@1} -> fit_height(Lines, Width, Height@1, Vertical); none -> Lines end. -file("src/spruce/block.gleam", 522). -spec pad_pos(binary(), integer(), spruce@layout:pos()) -> binary(). pad_pos(Text, Width, Pos) -> case Pos of start -> spruce@align:pad_right(Text, Width); center -> spruce@align:pad_center(Text, Width); 'end' -> spruce@align:pad_left(Text, Width) end. -file("src/spruce/block.gleam", 198). -spec content_region(spruce:spruce(), binary(), block()) -> list(binary()). content_region(Sp, Content, Block) -> Wrapped = case erlang:element(12, Block) of {some, Width} when Width > 0 -> spruce@align:wrap(Content, Width); _ -> Content end, Raw_lines = gleam@string:split(Wrapped, <<"\n"/utf8>>), Region_width = case erlang:element(12, Block) of {some, Width@1} when Width@1 > 0 -> Width@1; _ -> find_max_width(Raw_lines, 0) end, _pipe = Raw_lines, _pipe@1 = gleam@list:map( _pipe, fun(Line) -> pad_pos(Line, Region_width, erlang:element(14, Block)) end ), _pipe@2 = apply_height( _pipe@1, Region_width, erlang:element(13, Block), erlang:element(15, Block) ), gleam@list:map( _pipe@2, fun(Line@1) -> spruce@style:render(Sp, foreground_style(Block), Line@1) end ). -file("src/spruce/block.gleam", 182). ?DOC(" Render `content` as one block using the given options.\n"). -spec render(spruce:spruce(), binary(), block()) -> binary(). render(Sp, Content, Block) -> Content_lines = content_region(Sp, Content, Block), Padded = apply_padding(Sp, Content_lines, Block), Bordered = apply_border(Sp, Padded, Block), _pipe = Bordered, _pipe@1 = apply_margin( _pipe, spruce@internal@layout:indent_prefix(Sp), erlang:element(8, Block), erlang:element(9, Block), erlang:element(10, Block), erlang:element(11, Block) ), gleam@string:join(_pipe@1, <<"\n"/utf8>>).