Packages

HTML templates → type-safe Gleam modules. Write familiar markup instead of nested function calls. No more bracket-counting nightmares.

Current section

Files

Jump to
ghtml src ghtml@watcher.erl
Raw

src/ghtml@watcher.erl

-module(ghtml@watcher).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ghtml/watcher.gleam").
-export([get_mtime/1, get_all_mtimes/1, process_single_file/1, start_watching/1]).
-export_type([watcher_message/0, watcher_state/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(false).
-type watcher_message() :: {init,
gleam@erlang@process:subject(watcher_message())} |
check |
stop.
-type watcher_state() :: {watcher_state,
binary(),
gleam@dict:dict(binary(), integer()),
gleam@option:option(gleam@erlang@process:subject(watcher_message()))}.
-file("src/ghtml/watcher.gleam", 53).
?DOC(false).
-spec get_mtime(binary()) -> {ok, integer()} | {error, nil}.
get_mtime(Path) ->
case simplifile_erl:file_info(Path) of
{ok, Info} ->
{ok, erlang:element(10, Info)};
{error, _} ->
{error, nil}
end.
-file("src/ghtml/watcher.gleam", 61).
?DOC(false).
-spec get_all_mtimes(binary()) -> gleam@dict:dict(binary(), integer()).
get_all_mtimes(Root) ->
_pipe = ghtml@scanner:find_ghtml_files(Root),
_pipe@1 = gleam@list:filter_map(_pipe, fun(Path) -> case get_mtime(Path) of
{ok, Mtime} ->
{ok, {Path, Mtime}};
{error, _} ->
{error, nil}
end end),
maps:from_list(_pipe@1).
-file("src/ghtml/watcher.gleam", 117).
?DOC(false).
-spec schedule_check(gleam@erlang@process:subject(watcher_message())) -> nil.
schedule_check(Subject) ->
gleam@erlang@process:send_after(Subject, 500, check),
nil.
-file("src/ghtml/watcher.gleam", 180).
?DOC(false).
-spec process_single_file(binary()) -> nil.
process_single_file(Source_path) ->
Output_path = ghtml@scanner:to_output_path(Source_path),
case simplifile:read(Source_path) of
{ok, Content} ->
Hash = ghtml@cache:hash_content(Content),
case ghtml@parser:parse(Content) of
{ok, Template} ->
Gleam_code = ghtml@codegen:generate(
Template,
Source_path,
Hash
),
case simplifile:write(Output_path, Gleam_code) of
{ok, _} ->
gleam_stdlib:println(
<<" Generated: "/utf8, Output_path/binary>>
);
{error, E} ->
gleam_stdlib:println(
<<" Error writing: "/utf8,
(gleam@string:inspect(E))/binary>>
)
end;
{error, Errors} ->
gleam_stdlib:println(<<" Parse errors:"/utf8>>),
gleam@list:each(
Errors,
fun(E@1) ->
gleam_stdlib:println(
<<<<<<" Line "/utf8,
(erlang:integer_to_binary(
erlang:element(
2,
erlang:element(
2,
erlang:element(2, E@1)
)
)
))/binary>>/binary,
": "/utf8>>/binary,
(erlang:element(3, E@1))/binary>>
)
end
)
end;
{error, E@2} ->
gleam_stdlib:println(
<<" Error reading: "/utf8, (gleam@string:inspect(E@2))/binary>>
)
end.
-file("src/ghtml/watcher.gleam", 124).
?DOC(false).
-spec check_for_changes(watcher_state()) -> watcher_state().
check_for_changes(State) ->
Current_files = ghtml@scanner:find_ghtml_files(erlang:element(2, State)),
Current_mtimes = get_all_mtimes(erlang:element(2, State)),
gleam@list:each(
Current_files,
fun(Path) ->
Should_process = case gleam_stdlib:map_get(
erlang:element(3, State),
Path
) of
{error, _} ->
gleam_stdlib:println(<<"New file: "/utf8, Path/binary>>),
true;
{ok, Old_mtime} ->
case gleam_stdlib:map_get(Current_mtimes, Path) of
{ok, New_mtime} when New_mtime =/= Old_mtime ->
gleam_stdlib:println(
<<"Modified: "/utf8, Path/binary>>
),
true;
_ ->
false
end
end,
case Should_process of
true ->
process_single_file(Path);
false ->
nil
end
end
),
_pipe = maps:keys(erlang:element(3, State)),
gleam@list:each(
_pipe,
fun(Old_path) -> case gleam@list:contains(Current_files, Old_path) of
false ->
gleam_stdlib:println(<<"Deleted: "/utf8, Old_path/binary>>),
Gleam_path = ghtml@scanner:to_output_path(Old_path),
case simplifile_erl:delete(Gleam_path) of
{ok, _} ->
gleam_stdlib:println(
<<" Removed: "/utf8, Gleam_path/binary>>
);
{error, _} ->
nil
end;
true ->
nil
end end
),
case erlang:element(4, State) of
{some, Subject} ->
schedule_check(Subject);
none ->
nil
end,
{watcher_state,
erlang:element(2, State),
Current_mtimes,
erlang:element(4, State)}.
-file("src/ghtml/watcher.gleam", 97).
?DOC(false).
-spec handle_message(watcher_state(), watcher_message()) -> gleam@otp@actor:next(watcher_state(), watcher_message()).
handle_message(State, Message) ->
case Message of
stop ->
gleam@otp@actor:stop();
{init, Subject} ->
New_state = {watcher_state,
erlang:element(2, State),
erlang:element(3, State),
{some, Subject}},
schedule_check(Subject),
gleam@otp@actor:continue(New_state);
check ->
New_state@1 = check_for_changes(State),
gleam@otp@actor:continue(New_state@1)
end.
-file("src/ghtml/watcher.gleam", 74).
?DOC(false).
-spec start_watching(binary()) -> gleam@erlang@process:subject(watcher_message()).
start_watching(Root) ->
Initial_mtimes = get_all_mtimes(Root),
Initial_state = {watcher_state, Root, Initial_mtimes, none},
Started@1 = case begin
_pipe = gleam@otp@actor:new(Initial_state),
_pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_message/2),
gleam@otp@actor:start(_pipe@1)
end of
{ok, Started} -> Started;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ghtml/watcher"/utf8>>,
function => <<"start_watching"/utf8>>,
line => 79,
value => _assert_fail,
start => 2214,
'end' => 2326,
pattern_start => 2225,
pattern_end => 2236})
end,
Actor_subject = erlang:element(3, Started@1),
gleam@erlang@process:send(Actor_subject, {init, Actor_subject}),
gleam_stdlib:println(<<"Watching for changes... (Ctrl+C to stop)"/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
Actor_subject.