Files
azos/features/lauretta/emacs/config.org
T

13 KiB

Aner's Emacs Lauretta Configuration

Base setup

Require

(require 'azos-emacs-base)
(require 'azos-emacs-dev)
(require 'azos-emacs-editor)
(require 'azos-emacs-exwm)
(require 'azos-emacs-station)

Lauretta specific

LLM

(setq
 gptel-model   'openai/gpt-oss-120b
 gptel-backend
 (gptel-make-openai "Groq"
   :host "api.groq.com"
   :endpoint "/openai/v1/chat/completions"
   :stream t
   :key "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"
   :models '(openai/gpt-oss-120b)))

Agent Shell

(setq agent-shell-opencode-default-model-id "opencode/big-pickle")
;; (setq agent-shell-preferred-agent-config (agent-shell-opencode-make-agent-config))

Headphones

(defun azos/connect-headphones ()
  (interactive)
    (start-process-shell-command "connect-headphones" nil "azos-connect-headphones-whmx4000"))

(define-key azos/global-minor-mode/open-keymap
    (kbd "h") 'azos/connect-headphones)

Tab bar setup

(when (fboundp #'azos/bat/enable-tab-display)
  (azos/bat/enable-tab-display))

(when (fboundp #'azos/network/enable-tab-display)
  (azos/network/enable-tab-display))

(when (fboundp #'azos/audio/enable-tab-display)
  (azos/audio/enable-tab-display))

Nixpkgs Search

(defun azos/nixpkgs-parse-json-lines (str)
  "Parse JSON Lines format (one JSON object per line) from STR."
        (mapcar (lambda (line)
                  (and (not (string-empty-p line))
                       (string-match "^{" line)
                       (condition-case nil
                           (json-parse-string line)
                         (error nil))))
                (split-string (string-trim str) "\n" t)))

(defun azos/nixpkgs-g (key hash)
  "Get KEY from HASH table."
  (when (hash-table-p hash)
    (gethash key hash)))

(defun azos/nixpkgs-search ()
  "Search for a nixpkgs package and show its info."
  (interactive)
  (let* ((pattern (read-string "Search pattern: "))
         (json-output (shell-command-to-string
                       (format "nix-search --json --max-results 50 '%s'" pattern)))
         (results (and json-output
                       (not (string-empty-p json-output))
                       (azos/nixpkgs-parse-json-lines json-output)))
         (packages (delq nil (mapcar (lambda (item)
                                       (let ((pname (azos/nixpkgs-g "package_pname" item)))
                                         (when pname
                                           (cons pname item))))
                                     results))))
    (if packages
        (let* ((selected (completing-read "Package: " (mapcar #'car packages) nil t))
               (package-data (cdr (assoc-string selected packages))))
          (let ((buf (get-buffer-create "*nixpkgs-package-info*")))
            (with-current-buffer buf
              (erase-buffer)
              (if package-data
                  (progn
                    (insert (format "Package: %s\n\n" selected))
                    (insert (format "Version: %s\n" (or (azos/nixpkgs-g "package_pversion" package-data) "unknown")))
                    (insert (format "Attr: %s\n" (or (azos/nixpkgs-g "package_attr_name" package-data) "unknown")))
                    (insert (format "\nDescription: %s\n"
                                   (or (azos/nixpkgs-g "package_description" package-data) "none")))
                    (let ((programs (azos/nixpkgs-g "package_programs" package-data)))
                      (when (vectorp programs)
                        (insert (format "\nPrograms: %s\n"
                                       (mapconcat #'identity (append programs nil) " ")))))
                    (let ((homepage (let ((h (azos/nixpkgs-g "package_homepage" package-data)))
                                      (when (vectorp h) (aref h 0)))))
                      (when homepage
                        (insert (format "\nHomepage: %s\n" homepage))))
                    (let ((licenses (azos/nixpkgs-g "package_license" package-data)))
                      (when (vectorp licenses)
                        (insert (format "\nLicense: %s\n"
                                       (mapconcat (lambda (l)
                                                    (or (azos/nixpkgs-g "fullName" l) ""))
                                                  (append licenses nil) ", ")))))
                (insert (format "Package: %s\n\n" selected)
                        "\nNo additional info available.")))
              (goto-char (point-min)))
            (display-buffer buf)))
      (message "No packages found matching '%s'" pattern))))

(define-key azos/global-minor-mode/open-keymap
    (kbd "n") 'azos/nixpkgs-search)

CalDAV / Org Sync

(require 'org-caldav)

(defvar azos/lauretta/nextcloud-user "aner"
  "Nextcloud username for CalDAV sync.")

(setq org-caldav-url "https://nextcloud.zakobar.com/remote.php/dav/calendars/1ddd03a6-4c2d-103c-9f7b-27b20313341d"
      org-caldav-calendar-id "personal"
      org-caldav-inbox "~/org/caldav-inbox.org"
      org-caldav-files '("~/org/todo.org")
      org-icalendar-timezone "Asia/Jerusalem")

(defun azos/caldav-sync ()
  "Sync org-caldav with Nextcloud calendar, reading password from pass."
  (interactive)
  (let* ((password (string-trim
                    (shell-command-to-string
                     (format "pass zakobar.com/users/%s" azos/lauretta/nextcloud-user))))
         (url-http-real-basic-auth-storage
          (list (list "nextcloud.zakobar.com:443"
                      (cons azos/lauretta/nextcloud-user password)))))
    (org-caldav-sync)))

(define-key azos/global-minor-mode/open-keymap
    (kbd "C") 'azos/caldav-sync)

Beacon Remote Jobs

(defvar azos/beacon/host "aner@192.168.1.200"
  "SSH connection for beacon machine.")

(defvar azos/beacon/max-logs 5
  "Number of most-recent logs to keep per project on beacon.")

(defvar azos/beacon/keymap (make-sparse-keymap)
  "Keymap for beacon remote job commands (M-o b prefix).")

(define-key azos/global-minor-mode/open-keymap (kbd "b") azos/beacon/keymap)

(defun azos/beacon--project-root ()
  (or (and (fboundp 'projectile-project-root) (projectile-project-root))
      (error "Not in a projectile project")))

(defun azos/beacon--project-name (root)
  (file-name-nondirectory (directory-file-name root)))

(defun azos/beacon--list-python-files (root)
  (split-string
   (shell-command-to-string
    (format "cd %s && git ls-files | grep '\\.py$'" (shell-quote-argument root)))
   "\n" t))

(defun azos/beacon--list-executables (root)
  (split-string
   (shell-command-to-string
    (format "cd %s && git ls-files | while IFS= read -r f; do [ -x \"$f\" ] && echo \"$f\"; done"
            (shell-quote-argument root)))
   "\n" t))

(defun azos/beacon--ssh-run (script)
  "Pipe SCRIPT as bash to beacon over SSH stdin. Error on non-zero exit."
  (with-temp-buffer
    (insert script)
    (let ((ret (call-process-region (point-min) (point-max) "ssh" nil t nil
                                    azos/beacon/host "bash")))
      (unless (zerop ret)
        (error "Beacon SSH error (exit %d): %s" ret (string-trim (buffer-string)))))))

(defun azos/beacon--ssh-query (cmd &optional allow-exit-one)
  "Run CMD on beacon, return output string. Error on failure.
With ALLOW-EXIT-ONE, exit code 1 is also treated as success (for tmux ls)."
  (with-temp-buffer
    (let ((ret (call-process "ssh" nil t nil azos/beacon/host cmd)))
      (unless (or (zerop ret) (and allow-exit-one (= ret 1)))
        (error "Beacon SSH error (exit %d): %s" ret (string-trim (buffer-string)))))
    (buffer-string)))

(defun azos/beacon--dispatch (root cmd label)
  "Sync ROOT to beacon and run CMD in project dir under direnv.
LABEL names the tmux session and log file."
  (let* ((project-name (azos/beacon--project-name root))
         (timestamp    (format-time-string "%Y%m%d-%H%M%S"))
         (session      (format "%s-%s-%s" project-name label timestamp))
         (log-name     (format "%s-%s.log" label timestamp)))
    (message "Syncing %s to beacon..." project-name)
    (azos/beacon--ssh-run (format "mkdir -p ~/beacon-projects/%s\n" project-name))
    (with-temp-buffer
      (let ((ret (call-process-shell-command
                  (format "bash -c %s"
                          (shell-quote-argument
                           (format "cd %s && git ls-files | rsync -avz --files-from=- . %s:~/beacon-projects/%s/"
                                   root azos/beacon/host project-name)))
                  nil t nil)))
        (unless (zerop ret)
          (error "Beacon rsync failed (exit %d): %s" ret (string-trim (buffer-string))))))
    (azos/beacon--ssh-run
     (format "RDIR=~/beacon-projects/%s
LDIR=~/beacon-logs/%s
mkdir -p \"$LDIR\"
direnv allow \"$RDIR\"
tmux new-session -d -s %s -- bash -c \"cd $RDIR && direnv exec . %s 2>&1 | tee $LDIR/%s\"
"
             project-name project-name
             (shell-quote-argument session)
             cmd log-name))
    (azos/beacon--ssh-run
     (format "find ~/beacon-logs/%s -name '*.log' -printf '%%T@ %%p\\n' 2>/dev/null | sort -rn | tail -n +%d | cut -d' ' -f2- | xargs -r rm -f\n"
             project-name (1+ azos/beacon/max-logs)))
    (message "Beacon job started: %s" session)))

(defun azos/beacon/run-python ()
  "Sync current project to beacon and run a selected Python file."
  (interactive)
  (let* ((root  (azos/beacon--project-root))
         (files (azos/beacon--list-python-files root))
         (file  (completing-read "Python file: " files nil t))
         (label (file-name-sans-extension (file-name-nondirectory file))))
    (azos/beacon--dispatch root (format "python3 %s" file) label)))

(defun azos/beacon/run-exec ()
  "Sync current project to beacon and run a selected executable."
  (interactive)
  (let* ((root  (azos/beacon--project-root))
         (files (azos/beacon--list-executables root))
         (file  (completing-read "Executable: " files nil t))
         (label (file-name-sans-extension (file-name-nondirectory file))))
    (azos/beacon--dispatch root (format "./%s" file) label)))

(defun azos/beacon/run-command ()
  "Sync current project to beacon and run an arbitrary command."
  (interactive)
  (let* ((root  (azos/beacon--project-root))
         (cmd   (read-string "Command: "))
         (label (replace-regexp-in-string
                 "[^a-zA-Z0-9-]" "-"
                 (substring cmd 0 (min 20 (length cmd))))))
    (azos/beacon--dispatch root cmd label)))

(defun azos/beacon/list-jobs ()
  "Show all running beacon tmux sessions."
  (interactive)
  (async-shell-command
   (format "ssh %s 'tmux ls 2>/dev/null || echo \"No jobs running\"'" azos/beacon/host)
   "*beacon-jobs*"))

(defun azos/beacon/kill-job ()
  "Kill a beacon tmux session selected interactively."
  (interactive)
  (let* ((output   (azos/beacon--ssh-query "tmux ls -F '#S' 2>/dev/null" t))
         (sessions (split-string (string-trim output) "\n" t))
         (session  (completing-read "Kill job: " sessions nil t)))
    (azos/beacon--ssh-run (format "tmux kill-session -t %s\n" (shell-quote-argument session)))
    (message "Killed beacon job: %s" session)))

(defun azos/beacon--tail-path (path)
  (async-shell-command
   (format "ssh %s %s" azos/beacon/host
           (shell-quote-argument (format "tail -f %s" path)))
   (format "*beacon-tail-%s*" (file-name-nondirectory path))))

(defun azos/beacon/tail-log (&optional arg)
  "Tail the most recent beacon log.
With prefix ARG, prompt for a pattern then select from matches."
  (interactive "P")
  (let* ((sorted-output (azos/beacon--ssh-query
                         "find ~/beacon-logs -name '*.log' -printf '%T@ %P\n' 2>/dev/null | sort -rn | cut -d' ' -f2-"))
         (logs (split-string (string-trim sorted-output) "\n" t)))
    (when (null logs) (error "No logs found on beacon"))
    (if (not arg)
        (azos/beacon--tail-path (format "~/beacon-logs/%s" (car logs)))
      (let* ((pattern (read-string "Log pattern: "))
             (matches (seq-filter (lambda (l) (string-match-p pattern l)) logs))
             (log (if (= (length matches) 1)
                      (car matches)
                    (completing-read "Tail log: " matches nil t))))
        (azos/beacon--tail-path (format "~/beacon-logs/%s" log))))))

(define-key azos/beacon/keymap (kbd "p") #'azos/beacon/run-python)
(define-key azos/beacon/keymap (kbd "e") #'azos/beacon/run-exec)
(define-key azos/beacon/keymap (kbd "c") #'azos/beacon/run-command)
(define-key azos/beacon/keymap (kbd "l") #'azos/beacon/list-jobs)
(define-key azos/beacon/keymap (kbd "k") #'azos/beacon/kill-job)
(define-key azos/beacon/keymap (kbd "t") #'azos/beacon/tail-log)

Provide

(provide 'azos-emacs-lauretta)