4.2 KiB
4.2 KiB
azos/emacs
Gotchas
async-shell-commandspawns subprocesses withTERM=dumband no real controlling tty (confirmed: noINSIDE_EMACS, pty exists but curses can't use it). Any gpg/pinentry prompt triggered from such a process (e.g. signed git commits) fails with "Inappropriate ioctl for device" once the pinentry PIN cache expires — pinentry-emacs mode silently isn't engaged either, since gpg only requests it whenINSIDE_EMACSis set, whichasync-shell-commanddoesn't set (unlikeM-x shell=/comint, which does). Fix: run the command in a real pty via =vterminstead (confirmed working —vterm-term-environment-variableis set toxterm-256color). Fixed inazos/roam/backup(features/lauretta/emacs/config.org) 2026-10-04.- A nix rebuild (
azos-lauretta-update) only regenerates files on disk (e.g.config.org) — it never reloads anything into an already-running Emacs session.setq=/=defvarforms evaluated at startup (e.g.mu4e-contexts) stay stale until that exact top-level form is re-evaluated, e.g. viaemacsclient -e '(load-file "/tmp/x.el")'on a file containing just that extracted sexp (match parens exactly — an off-by-one line range truncates the form and errors "End of file during parsing" instead of warning about staleness). Discovered via mu4e context drift, see azos/mail Gotchas for the full incident. org-babelemacs-lispsource blocks evaluate with dynamic binding by default (ob-emacs-lisp.eldefaults:lexicalto"no"), andconfig.orgsets no:lexicalheader anywhere (file-wide or per-block). This silently breaks closures in async code: a pattern like(let ((output "")) (make-process :filter (lambda (_p chunk) (setq output ...)) :sentinel (lambda (_p _e) ... output ...)))fails because the let-boundoutputunwinds before the async filter/sentinel callbacks run — they don't lexically close over it. The failure is silent: errors like "Symbol's value as variable is void: output" only appear in*Messages*, not as visible UI errors, and whatever the sentinel was supposed to set (e.g.elfeed-feeds) just staysnil. This hit the elfeed-protocol Nextcloud News auth block (fetches apass(1)password asynchronously viamake-processto avoid blocking Emacs's command loop and deadlocking with pinentry-emacs, then setselfeed-feedsfrom the sentinel) —elfeed-updateappeared to "do nothing" because of this exact bug. Fix/convention: for any async Emacs Lisp in this repo's org-babel blocks (process filters/sentinels, timers, callbacks) that needs to carry state across the async boundary, don't rely on closures overlet-bound locals unless the block explicitly sets:lexical yes. Instead store state on the process object itself viaprocess-put=/=process-get(works regardless of lexical/dynamic binding) — this is the pattern now used in the elfeed-protocol block. Fixed infeatures/lauretta/emacs/config.org(Elfeed Nextcloud News Sync section) 2026-10-05.- Flake inputs that ship a prebuilt Emacs package (e.g.
evil-hl-line'spackages.default) are built against the input's own pinned nixpkgs, so they propagate deps (evil) byte-compiled by a different Emacs version. Both copies end up inemacs-packages-depsand the stale one can shadow ours on the load-path. After the Emacs 30.2 → 31.1 bump (2026-10-13) this gavevoid-variable evil-local-mode--set-explicitlyon every command: old .elc top-level forms (hook adds oldevil-local-mode-set-explicitly, no new defvar) mixed with JIT native-comp swapping in 31-macro function bodies that reference the new--set-explicitlyvar. Fix/convention: build such inputs against our ownpkgs.emacs.pkgs(never take theirpackages.default).evil-hl-lineupstream now exposeslib.mkEvilHlLine epkgsandoverlays.defaultfor this; azos-core useslib.mkEvilHlLine pkgs.emacs.pkgsinsuites/base/emacs/default.nix. Diagnose withfind -L <emacs-packages-deps>/share/emacs/site-lisp/elpa -name '*.elc' | xargs sed -s -n 3p | sort | uniq -c— any mixed "in Emacs version" values means a foreign package set leaked in.