Building rtdvi

Requirements

Build

cargo build --release

The binary lands at target/release/rtdvi.

Feature flags

rtdvi has three optional features that change which engines are compiled in. Exactly one WASM runtime must be selected — the two are mutually exclusive.

WASM runtime (pick one)

The default runtime is wasmtime — the "ready-to-drink" choice. It supports every plugin type including those that use WASM exceptions (e.g. mlua-wasm), at the cost of a heavier build. Switch to wasmi only if you want a streamlined binary and accept the compatibility trade-off; wasmi may gain exceptions support in a future release.

FeatureDefaultDescription
runtime-wasmtimeJIT-compiled WASM via wasmtime. Full plugin compatibility, including WASM exceptions (mlua-wasm). ~18 MB release binary.
runtime-wasmiInterpreted WASM via wasmi. Streamlined build: smaller binary, far fewer dependencies. Plugins that use WASM exceptions (e.g. mlua-wasm) cannot load — plain Rust plugins (wasm32-unknown-unknown) work fine.

Lua engine (additive)

FeatureDefaultDescription
lua-engineEnables in-process Lua 5.4 scripting via mlua (vendored, no system Lua needed). Can be combined with either WASM runtime.

Common build variants

# Default — wasmtime JIT, full compatibility, no Lua
cargo build --release

# Lighter build — wasmi interpreter, no Lua
cargo build --release --no-default-features --features runtime-wasmi

# wasmtime + Lua
cargo build --release --features lua-engine

# wasmi + Lua  (smallest full-featured build)
cargo build --release --no-default-features --features runtime-wasmi,lua-engine

Omitting both runtimes or enabling both are compile errors.

Distribution builds

The standard cargo build --release produces a dynamically linked binary that requires glibc 2.34+ (Ubuntu 22.04, Debian 12, RHEL 9, Fedora 36 or newer). For a binary that runs on any Linux distro — including Alpine, Void, and older releases — build against the musl libc target instead, which produces a fully static binary with no system library dependencies.

# Install the musl target (once)
rustup target add x86_64-unknown-linux-musl

# On Debian/Ubuntu: apt-get install musl-tools
# On Fedora:        dnf install musl-gcc
# On Arch:          pacman -S musl

cargo build --release --target x86_64-unknown-linux-musl
# → target/x86_64-unknown-linux-musl/release/rtdvi  (fully static)

Verify it is static:

file target/x86_64-unknown-linux-musl/release/rtdvi
# ELF 64-bit LSB executable, x86-64, statically linked

Cross-compilation (other architectures)

Use cross, which provides Docker images with the correct sysroots:

cargo install cross --locked

cross build --release --target aarch64-unknown-linux-musl   # Linux ARM64
cross build --release --target x86_64-unknown-linux-musl    # Linux x86_64

For macOS targets, build natively on macOS:

rustup target add aarch64-apple-darwin x86_64-apple-darwin
cargo build --release --target aarch64-apple-darwin   # Apple Silicon
cargo build --release --target x86_64-apple-darwin    # Intel Mac

Release artefacts

The GitHub Actions workflow (.github/workflows/release.yml) builds all four targets automatically on every version tag and attaches the compressed binaries to the GitHub release. Push a tag to trigger it:

git tag v0.1.0
git push origin v0.1.0

Install

cargo install --path .

Drops rtdvi into ~/.cargo/bin/ (make sure that's on your PATH).

Optional rvi short alias

The canonical command is rtdvi. If you'd like the shorter rvi, opt in:

make rvi-alias       # symlinks rvi -> rtdvi in ~/.cargo/bin
make rvi-unalias     # remove it

This is not installed by default on purpose: rvi is the traditional name for restricted vi, and the r* restricted-editor family (rvim, rview, rnano, rbash) ships on most systems. Keeping the default binary canonical avoids PATH collisions and packaging conflicts; the alias is there for those who want it. The target refuses to overwrite an existing rvi that isn't already our own symlink.

Run

rtdvi path/to/file
rtdvi          # scratch buffer

Logging

rtdvi writes a log to ./editor.log in the working directory. Verbosity is controlled by $RTDVI_LOG:

RTDVI_LOG=debug rtdvi foo.c

Useful when troubleshooting LSP or colorscheme load failures — non-fatal errors are silenced from the UI but logged.

Tests

cargo test           # all unit + integration tests (debug)
cargo test --release # release-mode timings for the perf tests

The integration tests use ratatui::backend::TestBackend to render into an in-memory grid and assert on the resulting cells, so they exercise the entire pipeline including the renderer.

Layout

src/
  main.rs              CLI, terminal setup, event loop
  editor.rs            the Editor aggregate (state, registries)
  buffer.rs            ropey-backed text buffer, undo
  cursor.rs            Cursor + Selection types
  window.rs / tab.rs   split tree, tab pages
  mode/                normal/insert/visual/visual_line/visual_block/command/search
  keymap/              Key, KeyMods, KeyTrie, ActionRegistry
  command/             ExCommand trait + builtin commands
  completion.rs        :command-line tab completion + popup
  colorscheme.rs       vim .vim colorscheme parser
  syntax.rs            filetype detection + syntax engine
  lsp/                 LSP client / manager / transport
  ui/                  rendering (ratatui)
  motion.rs            cursor motions
  edit_actions.rs      i / a / o / O / u / <C-r>
  delete_actions.rs    dd / dw / dj / dk / d$ / d0 / dG / dgg / x / X
  yank_actions.rs      yy / yj / yk / yw / y$ / yG / Y
  visual_actions.rs    v / V / <C-v>, d / y / c, block I / A replay
  replace_actions.rs   r{c}
  bracket_actions.rs   % match, ]] [[ section motions
  search_actions.rs    /, ?, n, N
  window_actions.rs    <C-w>… split / focus / equalise
  lsp_actions.rs       gd / K / [d / ]d
text/width.rs          display-column math (CJK, tabs)

Dependencies

CrateFeature flagWhy
ropeyalwaysrope-backed text buffer
ratatuialwaysTUI rendering
crosstermalwaysterminal I/O backend
regexalwayssearch, syntax patterns
unicode-widthalwaysdisplay-column math
unicode-segmentationalwaysgrapheme iteration
serde, tomlalwaysconfig
serde_jsonalwaysLSP messages
lsp-types 0.95alwaysLSP message structs (pinned: 0.97 swapped UrlUri)
mime_guessalwaysextra filetype detection
clapalwaysCLI args
thiserror / anyhowalwayserror types
tracing + appenderalwayslogging
wasmtimeruntime-wasmtimeJIT WASM engine (~140 transitive crates)
wasmiruntime-wasmiinterpreter WASM engine (much lighter)
mlualua-enginein-process Lua 5.4 (vendored)
tempfiledev-onlytest fixtures
watdev-onlyWAT text-format parsing in tests