vorto 0.15.4

A Vim-flavored modal terminal editor with batteries included: tree-sitter, LSP, fuzzy pickers, vim-surround, multi-cursor, and optional Copilot.
vorto-0.15.4 is not a library.

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-server and an :agent pane that runs an AI coding agent inside the editor — both silent when not configured.

Installation

From crates.io:

cargo install vorto

From source:

git clone https://github.com/vorto-editor/vorto.git
cd vorto
make install            # installs to ~/.local/bin
# or
cargo build --release   # binary at target/release/vorto

Requires a Rust toolchain (edition 2024). A C compiler is needed when building tree-sitter grammars.

vorto [FILE]
vorto -h | --help
vorto -V | --version

Features

Editing

  • Normal / Insert / Visual (char, line, block) / Command modes
  • Operators: d y c > <
  • 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-aware if af (function), ic ac (class), i, a, (parameter)
  • Multi-cursor: + add next match, Shift-Down add below, - pop, <space>, clear
  • Code folding: za toggle, zo open, zc close the fold under the cursor; zR open all, zM close all. Fold ranges come from a language's tree-sitter folds.scm when available, falling back to indentation so folding works in any buffer. A collapsed fold shows a ⋯ N lines marker on its header row; vertical motions step over hidden lines. Folds are per-pane and survive buffer switches
  • Jump labels: gw (easymotion-style 2-char word jumps)
  • Jump history: <C-o> / <C-i> (or Tab) walk the per-pane jumplist; :jumps / <space>j open a fuzzy picker over it
  • Bookmarks (harpoon-style): <space>ma add, <space>md remove, <space>mm open the picker; :bookmarks (alias :bm) takes add / 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 via arboard

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 44 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, julia, gleam, scala, odin, proto, cmake, xml.
  • Install on demand — only the grammars you use are built and cached:
    vorto grammar list
    vorto grammar install rust python
    vorto grammar install --all
    vorto grammar install-queries rust
    vorto grammar remove rust
    
  • Or from inside the editor with :grammar — opens a modal listing every grammar and its install status; j/k to move, Enter to install the selected grammar (asynchronously, in the background), d to 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.scm for coloring, indents.scm for auto-indent, textobjects.scm for tree-sitter text objects, and folds.scm for syntax-aware code folding (indentation-based folds when absent).
  • 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
    • Changed files — <space>g (files differing from HEAD)
    • Document symbols — <space><space> (LSP)
  • File explorer tree on <space>e — navigate with j k l / arrows, toggle hidden files with ., toggle .gitignored files with h, filter with /, and create / delete / rename / move with a / 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

  • :theme opens a filterable picker that previews each theme live on the current buffer as you move the cursor; Enter applies and persists it to config.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 ansi theme that uses your terminal's own palette. See Themes for the full reference.

AI (optional)

  • Inline completions — if copilot-language-server is on your PATH, 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 — :agent opens 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 :agent launches the configured default, or opens a picker the first time and remembers your choice. Re-running :agent focuses 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 except Ctrl-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 @file go further: they build a prompt about the active buffer and send it to the agent. Use @selection instead of @file to scope it to the visually-selected text: select in visual mode, press :, and the selection is captured for :agent explain @selection and embedded in the prompt as a code block. An unsaved or scratch buffer used as @file is 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 in config.toml (see below).

Git

  • Diff gutter: + added, ~ modified, ⋮ deleted marker
  • File picker honors .gitignore and your global excludes file
  • Status bar surfaces buffer dirty state
  • Conflict markers: <<<<<<< / ======= / >>>>>>> blocks (and the diff3 ||||||| base) are highlighted — a colored bar on each marker line and a dim tint on the "ours" / "theirs" sides, layered under syntax. Jump between conflicts with ]c / [c, and resolve the one at the cursor with :conflict ours / theirs / both / none (undoable). Works on both git conflicts and the autoreload = "merge" markers below.

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 with u). 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) vs disk) 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 :agent launcher:

    [agent]
    default = "claude"      # bare :agent launches this; unset → picker
    
    [agents.claude]         # override a built-in or add a new agent
    command = "claude"
    args = ["--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_args = ["{prompt}"]
    

    A workspace-local .vorto/config.toml takes precedence over the global file when present.

  • grammars/ — installed tree-sitter .so libraries

  • queries/<lang>/ — installed highlights.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
keyword           = "mauve"
"function.macro"  = { fg = "mauve", modifiers = ["bold"] }
comment           = { fg = "#6c7086", modifiers = ["italic"] }
"ui.selection"    = { bg = "#313244" }

[palette]            # must come last (a TOML table header captures the
mauve = "#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

at your option.