-module(filespy). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new/0, add_dir/2, add_dirs/2, set_actor_handler/2, set_initial_state/2, set_handler/2, set_initializer/2, selector/0, spec/1, start/1]). -export_type([no_directories/0, has_directories/0, no_handler/0, has_handler/0, no_initial_state/0, has_initial_state/0, event/0, change/0, builder/4]). -type no_directories() :: any(). -type has_directories() :: any(). -type no_handler() :: any(). -type has_handler() :: any(). -type no_initial_state() :: any(). -type has_initial_state() :: any(). -type event() :: created | modified | closed | deleted | renamed | attribute | {unknown, gleam@erlang@atom:atom_()}. -type change() :: {change, binary(), list(event())}. -opaque builder(GXZ, GYA, GYB, GYC) :: {builder, list(binary()), gleam@option:option(fun((change(), GXZ) -> gleam@otp@actor:next(change(), GXZ))), gleam@option:option(fun(() -> GXZ))} | {gleam_phantom, GYA, GYB, GYC}. -spec new() -> builder(any(), no_directories(), no_handler(), no_initial_state()). new() -> {builder, [], none, none}. -spec add_dir(builder(GYL, any(), GYN, GYO), binary()) -> builder(GYL, has_directories(), GYN, GYO). add_dir(Builder, Directory) -> {builder, [Directory | erlang:element(2, Builder)], erlang:element(3, Builder), erlang:element(4, Builder)}. -spec add_dirs(builder(GYX, any(), GYZ, GZA), list(binary())) -> builder(GYX, has_directories(), GYZ, GZA). add_dirs(Builder, Directories) -> {builder, gleam@list:append(Directories, erlang:element(2, Builder)), erlang:element(3, Builder), erlang:element(4, Builder)}. -spec set_actor_handler( builder(GZT, GZU, no_handler(), GZV), fun((change(), GZT) -> gleam@otp@actor:next(change(), GZT)) ) -> builder(GZT, GZU, has_handler(), GZV). set_actor_handler(Builder, Handler) -> {builder, erlang:element(2, Builder), {some, Handler}, erlang:element(4, Builder)}. -spec set_initial_state(builder(HAF, HAG, HAH, no_initial_state()), HAF) -> builder(HAF, HAG, HAH, has_initial_state()). set_initial_state(Builder, State) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), {some, fun() -> State end}}. -spec set_handler( builder(nil, GZK, no_handler(), no_initial_state()), fun((binary(), event()) -> nil) ) -> builder(nil, GZK, has_handler(), has_initial_state()). set_handler(Builder, Handler) -> Wrapped_handler = fun(Event, _) -> {change, Path, Events} = Event, gleam@list:each(Events, fun(Ev) -> Handler(Path, Ev) end), gleam@otp@actor:continue(nil) end, _pipe = Builder, _pipe@1 = set_actor_handler(_pipe, Wrapped_handler), set_initial_state(_pipe@1, nil). -spec set_initializer( builder(HAQ, HAR, HAS, no_initial_state()), fun(() -> HAQ) ) -> builder(HAQ, HAR, HAS, has_initial_state()). set_initializer(Builder, Initializer) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), {some, Initializer}}. -spec to_event(gleam@dynamic:dynamic_()) -> {ok, event()} | {error, list(gleam@dynamic:decode_error())}. to_event(From) -> gleam@result:'try'( gleam_erlang_ffi:atom_from_dynamic(From), fun(Event) -> Created = erlang:binary_to_atom(<<"created"/utf8>>), Deleted = erlang:binary_to_atom(<<"deleted"/utf8>>), Modified = erlang:binary_to_atom(<<"modified"/utf8>>), Closed = erlang:binary_to_atom(<<"closed"/utf8>>), Renamed = erlang:binary_to_atom(<<"renamed"/utf8>>), Attrib = erlang:binary_to_atom(<<"attribute"/utf8>>), Removed = erlang:binary_to_atom(<<"removed"/utf8>>), case Event of Ev when Ev =:= Created -> {ok, created}; Ev@1 when Ev@1 =:= Deleted -> {ok, deleted}; Ev@2 when Ev@2 =:= Modified -> {ok, modified}; Ev@3 when Ev@3 =:= Closed -> {ok, closed}; Ev@4 when Ev@4 =:= Renamed -> {ok, renamed}; Ev@5 when Ev@5 =:= Removed -> {ok, deleted}; Ev@6 when Ev@6 =:= Attrib -> {ok, attribute}; Other -> {ok, {unknown, Other}} end end ). -spec selector() -> gleam@erlang@process:selector(change()). selector() -> _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting_anything( _pipe, fun(Event) -> _assert_subject = (gleam@dynamic:tuple3( fun gleam@dynamic:dynamic/1, fun gleam@dynamic:dynamic/1, gleam@dynamic:tuple2( fun(L) -> _pipe@1 = gleam@dynamic:unsafe_coerce(L), _pipe@2 = unicode:characters_to_binary(_pipe@1), {ok, _pipe@2} end, gleam@dynamic:list(fun to_event/1) ) ))(Event), {ok, {_, _, {Path, Events}}} = 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 => <<"filespy"/utf8>>, function => <<"selector"/utf8>>, line => 224}) end, {change, Path, Events} end ). -spec spec(builder(HBF, has_directories(), has_handler(), has_initial_state())) -> gleam@otp@actor:spec(HBF, change()). spec(Builder) -> _assert_subject = erlang:element(3, Builder), {some, Handler} = case _assert_subject of {some, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"filespy"/utf8>>, function => <<"spec"/utf8>>, line => 246}) end, _assert_subject@1 = erlang:element(4, Builder), {some, Initializer} = case _assert_subject@1 of {some, _} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@1, module => <<"filespy"/utf8>>, function => <<"spec"/utf8>>, line => 247}) end, {spec, fun() -> {Oks, Errs} = begin _pipe = erlang:element(2, Builder), _pipe@2 = gleam@list:map( _pipe, fun(Dir) -> Atom = erlang:binary_to_atom( <<"fs_watcher"/utf8, Dir/binary>> ), _pipe@1 = fs:start_link(Atom, Dir), gleam@result:map(_pipe@1, fun(Pid) -> {Pid, Atom} end) end ), gleam@result:partition(_pipe@2) end, case Errs of [] -> _pipe@3 = Oks, gleam@list:each( _pipe@3, fun(Res) -> {_, Atom@1} = Res, fs:subscribe(Atom@1) end ), {ready, Initializer(), selector()}; Errs@1 -> gleam@list:each( Oks, fun(Res@1) -> {Pid@1, _} = Res@1, gleam@erlang@process:kill(Pid@1) end ), {failed, <<"Failed to start watcher: "/utf8, (gleam@string:inspect(Errs@1))/binary>>} end end, 5000, Handler}. -spec start( builder(any(), has_directories(), has_handler(), has_initial_state()) ) -> {ok, gleam@erlang@process:subject(change())} | {error, gleam@otp@actor:start_error()}. start(Builder) -> _pipe = spec(Builder), gleam@otp@actor:start_spec(_pipe).