Files
roam/azosemacs.org
2026-10-14 09:41:44 +03:00

14 lines
4.2 KiB
Org Mode

:PROPERTIES:
:ID: b8094a02-528a-4eeb-a021-4ffc7396f0f3
:END:
#+title: azos/emacs
#+filetags: :project: :knowledge: :emacs:
** Gotchas
- =async-shell-command= spawns subprocesses with =TERM=dumb= and no real controlling tty (confirmed: no =INSIDE_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 when =INSIDE_EMACS= is set, which =async-shell-command= doesn't set (unlike =M-x shell=/comint, which does). Fix: run the command in a real pty via =vterm= instead (confirmed working — =vterm-term-environment-variable= is set to =xterm-256color=). Fixed in =azos/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=/=defvar= forms evaluated at startup (e.g. =mu4e-contexts=) stay stale until that exact top-level form is re-evaluated, e.g. via =emacsclient -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 [[id:da416dd3-d7bb-4a81-83fb-a5543817b462][azos/mail]] Gotchas for the full incident.
- =org-babel= =emacs-lisp= source blocks evaluate with *dynamic* binding by default (=ob-emacs-lisp.el= defaults =:lexical= to ="no"=), and =config.org= sets no =:lexical= header 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-bound =output= unwinds 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 stays =nil=. This hit the elfeed-protocol Nextcloud News auth block (fetches a =pass(1)= password asynchronously via =make-process= to avoid blocking Emacs's command loop and deadlocking with pinentry-emacs, then sets =elfeed-feeds= from the sentinel) — =elfeed-update= appeared 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 over =let=-bound locals unless the block explicitly sets =:lexical yes=. Instead store state on the process object itself via =process-put=/=process-get= (works regardless of lexical/dynamic binding) — this is the pattern now used in the elfeed-protocol block. Fixed in =features/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='s =packages.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 in =emacs-packages-deps= and the stale one can shadow ours on the load-path. After the Emacs 30.2 → 31.1 bump (2026-10-13) this gave =void-variable evil-local-mode--set-explicitly= on every command: old .elc top-level forms (hook adds old =evil-local-mode-set-explicitly=, no new defvar) mixed with JIT native-comp swapping in 31-macro function bodies that reference the new =--set-explicitly= var. Fix/convention: build such inputs against our own =pkgs.emacs.pkgs= (never take their =packages.default=). =evil-hl-line= upstream now exposes =lib.mkEvilHlLine epkgs= and =overlays.default= for this; azos-core uses =lib.mkEvilHlLine pkgs.emacs.pkgs= in =suites/base/emacs/default.nix=. Diagnose with =find -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.
[[id:bf4dde56-0967-4374-94ed-771301e47c66][azos]]