-module(olive@watcher). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([start/1]). -export_type([message/0, state/0, internal_msg/0, watch_events/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( " The `watcher` module watches a list of dir and triggers a `FilesChanged` message\n" " to be handled by calling code.\n" ). -type message() :: files_changed. -type state() :: {state, gleam@option:option(gleam@erlang@process:timer()), gleam@erlang@process:subject(message())}. -opaque internal_msg() :: trigger_files_changed | ignore_changes. -type watch_events() :: event_needing_rebuild | other_events. -file("src/olive/watcher.gleam", 55). -spec maybe_cancel_timer(gleam@option:option(gleam@erlang@process:timer())) -> nil. maybe_cancel_timer(Timer) -> case Timer of {some, Timer@1} -> gleam@erlang@process:cancel_timer(Timer@1), nil; none -> nil end. -file("src/olive/watcher.gleam", 37). -spec do_loop(internal_msg(), state()) -> gleam@otp@actor:next(any(), state()). do_loop(Msg, State) -> case Msg of ignore_changes -> gleam@otp@actor:continue(State); trigger_files_changed -> maybe_cancel_timer(erlang:element(2, State)), Timer = gleam@erlang@process:send_after( erlang:element(3, State), 50, files_changed ), gleam@otp@actor:continue( begin _record = State, {state, {some, Timer}, erlang:element(3, _record)} end ) end. -file("src/olive/watcher.gleam", 106). ?DOC(" Converts an atom to an event\n"). -spec atom_to_watch_events() -> gleam@dynamic@decode:decoder(watch_events()). atom_to_watch_events() -> Modified = erlang:binary_to_atom(<<"modified"/utf8>>), Renamed = erlang:binary_to_atom(<<"renamed"/utf8>>), gleam@dynamic@decode:new_primitive_decoder( <<"Atom"/utf8>>, fun(Data) -> case gleam_erlang_ffi:atom_from_dynamic(Data) of {ok, Ev} when Ev =:= Modified -> {ok, event_needing_rebuild}; {ok, Ev@1} when Ev@1 =:= Renamed -> {ok, event_needing_rebuild}; _ -> {ok, other_events} end end ). -file("src/olive/watcher.gleam", 82). -spec watch_decoder(gleam@dynamic:dynamic_()) -> internal_msg(). watch_decoder(Msg) -> Decoder = begin gleam@dynamic@decode:subfield( [2, 1], gleam@dynamic@decode:list(atom_to_watch_events()), fun(Events) -> gleam@dynamic@decode:success(Events) end ) end, case gleam@dynamic@decode:run(Msg, Decoder) of {ok, Events@1} -> case gleam@list:contains(Events@1, event_needing_rebuild) of true -> trigger_files_changed; false -> ignore_changes end; {error, _} -> olive@logging:log_error( <<"Error occured while watching files"/utf8>> ), ignore_changes end. -file("src/olive/watcher.gleam", 65). -spec watch_folder(binary()) -> {ok, gleam@erlang@process:selector(internal_msg())} | {error, nil}. watch_folder(Dir) -> Atom = erlang:binary_to_atom(<<"fs_watcher_"/utf8, Dir/binary>>), case fs:start_link(Atom, Dir) of {ok, _} -> fs:subscribe(Atom), Selectors = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting_anything( _pipe, fun watch_decoder/1 ) end, {ok, Selectors}; {error, _} -> olive@logging:log_error( <<"Error occured while watching folder: "/utf8, Dir/binary>> ), {error, nil} end. -file("src/olive/watcher.gleam", 26). -spec start(gleam@erlang@process:subject(message())) -> {ok, gleam@erlang@process:subject(internal_msg())} | {error, gleam@otp@actor:start_error()}. start(Watch_subject) -> gleam@otp@actor:start_spec( {spec, fun() -> case watch_folder(<<"src"/utf8>>) of {ok, Selectors} -> {ready, {state, none, Watch_subject}, Selectors}; {error, _} -> {failed, <<"Could not start watch actor with folder src"/utf8>>} end end, 5000, fun do_loop/2} ).