Skip to main content

src/molt@internal@document@comments.erl

-module(molt@internal@document@comments).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/document/comments.gleam").
-export([set_comments/3, get_comments/2, move_comments/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/molt/internal/document/comments.gleam", 54).
?DOC(false).
-spec write_comments(
    molt@types:document(),
    list(molt@types:path_segment()),
    molt@ops:comments()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
write_comments(Doc, Segments, Comments) ->
    {comments, Leading, Trailing} = Comments,
    gleam@result:'try'(
        molt@cst:set_leading_comments(erlang:element(4, Doc), Segments, Leading),
        fun(Tree1) ->
            gleam@result:'try'(
                molt@cst:set_trailing_comment(Tree1, Segments, Trailing),
                fun(Tree2) ->
                    {ok,
                        {document,
                            erlang:element(2, Doc),
                            erlang:element(3, Doc),
                            Tree2,
                            erlang:element(5, Doc)}}
                end
            )
        end
    ).

-file("src/molt/internal/document/comments.gleam", 36).
?DOC(false).
-spec reject_empty_path(
    list(molt@types:path_segment()),
    binary(),
    fun(() -> {ok, PMM} | {error, molt@error:molt_error()})
) -> {ok, PMM} | {error, molt@error:molt_error()}.
reject_empty_path(Segments, Operation, Continue) ->
    case Segments of
        [] ->
            {error,
                {invalid_operation,
                    Operation,
                    {some,
                        <<"the empty path is not a comment-bearing node; use get_document_comments / set_document_comments for document-level (head and tail) comments"/utf8>>}}};

        _ ->
            Continue()
    end.

-file("src/molt/internal/document/comments.gleam", 10).
?DOC(false).
-spec set_comments(molt@types:document(), binary(), molt@ops:comments()) -> {ok,
        molt@types:document()} |
    {error, molt@error:molt_error()}.
set_comments(Doc, P, Comments) ->
    gleam@result:'try'(
        molt@internal@path:parse(P),
        fun(Segments) ->
            reject_empty_path(
                Segments,
                <<"set_comments"/utf8>>,
                fun() ->
                    molt@internal@document@index:with_index(
                        Doc,
                        fun(Idx) ->
                            case molt@internal@document@index:resolve(
                                Idx,
                                Segments
                            ) of
                                {hit, _, {index_implicit_table, _}} ->
                                    {error,
                                        {invalid_operation,
                                            <<"set_comments"/utf8>>,
                                            {some,
                                                <<"implicit tables have no concrete node"/utf8>>}}};

                                {hit, _, _} ->
                                    write_comments(Doc, Segments, Comments);

                                {miss, _, _, _} ->
                                    {error, molt@error:not_found(P)};

                                {fresh, _} ->
                                    {error, molt@error:not_found(P)}
                            end
                        end
                    )
                end
            )
        end
    ).

-file("src/molt/internal/document/comments.gleam", 96).
?DOC(false).
-spec read_comments(molt@types:document(), list(molt@types:path_segment())) -> {ok,
        molt@ops:comments()} |
    {error, molt@error:molt_error()}.
read_comments(Doc, Segments) ->
    gleam@result:'try'(
        molt@cst:leading_comments(erlang:element(4, Doc), Segments),
        fun(Leading) ->
            gleam@result:'try'(
                molt@cst:trailing_comment(erlang:element(4, Doc), Segments),
                fun(Trailing) -> {ok, {comments, Leading, Trailing}} end
            )
        end
    ).

-file("src/molt/internal/document/comments.gleam", 73).
?DOC(false).
-spec get_comments(molt@types:document(), binary()) -> {ok, molt@ops:comments()} |
    {error, molt@error:molt_error()}.
get_comments(Doc, P) ->
    gleam@result:'try'(
        molt@internal@path:parse(P),
        fun(Segments) ->
            reject_empty_path(
                Segments,
                <<"get_comments"/utf8>>,
                fun() ->
                    molt@internal@document@index:with_index(
                        Doc,
                        fun(Idx) ->
                            case molt@internal@document@index:resolve(
                                Idx,
                                Segments
                            ) of
                                {hit, _, {index_implicit_table, _}} ->
                                    {error,
                                        {invalid_operation,
                                            <<"get_comments"/utf8>>,
                                            {some,
                                                <<"implicit tables have no concrete node"/utf8>>}}};

                                {hit, _, _} ->
                                    read_comments(Doc, Segments);

                                {miss, _, _, _} ->
                                    {error, molt@error:not_found(P)};

                                {fresh, _} ->
                                    {error, molt@error:not_found(P)}
                            end
                        end
                    )
                end
            )
        end
    ).

-file("src/molt/internal/document/comments.gleam", 168).
?DOC(false).
-spec ensure_comment_source(
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    binary()
) -> {ok, nil} | {error, molt@error:molt_error()}.
ensure_comment_source(Idx, Segments, Raw) ->
    case molt@internal@document@index:resolve(Idx, Segments) of
        {hit, _, {index_implicit_table, _}} ->
            {error,
                {invalid_operation,
                    <<"move_comments"/utf8>>,
                    {some,
                        <<"implicit tables have no concrete node carrying comments"/utf8>>}}};

        {hit, _, _} ->
            {ok, nil};

        {miss, _, _, _} ->
            {error, molt@error:not_found(Raw)};

        {fresh, _} ->
            {error, molt@error:not_found(Raw)}
    end.

-file("src/molt/internal/document/comments.gleam", 108).
?DOC(false).
-spec move_comments(molt@types:document(), binary(), binary()) -> {ok,
        molt@types:document()} |
    {error, molt@error:molt_error()}.
move_comments(Doc, From, To) ->
    gleam@result:'try'(
        molt@internal@path:parse(From),
        fun(From_segments) ->
            gleam@result:'try'(
                molt@internal@path:parse(To),
                fun(To_segments) ->
                    reject_empty_path(
                        From_segments,
                        <<"move_comments"/utf8>>,
                        fun() ->
                            reject_empty_path(
                                To_segments,
                                <<"move_comments"/utf8>>,
                                fun() ->
                                    molt@internal@document@index:with_index(
                                        Doc,
                                        fun(Idx) ->
                                            gleam@result:'try'(
                                                ensure_comment_source(
                                                    Idx,
                                                    From_segments,
                                                    From
                                                ),
                                                fun(_) ->
                                                    gleam@result:'try'(
                                                        molt@cst:leading_comments(
                                                            erlang:element(
                                                                4,
                                                                Doc
                                                            ),
                                                            From_segments
                                                        ),
                                                        fun(From_leading) ->
                                                            gleam@result:'try'(
                                                                molt@cst:trailing_comment(
                                                                    erlang:element(
                                                                        4,
                                                                        Doc
                                                                    ),
                                                                    From_segments
                                                                ),
                                                                fun(
                                                                    From_trailing
                                                                ) ->
                                                                    case {From_leading,
                                                                        From_trailing} of
                                                                        {[],
                                                                            none} ->
                                                                            {ok,
                                                                                Doc};

                                                                        {_, _} ->
                                                                            gleam@result:'try'(
                                                                                molt@cst:set_leading_comments(
                                                                                    erlang:element(
                                                                                        4,
                                                                                        Doc
                                                                                    ),
                                                                                    From_segments,
                                                                                    []
                                                                                ),
                                                                                fun(
                                                                                    Tree1
                                                                                ) ->
                                                                                    gleam@result:'try'(
                                                                                        molt@cst:set_trailing_comment(
                                                                                            Tree1,
                                                                                            From_segments,
                                                                                            none
                                                                                        ),
                                                                                        fun(
                                                                                            Tree2
                                                                                        ) ->
                                                                                            Doc2 = {document,
                                                                                                erlang:element(
                                                                                                    2,
                                                                                                    Doc
                                                                                                ),
                                                                                                erlang:element(
                                                                                                    3,
                                                                                                    Doc
                                                                                                ),
                                                                                                Tree2,
                                                                                                erlang:element(
                                                                                                    5,
                                                                                                    Doc
                                                                                                )},
                                                                                            gleam@result:'try'(
                                                                                                molt@cst:set_leading_comments(
                                                                                                    erlang:element(
                                                                                                        4,
                                                                                                        Doc2
                                                                                                    ),
                                                                                                    To_segments,
                                                                                                    From_leading
                                                                                                ),
                                                                                                fun(
                                                                                                    Tree3
                                                                                                ) ->
                                                                                                    gleam@result:'try'(
                                                                                                        molt@cst:set_trailing_comment(
                                                                                                            Tree3,
                                                                                                            To_segments,
                                                                                                            From_trailing
                                                                                                        ),
                                                                                                        fun(
                                                                                                            Tree4
                                                                                                        ) ->
                                                                                                            {ok,
                                                                                                                {document,
                                                                                                                    erlang:element(
                                                                                                                        2,
                                                                                                                        Doc2
                                                                                                                    ),
                                                                                                                    erlang:element(
                                                                                                                        3,
                                                                                                                        Doc2
                                                                                                                    ),
                                                                                                                    Tree4,
                                                                                                                    erlang:element(
                                                                                                                        5,
                                                                                                                        Doc2
                                                                                                                    )}}
                                                                                                        end
                                                                                                    )
                                                                                                end
                                                                                            )
                                                                                        end
                                                                                    )
                                                                                end
                                                                            )
                                                                    end
                                                                end
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).