-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.