-module(fmglee). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new/1, s/2, d/2, f/2, try_fmt/2, write/3, print/2, println/2, writef/2, printf/1, printlnf/1, fmt/2, try_build/1, build/1]). -export_type([fmt_error/0, fmt/0, formatter/0]). -type fmt_error() :: incorrect_value_type | too_many_values | not_enough_values. -type fmt() :: {s, binary()} | {d, integer()} | {f, float()}. -type formatter() :: {formatter, binary(), list(fmt())}. -spec new(binary()) -> formatter(). new(S) -> {formatter, S, []}. -spec s(formatter(), binary()) -> formatter(). s(Formatter, S) -> {formatter, erlang:element(2, Formatter), lists:append(erlang:element(3, Formatter), [{s, S}])}. -spec d(formatter(), integer()) -> formatter(). d(Formatter, D) -> {formatter, erlang:element(2, Formatter), lists:append(erlang:element(3, Formatter), [{d, D}])}. -spec f(formatter(), float()) -> formatter(). f(Formatter, F) -> {formatter, erlang:element(2, Formatter), lists:append(erlang:element(3, Formatter), [{f, F}])}. -spec process_fmt(binary(), binary(), binary(), list(fmt())) -> {ok, binary()} | {error, fmt_error()}. process_fmt(Placeholder, Value, Str, Values) -> case gleam@string:split_once(Str, Placeholder) of {ok, {First, Last}} -> fmt_iter( <<<>/binary, Last/binary>>, gleam@list:drop(Values, 1) ); {error, _} -> {error, incorrect_value_type} end. -spec fmt_iter(binary(), list(fmt())) -> {ok, binary()} | {error, fmt_error()}. fmt_iter(Str, Values) -> case Values of [{s, Value} | _] -> process_fmt(<<"%s"/utf8>>, Value, Str, Values); [{d, Value@1} | _] -> process_fmt( <<"%d"/utf8>>, gleam@int:to_string(Value@1), Str, Values ); [{f, Value@2} | _] -> process_fmt( <<"%f"/utf8>>, gleam@float:to_string(Value@2), Str, Values ); [] -> {ok, Str} end. -spec try_fmt(binary(), list(fmt())) -> {ok, binary()} | {error, fmt_error()}. try_fmt(S, V) -> _assert_subject = gleam@regex:from_string(<<"(\\%d|\\%f|\\%s)"/utf8>>), {ok, Re} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"fmglee"/utf8>>, function => <<"try_fmt"/utf8>>, line => 117}) end, Matches = erlang:length(gleam@regex:scan(Re, S)), Values = erlang:length(V), case {Matches > Values, Values > Matches} of {true, false} -> {error, not_enough_values}; {false, true} -> {error, too_many_values}; {_, _} -> fmt_iter(S, V) end. -spec write(binary(), list(fmt()), fun((binary()) -> nil)) -> nil. write(S, V, Writer) -> _assert_subject = try_fmt(S, V), {ok, Str} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"fmglee"/utf8>>, function => <<"write"/utf8>>, line => 99}) end, Writer(Str). -spec print(binary(), list(fmt())) -> nil. print(S, V) -> write(S, V, fun gleam@io:print/1). -spec println(binary(), list(fmt())) -> nil. println(S, V) -> write(S, V, fun gleam@io:println/1). -spec writef(formatter(), fun((binary()) -> nil)) -> nil. writef(Formatter, Writer) -> write(erlang:element(2, Formatter), erlang:element(3, Formatter), Writer). -spec printf(formatter()) -> nil. printf(Formatter) -> writef(Formatter, fun gleam@io:print/1). -spec printlnf(formatter()) -> nil. printlnf(Formatter) -> writef(Formatter, fun gleam@io:println/1). -spec fmt(binary(), list(fmt())) -> binary(). fmt(S, V) -> _assert_subject = try_fmt(S, V), {ok, Str} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"fmglee"/utf8>>, function => <<"fmt"/utf8>>, line => 107}) end, Str. -spec try_build(formatter()) -> {ok, binary()} | {error, fmt_error()}. try_build(Formatter) -> try_fmt(erlang:element(2, Formatter), erlang:element(3, Formatter)). -spec build(formatter()) -> binary(). build(Formatter) -> _assert_subject = try_build(Formatter), {ok, Str} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"fmglee"/utf8>>, function => <<"build"/utf8>>, line => 198}) end, Str.