about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@tvl.su>2023-08-29T12·43+0300
committerclbot <clbot@tvl.fyi>2023-08-29T14·07+0000
commite5f7fe430d582c96b911b79dad03fad7c2d6aa9e (patch)
tree16528afb6d7aabedac82244ef8f3556ed23f13c9
parentd6bce3f83d2c1052c38ecba1445bbc10a9f03123 (diff)
refactor(tazjin/gio-list-apps): refactor into dynamic Emacs module r/6534
Instead of producing a binary that gets called by Emacs, with
input/output serialisation, use a dynamic Emacs module that lets Emacs
more-or-less directly call the relevant GTK functions.

I'm doing this mostly as an experiment. Might be interesting to end up
with a dynamic module that I can dump some experimental code into that
improves my workflows.

To do this, I've exposed the emacs binary used by my Emacs
configuration in an additional `passthru` field. This ensures that the
module is linked against the right version of Emacs.

Change-Id: I1426994fe3455ed1b2a685c5a09705e29fa40950
Reviewed-on: https://cl.tvl.fyi/c/depot/+/9163
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
Autosubmit: tazjin <tazjin@tvl.su>
-rw-r--r--users/tazjin/emacs/config/functions.el9
-rw-r--r--users/tazjin/emacs/default.nix10
-rw-r--r--users/tazjin/gio-list-apps/Cargo.lock146
-rw-r--r--users/tazjin/gio-list-apps/Cargo.toml5
-rw-r--r--users/tazjin/gio-list-apps/default.nix9
-rw-r--r--users/tazjin/gio-list-apps/src/lib.rs31
-rw-r--r--users/tazjin/gio-list-apps/src/main.rs20
7 files changed, 178 insertions, 52 deletions
diff --git a/users/tazjin/emacs/config/functions.el b/users/tazjin/emacs/config/functions.el
index df36c7eb882c..3739d25122ef 100644
--- a/users/tazjin/emacs/config/functions.el
+++ b/users/tazjin/emacs/config/functions.el
@@ -2,6 +2,8 @@
 (require 'dash)
 (require 'map)
 
+(require 'gio-list-apps) ;; native module!
+
 (defun goto-line-with-feedback ()
   "Show line numbers temporarily, while prompting for the line number input"
   (interactive)
@@ -336,12 +338,7 @@ names, instead of only their names (which might change)."
   "Use `//users/tazjin/gio-list-apps' to retrieve a list of
 installed (and visible) XDG apps, and let users launch them."
   (interactive)
-  (let* ((apps-json (s-lines (s-trim (shell-command-to-string "gio-list-apps"))))
-         (apps (seq-map (lambda (app)
-                          (let ((parsed (json-parse-string app :object-type 'alist)))
-                            (cons (cdr (assoc 'name parsed))
-                                  (cdr (assoc 'commandline parsed)))))
-                        apps-json))
+  (let* ((apps (taz-list-xdg-apps))
 
          ;; Display the command that will be run as an annotation
          (completion-extra-properties
diff --git a/users/tazjin/emacs/default.nix b/users/tazjin/emacs/default.nix
index e9acf57da1dc..022d78ff4b85 100644
--- a/users/tazjin/emacs/default.nix
+++ b/users/tazjin/emacs/default.nix
@@ -13,7 +13,6 @@ pkgs.makeOverridable
 
     # $PATH for binaries that need to be available to Emacs
     emacsBinPath = lib.makeBinPath [
-      depot.users.tazjin.gio-list-apps
       (currentTelega pkgs.emacsPackages)
       pkgs.libwebp # for dwebp, required by telega
     ];
@@ -100,6 +99,9 @@ pkgs.makeOverridable
       tvlPackages.rcirc
       tvlPackages.term-switcher
       tvlPackages.tvl
+
+      # Dynamic/native modules
+      depot.users.tazjin.gio-list-apps
     ])));
 
     # Tired of telega.el runtime breakages through tdlib
@@ -138,6 +140,12 @@ pkgs.makeOverridable
     '').overrideAttrs
       (_: {
         passthru = {
+          # Expose original Emacs used for my configuration.
+          inherit emacs;
+
+          # Expose the pure emacs with all packages.
+          emacsWithPackages = tazjinsEmacs f;
+
           # Call overrideEmacs with a function (pkgs -> pkgs) to modify the
           # packages that should be included in this Emacs distribution.
           overrideEmacs = f': self l f';
diff --git a/users/tazjin/gio-list-apps/Cargo.lock b/users/tazjin/gio-list-apps/Cargo.lock
index f35779556603..b475b35a6cba 100644
--- a/users/tazjin/gio-list-apps/Cargo.lock
+++ b/users/tazjin/gio-list-apps/Cargo.lock
@@ -3,6 +3,12 @@
 version = 3
 
 [[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
+[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -25,12 +31,96 @@ dependencies = [
 ]
 
 [[package]]
+name = "ctor"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "emacs"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6797a940189d353de79bec32abe717aeeecd79a08236e84404c888354e040665"
+dependencies = [
+ "anyhow",
+ "ctor",
+ "emacs-macros",
+ "emacs_module",
+ "once_cell",
+ "rustc_version",
+ "thiserror",
+]
+
+[[package]]
+name = "emacs-macros"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69656fdfe7c2608b87164964db848b5c3795de7302e3130cce7131552c6be161"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "emacs_module"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3067bc974045ed2c6db333bd4fc30d3bdaafa6421a9a889fa7b2826b6f7f2fa"
+
+[[package]]
 name = "equivalent"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
 name = "futures-channel"
 version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -116,8 +206,8 @@ dependencies = [
 name = "gio-list-apps"
 version = "0.1.0"
 dependencies = [
+ "emacs",
  "gio",
- "serde_json",
 ]
 
 [[package]]
@@ -204,6 +294,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
 name = "indexmap"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -214,12 +310,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "itoa"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
-
-[[package]]
 name = "libc"
 version = "0.2.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -308,10 +398,28 @@ dependencies = [
 ]
 
 [[package]]
-name = "ryu"
-version = "1.0.15"
+name = "rustc_version"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
@@ -334,17 +442,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "serde_json"
-version = "1.0.105"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
 name = "serde_spanned"
 version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -369,12 +466,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
 
 [[package]]
+name = "strsim"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
+
+[[package]]
 name = "syn"
 version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
 dependencies = [
  "proc-macro2",
+ "quote",
  "unicode-ident",
 ]
 
diff --git a/users/tazjin/gio-list-apps/Cargo.toml b/users/tazjin/gio-list-apps/Cargo.toml
index f08260b9880b..eb62d1fcaf42 100644
--- a/users/tazjin/gio-list-apps/Cargo.toml
+++ b/users/tazjin/gio-list-apps/Cargo.toml
@@ -3,8 +3,9 @@ name = "gio-list-apps"
 version = "0.1.0"
 edition = "2021"
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[lib]
+crate-type = ["cdylib"]
 
 [dependencies]
+emacs = "0.18.0"
 gio = "0.18.1"
-serde_json = "1.0.105"
diff --git a/users/tazjin/gio-list-apps/default.nix b/users/tazjin/gio-list-apps/default.nix
index 200bf435420d..c63f4dd48786 100644
--- a/users/tazjin/gio-list-apps/default.nix
+++ b/users/tazjin/gio-list-apps/default.nix
@@ -1,9 +1,14 @@
-{ pkgs, lib, ... }:
+{ depot, pkgs, lib, ... }:
 
 pkgs.rustPlatform.buildRustPackage {
   name = "gio-list-apps";
   src = lib.cleanSource ./.;
   cargoLock.lockFile = ./Cargo.lock;
   nativeBuildInputs = [ pkgs.pkg-config ];
-  buildInputs = [ pkgs.gtk3 ];
+  buildInputs = [ pkgs.gtk3 depot.users.tazjin.emacs.emacs ];
+
+  postInstall = ''
+    mkdir -p $out/share/emacs/site-lisp
+    ln -s $out/lib/libgio_list_apps.so $out/share/emacs/site-lisp/gio-list-apps.so
+  '';
 }
diff --git a/users/tazjin/gio-list-apps/src/lib.rs b/users/tazjin/gio-list-apps/src/lib.rs
new file mode 100644
index 000000000000..55eb8dc0be20
--- /dev/null
+++ b/users/tazjin/gio-list-apps/src/lib.rs
@@ -0,0 +1,31 @@
+use emacs::{defun, Env, IntoLisp, Result, Value};
+use gio::traits::AppInfoExt;
+use gio::AppInfo;
+
+emacs::plugin_is_GPL_compatible!();
+
+#[emacs::module(defun_prefix = "taz", mod_in_name = false)]
+fn init(_: &Env) -> Result<()> {
+    Ok(())
+}
+
+/// Returns an alist of the currently available XDG applications (through their
+/// `.desktop' shortcuts), and the command line parameters needed to start them.
+///
+/// Hidden applications or applications without specified command-line
+/// parameters are not included.
+#[defun]
+fn list_xdg_apps(env: &Env) -> Result<Value> {
+    let mut visible_apps: Vec<Value> = vec![];
+
+    for app in AppInfo::all().into_iter().filter(AppInfo::should_show) {
+        if let Some(cmd) = app
+            .commandline()
+            .and_then(|p| Some(p.to_str()?.to_string()))
+        {
+            visible_apps.push(env.cons(app.name().as_str().into_lisp(env)?, cmd.into_lisp(env)?)?);
+        }
+    }
+
+    env.list(&visible_apps)
+}
diff --git a/users/tazjin/gio-list-apps/src/main.rs b/users/tazjin/gio-list-apps/src/main.rs
deleted file mode 100644
index c6b6b98d4d9c..000000000000
--- a/users/tazjin/gio-list-apps/src/main.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use gio::traits::AppInfoExt;
-use gio::AppInfo;
-use serde_json::json;
-
-fn main() {
-    for app in AppInfo::all() {
-        if app.should_show() {
-            if let Some(cmd) = app.commandline() {
-                println!(
-                    "{}",
-                    json!({
-                        "name": app.name().as_str(),
-                        "display_name": app.display_name().as_str(),
-                        "commandline": cmd,
-                    })
-                );
-            }
-        }
-    }
-}