Skip to content

Repository files navigation

ttt-vim

A Vim compatibility layer for the ttt editor, implemented as a single Lua plugin. Modal editing, the operator × motion × text-object grammar, visual modes, registers, marks, macros, dot-repeat, a : command line, and / search.

Originally built in ttt#386.

Requires ttt 1.1.0 or newer. The plugin depends on core additions in 1.1.0 — the key interceptor's precedence over Escape (needed to leave insert mode) and the ttt.command_line API (needed for : and /). On older builds Esc will not return you to normal mode and the command line will not open. The manifest declares api: 2, so an older editor refuses to load it rather than running it half-broken.

See REFERENCE.md for the full list of supported keys, the substitution regex subset, design notes, and known gaps.

Install

Copy this repo's plugin files into a plugin directory ttt scans — either ~/.config/ttt/plugins/vim/ or <workspace>/plugins/vim/:

plugin.ttt.json
init.lua

On first launch ttt will prompt to approve the plugin's permissions (keybindings, editor.read, editor.write, commands, fs.write, settings).

Configuration

Settings live under a vim object in settings.json:

Key Default Effect
vim.enabled true Start with Vim mode active.
vim.clipboard false Mirror the unnamed register to the system clipboard.

Development & testing

The test suite drives the real ttt binary via its --exec debug harness. It does not download a release — it builds ttt from source so the binary always matches the ttt it is tested against.

npm install
npm test          # builds ttt, then runs the vitest suite

npm test runs scripts/prepare-ttt.sh, which resolves a binary into .ttt-bin/ttt in this order:

  1. TTT_BIN=<path> — use an existing binary as-is.
  2. A sibling ../ttt checkout — build it in place.
  3. Otherwise clone ttt at TTT_REF (default main) and build it.

So with a local ../ttt checkout, npm test just works. In CI the same script clones and builds ttt (see .github/workflows/test.yml).

The plugin is one large init.lua by necessity: the ttt plugin sandbox cannot require sibling .lua files, so everything lives in one file, organized into do … end blocks (which also keep each scope under Lua 5.1's 200-local limit).

Differential fuzzer

tests/fuzz/ holds a seeded differential fuzzer that checks ttt-vim against real Vim as the oracle: it generates a random key sequence from a seed, replays it through both editors, and compares the saved files. Identical output ⇒ spec-compliant; a divergence is a ttt-vim bug or a documented gap. See tests/fuzz/DESIGN.md for the architecture and tests/fuzz/FINDINGS.md for what it has found.

npm run fuzz                       # seeds 1..200, ~8 actions each
FUZZ_START=1 FUZZ_COUNT=500 npm run fuzz
FUZZ_SEED=1337 npm run fuzz        # one seed, verbose (prints tokens + diff)

Requires vim on PATH (the oracle). Divergences are written as reproducible JSON reports under tests/fuzz/reports/ (git-ignored) — each carries the seed, token stream, both outputs, and a diff, so a failure reproduces from its seed alone. The fuzzer is on-demand and not part of npm test; the deterministic fixed-sequence parity check (tests/fuzz/differential.test.js) is.

To reduce a failing seed to a minimal repro:

node tests/fuzz/repro.mjs 40         # rerun one seed, print the diff
npm run fuzz:shrink 40               # delta-debug it to a minimal token sequence

About

Vim compatibility layer for the ttt editor (Lua plugin). Requires ttt 1.1.0+.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages