commit 05b8cc77e8f396d12749d1d5230ba71da95189f2
parent 51ca9bd4fca03293b3aba75818f21caa7e805b70
Author: Daniel Barlow <dan@telent.net>
Date: Sun, 20 Mar 2022 14:08:55 +0000
Merge remote-tracking branch 'samueldr/feature/sorted-apps-and-all-apps'
Diffstat:
2 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/saturn/default.nix b/saturn/default.nix
@@ -37,6 +37,7 @@ let inifile = let lua = lua5_3; in lua53Packages.buildLuaPackage rec {
lgi
luafilesystem
luaposix
+ penlight
readline
]);
in stdenv.mkDerivation {
diff --git a/saturn/main.fnl b/saturn/main.fnl
@@ -89,12 +89,20 @@
(local lfs (require :lfs))
(local inifile (require :inifile))
+(local List (require "pl.List"))
+(local stringx (require "pl.stringx"))
+(local tablex (require "pl.tablex"))
(local inspect (require :inspect))
(local posix (require :posix))
(local path {
:absolute? (fn [str] (= (str:sub 1 1) "/"))
+ :concat (fn [...] (table.concat [...] "/"))
})
+(local search-path {
+ :concat (fn [...] (table.concat [...] ":"))
+ })
+
(local Gtk lgi.Gtk)
(local GdkPixbuf lgi.GdkPixbuf)
@@ -152,19 +160,52 @@
vals (. parsed "Desktop Entry")]
(when vals.Icon
(tset vals "IconImage" (find-icon vals.Icon)))
+ (tset vals "ID" (f:sub 0 -9))
vals))
+(fn current-user-home []
+ "Returns current user's home directory."
+ (-> (posix.unistd.getuid)
+ (posix.pwd.getpwuid)
+ (. :pw_dir)))
+
+(fn xdg-data-home []
+ "Provides XDG_DATA_HOME or its default fallback value"
+ (local data-home (os.getenv "XDG_DATA_HOME"))
+ (if data-home
+ data-home
+ (path.concat (current-user-home) ".local/share/")))
+
+(fn xdg-data-dirs []
+ "Provides all data-dirs as a List. Most important first."
+ ;; Expected to be used with gmatch as a generator.
+ (let [dirs (List)]
+ (dirs:append (xdg-data-home))
+ (dirs:extend (stringx.split (os.getenv "XDG_DATA_DIRS") ":"))
+ dirs
+ ))
+
(fn all-apps []
+ ;; Each desktop entry representing an application is identified
+ ;; by its desktop file ID, which is based on its filename.
+ ;; — https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id
+ "Provides apps in a List, sorted by name"
(var apps-table {})
- (each [path (string.gmatch (os.getenv "XDG_DATA_DIRS") "[^:]*")]
- (let [apps (.. path "/applications/")]
- (when (lfs.attributes apps)
- (each [f (lfs.dir apps)]
+ ;; Reversing the data dirs gives priority to the first elements.
+ ;; This means conflicting `.desktop` files (or: desktop file ID) are given
+ ;; priority to the first elements by "simply" reading it last.
+ (each [path (List.iter (List.reverse (xdg-data-dirs)))]
+ (let [apps-dir (.. path "/applications/")]
+ (when (lfs.attributes apps-dir)
+ (each [f (lfs.dir apps-dir)]
(when (= (f:sub -8) ".desktop")
- (let [attrs (read-desktop-file (.. apps f))]
+ (let [attrs (read-desktop-file (.. apps-dir f))]
(when (not attrs.NoDisplay)
- (tset apps-table attrs.Name attrs))))))))
- apps-table)
+ (tset apps-table attrs.ID attrs))))))))
+ ;; We have a table indexed by IDs, we don't care about the indexing.
+ ;; Make a List and sort it by name.
+ (List.sort (List (tablex.values apps-table))
+ (fn [a b] (< (string.upper a.Name) (string.upper b.Name)))))
;; Exec entries in desktop files may contain %u %f and other characters
;; in which the launcher is supposed to interpolate filenames/urls etc.
@@ -234,7 +275,7 @@
:homogeneous true
})
scrolled-window (Gtk.ScrolledWindow {})]
- (each [_ app (pairs (all-apps))]
+ (each [app (List.iter (all-apps))]
(grid:insert (button-for app) -1))
(scrolled-window:add grid)
(window:add scrolled-window))