~ober/jerboa-emacs

Imported from ~/mine/jerboa-emacs

download snapshot

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