vorto
A Vim-flavored modal terminal editor, written in Rust.
Vorto is…
a modal terminal text editor with batteries included. Tree-sitter highlighting, Language Server Protocol support, fuzzy pickers, an in-editor AI agent pane, and optional Copilot inline completions — all in a single, dependency-light binary that starts instantly and needs no Node toolchain, plugin manager, or external repos to clone.
Why vorto
- Batteries included, not assembled. LSP, tree-sitter, fuzzy pickers, a file explorer, git gutter, themes, multi-cursor, and bookmarks all work out of the box — there is no plugin manager to learn and nothing to wire together.
- A single static binary. Pure Rust, no runtime dependencies beyond a C compiler for building grammars on demand.
- No Node, no clones. Tree-sitter grammars install on demand — no
tree-sitter-cli, no external repos, no Node toolchain. - Responsive by design. An async architecture keeps the UI snappy while language servers index and grammars parse in the background.
- Familiar. Vim-style modal editing with operators, motions,
tree-sitter text objects, multi-cursor, jump labels, bookmarks, and
.-repeat. - Themable. Helix-compatible TOML themes — most Helix theme files drop in unchanged.
- Optional AI. Ghost-text inline completions via
copilot-language-serverand an:agentpane that runs an AI coding agent inside the editor — both silent when not configured.
Installation
From crates.io:
From source:
# or
Requires a Rust toolchain (edition 2024). A C compiler is needed when building tree-sitter grammars.
|
|
Features
Editing
- Normal / Insert / Visual (char, line, block) / Command modes
- Operators:
dyc>< - Motions:
h j k l,w b e W B E ge gE,f F t T ; ,,gg G H M L,{ },%,<C-f> <C-b> <C-d> <C-u> - Search:
/ ?,n N,* #,gn gN - Text objects:
iw aw,i" a",i( a(,i{ a{,i[ a[,ip ap, plus tree-sitter-awareif af(function),ic ac(class),i, a,(parameter) - Multi-cursor:
+add next match,Shift-Downadd below,-pop,<space>,clear - Jump labels:
gw(easymotion-style 2-char word jumps) - Jump history:
<C-o>/<C-i>(orTab) walk the per-pane jumplist;:jumps/<space>jopen a fuzzy picker over it - Bookmarks (harpoon-style):
<space>maadd,<space>mdremove,<space>mmopen the picker;:bookmarks(alias:bm) takesadd/delete/list. Marked lines show a●in the gutter and persist per-project across restarts - Per-buffer cursor memory: switching back to a buffer restores the cursor where you left it (tracked independently per pane)
- Auto-pair brackets and quotes, language-aware comment toggle
(
<space>c), case toggle, line join, repeat with. - Undo / redo (
u/<C-r>), system clipboard yank/paste viaarboard
Language Server Protocol
| Feature | Binding / Trigger |
|---|---|
| Diagnostics | inline, navigate with ]d / [d |
| Hover | K (scrollable markdown popup) |
| Completion | <C-n> / <C-p> + trigger chars |
| Signature help | auto on ( / , |
| Code actions | <space>a |
| Goto definition | gd |
| Goto declaration | gD |
| Goto implementation | gi |
| References | gr (preview picker) |
| Rename | <space>r |
| Format on save | :w runs configured formatter |
Servers and formatters ship with built-in defaults for the common
languages (rust-analyzer, pyright, gopls, clangd, vtsls, and ~30
more). Override or add to them per-language in config.toml.
Tree-sitter
- Built-in grammar recipes for 37 languages: rust, python, go, javascript, typescript, tsx, toml, kotlin, c, cpp, java, bash, json, yaml, markdown, html, css, lua, ruby, zig, sql, dockerfile, make, hcl, diff, vue, svelte, haskell, elixir, nix, c-sharp, swift, php, dart, ocaml, graphql, fish.
- Install on demand — only the grammars you use are built and cached:
- Or from inside the editor with
:grammar— opens a modal listing every grammar and its install status;j/kto move,Enterto install the selected grammar (asynchronously, in the background),dto remove. The buffer re-highlights the moment an install finishes — no restart.:grammar install <name>…and:grammar remove <name>…work inline too, mirroring the CLI. - Uses
highlights.scmfor coloring,indents.scmfor auto-indent, andtextobjects.scmfor tree-sitter text objects. - Falls back to plain text when a grammar is unavailable.
UI
- Fuzzy pickers with live syntax-highlighted preview:
- Files —
:e(git-aware) - Buffers —
:ls/:buffers - Document symbols —
<space><space>(LSP)
- Files —
- File explorer tree on
<space>e— navigate withj k l/ arrows, toggle hidden files with., toggle.gitignored files withh, filter with/, and create / delete / rename / move witha/d/r/m - Splits:
:split/:vsplit,<space>w h/<space>w v, cycle with<C-w w> - Status bar with mode badge, filename, cursor position, dirty flag
- Configurable indentation guides (line / dot, skip levels)
- Mode-specific cursor shapes (block / bar / underline)
- Mouse support: click to move cursor, scroll to scroll
- Non-blocking toast notifications
Theming
:themeopens a filterable picker that previews each theme live on the current buffer as you move the cursor; Enter applies and persists it toconfig.toml, Esc reverts.- Helix-compatible TOML themes — a flat scope → color map with an
optional
[palette], so most Helix theme files drop in unchanged. - Dozens of built-ins (Catppuccin, tokyonight, nord, dracula, gruvbox,
rose-pine, kanagawa, ayu, …) plus an
ansitheme that uses your terminal's own palette. See Themes for the full reference.
AI (optional)
- Inline completions — if
copilot-language-serveris on yourPATH, vorto enables ghost-text inline completions: accept with<Tab>, dismiss with<Esc>. Missing the binary is a no-op — no errors, no prompts. - Agent launcher —
:agentopens an AI coding agent in a built-in pane inside vorto, running under a pseudo-terminal alongside your buffers (no external multiplexer required). A bare:agentlaunches the configured default, or opens a picker the first time and remembers your choice. Re-running:agentfocuses the existing pane instead of spawning another; the agent process keeps running even if you close its pane. While the agent pane is focused, every key goes to the agent exceptCtrl-W, which is reserved for window navigation (Ctrl-W h/j/k/l/w) so you can move focus back to a buffer.:agent explain @file/:agent chat @filego further: they build a prompt about the active buffer and send it to the agent. Use@selectioninstead of@fileto scope it to the visually-selected text: select in visual mode, press:, and the selection is captured for:agent explain @selectionand embedded in the prompt as a code block. An unsaved or scratch buffer used as@fileis snapshotted to a temp file first so the agent has something on disk to read. Built-in catalog: claude, codex, gemini, aider — override commands/args or the default inconfig.toml(see below).
Git
- Diff gutter:
+added,~modified,⋮deleted marker - File picker honors
.gitignoreand your global excludes file - Status bar surfaces buffer dirty state
Auto-reload
When the active buffer's file changes on disk, vorto reacts according to
the autoreload setting ([editor], overridable per language):
"replace"(default) — prompt to reload; if the buffer is dirty it warns that unsaved edits will be replaced (undo withu). Declining suppresses re-prompts until the file changes again."merge"— follow the external edit via a three-way merge instead of prompting; conflicts are written inline with<<<<<<</=======/>>>>>>>markers (local (your edits)vsdisk) and the result is undoable."none"— disable the watcher; reload manually with:reload.
Configuration
Configuration lives under $XDG_CONFIG_HOME/vorto/ (typically
~/.config/vorto/):
-
config.toml— editor settings, keymap, theme, per-language LSP / formatter / indent overrides, a[finder]table (hidden_patterns,max_items) controlling what the file picker and explorer treat as hidden, and an[agent]/[agents.*]section for the:agentlauncher:[] = "claude" # bare :agent launches this; unset → picker [] # override a built-in or add a new agent = "claude" = ["--model", "opus"] # How `:agent explain @file` passes its prompt at launch. `{prompt}` is # substituted with the text. Defaults to ["{prompt}"] (positional, as # claude/codex accept); aider needs ["--message", "{prompt}"]; set [] to # opt an agent out of launch-time seeding. = ["{prompt}"]A workspace-local
.vorto/config.tomltakes precedence over the global file when present. -
grammars/— installed tree-sitter.solibraries -
queries/<lang>/— installedhighlights.scm,indents.scm,textobjects.scm -
themes/<name>.toml— color themes (see below)
Themes
:theme opens a filterable picker (/ to filter, j/k to move) that
previews each theme live on the current buffer as you move the cursor;
Enter applies and saves theme = "<name>" to config.toml, Esc reverts.
Themes are Helix-compatible TOML — a flat scope → color map with an
optional [palette], so most Helix theme files drop in unchanged:
# ~/.config/vorto/themes/mytheme.toml
= "mauve"
= { = "mauve", = ["bold"] }
= { = "#6c7086", = ["italic"] }
= { = "#313244" }
[] # must come last (a TOML table header captures the
= "#cba6f7" # keys after it)
Color values are a [palette] name, a #rrggbb (or #rgb) hex literal,
or an ANSI color name. Scopes cover tree-sitter highlight captures
(keyword, function.method, …) and editor chrome — ui.background
(paints the whole editor; a theme that sets it recolors the background,
one that omits it keeps the terminal's), ui.selection, ui.linenr,
ui.statusline, ui.popup, ….
Built-in themes: ansi (terminal palette), the Catppuccin flavors
(catppuccin-latte, -frappe, -macchiato, -mocha), tokyonight,
nord, dracula, onedark/onelight, rose-pine, gruvbox-dark/
-light, everforest-dark/-light, kanagawa, solarized-dark/
-light, ayu-dark/-mirage/-light, and monokai-pro.
A file in themes/ shadows a built-in of the same name. The special
theme ansi uses your terminal's own 16-color palette and is always
available. Set the startup theme with theme = "<name>" in config.toml.
See the documentation site for the full configuration reference.
License
Licensed under either of
- MIT License (LICENSE-MIT)
- Apache License, Version 2.0 (LICENSE-APACHE)
at your option.