diff options
| author | Christopher R. Nelson <christopher.nelson@languidnights.com> | 2026-07-21 11:18:56 -0400 |
|---|---|---|
| committer | Christopher R. Nelson <christopher.nelson@languidnights.com> | 2026-07-21 11:18:56 -0400 |
| commit | 7e8472e1e2a0b39746ef86c041d56b92bab5a6b7 (patch) | |
| tree | 4d37a36c945446b4bded6989a780abe4cd3f2f1e /src/er_xdg_pipe_menu_cache.erl | |
| parent | 46b72a375101b54819f8750750017bd71e7c3798 (diff) | |
Wire up cache, file watcher, and Unix socket daemon
Adds a gen_server cache holding the rendered menu, an fs/inotify-based
watcher that debounces changes and invalidates it, a Unix domain
socket serving the cached binary, and the escript client Openbox
invokes (with an inline render fallback if the daemon isn't running).
Also documents local deployment (systemd user unit, Openbox menu.xml
wiring) in the README.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'src/er_xdg_pipe_menu_cache.erl')
| -rw-r--r-- | src/er_xdg_pipe_menu_cache.erl | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/er_xdg_pipe_menu_cache.erl b/src/er_xdg_pipe_menu_cache.erl new file mode 100644 index 0000000..a71526e --- /dev/null +++ b/src/er_xdg_pipe_menu_cache.erl @@ -0,0 +1,56 @@ +%%%------------------------------------------------------------------- +%% @doc Caches the rendered Openbox pipe menu in memory. +%% +%% Holds the last-rendered menu binary so socket clients get an +%% instant response. `invalidate/0' synchronously rescans the XDG +%% application directories, reparses every `.desktop' file and +%% re-renders the menu, replacing the cached binary. +%% @end +%%%------------------------------------------------------------------- + +-module(er_xdg_pipe_menu_cache). + +-behaviour(gen_server). + +-export([start_link/0, get_menu/0, invalidate/0, build/1]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2]). + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +-spec get_menu() -> binary(). +get_menu() -> + gen_server:call(?MODULE, get_menu). + +-spec invalidate() -> ok. +invalidate() -> + gen_server:cast(?MODULE, invalidate). + +%% Pure pipeline: explicit dirs in, rendered menu binary out. Kept +%% side-effect-free (besides reading the filesystem) and exported so +%% it can be unit tested directly and reused by the CLI client's +%% no-daemon fallback, without going through the gen_server at all. +-spec build([file:filename_all()]) -> binary(). +build(Dirs) -> + Files = er_xdg_pipe_menu_scanner:find_desktop_files(Dirs), + Entries = lists:filtermap(fun parse/1, Files), + er_xdg_pipe_menu_renderer:render(Entries). + +parse(File) -> + case er_xdg_pipe_menu_desktop_entry:parse_file(File) of + {ok, Entry} -> {true, Entry}; + {error, _} -> false + end. + +init([]) -> + {ok, build(er_xdg_pipe_menu_scanner:data_dirs())}. + +handle_call(get_menu, _From, Menu) -> + {reply, Menu, Menu}. + +handle_cast(invalidate, _Menu) -> + {noreply, build(er_xdg_pipe_menu_scanner:data_dirs())}. + +handle_info(_Info, State) -> + {noreply, State}. |
