Configuration¶
abax is configured through a single JSON settings file, a handful of environment variables, and a set of platform-correct runtime directories that hold its config, data, cache, and logs. Almost nothing needs configuring to get started — the defaults are sensible and every optional feature degrades gracefully when its dependency is absent — but this page documents every knob: where settings live, what each field does, the environment variables, the theme presets, the on-demand OpenDyslexic font, and pandoc detection for equation rendering.
Settings file¶
Settings are stored as JSON in settings.json inside abax's config directory (see Runtime directories below — typically …/abax/settings.json). The GUI and TUI load it at startup and write it back when you change a setting. If the file is missing or unreadable, abax silently uses the defaults, so deleting it is a safe way to reset.
JSON encoding uses msgspec when the fast-io extra is installed and falls back to the standard library otherwise; the behavior is identical either way. The schema is versioned and migrates lazily on read (for example, an old color_scheme field is renamed to theme automatically and written back).
Settings fields¶
| Field | Type | Default | Meaning |
|---|---|---|---|
theme |
string | "obsidian" |
GUI theme preset (see Themes). |
vim_mode |
bool | true |
Vim-style key bindings, on by default. |
tui_theme |
string | "obsidian" |
TUI color theme. |
zoom |
float | 1.0 |
GUI zoom factor. |
dyslexic_font |
bool | false |
Use the OpenDyslexic font across the GUI (see OpenDyslexic font). |
calc_model |
string | "" |
Last-used calculator model key (e.g. 16c, 15c, ti83, alg); restored on launch. Empty = default (HP-16C). |
calc_style |
string | "image" |
Last-used HP faceplate style (image or vector). |
calc_degrees |
bool | false |
Calculator Deg/Rad mode, restored on launch. |
last_sheet |
int | 0 |
Active sheet index, restored on launch. |
last_cell |
string | "" |
Cursor cell (A1), restored on launch. |
code_consent |
bool | false |
Whether you've consented to run untrusted code (console/terminal/scripts/macros). Set back to false to be prompted again. |
code_isolation |
string | "isolated" |
How code execution is isolated: off (in-process, no worker/limits), restricted (the out-of-process, resource-limited worker plus an AST allowlist applied to your code that blocks OS/filesystem/network access — a language-level block, not an OS boundary; sits between off and isolated in the cycle; the optional restricted extra adds RestrictedPython compile-time guards), isolated (out-of-process worker + resource limits), or strict (also OS-confine filesystem + network). Cycle it from the command palette; see Macros & scripting. |
faceplate_assets_dir |
string | "" |
Folder of calculator faceplate artwork (see Faceplate assets). |
show_toolbar |
bool | true |
Show the GUI toolbar. |
autosave_enabled |
bool | true |
Whether the GUI periodically autosaves settings.json. |
autosave_interval |
int | 30 |
Autosave cadence in seconds (when enabled). |
recent_files |
list | [] |
Recently opened file paths. |
window_geometry |
dict | {} |
Saved GUI window position/size. |
fm_buttons |
list | [] |
Your custom file-manager command buttons ({label, command}); see File manager. |
auto_install |
bool | true |
Auto-install optional dependencies (and show the first-run chooser); see Auto-install. Set false to opt out. |
deps_prompted |
bool | false |
Whether the first-run optional-feature chooser has been shown. Set back to false to be asked again. |
calc_iterative |
bool | false |
Resolve circular references by capped fixed-point iteration instead of surfacing #CIRC! (off by default, like Excel). |
calc_max_iterations |
int | 100 |
Maximum iterations for iterative calculation (when calc_iterative is on). |
calc_max_change |
float | 0.001 |
Convergence tolerance for iterative calculation — iteration stops once the largest cell change falls below this. |
high_contrast |
bool | false |
High-contrast accessibility mode. |
speak_on_move |
bool | false |
Speak the active cell aloud on cursor move (GUI + TUI); needs the tts extra. |
tui_screen_reader |
bool | false |
Single-line, reader-friendly TUI rendering for screen readers. |
plugins_enabled |
bool | false |
Whether third-party UDF/format plugins (entry points) may load. Off by default — loading runs third-party code with full privileges. |
live_data_enabled |
bool | false |
Whether the REST/WEBSOCKET live-data formulas may open network connections. Off by default so a workbook opened from disk can never phone home; enable via Tools → Enable live data or TUI :live on. URLs are limited to http/https/ws/wss. |
external_refs_enabled |
bool | false |
Whether closed-workbook external references (=[Book.abax]Sheet1!A1) may read other workbook files. Off by default so an opened file never pulls in others on its own; enable via Tools → Enable external references or TUI :extern on. Paths resolve relative to the open workbook's folder; only .abax/.json load. |
windowed_store_capacity |
int | 0 |
Bounds resident cells per sheet, spilling the rest to a private temp file. Three-way: 0 (default) = Auto — when a file is opened, only sheets with ≥ 100,000 populated cells are windowed (at 50,000 resident cells), so small workbooks are untouched; a positive value windows every sheet at that capacity; -1 = never. A memory ↔ latency trade-off that matters for very large data imports (lots of literal cells — ~48% steady-state saving measured on a 125k-cell sheet); formula-heavy sheets see little benefit (the value cache and key index stay resident). Dependency chains evaluate correctly at any capacity (up to ~10,000 cells deep — the engine's recursion headroom, independent of this setting). Opening a native .abax/.json file applies the policy during the load: cells stream straight into the windowed store (spilling past-capacity cells as they arrive), so a huge file never materializes fully in memory first — peak usage tracks the parsed file plus the resident window instead of the whole workbook (measured on a 150k-cell file: below even a plain un-windowed load, where the old load-then-migrate path briefly exceeded it). Other formats (CSV, Excel, …) still load into the plain store and then migrate, and changing the capacity on an already-open workbook re-homes its cells likewise — those paths briefly cost extra memory (~1.5× while cells move); the savings are the steady state after it. Set it from Preferences → System → Performance (or by hand in settings.json). |
chart_backend |
string | "auto" |
How embedded charts (Insert → Embedded chart (on sheet)…) render in the GUI: auto = matplotlib when it is installed, else the built-in pure-stdlib SVG renderer; svg = always the built-in renderer; matplotlib = matplotlib, falling back to SVG (with a status-bar hint) when it isn't installed. Both backends draw the same data. Set it from Preferences → Appearance → Embedded charts. |
schema_version |
int | 7 |
Settings schema version (managed by abax). |
You can edit settings.json by hand while abax is closed, but you rarely need to: the Preferences dialog (Edit → Preferences…, Ctrl+,) is the central place to manage every field, grouped into Appearance (GUI + TUI theme, font, zoom, toolbar, vim keys), Calculator (default model, faceplate style, angle mode, faceplate folder), and System (autosave, code-execution consent + isolation, optional-dependency install). Changing settings from the app is the recommended way — it persists and applies without a manual edit.
Startup script (init.py)¶
For power users, abax runs an optional Python script at CONFIG_DIR/init.py
(e.g. ~/.config/abax/init.py) when the GUI or TUI starts. It's your own
trusted config — like a .vimrc or .pythonrc, executed with your privileges —
and it receives an abax facade for rebinding keys, adding macro-menu
entries, and registering custom formula functions:
# ~/.config/abax/init.py
def to_top(ed):
ed.row = 0
ed._reclamp()
# Rebind a key (rebinds override the built-in bindings). Works in every TUI
# mode: "normal", "insert", "command", "rpn", "visual", "browser".
abax.bind_key("normal", "K", to_top, desc="jump to top")
abax.bind_key("insert", "ctrl+w", lambda ed: ed.delete_word(), desc="del word")
# Register a named entry for the macro menu / palette.
abax.register_macro_menu("Uppercase cell", lambda ed: ed.sheet.set_cell(
ed.row, ed.col, ed.sheet.get_raw(ed.row, ed.col).upper()))
# Register a custom formula function — usable in cells as =DOUBLE(A1).
def double(args):
return (args[0] or 0) * 2
abax.register_function("DOUBLE", double)
# kind="lazy" receives unevaluated argument nodes (control-flow functions);
# kind="context" receives (arg_nodes, ctx) like ROW/OFFSET. A user function
# may deliberately shadow a built-in of the same name.
Bare keys are matched as the literal keystroke, so case matters ("K" ≠ "k").
Modifier chords are normalized, so "Ctrl+S", "ctrl+s" and "C-s" all
name the same binding. Rebinds fire in whichever mode you registered them for
(the six modes above); in insert and command mode only non-printable chords
like ctrl+w are intercepted, so ordinary typing is never captured. Run
:map in the TUI to list all your rebinds, or :map <mode> for one mode.
The action is called with the editor. A broken init.py never blocks
startup — the error is captured and surfaced in the status line, and abax
carries on with its defaults. This is not the sandboxed code-execution path
(console/macros); it is your own config, trusted by design.
Runtime directories¶
abax never hardcodes paths. It resolves four OS-appropriate directories at startup and creates them if needed. When the platformdirs package (from the fast-io extra) is installed it uses that; otherwise a built-in fallback mirrors the same logic.
| Directory | Holds |
|---|---|
| CONFIG | settings.json, the macros/ folder for auto-discovered macros. |
| DATA | Persistent application data — an exchange/ subfolder for the generic JSON interchange format, and crash.log (a stack dump written on a native / Qt crash). |
| CACHE | Downloaded assets — the OpenDyslexic font (fonts/). |
| LOG | Log files. |
Typical locations per platform:
| Platform | CONFIG | DATA | CACHE | LOG |
|---|---|---|---|---|
| Windows | %APPDATA%\abax |
%LOCALAPPDATA%\abax |
%LOCALAPPDATA%\abax\Cache |
%LOCALAPPDATA%\abax\Logs |
| macOS | ~/Library/Application Support/abax |
same as config | ~/Library/Caches/abax |
~/Library/Logs/abax |
| Linux | $XDG_CONFIG_HOME/abax (~/.config/abax) |
$XDG_DATA_HOME/abax (~/.local/share/abax) |
$XDG_CACHE_HOME/abax (~/.cache/abax) |
…/abax/logs |
To see the exact paths on your machine, run:
It prints the config, data, cache, and log directories at the bottom of the report (see cli.md).
Environment variables¶
ABAX_QT_BINDING¶
Forces which Qt binding the GUI uses. abax prefers PySide6 (LGPL) and falls back to PyQt6; no GUI code branches on the binding, so the app runs identically on either. Set this to override the default order:
Only PyQt6 is treated specially: setting it forces the PyQt6 path even when PySide6 is installed. Any other value (or leaving it unset) keeps the default PySide6-then-PyQt6 order. This is mainly useful for testing both bindings. See getting-started.md for installing each one.
ABAX_FACEPLATE_DIR¶
Points at a faceplate-assets root — a directory that holds per-model subfolders of calculator faceplate artwork used by the GUI's photographic faceplate for the built-in RPN calculator. Each model subfolder must contain a background.png and at least one .kml layout file.
# Point at a local checkout's voyager assets
export ABAX_FACEPLATE_DIR=/path/to/qrpn-voyager/qrpn/assets/voyager
abax gui
See Faceplate assets for the full resolution order. abax bundles no artwork and never copies these files — it only reads them in place.
PANDOC¶
Points at a pandoc executable for rich equation rendering. See Pandoc below.
ABAX_NO_AUTOINSTALL¶
Set to any non-empty value to disable optional-dependency installs entirely — the first-run chooser won't appear and abax won't run pip (equivalent to auto_install: false in settings). See Auto-install.
Auto-install¶
abax's core is pure stdlib and every heavier capability is an optional package with a graceful fallback — abax installs nothing on its own. On first GUI launch it shows a chooser that explains each optional feature group; nothing is selected by default — you pick only what you want. Two presets make choosing a whole set one click: Thin (the lean everyday conveniences) and All (everything abax can use). Your selection is fetched in a background daemon thread (best-effort, non-blocking) and the fact that you were asked is remembered (deps_prompted), so the chooser doesn't reappear on its own. In the TUI/headless there's no dialog: a one-time notice points you at abax deps (install everything) or pip install abax[…] (specific extras).
- Best-effort and non-blocking. Startup and the UI never wait on
pip. If pip is unavailable, you're offline, or a build fails, abax silently keeps using its pure-Python fallbacks. - Once per machine. A marker file per package (under the cache directory's
autodeps/folder) means a slow or failing install is not retried on every launch. - Opt in, and revocable. Nothing installs unless you choose it.
auto_install: falsein settings (Preferences → System) orABAX_NO_AUTOINSTALL=1disables installs entirely. - The Qt GUI binding (PySide6/PyQt6) is not auto-installed — you need it to launch the GUI in the first place, so install it explicitly with
pip install abax[gui].
Add more any time: Tools → Install optional features or Preferences → System → Manage optional features… re-open the chooser; abax deps installs everything from the command line, synchronously; and abax --deps reports the install state and how many optional packages are present.
Themes¶
The GUI ships a set of theme presets in abax/gui/theming.py; the TUI has matching color themes. Set theme (GUI) or tui_theme (TUI) in settings.json, or switch from within the app. An unknown name falls back to the default (obsidian).
| Preset | Style |
|---|---|
obsidian |
Default dark theme. |
light |
Light theme. |
high_contrast |
High-contrast theme. |
nord |
Nord palette. |
dark_one |
Atom One Dark style. |
solarized |
Solarized. |
crt_green |
Green phosphor CRT. |
crt_amber |
Amber phosphor CRT. |
The GUI renders any preset through a token-based stylesheet, and the GUI theming module can also import themes from an Obsidian CSS snippet or a Zed JSON theme. The TUI maps each theme to the nearest 256-color terminal palette.
OpenDyslexic font¶
abax can use the OpenDyslexic typeface (SIL OFL 1.1), a free, openly licensed font designed to ease reading for people with dyslexia. When enabled it applies across the UI — menus and dialogs, the grid cells, and the Python console / terminal — while the calculator's LCD and the painted faceplates keep their own display fonts. The binaries are not bundled: when you enable the dyslexic font (the dyslexic_font setting, toggled in the GUI), abax downloads the Regular and Bold .otf files from the upstream GitHub repository (pinned to a fixed commit) into its cache directory (CACHE/fonts/) on first use.
The fetch is best-effort and offline-safe — any network or file error is logged and swallowed, so toggling the font on without a connection simply leaves it unavailable rather than raising an error. Once cached, the font is reused with no further network access.
Faceplate assets¶
The GUI's built-in RPN calculator can render a photographic faceplate (background image + key overlays + a .kml layout per calculator model). abax distributes none of this artwork; it reads asset files you supply. A faceplate is considered usable when its model folder contains a background.png and at least one *.kml layout file.
abax looks for a model's assets in this order and uses the first usable match:
- The
faceplate_assets_dirsetting, if set (the assets-root folder). - The
ABAX_FACEPLATE_DIRenvironment variable (also an assets-root folder). - A local
qrpn-voyager/orqv/checkout found beside the working directory, its parent, or the abax source tree — assets are expected underqrpn/assets/voyager/<model>/. Contributors who keep that checkout handy get the artwork with no configuration.
Both faceplate_assets_dir and ABAX_FACEPLATE_DIR should point at the assets root (the directory that holds the per-model subfolders), for example a local qrpn-voyager checkout's qrpn/assets/voyager.
Pandoc for equations¶
abax can render LaTeX math to MathML for its equation feature. It prefers a real pandoc binary and resolves one in this order:
- The
PANDOCenvironment variable, if it names an executable on thePATH. - A
pandocexecutable on thePATH. - A pandoc binary managed by the
pypandocpackage, if installed.
If none is found, abax can bootstrap one on demand by pip install-ing the pypandoc_binary wheel (which bundles the executable) and then exposing its path through the PANDOC environment variable. The whole process is graceful: with no network or no pip it simply reports pandoc as unavailable and falls back to a built-in subset MathML renderer — it never raises.
To point abax at a specific pandoc:
abax --deps reports whether pandoc is available and what the fallback is.
See also¶
- getting-started.md — install and first-run walkthrough.
- cli.md — command-line reference (including
--deps). - gui-guide.md — GUI menus, palette, and shortcuts.
- index.md — documentation home.