~ober/jerboa-emacs
Imported from ~/mine/jerboa-emacs
about
# jerboa-emacs
A Chez Scheme port of the jerboa-based Emacs-like text editor, featuring a TUI (terminal) backend and a Qt graphical frontend.
## Overview
jerboa-emacs is an Emacs-inspired editor built on top of:
- **[jerboa](https://git.jerboa.sh/ober/jerboa)** — Chez Scheme runtime with Gerbil-compatible stdlib
- **[jerboa-scintilla](https://git.jerboa.sh/ober/jerboa-scintilla)** — Scintilla editor component FFI bindings
- **[jerboa-shell (jsh)](https://git.jerboa.sh/ober/jerboa-shell)** — POSIX shell interpreter
- **[jerboa-qt](https://git.jerboa.sh/ober/jerboa-qt)** — Qt 5/6 GUI bindings (Qt backend only)
The TUI backend runs in a terminal using Scintilla's text model. The Qt backend provides a full graphical interface.
## Dependencies
### Required (TUI backend)
| Dependency | Purpose | Location |
|------------|---------|----------|
| Chez Scheme ≥ 9.6 | Scheme runtime | system |
| jerboa | Gerbil-compat stdlib | `vendor/jerboa` |
| jerboa-shell (jsh) | Shell interpreter | `vendor/jerboa-shell` |
| jerboa-sqlite | SQLite bindings used by jsh | `vendor/jerboa-sqlite` |
| jerboa-lsp | Optional Jerboa language server | `vendor/jerboa-lsp` |
| jerboa-scintilla | Scintilla editor FFI | `vendor/jerboa-scintilla` |
| jerboa-pcre2 | PCRE2 regex FFI | `vendor/jerboa-pcre2` |
| PCRE2 development headers | Native regex library | system |
| libvterm development headers | Terminal emulation shim for `make binary` | system |
On Debian/Ubuntu, install the native build prerequisites with:
```bash
sudo apt-get install build-essential pkg-config libpcre2-dev libvterm-dev
```
### Additional (Qt backend)
| Dependency | Purpose | Location |
|------------|---------|----------|
| Qt 5 or Qt 6 | GUI framework | system |
| QScintilla | Qt Scintilla widget | system |
| jerboa-qt | Qt FFI bindings | `vendor/jerboa-qt` |
## Build
All commands run from the project root.
### Jerboa build tools
`make build` and `make binary` build and use the vendored Jerboa multicall
toolchain at `vendor/jerboa/dist/{jerboa,jerbuild}`. The editor vendors and
builds its native Scheme/FFI dependencies under `vendor/`.
For systems that have the standalone Jerboa release toolchain but no full
Jerboa runtime checkout, use:
```bash
make ensure-jerboa-tools
make build-jerbuild
make jerbuild-check
```
`ensure-jerboa-tools` follows the same convention as `jerboa-code` and
`jerboa-shell`: it prefers project-local tools, a sibling `../jerboa` build, or
`PATH`, and otherwise downloads `jerboa-${JERBOA_VERSION}` into `.jerboa/bin`.
Downloaded toolchains are accepted only when their target-specific SHA-256
matches `dependencies.lock`; a checksum fetched beside the artifact is not a
trust root.
The `.jerbuild*` configs describe native target-host builds for macOS/Linux/
FreeBSD without requiring an installed full Jerboa runtime. Release targets use
the exact vendored `jerbuild` and statically link its pinned
`libjerboa_native.a`; failing crypto/TLS placeholder stubs are not part of
release binaries.
### Cross and target builds
Linux and FreeBSD target artifacts are built with `jerbuild` on the target OS.
From macOS, the Linux amd64 target uses SSH by default:
```bash
make linux-amd64 # writes ./jemacs-linux-amd64
```
The default SSH host is `linux.cons.io`; override it with
`LINUX_BUILD_HOST=host` and `LINUX_BUILD_ROOT=/path/to/jerboa-emacs`.
Linux arm64 and FreeBSD follow the `jerboa-shell` pattern and are built on a
matching target host:
```bash
make linux-arm64 # on Linux arm64, or set LINUX_ARM64_BUILD_HOST
make freebsd-amd64 # writes ./jemacs-freebsd-amd64
```
Native target-host jerbuild configs are also available:
```bash
jerbuild build --config .jerbuild.linux-amd64
jerbuild build --config .jerbuild.linux-arm64
jerbuild build --config .jerbuild.freebsd-amd64
```
### Vendor dependencies
```bash
make vendor-deps
```
This fetches the exact full commits recorded in `dependencies.lock` into
`vendor/` and rejects an existing checkout at any other revision. Archive,
container, static OpenSSL 3.5.7 LTS, Chez, and Tree-sitter inputs are likewise
digest- or commit-pinned. The default `make build` target verifies this graph
first; `make vendor-update` never follows a mutable upstream head.
### Build library modules
```bash
make build
```
This runs `jerbuild` to translate `.ss` Gerbil-syntax source files in `src/` to Chez-compatible `.sls` library files in `lib/`. The build is incremental.
To force a full rebuild:
```bash
make rebuild
```
### Build the jerboa-shell (jsh) library
The shell interpreter must be compiled separately:
```bash
cd vendor/jerboa-shell
make jsh-compile
```
### Run (TUI mode)
```bash
make run
```
This builds and launches the terminal editor.
### Run (Qt mode)
```bash
make run-qt
```
Requires the Qt backend build (see below).
### Authenticated local control sockets
`--repl PORT` enables the full-power loopback debug REPL. It always requires a
fresh 256-bit token, atomically published with the port in the mode-0600
`~/.jerboa-repl-port` file. The always-on `jerboa-client` IPC endpoint uses an
independent token in `~/.jemacs-server`. Both endpoints enforce bounded input,
deadlines, and one active connection. See
[docs/repl-server.md](docs/repl-server.md) for the protocol and threat model.
### Build Qt backend
```bash
make build-qt
```
The Qt backend consists of 45 modules in `src/jerboa-emacs/qt/` (~48,801 lines).
`make build-qt` simply runs the normal `make build` (which translates those
`.ss` modules to `.sls` alongside the rest of the editor) and then prints a
status banner — it does **not** compile a Qt binary by itself. To launch the Qt
frontend interpreted, use `make run-qt`; to produce a static `jemacs-qt` binary,
use `make static-qt` (below).
### Static binaries (Podman / Linux host)
```bash
make static-qt # fully static jemacs-qt, built via Podman (Containerfile.qt)
make static-tui # static TUI binary, built on a prepared Linux host
```
`static-qt` routes to `podman-static-qt`, which builds with **Podman** and
copies the resulting `jemacs-qt` out of the image. The `*-podman` targets
(`podman-deps`, `linux-static-qt-podman`, `linux-static-tui-podman`, ...) use
the same `PODMAN`, `PODMAN_PLATFORM`, `PODMAN_BUILD_FLAGS`, and
`PODMAN_RUN_FLAGS` variables.
## Testing
### Run all standard tests
```bash
make test
```
The suite includes hostile authentication, overlong-frame, traversal, endpoint
symlink, private-temp-file, and shell-metacharacter argv tests.
This runs: test-tier0, test-tier2, test-tier3, test-tier4, test-tier5, test-org, test-extra.
### Run specific test suites
| Command | Description |
|---------|-------------|
| `make test-functional` | Functional dispatch chain tests (250 tests) |
| `make test-term-hang` | Subprocess/blocking behavior diagnostic (13 tests) |
| `make test-tier0` | Core data structures |
| `make test-tier2` | Buffer and window primitives |
| `make test-tier3` | Editor core operations |
| `make test-tier4` | Shell integration |
| `make test-tier5` | Full editor commands |
| `make test-org` | Org-mode subsystem |
### Environment for tests
The Makefile sets these automatically:
```
LD_LIBRARY_PATH = vendor/jerboa-pcre2:vendor/jerboa-scintilla:vendor/jerboa-qt:vendor/jerboa-shell
JERBOA_SCINTILLA_LIB = vendor/jerboa-scintilla
JERBOA_PCRE2_LIB = vendor/jerboa-pcre2
```
## Release Evidence
Local release candidates use:
```bash
make audit
make sbom
make reproducibility-report
make editor-flow-evidence
make release-evidence
```
`make release-evidence` writes `dist/release-evidence/` with test, audit, SBOM,
reproducibility, target-host editor-flow status, build-environment, git-status,
release-input, and binary hash evidence. See `docs/release-evidence.md` for the
contents and remaining target-host review requirements.
## Source Layout
```
src/
jerboa-emacs/
core.ss — App state, frame, window data types
buffer.ss — Buffer management
editor-core.ss — Core editor commands
editor.ss — Command registration
editor-cmds-a.ss — Commands A-M
editor-cmds-b.ss — Commands N-Z, git operations
editor-cmds-c.ss — Additional commands
shell.ss — Shell integration (jsh-based)
subprocess.ss — Non-blocking subprocess execution
terminal.ss — Terminal emulation
keymap.ss — Key binding system
helm.ss — Helm completion framework
persist.ss — Session persistence
editor-extra-*.ss — Extended features (org, AI, VCS, media, etc.)
qt/ — Qt graphical backend (45 modules)
lib/
jerboa-emacs/ — Generated .sls files (DO NOT EDIT)
tests/
test-functional.ss — Dispatch chain integration tests
test-term-hang.ss — Subprocess blocking diagnostic
test-tier*.ss — Tiered unit tests
test-org-*.ss — Org-mode tests
```
## Architecture Notes
### jerbuild code generation
`.ss` files in `src/` use Gerbil-style syntax (`def`, `defstruct`, `:module/path` imports). The `jerbuild` tool (from jerboa) translates these to Chez Scheme `.sls` library files in `lib/`. **Never edit `.sls` files directly** — all changes go in `.ss` sources.
### Qt backend and port ordering
Chez Scheme's `open-process-ports` returns values in this order:
```scheme
(values write-stdin-port read-stdout-port read-stderr-port pid)
```
This differs from Gambit/Gerbil's `open-process`. All process I/O code uses this order.
### Shell integration
The `shell.ss` module embeds the `jsh` POSIX shell interpreter. The `subprocess.ss` module provides `run-process-interruptible` for non-blocking subprocess execution with C-g interrupt support — this is the recommended path for long-running commands.
Note: `gsh-capture` / `command-substitute` in jsh uses `open-output-file "/dev/fd/1"` which acquires a Chez port registry lock. Running this in a secondary thread can deadlock with Chez's scheduler. Use `run-process-interruptible` for subprocess output capture in threaded contexts.
### with-output-to-string
In Chez Scheme, `with-output-to-string` takes only a thunk:
```scheme
(with-output-to-string (lambda () (display-exception e)))
```
The Gerbil form `(with-output-to-string "" thunk)` is not valid in Chez.
## Key Variables (Makefile)
| Variable | Default | Description |
|----------|---------|-------------|
| `SCHEME` | `vendor/jerboa/.chez/bin/scheme` | Chez Scheme executable |
| `JERBOA` | `vendor/jerboa` | jerboa checkout |
| `JSH` | `vendor/jerboa-shell/src` | jsh source path |
Override on the command line: `make SCHEME=/usr/local/bin/chez build`
## Documentation
| Document | Description |
|----------|-------------|
| [docs/jemacs-vs-emacs.md](docs/jemacs-vs-emacs.md) | Feature comparison with GNU Emacs (48 categories, 2168+ commands) |
| [docs/helm.md](docs/helm.md) | Helm narrowing framework — architecture, matching engine, sources |
| [docs/shell.md](docs/shell.md) | Shell integration plan — jsh POSIX shell embedding |
| [docs/repl-server.md](docs/repl-server.md) | TCP debug REPL server for live introspection |
| [docs/50-features.md](docs/50-features.md) | 50 features roadmap to close the gap with GNU Emacs |
recent commits
- Document local mine repository authority ae5568b Jaime Fournier
- Remove jerboa-emacs untouchable policy d589d6b Jaime Fournier
- Save Qt editor and documentation updates 9532781 Jaime Fournier
- Update jpkg metadata for Forgejo 404348c Jaime Fournier
- P1.5: Per-window modelines 874abdc Jaime Fournier
- P1: LSP language awareness, async auto-save, snippet undo, helm actions, stub purge 472e5c2 Jaime Fournier
- Restore LSP request timeouts 306a96a Jaime Fournier
- Render which-key bindings as Qt list e5c30ee Jaime Fournier
- Make Qt helm occur results jumpable 46aa625 Jaime Fournier
- Implement Qt editor context menu mode a721a18 Jaime Fournier