src/gliff@internal@fuzzy_patch.erl

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

-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/fuzzy_patch.gleam", 59).
?DOC(false).
-spec consume_fuzzy(list(binary()), list(binary()), float()) -> {ok,
        list(binary())} |
    {error, binary()}.
consume_fuzzy(Lines, Expected, Threshold) ->
    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_fuzzy(Rest_lines, Rest_exp, Threshold);

                        false ->
                            Sim = gliff@internal@similarity:line_similarity(
                                Exp,
                                Line
                            ),
                            case Sim >= Threshold of
                                true ->
                                    consume_fuzzy(
                                        Rest_lines,
                                        Rest_exp,
                                        Threshold
                                    );

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

-file("src/gliff/internal/fuzzy_patch.gleam", 91).
?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/fuzzy_patch.gleam", 98).
?DOC(false).
-spec prepend_reversed(list(EPE), list(EPE)) -> list(EPE).
prepend_reversed(Items, Onto) ->
    case Items of
        [] ->
            Onto;

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

-file("src/gliff/internal/fuzzy_patch.gleam", 16).
?DOC(false).
-spec apply_edits_fuzzy(
    list(binary()),
    list(gliff@types:edit()),
    float(),
    list(binary())
) -> {ok, binary()} | {error, binary()}.
apply_edits_fuzzy(Lines, Edits, Threshold, 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_fuzzy(Lines, Expected, Threshold) of
                        {ok, Remaining@1} ->
                            apply_edits_fuzzy(
                                Remaining@1,
                                Rest_edits,
                                Threshold,
                                prepend_reversed(Expected, Acc)
                            );

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

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

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

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

-file("src/gliff/internal/fuzzy_patch.gleam", 6).
?DOC(false).
-spec apply_patch_fuzzy(binary(), list(gliff@types:edit()), float()) -> {ok,
        binary()} |
    {error, binary()}.
apply_patch_fuzzy(Text, Edits, Tolerance) ->
    Lines = split_lines(Text),
    Threshold = 1.0 - Tolerance,
    apply_edits_fuzzy(Lines, Edits, Threshold, []).