# hjkl
Vim-modal terminal editor. Standalone TUI built on the hjkl engine.
[](https://github.com/kryptic-sh/hjkl/actions/workflows/ci.yml)
[](https://crates.io/crates/hjkl)
[](../../LICENSE)
[](https://hjkl.kryptic.sh)
Native vim-modal editor. Single static binary, no plugins, no config files.
Built on the [hjkl-engine](https://crates.io/crates/hjkl-engine) + rope buffer.
## Status
`0.4.0` — multi-buffer editing, fuzzy file/buffer/grep pickers with
syntax-highlighted preview, tree-sitter highlighting + comment-marker overlay,
smart indent, `.editorconfig`, `softtabstop`, and clipboard via our in-house
[`hjkl-clipboard`](https://crates.io/crates/hjkl-clipboard) (sync + async, OSC
52 SSH fallback). See [SCOPE.md](SCOPE.md) for the full feature roadmap.
## Install
**macOS (Homebrew)**
```bash
brew install kryptic-sh/tap/hjkl
```
**Arch Linux (AUR)**
```bash
paru -S hjkl-bin
```
**Alpine Linux**
```bash
apk add --allow-untrusted hjkl-*.apk # download .apk from releases page
```
**Debian / Ubuntu** — `.deb` for amd64 + arm64 on the
[releases page](https://github.com/kryptic-sh/hjkl/releases).
**Fedora / RHEL** — `.rpm` for x86_64 + aarch64 on the same page.
**From source**
```bash
cargo install hjkl
```
Or grab a pre-built tarball for any platform from the
[releases page](https://github.com/kryptic-sh/hjkl/releases).
## Usage
```bash
hjkl # empty buffer
hjkl file.txt # open file
hjkl a.rs b.rs c.rs # open multiple files
hjkl -R file.txt # read-only
hjkl +42 file.txt # jump to line 42
hjkl +/foo file.txt # search for "foo" on open
hjkl +picker # open fuzzy file picker immediately
```
## Headless mode
Run ex commands against files without a terminal. No ratatui, no crossterm —
suitable for CI scripts and automated code-mods.
```bash
# Substitute and write back
hjkl --headless +:%s/old/new/g +:wq src/foo.rs
# Same with -c flag (colon is optional)
hjkl --headless -c '%s/old/new/g' -c 'wq' src/foo.rs
# Loop over many files
for f in src/**/*.rs; do
hjkl --headless +:%s/old/new/g +:wq "$f"
done
```
**Ordering**: all `-c CMD` flags run first (in flag order), then all `+cmd`
tokens (in argv order). The leading `:` is optional in both forms.
**No auto-write**: like vim, hjkl never writes implicitly. Include `:w`, `:wq`,
or `:x` in your command stream or the file is left unchanged.
**Exit codes**: `0` on success; `1` if any ex command returns an error or an I/O
failure occurs.
See [issue #26](https://github.com/kryptic-sh/hjkl/issues/26) for the
multi-phase roadmap (Phase 2: `--embed`, Phase 3: nvim-API msgpack-rpc).
### Embed mode (RPC)
`hjkl --embed` boots without a TUI and speaks JSON-RPC 2.0 over stdin/stdout
(newline-delimited, one request per line, one response per line). External code
can drive a live editor FSM — feed keystrokes, run ex commands, query buffer
state, cursor position, mode, and registers.
```bash
printf '{"jsonrpc":"2.0","method":"hjkl_input","params":["iHello"],"id":1}\n' \
'{"jsonrpc":"2.0","method":"hjkl_get_buffer","params":[],"id":2}\n' \
| hjkl --embed
```
See [`docs/embed-rpc.md`](../../docs/embed-rpc.md) for the full method
catalogue, error codes, and examples. Phase 2 of
[issue #26](https://github.com/kryptic-sh/hjkl/issues/26).
## What works (v0)
- Normal / Insert / Visual / Command modes with full mode-indicator cursor shape
- All standard motions, operators, and text objects (free from the engine FSM)
- Status line: filename, mode, cursor position, dirty marker; `REC@r` badge
while recording a macro; pending count + operator; search count `[n/m]`
- Cursor-line background (subtle blue-grey; suppressed during `:` / `/` prompts)
- `:w` save, `:q` quit, `:wq` / `:x` write-quit, `:e` open file
- `:set` options, `:%s` search-and-replace with confirmation prompt
- `:!cmd` shell exec, `:r !cmd` / `:r file` read-into-buffer
- `:reg`, `:marks`, `:jumps`, `:changes` — output shown as a centered info popup
- `/` / `?` incremental search with match highlighting
- Undo / redo, marks, registers (shared across buffer slots)
- Terminal resize handled mid-frame
- Read-only guard (`-R` flag + engine-level mutation block)
- Jump to line (`+N`) and search-on-open (`+/pattern`)
- **Multi-buffer**: open many files (`hjkl a.rs b.rs c.rs`); tab line at top
when more than one buffer is open; switch with `:bn` / `:bp` / `:bd[!]` /
`:bfirst` / `:blast` / `:b N` / `:b name` / `:ls` / `:buffers`; alt buffer
(`Ctrl-^` / `:b#`); cycle with `Shift-H` / `Shift-L` and `gt` / `gT` / `]b` /
`[b`; bulk save/quit with `:wa` / `:qa[!]` / `:wqa[!]`; helix-style `:q`
closes the active slot when more than one buffer is open
- **Fuzzy file picker** (`<Space><Space>` / `<Space>f` / `:picker` /
`hjkl +picker`) with syntax-highlighted preview
- **Buffer picker** (`<Space>b` / `:bpicker`)
- **Grep picker** (`<Space>/` / `:rg <pattern>`) — ripgrep-backed content search
with grep / findstr fallback; preview jumps to and highlights the match line
- **Tree-sitter syntax highlighting** (Rust, Markdown, JSON, TOML, SQL bundled)
- **Comment marker overlay** — `TODO` / `FIXME` / `FIX` / `NOTE` / `INFO` /
`WARN` markers highlighted; consecutive single-line comments inherit the
marker
- **Smart indent** — Enter / `o` / `O` auto-indent after `{` / `(` / `[`; close
brace on a new line auto-dedents
- **`.editorconfig` support** — `indent_style`, `indent_size`, `tab_width`, and
`max_line_length` applied on file open
- **Tab settings**: `tabstop`, `softtabstop`, `expandtab` (defaults: 4-space
soft tabs); tabs render as visually aligned spaces; Backspace deletes a soft
tab as a unit; `:set tabstop=N` updates rendering end-to-end
- **Per-buffer git diff signs** (`+` / `~` / `_` in the gutter) and tree-sitter
diagnostic signs
## What's deferred
- Splits / multiple windows
- Plugins / config files
- LSP
## Related crates
- [`hjkl-buffer`](https://crates.io/crates/hjkl-buffer) — rope-based buffer
- [`hjkl-engine`](https://crates.io/crates/hjkl-engine) — modal-editing FSM
- [`hjkl-editor`](https://crates.io/crates/hjkl-editor) — ex commands, search,
shell exec
- [`hjkl-bonsai`](https://crates.io/crates/hjkl-bonsai) — bundled tree-sitter
grammars + Neovim-flavoured highlight themes
- [`hjkl-clipboard`](https://crates.io/crates/hjkl-clipboard) — system clipboard
adapter
- [`hjkl-form`](https://crates.io/crates/hjkl-form) — single-line form input
built on the engine (used by pickers, `:` / `/` prompts)
- [`hjkl-picker`](https://crates.io/crates/hjkl-picker) — fuzzy picker subsystem
(`Picker`, `PickerLogic`, `FileSource`, `RgSource`, scorer)
- [`hjkl-ratatui`](https://crates.io/crates/hjkl-ratatui) — ratatui rendering
adapters + shared spinner
See [docs.rs/hjkl-engine](https://docs.rs/hjkl-engine) for the engine trait
reference.
## Links
- Website: <https://hjkl.kryptic.sh>
- Repository: <https://github.com/kryptic-sh/hjkl>
## License
MIT. See [LICENSE](../../LICENSE).