Skip to content

ADR 0008: Config/theme format is a minimal hand-rolled key=value format, not TOML

Status

Accepted

Context

Spec section 4 left the config/theme format open between TOML and "a minimal custom format," to hot-reload, with theme and config sharing one format. docs/ROADMAP.md tracked this as an open decision blocking Phase 4, along with the exact default text color (spec section 2: approx. #F5E6C8, "TBD, to be tuned by eye").

Decisions

1. Minimal key = value format, not TOML

The entire v1 config surface is four flat scalars: two colors, a font family, a font size (see core/src/config.c's defaults). Pulling in a TOML parser (a third external dependency, after Qt6 and Tree-sitter) to parse four flat key-value pairs doesn't earn its complexity budget — TOML's actual value (tables, arrays, typed literals, nesting) has no user here yet. The hand-rolled parser is about 60 lines: skip blank lines and # comments, split on the first =, trim whitespace. Fully auditable, zero dependencies, matches the "Minimal" pillar directly.

Revisit this if the config surface grows structure — e.g. per-language theme overrides, keybinding tables, or plugin settings with real nesting would outgrow a flat format fast, and that's the point at which TOML's complexity starts being worth paying for. Nothing in AseConfig's API (core/include/ase/config.h) assumes flat-forever; swapping the parser later doesn't change the public shape (string/int/color lookups by key).

2. Config and theme are the same file, same format

Exactly as the spec asked: one config.ase holds both editor settings (font_family, font_size) and theme colors (background, text). No separate theme-file concept in v1 — there's nothing yet that would motivate having more than one theme active at a time.

3. Default text color ships as #F5E6C8, "tuned by eye" becomes a

config edit, not a guess

The spec flagged the exact accent color as TBD, "to be tuned by eye" — work that requires a human looking at a rendered screen, not something to guess numerically. Phase 4 resolves this differently than by picking a "final" number: it ships #F5E6C8 (the spec's own approximation) as the default, and the config system itself — hot-reloaded — is the mechanism for tuning it. Open the editor, edit background/text in config.ase, save, see the change within ASE_CONFIG_POLL_MS milliseconds, no restart. This closes the ROADMAP open-decision item by making it a five-second edit instead of a hardcoded constant.

4. Hot-reload via mtime polling, not OS file-watch APIs

The GUI checks the config file's modification time on a timer (750ms, EditorViewport) rather than using inotify/FSEvents/ ReadDirectoryChangesW. Real file-watching APIs are meaningfully platform-specific code for a file that's read maybe once every few seconds at most — polling a stat() is negligible overhead and identical across Linux/macOS/Windows. Revisit only if profiling ever shows this timer costing something measurable (it won't, for one small file).

5. Missing config file: ship in-memory defaults, best-effort write a

starter file

ase_config_load never fails outright — a missing or malformed file just means the built-in defaults apply (see decision 3's values). On first run, ase_config_write_default_if_missing best-effort writes a commented starter file to the resolved path ($XDG_CONFIG_HOME/ase/config.ase, falling back to ~/.config/ase/config.ase on Unix; %APPDATA%\ase\config.ase on Windows) so there's something discoverable to edit — but only creates the immediate ase/ directory, not any missing parent (~/.config itself). If that parent doesn't exist, the write silently no-ops and the editor keeps running on in-memory defaults. Acceptable: ~/.config existing is near-universal on any system that's run other XDG-aware software, and the failure mode is "no starter file," never a crash or wrong behavior.

Consequences

Theming beyond "one background, one text color, one font" (e.g. the syntax highlighting capture styles from ADR 0007) stays hardcoded in EditorViewport for now — not yet exposed as config keys. Natural follow-up once someone actually wants to retune keyword-bold vs. comment-opacity without recompiling; tracked in docs/ROADMAP.md, not blocking this phase.