commit 31da3d0eb44fdab82e620d1cbdd35f31e8f1ee7f from: mtmn date: Thu Sep 17 22:58:40 2026 UTC cleanup commit - 2da793de0cd4883ac80a6ddb70d38e5392c2bda3 commit + 31da3d0eb44fdab82e620d1cbdd35f31e8f1ee7f blob - 7cc2a636f4b5d7ffb0f386885857845f94ef092a blob + 90746acf5ebc4767db1eb0802376063676ab79d4 --- hosts/bbox/overlays/config/magdalena/config.json.nix +++ hosts/bbox/overlays/config/magdalena/config.json.nix @@ -19,16 +19,6 @@ ".qwen", "saturn" ], - "fzf_opts": [ - "--highlight-line", - "--ansi", - "--layout=reverse", - "--border=rounded", - "--color=bg+:#2a1f2e,bg:-1,spinner:#c084b8,hl:#e08060", - "--color=fg:#c8b8bf,header:#c4607a,info:#7a6e7a,pointer:#c084b8", - "--color=marker:#e06fad,fg+:#f0dfe5,prompt:#7a9fd4,hl+:#f0a070", - "--color=border:#3d2a42" - ], "favorites": [ "${homeDir}/src", "${homeDir}/src/nix", blob - 15a61f61e7aab80997730b2704c127fe08cd7620 blob + 8b2cb2bdfe4df1507f10c19ef239df7fed214a43 --- hosts/impish/default.nix +++ hosts/impish/default.nix @@ -169,11 +169,8 @@ skopeo podman sccache - podlet buildah meson - butane - redo-sh knit go-task goreleaser @@ -221,15 +218,15 @@ xorriso jsonnet-bundler minisign + zf + gitleaks ]; lsp = [ gopls nixd zls - clojure-lsp ols - npins jsonnet-language-server ]; @@ -239,18 +236,9 @@ golangci-lint ]; - clojure = [ - babashka - clojure - clj-kondo - cljstyle - leiningen - ]; - lisp = [ haunt gnu-shepherd - gerbil chez ecl janet @@ -262,14 +250,6 @@ [fnlfmt] ]; - llm = [ - rtk - snip - gitingest - pi-coding-agent - ollama - ]; - gui = [ picard xnviewmp @@ -284,6 +264,9 @@ emscripten astroterm odin + npins + snip + pi-coding-agent ]; })); }; blob - 07ee7dd6e21834358ba81debb480c57da009916f blob + 2bca5dbc27fdb99394b361fece0f0ee2b124c29b Binary files hosts/void/overlays/config/magdalena/config.json.nix and hosts/void/overlays/config/magdalena/config.json.nix differ blob - 50a5ff03186b05831c1fcde13ea4b77f3a76c903 blob + 09e3303f75f18379849625ab4451acad2d24d43a Binary files hosts/work/overlays/config/magdalena/config.json.nix and hosts/work/overlays/config/magdalena/config.json.nix differ blob - 7e34237f3d17734f4f705bfe127f10277491cc9b (mode 644) blob + 1798d1212ece7f107439e6fbc2ff249861524b15 (mode 755) --- modules/mixins/dotfiles/bin/khal_notifier +++ modules/mixins/dotfiles/bin/khal_notifier @@ -1,204 +1,226 @@ -#!/usr/bin/env bb -;; vim: ft=clojure +#!/usr/bin/env janet -(ns khal-notifier - (:require [clojure.edn :as edn] - [clojure.string :as str] - [babashka.process :refer [shell]] - [babashka.fs :as fs])) +(defn blank? [s] + (or (nil? s) (= "" s))) -(defn all-day? [event] - (and (str/blank? (:start-time event)) - (str/blank? (:end-time event)))) +(defn path-join [parts] + (string/join parts "/")) -(defn state-file [] - (or (System/getenv "KHAL_NOTIFIER_STATE_FILE") - (str (fs/path (or (System/getenv "XDG_CACHE_HOME") - (fs/path (System/getProperty "user.home") ".cache")) - "khal_notifier" "notified-all-day.edn")))) +(defn dir-of [path] + (let [parts (string/split "/" path)] + (if (<= (length parts) 1) + "." + (path-join (slice parts 0 -2))))) -(defn read-notified-all-day [] - (try - (let [state (edn/read-string (slurp (state-file)))] - (if (set? state) state #{})) - (catch Exception _ #{}))) - -(defn write-notified-all-day [events] - (let [path (state-file)] +(defn mkdir-p [path] + (when (and (not (blank? path)) (nil? (os/stat path))) + (let [parent (dir-of path)] + (when (and (not (= parent path)) (not (= parent ".")) (not (blank? parent))) + (mkdir-p parent))) (try - (fs/create-dirs (fs/parent path)) - (spit path (pr-str events)) - true - (catch Exception e - (println (format "[WARN] Could not save all-day notification state: %s" - (ex-message e))) - false)))) + (do (os/mkdir path) true) + ([e] false)))) +(defn state-file [] + (or (os/getenv "KHAL_NOTIFIER_STATE_FILE") + (path-join [(or (os/getenv "XDG_CACHE_HOME") + (path-join [(or (os/getenv "HOME") "/tmp") ".cache"])) + "khal_notifier" + "notified-all-day.txt"]))) + +(defn read-notified [] + (try + (do + (def table @{}) + (each line (string/split "\n" (slurp (state-file))) + (when (not (blank? line)) + (put table line true))) + table) + ([e] @{}))) + +(defn write-notified [table] + (try + (do + (mkdir-p (dir-of (state-file))) + (spit (state-file) (string/join (keys table) "\n")) + true) + ([e] + (printf "WARN: Could not save all-day notification state: %s" e) + false))) + (defn event-key [event] - [(:start-date event) - (if (str/blank? (:uid event)) - [(:title event) (:organizer event)] - (:uid event))]) + (string/join + [(or (event :start-date) "") + (let [uid (or (event :uid) "")] + (if (blank? uid) + (string/join [(or (event :title) "") (or (event :organizer) "")] "::") + uid))] + "|")) -(defn run-cmd [cmd args & {:keys [timeout] :or {timeout 30000}}] +(defn run-cmd [cmd & args] (try - (if-not (fs/which cmd) - {:status :error :reason :enoent} - (let [result (apply shell {:out :string :err :string :timeout timeout} cmd args)] - {:status :ok :out (:out result) :code (:exit result)})) - (catch java.util.concurrent.TimeoutException _ - {:status :error :reason :timeout}) - (catch Exception e - {:status :error :reason e}))) + (do + (file/flush stdout) + (def proc (os/spawn [cmd ;args] :p {:out :pipe :err :out})) + (def out (or (ev/read (proc :out) :all) "")) + (def code (os/proc-wait proc)) + (os/proc-close proc) + {:status :ok :out (string out) :code code}) + ([e] {:status :error :reason e}))) +(defn cmd-ok? [result] + (and (= (result :status) :ok) (zero? (result :code)))) + (defn sync-pimsync [] - (println "[INFO] Syncing calendars with pimsync") - (let [result (run-cmd "pimsync" ["sync"] :timeout 60000)] - (cond - (and (= :ok (:status result)) (zero? (:code result))) - (do (println "[INFO] pimsync sync complete") true) + (print "INFO: Syncing calendars with pimsync") + (def result (run-cmd "pimsync" "sync")) + (cond + (cmd-ok? result) + (do (print "INFO: pimsync sync complete") true) - (= :ok (:status result)) - (do (println (format "[WARN] pimsync exited with code %d: %s" - (:code result) (str/trim (or (:out result) "")))) - false) + (= (result :status) :ok) + (do + (printf "WARN: pimsync exited with code %d: %s" + (result :code) (string/trim (or (result :out) ""))) + false) - (= :enoent (:reason result)) (do (println "[ERROR] pimsync not found") false) - (= :timeout (:reason result)) (do (println "[ERROR] pimsync timed out") false) - :else (do (println (format "[ERROR] pimsync failed: %s" (ex-message (:reason result)))) - false)))) + (do + (printf "ERROR: pimsync failed: %s" (result :reason)) + false))) (defn parse-event-line [line] - (let [parts (str/split line #"\|" 6) - cnt (count parts)] + (let [parts (string/split "|" line) + cnt (length parts) + at (fn [i] (or (get parts i) ""))] (case cnt - 6 {:start-date (nth parts 0) :start-time (nth parts 1) - :end-time (nth parts 2) :uid (nth parts 3) - :title (nth parts 4) :organizer (nth parts 5)} - 4 {:start-time (nth parts 0) :end-time (nth parts 1) - :title (nth parts 2) :organizer (nth parts 3)} - 3 {:start-time (nth parts 0) :end-time (nth parts 1) - :title (nth parts 2) :organizer ""} - 2 {:start-time (nth parts 0) :end-time "" - :title (nth parts 1) :organizer ""} - {:start-time "" :end-time "" :title (nth parts 0) :organizer ""}))) + 6 {:start-date (at 0) :start-time (at 1) :end-time (at 2) + :uid (at 3) :title (at 4) :organizer (at 5)} + 4 {:start-date "" :start-time (at 0) :end-time (at 1) + :uid "" :title (at 2) :organizer (at 3)} + 3 {:start-date "" :start-time (at 0) :end-time (at 1) + :uid "" :title (at 2) :organizer ""} + 2 {:start-date "" :start-time (at 0) :end-time "" + :uid "" :title (at 1) :organizer ""} + {:start-date "" :start-time "" :end-time "" + :uid "" :title (or (get parts 0) "") :organizer ""}))) (defn get-upcoming-events [lookahead] - (println (format "[INFO] Checking khal for events in the next %s" lookahead)) - (let [result (run-cmd "khal" ["list" "now" lookahead "--format" - (str "{start-date}|{start-time}|{end-time}|" - "{uid}|{title}|{organizer}")])] - (cond - (and (= :ok (:status result)) (zero? (:code result))) - (let [events (->> (:out result) - str/split-lines - (map str/trim) - (remove str/blank?) - (filter #(str/includes? % "|")) - (map parse-event-line) - (remove #(str/blank? (:title %))) - vec)] - (println (format "[INFO] Found %d upcoming event(s)" (count events))) - events) + (printf "INFO: Checking khal for events in the next %s" lookahead) + (def format-str "{start-date}|{start-time}|{end-time}|{uid}|{title}|{organizer}") + (def result (run-cmd "khal" "list" "now" lookahead "--format" format-str)) + (cond + (cmd-ok? result) + (do + (def lines (string/split "\n" (or (result :out) ""))) + (def events + (filter + (fn [e] (not (blank? (e :title)))) + (map parse-event-line + (filter + (fn [l] (and (not (blank? (string/trim l))) (string/find "|" l))) + lines)))) + (printf "INFO: Found %d upcoming event(s)" (length events)) + events) - (= :ok (:status result)) - (do (println (format "[WARN] khal exited with code %d: %s" - (:code result) (str/trim (or (:out result) "")))) - []) + (= (result :status) :ok) + (do + (printf "WARN: khal exited with code %d: %s" + (result :code) (string/trim (or (result :out) ""))) + []) - (= :enoent (:reason result)) (do (println "[ERROR] khal not found") []) - (= :timeout (:reason result)) (do (println "[ERROR] khal timed out") []) - :else (do (println "[ERROR] khal execution failed") [])))) + (do (print "ERROR: khal execution failed") []))) -(defn now-time [] - (-> (shell {:out :string} "date" "+%H:%M") :out str/trim)) +(defn now-hhmm [] + (let [d (os/date nil true)] + (string/format "%02d:%02d" (d :hours) (d :minutes)))) (defn event-started? [start end now] (cond - (str/blank? start) false - (str/blank? end) (<= (compare start now) 0) + (blank? start) false + (blank? end) (<= (compare start now) 0) (<= (compare start end) 0) (<= (compare start now) 0) - :else (or (<= (compare start now) 0) (<= (compare now end) 0)))) + (or (<= (compare start now) 0) (<= (compare now end) 0)))) -(defn filter-events [events] - (let [now (now-time)] - (remove #(event-started? (:start-time %) (:end-time %) now) events))) +(defn all-day? [event] + (and (blank? (event :start-time)) (blank? (event :end-time)))) (defn format-event [event] - (let [time-str (cond + (let [start (or (event :start-time) "") + end (or (event :end-time) "") + org (or (event :organizer) "") + time-str (cond (all-day? event) "All day" - (str/blank? (:end-time event)) (:start-time event) - :else (str (:start-time event) " - " (:end-time event)))] - (if (str/blank? (:organizer event)) + (blank? end) start + (string start " - " end))] + (if (blank? org) time-str - (str time-str "\nOrganizer: " (:organizer event))))) + (string time-str "\nOrganizer: " org)))) (defn send-notification [summary body] - (println (format "[INFO] Notifying: %s — %s" summary body)) - (let [result (run-cmd "notify-send" - ["--app-name" "khal_notifier" - "--urgency" "critical" - summary body])] - (cond - (and (= :ok (:status result)) (zero? (:code result))) true - (= :ok (:status result)) - (do (println (format "[ERROR] notify-send failed (code %d): %s" - (:code result) (str/trim (or (:out result) "")))) - false) - (= :enoent (:reason result)) (do (println "[ERROR] notify-send not found") false) - :else (do (println "[ERROR] notify-send failed") false)))) + (printf "INFO: Notifying: %s - %s" summary body) + (def result (run-cmd "notify-send" "--app-name" "khal_notifier" + "--urgency" "critical" summary body)) + (if (cmd-ok? result) + true + (do + (if (= (result :status) :ok) + (printf "ERROR: notify-send failed (code %d): %s" + (result :code) (string/trim (or (result :out) ""))) + (print "ERROR: notify-send failed")) + false))) (defn notify-events [events] - (loop [remaining events - notified (read-notified-all-day)] - (when-let [event (first remaining)] - (let [key (event-key event)] - (if (and (all-day? event) (contains? notified key)) - (do - (println (format "[INFO] Already notified: %s — All day" (:title event))) - (recur (rest remaining) notified)) - (let [sent? (send-notification (:title event) (format-event event)) - newly-notified (if (and sent? (all-day? event)) - (conj notified key) - notified)] - (when (not= notified newly-notified) - (write-notified-all-day newly-notified)) - (recur (rest remaining) newly-notified))))))) + (var notified (read-notified)) + (var dirty false) + (each event events + (let [key (event-key event) + seen (not (nil? (get notified key)))] + (if (and (all-day? event) seen) + (printf "INFO: Already notified: %s - All day" (event :title)) + (when (send-notification (event :title) (format-event event)) + (when (all-day? event) + (put notified key true) + (set dirty true)))))) + (when dirty + (write-notified notified))) (defn run-once [lookahead skip-sync] - (when-not skip-sync - (when-not (sync-pimsync) - (println "[WARN] Sync failed — continuing with local calendar data"))) - (let [events (get-upcoming-events lookahead) - filtered (filter-events events)] + (unless skip-sync + (unless (sync-pimsync) + (print "WARN: Sync failed - continuing with local calendar data"))) + (let [filtered (filter + (fn [e] (not (event-started? (e :start-time) (e :end-time) (now-hhmm)))) + (get-upcoming-events lookahead))] (if (empty? filtered) - (println "[INFO] No upcoming events") + (print "INFO: No upcoming events") (notify-events filtered)))) (defn parse-opts [args] - (loop [remaining args - opts {:lookahead "60m" :skip-sync false :help false}] - (if (empty? remaining) - opts - (let [arg (first remaining)] - (cond - (= arg "--help") (recur (rest remaining) (assoc opts :help true)) - (= arg "--skip-sync") (recur (rest remaining) (assoc opts :skip-sync true)) - (= arg "--lookahead") (recur (drop 2 remaining) (assoc opts :lookahead (second remaining))) - :else (recur (rest remaining) opts)))))) + (var lookahead "60m") + (var skip-sync false) + (var help false) + (var i 0) + (while (< i (length args)) + (let [arg (get args i)] + (cond + (= arg "--help") (set help true) + (= arg "--skip-sync") (set skip-sync true) + (= arg "--lookahead") + (do + (def val (get args (+ i 1))) + (if (nil? val) + (do (print "ERROR: --lookahead needs a value") (os/exit 2)) + (set lookahead val)) + (++ i)))) + (++ i)) + {:lookahead lookahead :skip-sync skip-sync :help help}) (defn print-usage [] - (println "Usage: khal_notifier [options]") - (println) - (println "Options:") - (println " --lookahead TIME How far ahead to check (default: 60m)") - (println " --skip-sync Skip pimsync sync") - (println " --help Show this help")) + (print "Usage: khal_notifier [options]\n\nOptions:\n --lookahead TIME How far ahead to check (default: 60m)\n --skip-sync Skip pimsync sync\n --help Show this help")) -(defn -main [& args] - (let [{:keys [lookahead skip-sync help]} (parse-opts args)] +(defn main [& raw-args] + (let [{:lookahead lookahead :skip-sync skip-sync :help help} + (parse-opts (slice raw-args 1))] (if help - (do (print-usage) (System/exit 0)) + (do (print-usage) (os/exit 0)) (run-once lookahead skip-sync)))) - -(apply -main *command-line-args*) blob - f7e89e6ed912be88257ad76d868a013c8adad5f3 blob + 42f6412011bd44cbec1df9bd99ac1c525abbbf04 --- modules/mixins/dotfiles/bin/plsmenu +++ modules/mixins/dotfiles/bin/plsmenu @@ -32,9 +32,9 @@ else fi if eval "$("$HOME/bin/amen")" && zsh -c "mpd_add_to_playlist '$playlist'"; then - notify-send -u normal "mpd" "saved a track to $playlist" + notify-send -u normal "mpd" "saved to $playlist" exit 0 else - notify-send -u critical "mpd" "could not save a track" + notify-send -u critical "mpd" "could not save to $playlist" exit 1 fi blob - c1c7580dd8ed8400cef4b0c20b0c254efd88a086 blob + 21edcbdf3e421e6a2c8e818a3b971b6366373d31 --- modules/mixins/dotfiles/config/magdalena/config.json.nix +++ modules/mixins/dotfiles/config/magdalena/config.json.nix @@ -16,16 +16,6 @@ ".nix-data", "saturn" ], - "fzf_opts": [ - "--highlight-line", - "--ansi", - "--layout=reverse", - "--border=rounded", - "--color=bg+:#222222,bg:#101010,spinner:#8a8a8a,hl:#d2d2d2", - "--color=fg:#999999,header:#a2a2a2,info:#5e5e5e,pointer:#999999", - "--color=marker:#999999,fg+:#999999,prompt:#999999,hl+:#999999", - "--color=border:#353535" - ], "fav_dirs": [ "${homeDir}/src", "${homeDir}/src/misc",