Current section
Files
Jump to
Current section
Files
src/filespy.erl
-module(filespy).
-compile([no_auto_import, nowarn_unused_vars]).
-export([new/0, add_dir/2, set_actor_handler/2, set_initial_state/2, set_handler/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(GVS, GVT, GVU, GVV) :: {builder,
list(binary()),
gleam@option:option(fun((change(), GVS) -> gleam@otp@actor:next(change(), GVS))),
gleam@option:option(GVS)} |
{gleam_phantom, GVT, GVU, GVV}.
-spec new() -> builder(any(), no_directories(), no_handler(), no_initial_state()).
new() ->
{builder, [], none, none}.
-spec add_dir(builder(GWE, any(), GWG, GWH), binary()) -> builder(GWE, has_directories(), GWG, GWH).
add_dir(Builder, Directory) ->
{builder,
[Directory | erlang:element(2, Builder)],
erlang:element(3, Builder),
erlang:element(4, Builder)}.
-spec set_actor_handler(
builder(GWZ, GXA, no_handler(), GXB),
fun((change(), GWZ) -> gleam@otp@actor:next(change(), GWZ))
) -> builder(GWZ, GXA, has_handler(), GXB).
set_actor_handler(Builder, Handler) ->
{builder,
erlang:element(2, Builder),
{some, Handler},
erlang:element(4, Builder)}.
-spec set_initial_state(builder(GXL, GXM, GXN, no_initial_state()), GXL) -> builder(GXL, GXM, GXN, has_initial_state()).
set_initial_state(Builder, State) ->
{builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
{some, State}}.
-spec set_handler(
builder(nil, GWQ, no_handler(), no_initial_state()),
fun((binary(), event()) -> nil)
) -> builder(nil, GWQ, 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 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 => 196})
end,
{change, Path, Events}
end
).
-spec spec(builder(GYA, has_directories(), has_handler(), has_initial_state())) -> gleam@otp@actor:spec(GYA, 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 => 218})
end,
_assert_subject@1 = erlang:element(4, Builder),
{some, Initial_state} = 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 => 219})
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, Initial_state, 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).