-module(gliff@internal@unified).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gliff/internal/unified.gleam").
-export([edits_to_hunks/2, to_unified/3, to_unified_with/4, from_unified/1]).
-export_type([indexed_edit/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(false).
-type indexed_edit() :: {indexed_edit, gliff@types:edit(), integer(), integer()}.
-file("src/gliff/internal/unified.gleam", 62).
?DOC(false).
-spec edit_size(gliff@types:edit()) -> {integer(), integer()}.
edit_size(Edit) ->
case Edit of
{equal, Lines} ->
N = erlang:length(Lines),
{N, N};
{delete, Lines@1} ->
{erlang:length(Lines@1), 0};
{insert, Lines@2} ->
{0, erlang:length(Lines@2)}
end.
-file("src/gliff/internal/unified.gleam", 43).
?DOC(false).
-spec index_edits(
list(gliff@types:edit()),
integer(),
integer(),
list(indexed_edit())
) -> list(indexed_edit()).
index_edits(Edits, Old_pos, New_pos, Acc) ->
case Edits of
[] ->
lists:reverse(Acc);
[Edit | Rest] ->
Entry = {indexed_edit, Edit, Old_pos, New_pos},
{Old_advance, New_advance} = edit_size(Edit),
index_edits(
Rest,
Old_pos + Old_advance,
New_pos + New_advance,
[Entry | Acc]
)
end.
-file("src/gliff/internal/unified.gleam", 188).
?DOC(false).
-spec has_changes(list(indexed_edit())) -> boolean().
has_changes(Indexed) ->
case Indexed of
[] ->
false;
[Entry | Rest] ->
case erlang:element(2, Entry) of
{equal, _} ->
has_changes(Rest);
_ ->
true
end
end.
-file("src/gliff/internal/unified.gleam", 213).
?DOC(false).
-spec count_lines_in_edits(list(gliff@types:edit()), integer(), integer()) -> {integer(),
integer()}.
count_lines_in_edits(Edits, Old_acc, New_acc) ->
case Edits of
[] ->
{Old_acc, New_acc};
[Edit | Rest] ->
{O, N} = edit_size(Edit),
count_lines_in_edits(Rest, Old_acc + O, New_acc + N)
end.
-file("src/gliff/internal/unified.gleam", 199).
?DOC(false).
-spec build_single_hunk(list(indexed_edit())) -> gliff@types:hunk().
build_single_hunk(Entries) ->
case Entries of
[] ->
{hunk, 1, 0, 1, 0, []};
[First | _] ->
Edits = gleam@list:map(Entries, fun(E) -> erlang:element(2, E) end),
Old_start = erlang:element(3, First) + 1,
New_start = erlang:element(4, First) + 1,
{Old_count, New_count} = count_lines_in_edits(Edits, 0, 0),
{hunk, Old_start, Old_count, New_start, New_count, Edits}
end.
-file("src/gliff/internal/unified.gleam", 244).
?DOC(false).
-spec format_edit(gliff@types:edit()) -> binary().
format_edit(Edit) ->
case Edit of
{equal, Lines} ->
gleam@string:join(
gleam@list:map(
Lines,
fun(L) -> <<<<" "/utf8, L/binary>>/binary, "\n"/utf8>> end
),
<<""/utf8>>
);
{delete, Lines@1} ->
gleam@string:join(
gleam@list:map(
Lines@1,
fun(L@1) ->
<<<<"-"/utf8, L@1/binary>>/binary, "\n"/utf8>>
end
),
<<""/utf8>>
);
{insert, Lines@2} ->
gleam@string:join(
gleam@list:map(
Lines@2,
fun(L@2) ->
<<<<"+"/utf8, L@2/binary>>/binary, "\n"/utf8>>
end
),
<<""/utf8>>
)
end.
-file("src/gliff/internal/unified.gleam", 268).
?DOC(false).
-spec digit_to_string(integer()) -> binary().
digit_to_string(D) ->
case D of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
6 ->
<<"6"/utf8>>;
7 ->
<<"7"/utf8>>;
8 ->
<<"8"/utf8>>;
_ ->
<<"9"/utf8>>
end.
-file("src/gliff/internal/unified.gleam", 261).
?DOC(false).
-spec do_int_to_string(integer()) -> binary().
do_int_to_string(N) ->
case N < 10 of
true ->
digit_to_string(N);
false ->
<<(do_int_to_string(N div 10))/binary,
(digit_to_string(N rem 10))/binary>>
end.
-file("src/gliff/internal/unified.gleam", 254).
?DOC(false).
-spec int_to_string(integer()) -> binary().
int_to_string(N) ->
case N < 0 of
true ->
<<"-"/utf8, (do_int_to_string(- N))/binary>>;
false ->
do_int_to_string(N)
end.
-file("src/gliff/internal/unified.gleam", 229).
?DOC(false).
-spec format_hunk(gliff@types:hunk()) -> binary().
format_hunk(Hunk) ->
Header = <<<<<<<<<<<<<<<<"@@ -"/utf8,
(int_to_string(erlang:element(2, Hunk)))/binary>>/binary,
","/utf8>>/binary,
(int_to_string(erlang:element(3, Hunk)))/binary>>/binary,
" +"/utf8>>/binary,
(int_to_string(erlang:element(4, Hunk)))/binary>>/binary,
","/utf8>>/binary,
(int_to_string(erlang:element(5, Hunk)))/binary>>/binary,
" @@\n"/utf8>>,
Body = gleam@string:join(
gleam@list:map(erlang:element(6, Hunk), fun format_edit/1),
<<""/utf8>>
),
<<Header/binary, Body/binary>>.
-file("src/gliff/internal/unified.gleam", 283).
?DOC(false).
-spec take_last(list(DXR), integer()) -> list(DXR).
take_last(Items, N) ->
Len = erlang:length(Items),
gleam@list:drop(Items, case Len > N of
true ->
Len - N;
false ->
0
end).
-file("src/gliff/internal/unified.gleam", 85).
?DOC(false).
-spec find_change_groups_loop(
list(indexed_edit()),
integer(),
list(indexed_edit()),
list(list(indexed_edit()))
) -> list(list(indexed_edit())).
find_change_groups_loop(Indexed, Context, Current_group, Groups) ->
case Indexed of
[] ->
case Current_group of
[] ->
lists:reverse(Groups);
_ ->
lists:reverse([lists:reverse(Current_group) | Groups])
end;
[Entry | Rest] ->
case erlang:element(2, Entry) of
{equal, Lines} ->
N = erlang:length(Lines),
case Current_group of
[] ->
Ctx_lines = take_last(Lines, Context),
Ctx_count = erlang:length(Ctx_lines),
case Ctx_count > 0 of
true ->
Ctx_entry = {indexed_edit,
{equal, Ctx_lines},
(erlang:element(3, Entry) + N) - Ctx_count,
(erlang:element(4, Entry) + N) - Ctx_count},
find_change_groups_loop(
Rest,
Context,
[Ctx_entry],
Groups
);
false ->
find_change_groups_loop(
Rest,
Context,
Current_group,
Groups
)
end;
_ ->
Has_more_changes = has_changes(Rest),
case {Has_more_changes, N > (Context * 2)} of
{_, true} ->
Tail_ctx = gleam@list:take(Lines, Context),
Tail_entry = {indexed_edit,
{equal, Tail_ctx},
erlang:element(3, Entry),
erlang:element(4, Entry)},
Finished_group = lists:reverse(
[Tail_entry | Current_group]
),
Head_ctx = take_last(Lines, Context),
Head_count = erlang:length(Head_ctx),
Head_entry = {indexed_edit,
{equal, Head_ctx},
(erlang:element(3, Entry) + N) - Head_count,
(erlang:element(4, Entry) + N) - Head_count},
find_change_groups_loop(
Rest,
Context,
[Head_entry],
[Finished_group | Groups]
);
{false, _} when N > Context ->
Tail_ctx@1 = gleam@list:take(Lines, Context),
Tail_entry@1 = {indexed_edit,
{equal, Tail_ctx@1},
erlang:element(3, Entry),
erlang:element(4, Entry)},
Finished_group@1 = lists:reverse(
[Tail_entry@1 | Current_group]
),
find_change_groups_loop(
Rest,
Context,
[],
[Finished_group@1 | Groups]
);
{_, _} ->
find_change_groups_loop(
Rest,
Context,
[Entry | Current_group],
Groups
)
end
end;
_ ->
case Current_group of
[] ->
find_change_groups_loop(
Rest,
Context,
[Entry],
Groups
);
_ ->
find_change_groups_loop(
Rest,
Context,
[Entry | Current_group],
Groups
)
end
end
end.
-file("src/gliff/internal/unified.gleam", 78).
?DOC(false).
-spec find_change_groups(list(indexed_edit()), integer()) -> list(list(indexed_edit())).
find_change_groups(Indexed, Context) ->
find_change_groups_loop(Indexed, Context, [], []).
-file("src/gliff/internal/unified.gleam", 73).
?DOC(false).
-spec build_hunks(list(indexed_edit()), integer()) -> list(gliff@types:hunk()).
build_hunks(Indexed, Context) ->
Change_groups = find_change_groups(Indexed, Context),
gleam@list:map(Change_groups, fun(Group) -> build_single_hunk(Group) end).
-file("src/gliff/internal/unified.gleam", 34).
?DOC(false).
-spec edits_to_hunks(list(gliff@types:edit()), integer()) -> list(gliff@types:hunk()).
edits_to_hunks(Edits, Context) ->
Indexed = index_edits(Edits, 0, 0, []),
build_hunks(Indexed, Context).
-file("src/gliff/internal/unified.gleam", 5).
?DOC(false).
-spec to_unified(list(gliff@types:edit()), binary(), binary()) -> binary().
to_unified(Edits, Old_name, New_name) ->
Hunks = edits_to_hunks(Edits, 3),
Header = <<<<<<<<"--- "/utf8, Old_name/binary>>/binary, "\n+++ "/utf8>>/binary,
New_name/binary>>/binary,
"\n"/utf8>>,
Body = gleam@string:join(
gleam@list:map(Hunks, fun format_hunk/1),
<<""/utf8>>
),
<<Header/binary, Body/binary>>.
-file("src/gliff/internal/unified.gleam", 16).
?DOC(false).
-spec to_unified_with(list(gliff@types:edit()), binary(), binary(), integer()) -> binary().
to_unified_with(Edits, Old_name, New_name, Context) ->
Hunks = edits_to_hunks(Edits, Context),
Header = <<<<<<<<"--- "/utf8, Old_name/binary>>/binary, "\n+++ "/utf8>>/binary,
New_name/binary>>/binary,
"\n"/utf8>>,
Body = gleam@string:join(
gleam@list:map(Hunks, fun format_hunk/1),
<<""/utf8>>
),
<<Header/binary, Body/binary>>.
-file("src/gliff/internal/unified.gleam", 299).
?DOC(false).
-spec skip_file_headers(list(binary())) -> list(binary()).
skip_file_headers(Lines) ->
case Lines of
[<<"---"/utf8, _/binary>>, <<"+++ "/utf8, _/binary>> | Rest] ->
Rest;
[_ | Rest@1] ->
skip_file_headers(Rest@1);
[] ->
[]
end.
-file("src/gliff/internal/unified.gleam", 399).
?DOC(false).
-spec digit_value(binary()) -> {ok, integer()} | {error, nil}.
digit_value(D) ->
case D of
<<"0"/utf8>> ->
{ok, 0};
<<"1"/utf8>> ->
{ok, 1};
<<"2"/utf8>> ->
{ok, 2};
<<"3"/utf8>> ->
{ok, 3};
<<"4"/utf8>> ->
{ok, 4};
<<"5"/utf8>> ->
{ok, 5};
<<"6"/utf8>> ->
{ok, 6};
<<"7"/utf8>> ->
{ok, 7};
<<"8"/utf8>> ->
{ok, 8};
<<"9"/utf8>> ->
{ok, 9};
_ ->
{error, nil}
end.
-file("src/gliff/internal/unified.gleam", 370).
?DOC(false).
-spec parse_int_loop(list(binary()), integer(), boolean()) -> {ok, integer()} |
{error, binary()}.
parse_int_loop(Chars, Acc, Started) ->
case Chars of
[] ->
case Started of
true ->
{ok, Acc};
false ->
{error, <<"Empty integer"/utf8>>}
end;
[<<"-"/utf8>> | Rest] ->
case Started of
false ->
case parse_int_loop(Rest, 0, false) of
{ok, N} ->
{ok, - N};
{error, E} ->
{error, E}
end;
true ->
{error, <<"Unexpected '-'"/utf8>>}
end;
[D | Rest@1] ->
case digit_value(D) of
{ok, V} ->
parse_int_loop(Rest@1, (Acc * 10) + V, true);
{error, _} ->
{error, <<"Not a digit: "/utf8, D/binary>>}
end
end.
-file("src/gliff/internal/unified.gleam", 366).
?DOC(false).
-spec parse_int(binary()) -> {ok, integer()} | {error, binary()}.
parse_int(S) ->
parse_int_loop(gleam@string:to_graphemes(S), 0, false).
-file("src/gliff/internal/unified.gleam", 350).
?DOC(false).
-spec parse_range(binary()) -> {ok, {integer(), integer()}} | {error, binary()}.
parse_range(Range) ->
case gleam@string:split(Range, <<","/utf8>>) of
[Start_str, Count_str] ->
case {parse_int(Start_str), parse_int(Count_str)} of
{{ok, S}, {ok, C}} ->
{ok, {S, C}};
{_, _} ->
{error, <<"Invalid range numbers"/utf8>>}
end;
[Start_str@1] ->
case parse_int(Start_str@1) of
{ok, S@1} ->
{ok, {S@1, 1}};
{error, _} ->
{error, <<"Invalid range number"/utf8>>}
end;
_ ->
{error, <<"Invalid range"/utf8>>}
end.
-file("src/gliff/internal/unified.gleam", 335).
?DOC(false).
-spec parse_ranges(binary()) -> {ok,
{integer(), integer(), integer(), integer()}} |
{error, binary()}.
parse_ranges(Range_str) ->
case gleam@string:split(Range_str, <<" "/utf8>>) of
[Old_range, New_range | _] ->
case {parse_range(gleam@string:drop_start(Old_range, 1)),
parse_range(gleam@string:drop_start(New_range, 1))} of
{{ok, {Os, Oc}}, {ok, {Ns, Nc}}} ->
{ok, {Os, Oc, Ns, Nc}};
{_, _} ->
{error, <<"Invalid range: "/utf8, Range_str/binary>>}
end;
_ ->
{error, <<"Invalid range format: "/utf8, Range_str/binary>>}
end.
-file("src/gliff/internal/unified.gleam", 328).
?DOC(false).
-spec parse_hunk_header(binary()) -> {ok,
{integer(), integer(), integer(), integer()}} |
{error, binary()}.
parse_hunk_header(Header) ->
case gleam@string:split(Header, <<"@@"/utf8>>) of
[_, Range_str | _] ->
parse_ranges(gleam@string:trim(Range_str));
_ ->
{error, <<"Invalid hunk header: "/utf8, Header/binary>>}
end.
-file("src/gliff/internal/unified.gleam", 442).
?DOC(false).
-spec group_raw_body_loop(list(gliff@types:edit()), list(gliff@types:edit())) -> list(gliff@types:edit()).
group_raw_body_loop(Edits, Acc) ->
case Edits of
[] ->
Acc;
[{equal, L1}, {equal, L2} | Rest] ->
group_raw_body_loop([{equal, lists:append(L1, L2)} | Rest], Acc);
[{insert, L1@1}, {insert, L2@1} | Rest@1] ->
group_raw_body_loop(
[{insert, lists:append(L1@1, L2@1)} | Rest@1],
Acc
);
[{delete, L1@2}, {delete, L2@2} | Rest@2] ->
group_raw_body_loop(
[{delete, lists:append(L1@2, L2@2)} | Rest@2],
Acc
);
[Edit | Rest@3] ->
group_raw_body_loop(Rest@3, [Edit | Acc])
end.
-file("src/gliff/internal/unified.gleam", 437).
?DOC(false).
-spec group_raw_body(list(gliff@types:edit())) -> list(gliff@types:edit()).
group_raw_body(Edits) ->
_pipe = group_raw_body_loop(Edits, []),
lists:reverse(_pipe).
-file("src/gliff/internal/unified.gleam", 415).
?DOC(false).
-spec parse_hunk_body(list(binary()), list(gliff@types:edit())) -> {list(gliff@types:edit()),
list(binary())}.
parse_hunk_body(Lines, Acc) ->
case Lines of
[] ->
{group_raw_body(lists:reverse(Acc)), []};
[<<"@@"/utf8, _/binary>> = Rest_line | Rest] ->
{group_raw_body(lists:reverse(Acc)), [Rest_line | Rest]};
[Line | Rest@1] ->
Edit = case gleam@string:first(Line) of
{ok, <<"+"/utf8>>} ->
{insert, [gleam@string:drop_start(Line, 1)]};
{ok, <<"-"/utf8>>} ->
{delete, [gleam@string:drop_start(Line, 1)]};
{ok, <<" "/utf8>>} ->
{equal, [gleam@string:drop_start(Line, 1)]};
_ ->
{equal, [Line]}
end,
parse_hunk_body(Rest@1, [Edit | Acc])
end.
-file("src/gliff/internal/unified.gleam", 307).
?DOC(false).
-spec parse_hunks(list(binary()), list(gliff@types:hunk())) -> {ok,
list(gliff@types:hunk())} |
{error, binary()}.
parse_hunks(Lines, Acc) ->
case Lines of
[] ->
{ok, lists:reverse(Acc)};
[<<""/utf8>> | Rest] ->
parse_hunks(Rest, Acc);
[<<"@@"/utf8, _/binary>> = Header | Rest@1] ->
case parse_hunk_header(Header) of
{ok, {Old_start, Old_count, New_start, New_count}} ->
{Edits, Remaining} = parse_hunk_body(Rest@1, []),
Hunk = {hunk,
Old_start,
Old_count,
New_start,
New_count,
Edits},
parse_hunks(Remaining, [Hunk | Acc]);
{error, E} ->
{error, E}
end;
[Line | _] ->
{error, <<"Unexpected line: "/utf8, Line/binary>>}
end.
-file("src/gliff/internal/unified.gleam", 293).
?DOC(false).
-spec parse_unified(binary()) -> {ok, list(gliff@types:hunk())} |
{error, binary()}.
parse_unified(Input) ->
Lines = gleam@string:split(Input, <<"\n"/utf8>>),
Content_lines = skip_file_headers(Lines),
parse_hunks(Content_lines, []).
-file("src/gliff/internal/unified.gleam", 28).
?DOC(false).
-spec from_unified(binary()) -> {ok, list(gliff@types:hunk())} |
{error, binary()}.
from_unified(Unified) ->
parse_unified(Unified).