diff options
| author | Christopher R. Nelson <christopher.nelson@languidnights.com> | 2026-07-20 22:56:01 -0400 |
|---|---|---|
| committer | Christopher R. Nelson <christopher.nelson@languidnights.com> | 2026-07-20 22:56:01 -0400 |
| commit | 7db20cd2ac2c8b8774a8ae02a7b233541666c865 (patch) | |
| tree | 38f97001dc6c486e5a7a254b071b23f1d6bce51a /src/er_xdg_pipe_menu_scanner.erl | |
| parent | 13491ac0c68e24e6aeb5d47e8b89777979ad6320 (diff) | |
Add XDG applications directory scanner
Resolves the ordered list of "applications" directories to search per
the XDG Base Directory Specification: XDG_DATA_HOME (default
~/.local/share) first, then XDG_DATA_DIRS (default /usr/local/share,
/usr/share). Each variable falls back to its default independently
when unset or empty, so a Flatpak-style XDG_DATA_DIRS override is
honored in place of the default rather than merged with it.
find_desktop_files/0,1 recursively collects .desktop files from those
dirs, skipping ones that don't exist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'src/er_xdg_pipe_menu_scanner.erl')
| -rw-r--r-- | src/er_xdg_pipe_menu_scanner.erl | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/src/er_xdg_pipe_menu_scanner.erl b/src/er_xdg_pipe_menu_scanner.erl new file mode 100644 index 0000000..131b4f6 --- /dev/null +++ b/src/er_xdg_pipe_menu_scanner.erl @@ -0,0 +1,62 @@ +%%%------------------------------------------------------------------- +%% @doc Locates .desktop files under the XDG application directories. +%% +%% Directory precedence follows the XDG Base Directory Specification: +%% the user's data home (most specific, so its entries should win over +%% system ones downstream) is searched first, then each directory in +%% `XDG_DATA_DIRS'. Each of `XDG_DATA_HOME' and `XDG_DATA_DIRS' falls +%% back to its spec-defined default independently when unset or empty +%% -- so a Flatpak-aware `XDG_DATA_DIRS' (which typically adds +%% `~/.local/share/flatpak/exports/share') is honored in place of the +%% default rather than merged with it. +%% @end +%%%------------------------------------------------------------------- + +-module(er_xdg_pipe_menu_scanner). + +-export([data_dirs/0, find_desktop_files/0, find_desktop_files/1]). + +-define(DEFAULT_DATA_DIRS, ["/usr/local/share", "/usr/share"]). + +-spec data_dirs() -> [file:filename_all()]. +data_dirs() -> + [filename:join(Dir, "applications") || Dir <- data_home() ++ data_dirs_list()]. + +-spec find_desktop_files() -> [file:filename_all()]. +find_desktop_files() -> + find_desktop_files(data_dirs()). + +-spec find_desktop_files([file:filename_all()]) -> [file:filename_all()]. +find_desktop_files(Dirs) -> + lists:flatmap(fun find_in_dir/1, Dirs). + +find_in_dir(Dir) -> + case filelib:is_dir(Dir) of + true -> filelib:wildcard(filename:join(Dir, "**/*.desktop")); + false -> [] + end. + +data_home() -> + case env("XDG_DATA_HOME") of + undefined -> + case env("HOME") of + undefined -> []; + Home -> [filename:join([Home, ".local", "share"])] + end; + Dir -> + [Dir] + end. + +data_dirs_list() -> + case env("XDG_DATA_DIRS") of + undefined -> ?DEFAULT_DATA_DIRS; + Value -> [D || D <- string:split(Value, ":", all), D =/= ""] + end. + +%% The spec treats an unset and an empty variable the same way. +env(Name) -> + case os:getenv(Name) of + false -> undefined; + "" -> undefined; + Value -> Value + end. |
