-module(radiate). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/radiate.gleam"). -export([new/0, add_dir/2, on_reload/2, before_reload/2, set_initializer/2, start_state/1, start/1]). -export_type([no_directories/0, has_directories/0, no_initializer/0, has_initializer/0, no_callback/0, has_callback/0, has_before_callback/0, no_before_callback/0, builder/6, module_/0, what/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. -type no_directories() :: any(). -type has_directories() :: any(). -type no_initializer() :: any(). -type has_initializer() :: any(). -type no_callback() :: any(). -type has_callback() :: any(). -type has_before_callback() :: any(). -type no_before_callback() :: any(). -opaque builder(GCF, GCG, GCH, GCI, GCJ, GCK) :: {builder, list(binary()), fun((GCF, binary()) -> GCF), gleam@option:option(fun((gleam@erlang@process:subject(filespy:change(GCG))) -> {ok, gleam@otp@actor:initialised(nil, filespy:change(GCG), gleam@erlang@process:subject(filespy:change(GCG)))} | {error, GCG})), gleam@option:option(fun((GCF, binary()) -> GCF))} | {gleam_phantom, GCH, GCI, GCJ, GCK}. -type module_() :: any(). -type what() :: any(). -file("src/radiate.gleam", 62). ?DOC(" Construct a new builder\n"). -spec new() -> builder(nil, nil, no_directories(), no_initializer(), no_callback(), no_before_callback()). new() -> _pipe = fun(State, Path) -> gleam_stdlib:println( <<<<"Change in "/utf8, Path/binary>>/binary, ", reloading."/utf8>> ), State end, {builder, [], _pipe, none, none}. -file("src/radiate.gleam", 80). ?DOC( " Add a directory to watch. The path can be relative or absolute.\n" " macOS users: always use `\".\"` or an absolute path, otherwise it won't work\n" " properly!\n" ). -spec add_dir(builder(GCR, nil, any(), GCT, GCU, GCV), binary()) -> builder(GCR, nil, has_directories(), GCT, GCU, GCV). add_dir(Builder, Dir) -> {builder, [Dir | erlang:element(2, Builder)], erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder)}. -file("src/radiate.gleam", 107). ?DOC(" Add a callback to be run after reload\n"). -spec on_reload( builder(GDI, nil, GDJ, GDK, no_callback(), GDL), fun((GDI, binary()) -> GDI) ) -> builder(GDI, nil, GDJ, GDK, has_callback(), GDL). on_reload(Builder, Callback) -> {builder, erlang:element(2, Builder), Callback, erlang:element(4, Builder), erlang:element(5, Builder)}. -file("src/radiate.gleam", 134). ?DOC(" Add a callback to handle a process before reloading modules\n"). -spec before_reload( builder(GDY, nil, GDZ, GEA, GEB, no_before_callback()), fun((GDY, binary()) -> GDY) ) -> builder(GDY, nil, GDZ, GEA, GEB, has_before_callback()). before_reload(Builder, Before_callback) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), {some, Before_callback}}. -file("src/radiate.gleam", 164). ?DOC( " Add an initializer\n" "\n" " This will be run in the file watcher process, so it can be useful to, for\n" " example, add state to an actor\n" ). -spec set_initializer( builder(GEO, nil, GEP, no_initializer(), GEQ, GER), fun((gleam@erlang@process:subject(filespy:change(nil))) -> {ok, gleam@otp@actor:initialised(nil, filespy:change(nil), gleam@erlang@process:subject(filespy:change(nil)))} | {error, nil}) ) -> builder(GEO, nil, GEP, has_initializer(), GEQ, GER). set_initializer(Builder, Initializer) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), {some, Initializer}, erlang:element(5, Builder)}. -file("src/radiate.gleam", 237). ?DOC(" Execute the file reload\n"). -spec execute_reload( builder(GGC, nil, has_directories(), has_initializer(), any(), any()), GGC, binary() ) -> GGC. execute_reload(Builder, State, Path) -> Build_result = shellout:command( <<"gleam"/utf8>>, [<<"build"/utf8>>], <<"."/utf8>>, [] ), case Build_result of {ok, _} -> Mods = code:modified_modules(), gleam@list:each(Mods, fun code:purge/1), _ = code:atomic_load(Mods), (erlang:element(3, Builder))(State, Path); {error, {_, Message}} -> _pipe = Message, gleam_stdlib:print_error(_pipe), State end. -file("src/radiate.gleam", 269). ?DOC(" Start reloader, ensuring that a state has been set\n"). -spec start_state( builder(nil, nil, has_directories(), has_initializer(), any(), any()) ) -> {ok, gleam@otp@actor:started(gleam@erlang@process:subject(filespy:change(nil)))} | {error, gleam@otp@actor:start_error()}. start_state(Builder) -> _pipe = filespy:new(), _pipe@3 = filespy:set_initializer( _pipe, fun(Subject) -> Init@1 = case erlang:element(4, Builder) of {some, Init} -> Init; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"radiate"/utf8>>, function => <<"start_state"/utf8>>, line => 281, value => _assert_fail, start => 5632, 'end' => 5675, pattern_start => 5643, pattern_end => 5653}) end, Initialised = Init@1(Subject), case Initialised of {ok, Initialised@1} -> _pipe@1 = Initialised@1, _pipe@2 = gleam@otp@actor:returning(_pipe@1, Subject), {ok, _pipe@2}; {error, _} -> {error, <<"Error during initializing"/utf8>>} end end ), _pipe@4 = filespy:add_dirs(_pipe@3, erlang:element(2, Builder)), _pipe@5 = filespy:set_actor_handler(_pipe@4, fun(State, Msg) -> case Msg of {custom, _} -> gleam@otp@actor:continue(State); {change, Path, Events} -> gleam@list:fold( Events, State, fun(State@1, Event) -> case Event of closed -> case gleam_stdlib:string_ends_with( Path, <<".gleam"/utf8>> ) of true -> case erlang:element(5, Builder) of {some, Before} -> State@2 = Before( State@1, Path ), execute_reload( Builder, State@2, Path ); _ -> execute_reload( Builder, State@1, Path ) end, State@1; _ -> State@1 end; modified -> case gleam_stdlib:string_ends_with( Path, <<".gleam"/utf8>> ) of true -> case erlang:element(5, Builder) of {some, Before} -> State@2 = Before( State@1, Path ), execute_reload( Builder, State@2, Path ); _ -> execute_reload( Builder, State@1, Path ) end, State@1; _ -> State@1 end; _ -> State@1 end end ), gleam@otp@actor:continue(State) end end), filespy:start(_pipe@5). -file("src/radiate.gleam", 212). ?DOC(" Start reloader, if no state has been set\n"). -spec start( builder(nil, nil, has_directories(), no_initializer(), any(), any()) ) -> {ok, gleam@otp@actor:started(gleam@erlang@process:subject(filespy:change(nil)))} | {error, gleam@otp@actor:start_error()}. start(Builder) -> _pipe = Builder, _pipe@5 = set_initializer( _pipe, fun(Subject) -> Selector = begin _pipe@1 = gleam_erlang_ffi:new_selector(), gleam@erlang@process:select(_pipe@1, Subject) end, _pipe@2 = gleam@otp@actor:initialised(nil), _pipe@3 = gleam@otp@actor:returning(_pipe@2, Subject), _pipe@4 = gleam@otp@actor:selecting(_pipe@3, Selector), {ok, _pipe@4} end ), start_state(_pipe@5).