Packages

Elixir code reloader. Maintained fork of exsync.

Current section

Files

Jump to
exsynchro lib exsync src_monitor.ex
Raw

lib/exsync/src_monitor.ex

defmodule ExSync.SrcMonitor do
use GenServer
@throttle_timeout_ms 100
defmodule State do
defstruct [:throttle_timer, :file_events, :watcher_pid]
end
def start_link(_opts \\ []) do
GenServer.start_link(__MODULE__, [])
end
@impl GenServer
def init([]) do
{:ok, watcher_pid} =
FileSystem.start_link(
dirs: ExSync.Config.src_dirs(),
backend: Application.get_env(:file_system, :backend)
)
FileSystem.subscribe(watcher_pid)
ExSync.Logger.debug("ExSync source monitor started.")
{:ok, %State{watcher_pid: watcher_pid}}
end
@impl GenServer
def handle_info({:file_event, watcher_pid, {path, events}}, %{watcher_pid: watcher_pid} = state) do
matching_extension? = Path.extname(path) in ExSync.Config.src_extensions()
# This varies based on editor and OS - when saving a file in neovim on linux,
# events received are:
# :modified
# :modified, :closed
# :attribute
# Rather than coding specific behaviors for each OS, look for the modified event in
# isolation to trigger things.
matching_event? = :modified in events
included? =
!Enum.any?(
ExSync.Config.src_exclusions(),
&Regex.match?(&1, path)
)
state =
if matching_extension? && matching_event? && included? do
maybe_recomplete(state)
else
state
end
{:noreply, state}
end
def handle_info({:file_event, watcher_pid, :stop}, %{watcher_pid: watcher_pid} = state) do
ExSync.Logger.debug("ExSync src monitor stopped.")
{:noreply, state}
end
def handle_info(:throttle_timer_complete, %State{} = state) do
ExSync.Utils.recomplete()
state = %State{state | throttle_timer: nil}
{:noreply, state}
end
defp maybe_recomplete(%State{throttle_timer: nil} = state) do
throttle_timer = Process.send_after(self(), :throttle_timer_complete, @throttle_timeout_ms)
%State{state | throttle_timer: throttle_timer}
end
defp maybe_recomplete(%State{} = state), do: state
end