src/gliff@internal@patch.erl

-module(gliff@internal@patch).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gliff/internal/patch.gleam").
-export([apply_patch/2]).

-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(false).

-file("src/gliff/internal/patch.gleam", 10).
?DOC(false).
-spec split_lines(binary()) -> list(binary()).
split_lines(Text) ->
    case Text of
        <<""/utf8>> ->
            [];

        _ ->
            gleam@string:split(Text, <<"\n"/utf8>>)
    end.

-file("src/gliff/internal/patch.gleam", 54).
?DOC(false).
-spec consume_lines(list(binary()), list(binary())) -> {ok, list(binary())} |
    {error, binary()}.
consume_lines(Lines, Expected) ->
    case Expected of
        [] ->
            {ok, Lines};

        [Exp | Rest_exp] ->
            case Lines of
                [] ->
                    {error,
                        <<"Unexpected end of input, expected: "/utf8,
                            Exp/binary>>};

                [Line | Rest_lines] ->
                    case Line =:= Exp of
                        true ->
                            consume_lines(Rest_lines, Rest_exp);

                        false ->
                            {error,
                                <<<<<<<<"Mismatch: expected '"/utf8,
                                                Exp/binary>>/binary,
                                            "' but got '"/utf8>>/binary,
                                        Line/binary>>/binary,
                                    "'"/utf8>>}
                    end
            end
    end.

-file("src/gliff/internal/patch.gleam", 75).
?DOC(false).
-spec prepend_reversed(list(EUP), list(EUP)) -> list(EUP).
prepend_reversed(Items, Onto) ->
    case Items of
        [] ->
            Onto;

        [H | T] ->
            prepend_reversed(T, [H | Onto])
    end.

-file("src/gliff/internal/patch.gleam", 17).
?DOC(false).
-spec apply_edits(list(binary()), list(gliff@types:edit()), list(binary())) -> {ok,
        binary()} |
    {error, binary()}.
apply_edits(Lines, Edits, Acc) ->
    case Edits of
        [] ->
            case Lines of
                [] ->
                    {ok, gleam@string:join(lists:reverse(Acc), <<"\n"/utf8>>)};

                Remaining ->
                    {ok,
                        gleam@string:join(
                            lists:append(lists:reverse(Acc), Remaining),
                            <<"\n"/utf8>>
                        )}
            end;

        [Edit | Rest_edits] ->
            case Edit of
                {equal, Expected} ->
                    case consume_lines(Lines, Expected) of
                        {ok, Remaining@1} ->
                            apply_edits(
                                Remaining@1,
                                Rest_edits,
                                prepend_reversed(Expected, Acc)
                            );

                        {error, E} ->
                            {error, E}
                    end;

                {delete, Expected@1} ->
                    case consume_lines(Lines, Expected@1) of
                        {ok, Remaining@2} ->
                            apply_edits(Remaining@2, Rest_edits, Acc);

                        {error, E@1} ->
                            {error, E@1}
                    end;

                {insert, New_lines} ->
                    apply_edits(
                        Lines,
                        Rest_edits,
                        prepend_reversed(New_lines, Acc)
                    )
            end
    end.

-file("src/gliff/internal/patch.gleam", 5).
?DOC(false).
-spec apply_patch(binary(), list(gliff@types:edit())) -> {ok, binary()} |
    {error, binary()}.
apply_patch(Text, Edits) ->
    Lines = split_lines(Text),
    apply_edits(Lines, Edits, []).