Skip to content

Configuration

CtrlUserKnown edited this page Aug 18, 2026 · 1 revision

Configuration

ctrlvim is configured in TOML rather than a config script. ~/.config/ctrlvim/config.toml is written for you the first time cvi runs, and is never overwritten once it exists.

The split that makes a TOML config work for an editor as extensible as Neovim is declarative versus imperative. TOML expresses the wiring: which options are set, which key runs which command, which event triggers which command, which plugins to load. Anything that needs actual logic lives in a plugin that the config then refers to by name. See Plugins for how that side works, and Language Servers for the separate lsp.lua file that declares language servers the same way real Neovim does.

The bridge between the two is the Ex command. A keymap's right hand side and an autocommand's command are both ordinary : commands, so a plugin contributes behavior by registering a command like :Format, and the config just names it.

[ui]

[ui]
drawer = false     # open the file drawer (Ctrl+B sidebar) on startup
sidebar = false     # legacy alias for drawer
tabs = false        # show the tab bar; off by default
mouse = true        # mouse support; wheel, clicks on rows/tabs/toggles
icons = "auto"      # "auto" | "nerd" | "text"
theme = "Tokyo Night"

These same keys are also readable at the top level of the file without the [ui] table, for backward compatibility. CTRLVIM_NERD_FONT=1 or =0 overrides icons = "auto" at the environment level.

[options]

[options] is deliberately untyped. Every key becomes a :set argument, so any option the editing engine understands works here immediately, with no change needed to the config parser.

[options]
number = true
wrap = false
tabstop = 4
shiftwidth = 4
foldmethod = "indent"

A boolean true becomes a bare :set flag, false becomes the no prefixed form, and strings and integers pass through as key=value.

[keymaps]

Settings about the mapping table itself, separate from the individual [[keymap]] entries below.

[keymaps]
defaults = true   # false starts from an empty mapping table
leader = " "      # what <leader> expands to; only the first character is used

[[keymap]]

[[keymap]]
mode = "n"                  # n, i, v, ... defaults to "n"
lhs = "<leader>f"
rhs = ":Files<CR>"
desc = "fuzzy file browser"

lhs and rhs use the same <...> notation Vim does: <leader>, <C-x>, <A-x> (or <M-x>), <C-S-x>, arrow keys, F-keys, and <S-Tab> are all bindable, in Normal, Insert, and Visual mode. Overlapping chords resolve on the timeoutlen option the way Vim's do, so <leader>q and <leader>qq can coexist.

desc is what ? and the which-key popup show for the mapping. Both read the live mapping table, so a mapping added here appears in the help screen with no other change, and a desc you never set falls back to showing the raw right hand side instead.

A mapping whose lhs does not parse is reported in the status line rather than silently dropped.

[[unmap]]

Removes a built in mapping outright, for a chord you never use and want gone rather than merely shadowed.

[[unmap]]
mode = "n"
lhs = "<A-j>"

Binding the same lhs with [[keymap]] already shadows a default; [[unmap]] is for when you want the key to do nothing at all, or [keymaps] defaults = false to drop every built in mapping at once.

[[command]]

Defines a user : command as an alias for an Ex command line, evaluated before keymaps so a mapping's right hand side can refer to a command config itself just defined.

[[command]]
name = "RunPython"
expansion = "!python3 %:p"

[[autocmd]]

[[autocmd]]
event = "BufWritePre"
pattern = "*.rs"
command = "Format"

pattern defaults to * and matches against the active buffer's label.

[[plugin]]

See Plugins for the full picture. In brief:

[[plugin]]
name = "hello"
path = "~/.config/ctrlvim/plugins/hello.lua"
event = "BufWritePre"   # omit to load eagerly at startup
enabled = true           # false keeps it declared without loading it

[filetype]

Extends filetype detection without needing a compiled grammar change.

[filetype.extension]
zig = "zig"
mdx = "markdown"

[filetype.filename]
Justfile = "just"

[filetype.pattern]
"*.frobnicate" = "frob"

Declaring a filetype here does not by itself add syntax highlighting, that needs a tree sitter grammar compiled in. What it does give a buffer is an identity: this is what lsp.lua's filetypes field matches against, and what gets reported to a language server.

Editing configuration from the Settings tab

The dashboard's Settings tab can flip a handful of the most common [ui] and [options] values live, and writes the change straight back to config.toml. That write goes through a TOML editor that preserves formatting rather than re-serializing the whole file, so a hand written config keeps its comments, its ordering, and every section the Settings tab does not manage, such as your [[keymap]] entries.

Full example

[ui]
drawer = true
mouse = true
icons = "nerd"

[options]
number = true
relativenumber = true
ignorecase = true
smartcase = true

[keymaps]
leader = " "

[[keymap]]
lhs = "<leader>f"
rhs = ":Files<CR>"
desc = "fuzzy file browser"

[[autocmd]]
event = "BufWritePre"
pattern = "*.rs"
command = "Format"

[[plugin]]
name = "hello"
path = "~/.config/ctrlvim/plugins/hello.lua"

Clone this wiki locally