Emacs Settings

This page lists the Emacs variables you can change to adjust how Emanix behaves, with their defaults. It is for someone who has a consuming flake and wants a different status-bar rhythm, font or buffer group without patching the distribution.

These are Emacs variables, not Nix options. For the emanix.* options, see Options.

1. Where to set them

Emacs loads ~/.config/emacs/personal.el last, after the distribution's config.el, so a setting there overrides the default. Your consuming flake writes that file through Home Manager. A missing file is ignored. An error in it is logged and never stops the desktop from starting.

;; ~/.config/emacs/personal.el
(setq emanix/modeline-threshold 50)
(setq emanix-prose-width 100)

Each variable below is one of two kinds, and the kind decides how you set it:

  • A defcustom has a type and works with setq, with M-x customize-variable and with .dir-locals.el.
  • A defvar is a plain variable. Use setq, or add-to-list for a list. customize does not know it.

Know when a variable is read. Some are read on every use and take effect at once. Others are read once, when a mode turns on, and need a restart of that mode. The tables say which.

2. Status bar

EWM has no status bar, so Emacs draws one in the tab bar: volume, wifi, cpu, ram, gpu, any segments you add, the clock and the battery. Everything but volume reads /sys or /proc, so nothing forks at the render rate.

Variable Default Kind Meaning
emanix/modeline-interval 3 defcustom, integer Seconds between refreshes of the bar. Every segment this timer drives reads sysfs or procfs; do not put a subprocess on it
emanix/modeline-probe-interval 15 defcustom, integer Seconds between volume probes. Volume is the one segment that needs a subprocess (wpctl), and under EWM each subprocess also costs an activation token and a journal line. It changes only when you turn a knob, so it polls on its own slow timer
emanix/modeline-threshold 25 defcustom, integer The cpu, ram and gpu segments appear only while their value is above this percent
emanix/modeline-battery-hide-capacity 99 defcustom, integer The battery segment is hidden at or above this capacity when the battery is neither charging nor discharging. While it charges or discharges, it always shows
emanix/modeline-extra-segments nil defcustom, list of functions The consumer extension point. Each function takes no arguments and returns a string, or nil to show nothing. Segments draw after gpu and before the clock, so the clock and the battery stay at the right-hand end

The two intervals are read when the mode turns on. emanix/modeline-mode is already on when personal.el loads, so a setq of either interval changes nothing until you restart the mode:

(setq emanix/modeline-interval 5)
(emanix/modeline-mode -1)
(emanix/modeline-mode 1)

The threshold, the battery capacity and the segment list are read at every refresh and take effect on the next one.

Register a segment with add-to-list, not by advising the renderer. The renderer, emanix/modeline--render, is private and moves. A check in the distribution holds the extension point stable:

(defun my/load-segment ()
  (when (file-readable-p "/proc/loadavg")
    (with-temp-buffer
      (insert-file-contents "/proc/loadavg")
      (format "load %s" (car (split-string (buffer-string)))))))
(add-to-list 'emanix/modeline-extra-segments #'my/load-segment)

A segment that signals is dropped, with a message in *Messages*, and the bar still draws. Read /sys or /proc in a segment; do not start a process.

3. Theme

Variable Default Kind Meaning
emanix/theme-state-dir ~/.config/dotfiles defcustom, directory Where Emacs keeps the runtime theme state: the active-theme marker and one last-<variant> marker per variant. Emacs writes here. The name predates Emacs owning the contents
emanix/theme-apply-functions nil defcustom, list of functions The consumer extension point for a theme switch. Each function receives the plan (:name, :dir, :variant, :emacs-theme, :links, :gtk). A function that signals is reported and skipped

Theming explains the switch and the hook in full. The build-time theme is the Nix option emanix.theme, not a variable here.

4. Prose rendering

Org buffers render as prose: a proportional body font, scaled headings and a centred reading column. These are read when emanix-prose-mode turns on in a buffer. A buffer that is already open keeps its old values until you toggle the mode off and on.

Variable Default Kind Meaning
emanix-prose-body-font IBM Plex Sans defcustom, string Proportional family for body text
emanix-prose-heading-font IBM Plex Serif defcustom, string Family for headings
emanix-prose-mono-font JetBrains Mono defcustom, string Monospace family for code, tables and blocks
emanix-prose-width 90 defcustom, integer Width in characters of the centred reading column
emanix-prose-left-margin 4 defcustom, integer Left margin in characters
emanix-prose-heading-scales (1.6 1.4 1.25 1.15 1.05 1.0) defcustom, list of numbers Height multiplier for heading levels 1 to 6

A file opts out with the file-local variable eval: (emanix-prose-mode -1).

5. Buffers and windows

Variable Default Kind Meaning
emanix/buffer-group-alist five groups: agenda, org, dired, files, * defvar, alist of (NAME . PREDICATE) The groups C-c K offers (emanix/kill-buffer-group). A predicate takes a buffer and returns non-nil to kill it. agenda is only what the last agenda run opened, org, dired and files are what they say, and * is everything not protected
emanix/buffer-protect-names ("*scratch*" "*Messages*") defvar, list of strings Buffers no group kill ever reaches. Buffers whose name starts with a space are protected as well, with no setting
emanix/windmove-active t defvar Set it to nil, buffer-locally, to hand M-h M-j M-k M-l back to a major mode
emanix/terminal-glyph-substitutions a list of (WIDE-CHAR . CELL-WIDTH-CHAR) pairs defvar, alist Characters in terminal buffers that the font draws off the cell grid, replaced on screen by glyphs that fit. The text itself is untouched, so copy and search still see the original

Add a group of your own. Every kill still goes through kill-buffer, so a modified file still asks to save, and a protected buffer is filtered out before any predicate runs:

(add-to-list 'emanix/buffer-group-alist
             (cons "notes"
                   (lambda (buf) (emanix/buffer-under-p buf "~/notes"))))

emanix/buffer-under-p is the helper for path-specific groups.

6. Tools

Variable Default Kind Meaning
emanix/agent-shell-save-before-prompt t defcustom, boolean Save modified project buffers before each prompt to an agent. The agent reads files from disk, so without this it cannot see unsaved edits. With it, every prompt commits your unsaved work and entangles your edits with the agent's. The formatter runs on save, so pressing RET in an agent shell can reformat a file you were editing in another window
emanix/arc-capture-target ~/docs/org/arc.org defcustom, file The org file that w in an answer buffer files the answer into. The default is under your home directory; the distribution cannot know where your notes live
emanix-web-djlint-profile jinja defcustom, string The template language passed to djlint --profile. Set it per tree in .dir-locals.el; a command-line profile overrides one in the tree's own djlint config
emanix-welcome-repo-candidates the $EMANIX_DOTFILES directory, ~/flake, /etc/nixos defcustom, list of directories Where the welcome buffer looks for your configuration repository, in order. The first directory holding both a flake.nix and a .git wins. nil entries are ignored

The default of emanix-welcome-repo-candidates is computed when the file loads, so the EMANIX_DOTFILES variable must be in Emacs's environment by then. See the environment variable table.

7. Read, do not set

  • emanix/init-error is nil on a healthy start. Anything else is the error that stopped config.el; see Keybindings.
  • emanix/modeline-status is the cached string the bar displays.

8. What you now know

Every setting above lives in personal.el. A defcustom takes setq or customize; a defvar takes setq or add-to-list. Two of them, emanix/modeline-interval and emanix/modeline-probe-interval, need emanix/modeline-mode restarted. The extension points — a segment function or a theme hook — take a function and never need a patch to the distribution.