Skip to main content

src/spruce@details.erl

-module(spruce@details).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/spruce/details.gleam").
-export([new/0, add/3, hide_internal/1, render/2]).
-export_type([details/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(" Key-value detail rendering for compact terminal lines.\n").

-opaque details() :: {details, list({binary(), binary()}), boolean()}.

-file("src/spruce/details.gleam", 15).
?DOC(" Create an empty details collection.\n").
-spec new() -> details().
new() ->
    {details, [], true}.

-file("src/spruce/details.gleam", 20).
?DOC(" Add a key-value pair, preserving insertion order.\n").
-spec add(details(), binary(), binary()) -> details().
add(Details, Key, Value) ->
    {details,
        [{Key, Value} | erlang:element(2, Details)],
        erlang:element(3, Details)}.

-file("src/spruce/details.gleam", 25).
?DOC(" Omit keys beginning with `_` when rendering.\n").
-spec hide_internal(details()) -> details().
hide_internal(Details) ->
    {details, erlang:element(2, Details), false}.

-file("src/spruce/details.gleam", 70).
-spec contains_ascii_control(binary()) -> boolean().
contains_ascii_control(Value) ->
    _pipe = Value,
    _pipe@1 = gleam@string:to_utf_codepoints(_pipe),
    gleam@list:any(_pipe@1, fun(Cp) -> gleam_stdlib:identity(Cp) < 32 end).

-file("src/spruce/details.gleam", 47).
-spec escape_value(binary()) -> binary().
escape_value(Value) ->
    Needs_quoting = ((gleam_stdlib:contains_string(Value, <<" "/utf8>>) orelse gleam_stdlib:contains_string(
        Value,
        <<"="/utf8>>
    ))
    orelse gleam_stdlib:contains_string(Value, <<"\""/utf8>>))
    orelse contains_ascii_control(Value),
    case Needs_quoting of
        false ->
            Value;

        true ->
            Escaped = begin
                _pipe = Value,
                _pipe@1 = gleam@string:replace(
                    _pipe,
                    <<"\\"/utf8>>,
                    <<"\\\\"/utf8>>
                ),
                _pipe@2 = gleam@string:replace(
                    _pipe@1,
                    <<"\""/utf8>>,
                    <<"\\\""/utf8>>
                ),
                _pipe@3 = gleam@string:replace(
                    _pipe@2,
                    <<"\t"/utf8>>,
                    <<"\\t"/utf8>>
                ),
                _pipe@4 = gleam@string:replace(
                    _pipe@3,
                    <<"\n"/utf8>>,
                    <<"\\n"/utf8>>
                ),
                gleam@string:replace(_pipe@4, <<"\r"/utf8>>, <<"\\r"/utf8>>)
            end,
            <<<<"\""/utf8, Escaped/binary>>/binary, "\""/utf8>>
    end.

-file("src/spruce/details.gleam", 41).
-spec render_pair(spruce:spruce(), {binary(), binary()}) -> binary().
render_pair(Sp, Pair) ->
    {Key, Value} = Pair,
    Text = <<<<Key/binary, "="/utf8>>/binary, (escape_value(Value))/binary>>,
    spruce@style:render(Sp, spruce@palette:hash(Sp, Key), Text).

-file("src/spruce/details.gleam", 30).
?DOC(" Render details as space-separated `key=value` pairs.\n").
-spec render(spruce:spruce(), details()) -> binary().
render(Sp, Details) ->
    _pipe = erlang:element(2, Details),
    _pipe@1 = lists:reverse(_pipe),
    _pipe@2 = gleam@list:filter(
        _pipe@1,
        fun(Pair) ->
            {Key, _} = Pair,
            erlang:element(3, Details) orelse not gleam_stdlib:string_starts_with(
                Key,
                <<"_"/utf8>>
            )
        end
    ),
    _pipe@3 = gleam@list:map(
        _pipe@2,
        fun(_capture) -> render_pair(Sp, _capture) end
    ),
    gleam@string:join(_pipe@3, <<" "/utf8>>).