-module(etui@span).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/span.gleam").
-export([span_plain/1, span_styled/2, span_link/2, with_link/2, span_fg/2, span_bg/2, span_modifier/2, span_width/1, line_new/1, line_plain/1, line_aligned/2, span_bold/1, span_italic/1, span_dim/1, span_underline/1, line_width/1, render_line/4]).
-export_type([span/0, line/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.
-type span() :: {span,
binary(),
etui@style:color(),
etui@style:color(),
etui@style:modifier(),
binary()}.
-type line() :: {line, list(span()), etui@text:alignment()}.
-file("src/etui/span.gleam", 46).
?DOC(" Span with default terminal colors and no modifier.\n").
-spec span_plain(binary()) -> span().
span_plain(Content) ->
{span, Content, default, default, etui@style:none(), <<""/utf8>>}.
-file("src/etui/span.gleam", 57).
?DOC(" Span with explicit style applied.\n").
-spec span_styled(binary(), etui@style:style()) -> span().
span_styled(Content, S) ->
{span,
Content,
erlang:element(2, S),
erlang:element(3, S),
erlang:element(4, S),
<<""/utf8>>}.
-file("src/etui/span.gleam", 68).
?DOC(
" Span with an OSC 8 clickable hyperlink.\n"
" Terminals that support OSC 8 (iTerm2, Kitty, VTE, Windows Terminal) will\n"
" render the text as a clickable link. Others display it as plain text.\n"
"\n"
" ```gleam\n"
" span.span_link(\"docs.gleam.run\", \"https://docs.gleam.run\")\n"
" ```\n"
).
-spec span_link(binary(), binary()) -> span().
span_link(Content, Uri) ->
{span, Content, default, default, etui@style:none(), Uri}.
-file("src/etui/span.gleam", 79).
?DOC(" Add an OSC 8 hyperlink URI to an existing span.\n").
-spec with_link(span(), binary()) -> span().
with_link(Sp, Uri) ->
{span,
erlang:element(2, Sp),
erlang:element(3, Sp),
erlang:element(4, Sp),
erlang:element(5, Sp),
Uri}.
-file("src/etui/span.gleam", 84).
?DOC(" Set foreground color on a span.\n").
-spec span_fg(span(), etui@style:color()) -> span().
span_fg(Sp, Color) ->
{span,
erlang:element(2, Sp),
Color,
erlang:element(4, Sp),
erlang:element(5, Sp),
erlang:element(6, Sp)}.
-file("src/etui/span.gleam", 89).
?DOC(" Set background color on a span.\n").
-spec span_bg(span(), etui@style:color()) -> span().
span_bg(Sp, Color) ->
{span,
erlang:element(2, Sp),
erlang:element(3, Sp),
Color,
erlang:element(5, Sp),
erlang:element(6, Sp)}.
-file("src/etui/span.gleam", 94).
?DOC(" Add a modifier to a span.\n").
-spec span_modifier(span(), etui@style:modifier()) -> span().
span_modifier(Sp, Modifier) ->
{span,
erlang:element(2, Sp),
erlang:element(3, Sp),
erlang:element(4, Sp),
etui@style:add(erlang:element(5, Sp), Modifier),
erlang:element(6, Sp)}.
-file("src/etui/span.gleam", 99).
?DOC(" Total cell width of a span.\n").
-spec span_width(span()) -> integer().
span_width(Sp) ->
etui@text:cell_width(erlang:element(2, Sp)).
-file("src/etui/span.gleam", 104).
?DOC(" Line from a list of spans, left-aligned.\n").
-spec line_new(list(span())) -> line().
line_new(Spans) ->
{line, Spans, left}.
-file("src/etui/span.gleam", 109).
?DOC(" Line with a single unstyled string, left-aligned.\n").
-spec line_plain(binary()) -> line().
line_plain(Content) ->
{line, [span_plain(Content)], left}.
-file("src/etui/span.gleam", 114).
?DOC(" Line from spans with explicit alignment.\n").
-spec line_aligned(list(span()), etui@text:alignment()) -> line().
line_aligned(Spans, Alignment) ->
{line, Spans, Alignment}.
-file("src/etui/span.gleam", 119).
?DOC(" Bold span (default colors + bold modifier).\n").
-spec span_bold(binary()) -> span().
span_bold(Content) ->
{span, Content, default, default, etui@style:bold(), <<""/utf8>>}.
-file("src/etui/span.gleam", 130).
?DOC(" Italic span (default colors + italic modifier).\n").
-spec span_italic(binary()) -> span().
span_italic(Content) ->
{span, Content, default, default, etui@style:italic(), <<""/utf8>>}.
-file("src/etui/span.gleam", 141).
?DOC(" Dim span (default colors + dim modifier).\n").
-spec span_dim(binary()) -> span().
span_dim(Content) ->
{span, Content, default, default, etui@style:dim(), <<""/utf8>>}.
-file("src/etui/span.gleam", 152).
?DOC(" Underline span (default colors + underline modifier).\n").
-spec span_underline(binary()) -> span().
span_underline(Content) ->
{span, Content, default, default, etui@style:underline(), <<""/utf8>>}.
-file("src/etui/span.gleam", 163).
?DOC(" Total cell width of a line (sum of span widths).\n").
-spec line_width(line()) -> integer().
line_width(L) ->
gleam@list:fold(
erlang:element(2, L),
0,
fun(Acc, Sp) -> Acc + span_width(Sp) end
).
-file("src/etui/span.gleam", 195).
-spec render_spans(
etui@buffer:buffer(),
etui@geometry:position(),
list(span()),
integer(),
integer()
) -> etui@buffer:buffer().
render_spans(Buf, Pos, Spans, X, X_end) ->
case Spans of
[] ->
Buf;
[Sp | Rest] ->
case X >= X_end of
true ->
Buf;
false ->
Avail = X_end - X,
Content = etui@text:truncate(
erlang:element(2, Sp),
Avail,
<<""/utf8>>
),
W = etui@text:cell_width(Content),
Buf2 = etui@buffer:set_string_linked(
Buf,
{position, X, erlang:element(3, Pos)},
Content,
erlang:element(3, Sp),
erlang:element(4, Sp),
erlang:element(5, Sp),
erlang:element(6, Sp)
),
render_spans(Buf2, Pos, Rest, X + W, X_end)
end
end.
-file("src/etui/span.gleam", 174).
?DOC(
" Render a line into the buffer at `pos`, clipped to `max_width` cells.\n"
" Each span is drawn with its own fg/bg/modifier. Spans beyond max_width\n"
" are silently dropped; a span that straddles the boundary is truncated.\n"
" The line's `alignment` field shifts the start position within the available width.\n"
).
-spec render_line(
etui@buffer:buffer(),
etui@geometry:position(),
line(),
integer()
) -> etui@buffer:buffer().
render_line(Buf, Pos, L, Max_width) ->
case Max_width =< 0 of
true ->
Buf;
false ->
Content_width = line_width(L),
Offset = case erlang:element(3, L) of
left ->
0;
right ->
gleam@int:max(0, Max_width - Content_width);
center ->
gleam@int:max(0, (Max_width - Content_width) div 2)
end,
Start_x = erlang:element(2, Pos) + Offset,
render_spans(
Buf,
Pos,
erlang:element(2, L),
Start_x,
erlang:element(2, Pos) + Max_width
)
end.