Read this in other languages: 简体中文
The project monkey-vim, aims to make a powerful and fast terminal-native IDE.
Positioning: monkey-vim targets pure terminal environments — no GUI, no gvim, no built-in terminal multiplexing. Use it in:
| Environment | Description |
|---|---|
| Linux Terminal | xterm, kitty, alacritty, wezterm, gnome-terminal, etc. |
| macOS Terminal | Terminal.app, iTerm2, kitty, etc. |
| WSL | Windows Subsystem for Linux (WSL2 recommended) |
| Server TTY | Bare Linux console (tty1–tty63), Vim default 8/16-color highlighting (sonokai needs ≥256 colors) |
| kmscon | Kernel Mode Setting console — modern TTY replacement with true color and Unicode support |
Top-level workspace management (multiple sessions and terminals) and AI integration (agent TUIs such as Claude Code or opencode) are both delegated to tmux or your terminal emulator's tabs; in-editor splits and tabs work as usual.
- vim 9.0+ (9.1.1984+ for the OSC 52 clipboard over SSH; the one-click installer builds a current Vim)
- A terminal environment (no GUI / gvim support)
Pick one of the two ways below: a one-click script, or manual setup.
Build Vim and install monkey-vim with all dependencies and plugins automatically:
curl -fsSL https://raw.githubusercontent.com/QMonkey/monkey-vim/master/install.sh | bashWhat the script does, step by step:
- Install Vim build dependencies (GTK3/4 + Wayland or X11 per display server; Python3/Perl/Ruby/Lua)
- Pre-authorize
sudoonce and keep the credentials alive in a background loop, so long downloads/compiles never trigger a mid-run password re-prompt (unattended runs won't stall) - Install Homebrew (Linuxbrew) as the fallback package manager — its shellenv is persisted to your shell rc files (with PATH dedup guards) even when Homebrew already existed
- Clone and compile Vim from source, then
make install - Clone monkey-vim to
~/Documents/monkey-vim(or update it if already cloned) - Install required tools + optional LSP servers via
checkhealth.sh --install(apt/zypper/dnf/pacman/brew, npm, pip, go install, rustup). npm is installed explicitly when missing (Debian/Ubuntunodejsalone doesn't provide it); global npm packages skipsudowhenever the npm prefix is user-writable; fzf prefers Homebrew so you get a current version instead of the distro's - Persist
~/go/bin,~/.cargo/bin(and/usr/local/bin) in your shell rc files - Symlink
.vimrc,.clang-format, and the efm-langserver config; create runtime directories - Install all Vim plugins (
:PlugInstall) automatically
The script keeps the Vim source tree at
~/Documents/vim(no cleanup), so you can rebuild later withgit pull+make.The script only rebuilds Vim when the installed one is below 9.0 or its
vim --versionfeatures are incomplete — version alone isn't enough. The required features mirror the builds below:+clipboardand+clipboard_provider(clipboard providers power the osc52/tmux fallbacks; the feature landed in 9.1.1857, so distro builds of 9.1.0–9.1.1846 are rebuilt) plus, per platform,+xterm_clipboard(WSL),+wayland_clipboardor+xterm_clipboard(Linux desktop); the core set is+python3 +lua +perl +ruby +terminal +cscope +multi_byte.PATH changes only apply to shells started after the install. When it finishes, the script prints how to apply them to the current terminal (
source <rc file>orexec $SHELL).
Install by hand, following the steps in order:
git clone https://github.com/QMonkey/monkey-vim.git| Tool | Purpose | Required |
|---|---|---|
| curl | Plugin manager bootstrap | Yes |
| git | Plugin manager, vim-fugitive | Yes |
| ripgrep (rg) | ctrlsf code search + fzf.vim file search | Yes |
| universal-ctags | gutentags tag generation | Yes |
GNU Global (global) |
gutentags gtags (GTAGS) generation & navigation | Recommended |
Pygments (pygmentize) |
gtags parser for non-C/C++ languages (Python, Go, Rust, JS, etc.) | Recommended |
| fzf | Fuzzy finder (fzf.vim) | Yes |
| bat | Syntax-highlighted file preview in fzf | Recommended |
| Homebrew | Fallback package manager for tools not in system repos (lua-language-server, marksman, fzf) | Required |
# Install Homebrew (all Linux distros — required for tools not in system repos)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
# Ubuntu/Debian
sudo apt-get install curl git ripgrep universal-ctags global python3-pygments nodejs npm gcc
brew install fzf bat
# OpenSUSE
sudo zypper install curl git ripgrep universal-ctags global python3-Pygments fzf bat nodejs npm gcc
# CentOS (enable EPEL for ripgrep/ctags/global/pygments/fzf/bat)
sudo dnf install epel-release
sudo dnf install curl git ripgrep universal-ctags global global-ctags python3-pygments fzf bat nodejs npm gcc
# Arch Linux
sudo pacman -S curl git ripgrep ctags global python-pygments fzf bat nodejs npm gcc
# macOS
brew install curl git ripgrep universal-ctags global pygments fzf bat nodeLanguage Server Protocol support is provided by yegappan/lsp. Install the servers for languages you use:
| Language | LSP Server | Install |
|---|---|---|
| C/C++ | clangd | sudo apt-get install clangd, sudo zypper install clang, sudo dnf install clang-tools-extra, sudo pacman -S clang, or brew install llvm |
| Go | gopls | go install golang.org/x/tools/gopls@latest |
| Python | python-lsp-server | pip3 install python-lsp-server |
| Zig | zls | brew install zls (recommended, keeps zig/zls matched) or download from https://zigtools.org/zls/install/ |
| Rust | rust-analyzer | rustup component add rust-analyzer |
| Lua | lua-language-server | brew install lua-language-server or sudo pacman -S lua-language-server |
| Shell | bash-language-server | npm install -g bash-language-server |
| Vim | vim-language-server | npm install -g vim-language-server |
| JavaScript | typescript-language-server | npm install -g typescript-language-server typescript |
| TypeScript | typescript-language-server | npm install -g typescript-language-server typescript |
| JSON | vscode-json-language-server | npm install -g vscode-langservers-extracted |
| YAML | yaml-language-server | npm install -g yaml-language-server |
| Markdown | marksman | brew install marksman or sudo pacman -S marksman |
| Markdown | efm-langserver | go install github.com/mattn/efm-langserver@latest |
Some LSP servers offload formatting/linting to external tools that must be installed separately. Without them the feature silently degrades (falls back to built-in diagnostics or skips the tool):
| Language | Tool | Role | Install |
|---|---|---|---|
| C/C++ | clang-tidy | linter (via clangd --clang-tidy) |
sudo apt-get install clang-tidy, sudo zypper install clang, sudo dnf install clang-tools-extra, sudo pacman -S clang, or brew install llvm |
| Go | staticcheck | linter (via gopls staticcheck) |
go install honnef.co/go/tools/cmd/staticcheck@latest |
| Shell | shfmt | formatter (via bash-language-server) |
go install mvdan.cc/sh/v3/cmd/shfmt@latest |
| Python | black | formatter (via pylsp black plugin) |
pip3 install black |
| Markdown | prettier | formatter (via efm-langserver) |
npm install -g prettier |
| Markdown | markdownlint-cli2 | linter (via efm-langserver) |
npm install -g markdownlint-cli2 |
# Ubuntu/Debian
sudo apt-get install gcc g++ clangd clang-tidy
# OpenSUSE
sudo zypper install gcc gcc-c++ clang
# CentOS
sudo dnf install gcc gcc-c++ clang clang-tools-extra
# Arch Linux
sudo pacman -S gcc clang
# macOS
brew install gcc llvm# Install the latest version of Go, then:
go install golang.org/x/tools/gopls@latest
# Optional: staticcheck linter (used by gopls)
go install honnef.co/go/tools/cmd/staticcheck@latest# Python 3 is required (install via system package manager if not present)
pip3 install python-lsp-server
# Optional: formatters/linters (black is used by the pylsp black plugin)
pip3 install black autopep8 flake8 pylint# Install LSP server
npm install -g typescript-language-server typescriptZig syntax highlighting, indentation, and filetype detection are built into Vim 9.2+ — no plugin needed. Install Zig and the ZLS language server:
# Recommended: Homebrew keeps zig and zls versions in sync
brew install zig zls # macOS / Linuxbrew
# Or download matched prebuilt binaries:
# zig: https://ziglang.org/download/
# zls: https://zigtools.org/zls/install/Important: zls is tied to a specific Zig version and refuses to start on a mismatch. Install
zigandzlsfrom the same source (Homebrew or the official download tool) so they stay in sync. Distro packages often lag: Ubuntu/Debian stable ship nozig, and Arch'szlstrails Arch'szig, so they usually mismatch.
Format-on-save uses ZLS (matches zig fmt); no separate formatter is needed. Build-on-save diagnostics (enable_build_on_save) can be enabled in a zls.json next to build.zig.
# Install rustup (includes rustc & cargo), then:
rustup component add rust-analyzer# Install LSP server
npm install -g yaml-language-server# Install LSP server, then the shfmt formatter it depends on
npm install -g bash-language-server
go install mvdan.cc/sh/v3/cmd/shfmt@latestPreview Markdown in browser via WSL/glow:
# Option 1: glow (terminal Markdown renderer)
# https://github.com/charmbracelet/glow
brew install glow # macOS / Linuxbrew
sudo pacman -S glow # Arch Linux
sudo apt-get install glow # Debian 13+
go install github.com/charmbracelet/glow@latest # Ubuntu / OpenSUSE / CentOS, or any platform with Go
# Option 2: Open in Windows browser (WSL only)
# :!explorer.exe %Format & lint are provided by efm-langserver (formatter: prettier, linter: markdownlint-cli2):
go install github.com/mattn/efm-langserver@latest
npm install -g prettier markdownlint-cli2
# Link the efm config (config.yaml + .markdownlint.jsonc) to efm's default path
ln -sf $(pwd)/configs/efm-langserver ~/.config/efm-langserverVim uses common Unicode characters (⎇, │, ▸, ·, ¬) and works without extra fonts. A Nerd Font is optional if you prefer the Powerline-style look.
Verify that all required dependencies and optional LSP servers are available:
./checkhealth.shPass --install to automatically install missing dependencies (required tools + optional LSP servers). Supports apt/zypper/dnf/pacman/brew, npm, pip, go install, and rustup:
./checkhealth.sh --install- Linux, Mac, WSL, and kmscon
cd monkey-vim
ln -sf $(pwd)/.vimrc ~/.vimrc
ln -sf $(pwd)/configs/.clang-format ~/.clang-format # global clang-format style (optional)
ln -sf $(pwd)/configs/efm-langserver ~/.config/efm-langserver # efm: markdown format/lint (optional)
vimcd monkey-vim
git pull:PlugInstall
:PlugUpdate
:PlugUpgrade
:PlugCleankmscon is a Linux KMS/DRM-based system console that replaces the legacy tty with full Unicode support, multi-seat capability, and true color rendering. It is an excellent companion for monkey-vim on headless servers.
# Ubuntu/Debian (older versions without terminfo)
sudo apt-get install kmscon
# OpenSUSE (Tumbleweed / Leap 15.x)
sudo zypper install kmscon
# Arch Linux
sudo pacman -S kmscon
# CentOS — not in official/EPEL repos, build from source below instead
# Build from source (requires meson, ninja, and ncurses for tic)
git clone https://github.com/kmscon/kmscon.git
cd kmscon
meson setup builddir/
meson install -C builddir/Building from source automatically compiles and installs the kmscon terminfo entry via tic, so vim can detect terminal capabilities correctly without any TERM workaround. The default prefix is /usr/local; append --prefix=/usr to the meson setup command to install system-wide.
On older systems, dependencies like libtsm may be too old to satisfy the build requirements. In that case, use the package manager version and apply the TERM workaround in section 6.3.
To make kmscon the default system console instead of the legacy tty/getty, replace agetty with kmscon on the desired tty:
# Stop the existing getty on tty1
sudo systemctl stop getty@tty1.service
sudo systemctl disable getty@tty1.service
# Create a kmscon service for tty1
sudo mkdir -p /etc/systemd/system/getty.target.wants
sudo ln -s /usr/lib/systemd/system/kmsconvt@.service \
/etc/systemd/system/getty.target.wants/kmsconvt@tty1.service
# Override ExecStart to use kmscon's own terminal type
sudo systemctl edit kmsconvt@tty1.serviceAdd the following override:
[Service]
ExecStart=
ExecStart=/usr/bin/kmscon "--vt=%I" --seats=seat0 --no-switchvt --login -- /sbin/agetty -o '-p -- \\u' - kmsconThe last argument kmscon is agetty's <termtype> positional argument and sets TERM=kmscon, which matches the terminfo entry installed during build.
The terminal type differs by kmscon version, because the kmscon terminfo entry is only shipped since 10.0.0:
# kmscon 10.0.0+ (ships scripts/terminfo/kmscon.ti, default TERM=kmscon)
ExecStart=/usr/bin/kmscon "--vt=%I" --seats=seat0 --no-switchvt --login -- /sbin/agetty -o '-p -- \\u' - kmscon
# kmscon 9.x (no kmscon terminfo entry; use xterm-256color)
ExecStart=/usr/bin/kmscon "--vt=%I" --seats=seat0 --no-switchvt --login -- /sbin/agetty -o '-p -- \\u' - xterm-256colorIf your agetty build supports the --noclear flag, you may insert it before the - to keep the kmscon splash on the login prompt; it is purely cosmetic.
# Start kmscon on tty1
sudo systemctl start kmsconvt@tty1.serviceAfter reboot, press Ctrl+Alt+F1 to switch to the kmscon-enhanced tty1. You can repeat this for tty2–tty6 as needed.
systemctl start runs a unit once and ignores the [Install] section entirely, so it never touches autovt@.service. systemctl enable reads [Install] and creates symlinks, including the Alias=autovt@.service.
tty2–tty6 are not started from getty.target.wants; systemd-logind spawns each newly-activated VT as autovt@ttyN.service, which resolves through the autovt@.service alias. That alias ships in Debian/Ubuntu's kmsconvt@.service:
[Install]
WantedBy=getty.target
DefaultInstance=tty1
Alias=autovt@.serviceSo:
systemctl enable kmsconvt@tty1.service→ only tty1 (instance aliasautovt@tty1.service).systemctl enable kmsconvt@.service(template, no ttyN) → every VT, because it creates/etc/systemd/system/autovt@.service -> kmsconvt@.service.
The ln -s ... kmsconvt@tty1.service + start flow above therefore affects only tty1. If tty2–tty6 unexpectedly become kmscon, check for a leftover alias (see 6.5 to revert).
kmscon supports true color (24-bit). monkey-vim detects this automatically via has('termguicolors') and renders GUI colors directly.
If kmscon was installed via package manager (older versions without terminfo) or the terminfo entry is missing, vim may fail with E558: Terminal entry not found in terminfo. In that case, add the following to your shell profile:
# Add to your shell profile (~/.bashrc, ~/.zshrc, etc.)
export TERM=xterm-256color
export COLORTERM=truecolorThe COLORTERM=truecolor is required so vim still detects true color support when TERM is set to xterm-256color. Note that using xterm-256color instead of kmscon's native terminfo may cause minor display artifacts in vim due to terminal capability mismatches. For the best experience, build from source (10.0.0+) to get the native terminfo entry.
If you run tmux inside kmscon, tmux overrides $TERM with tmux / tmux-256color. This is expected and correct — do not change it back. tmux derives its internal TERM from the outer terminal and exposes its own accurate capabilities, so vim and other ncurses programs work correctly. Only the outer $TERM (before entering tmux) matters: keep it as kmscon on 10.0.0+ or xterm-256color on 9.x.
The Linux framebuffer console (tty1–tty63, TERM=linux) only exposes 8/16 colors (&t_Co < 256), which triggers sonokai's guard (&t_Co < 256 -> finish) and leaves Vim's built-in 8/16-color highlighting, so code stays readable. sonokai itself does not require true color — it renders fine with the cterm palette on any 256-color terminal — but it does refuse to load when fewer than 256 colors are available. For the full sonokai scheme on a physical console, replace tty with kmscon (section 6.2) or use any 256-color/true-color terminal.
If you run tmux on a bare tty (not kmscon), tmux defaults to default-terminal=tmux-256color, which advertises 256 colors and xterm-style key sequences to every program inside it — even though the underlying console only has 8/16 colors. monkey-vim already detects this (it walks the process tree to see the real tty behind the tmux client) and falls back to Vim's built-in highlighting, so vim itself stays correct regardless. Other programs, however, do not get that protection and may render 256-color escapes the console cannot show. To keep them correct, set tmux's terminal type to match the 8-color console:
# In ~/.tmux.conf — only for tmux running on a bare Linux tty
set -g default-terminal "tmux"
set -g terminal-overrides ",linux:colors=16"The first line makes tmux advertise a plain 8-color terminal to programs; the second tells tmux the underlying linux console has 16 colors (8 base + 8 bright) so it can downconvert sensibly. Do not add these lines when tmux runs under kmscon or a normal terminal emulator — there tmux-256color is correct.
kmscon uses the system's built-in font renderer. If you prefer Powerline-style icons, install a system monospace font of your choice.
To hand the virtual consoles back to agetty:
# Stop the kmscon instance
sudo systemctl stop kmsconvt@tty1.service
# Remove the tty1 wants link created in section 6.2
sudo rm -f /etc/systemd/system/getty.target.wants/kmsconvt@tty1.service
# Restore getty on tty1
sudo systemctl enable getty@tty1.service
sudo systemctl start getty@tty1.serviceIf you previously ran systemctl enable kmsconvt@.service (the template), the autovt@.service alias now points at kmscon and keeps replacing every VT. Revert it explicitly:
# Point autovt@.service back at getty (drop the kmscon alias)
sudo systemctl disable kmsconvt@.service
sudo rm -f /etc/systemd/system/autovt@.service
# Re-enable getty (also restores getty@tty1.service)
sudo systemctl enable getty@.service
# Reload so logind picks up the change for newly-activated VTs
sudo systemctl daemon-reloadVerify the alias points at getty again:
readlink -f /etc/systemd/system/autovt@.service /usr/lib/systemd/system/autovt@.serviceIt should resolve to getty@.service.
| Plugin | Purpose |
|---|---|
| yegappan/lsp | Language Server Protocol client |
| hrsh7th/vim-vsnip | Snippet engine |
| hrsh7th/vim-vsnip-integ | LSP snippet integration |
| rafamadriz/friendly-snippets | Snippet collection |
| junegunn/fzf.vim | Fuzzy file/buffer/tag finder |
| dyng/ctrlsf.vim | Async code search (rg/ag backend) |
| sainnhe/sonokai | Colorscheme |
| mg979/vim-visual-multi | Multiple cursors |
| monkoose/vim9-stargate | Easy motion (replaces vim-sneak) |
| tpope/vim-fugitive | Git wrapper |
| airblade/vim-gitgutter | Git diff in sign column |
| ludovicchabant/vim-gutentags | Automatic ctags & gtags (GNU Global) generation |
| justinmk/vim-dirvish | Directory viewer (replaces netrw) |
| tpope/vim-surround | Surround text with parens/quotes/etc |
| svermeulen/vim-subversive | Substitute with clipboard |
| andymass/vim-matchup | Extended % matching |
| wellle/targets.vim | Additional text objects |
| michaeljsmith/vim-indent-object | Indent-based text objects |
| cohama/lexima.vim | Auto-close brackets/parens |
| tpope/vim-repeat | Repeat plugin maps with . |
| tpope/vim-eunuch | UNIX shell helpers (:SudoWrite, :W, :Delete, etc.) |
| tpope/vim-obsession | Session management |
| Konfekt/FastFold | Faster folding for large files |
| haya14busa/vim-asterisk | Improved * / # search |
| kshenoy/vim-signature | Visual marks |
| junegunn/gv.vim | Git commit browser |
| romainl/vim-qf | Quickfix/Location list helpers |
The "Leader" key below means comma key.
s Replace a motion/text object with clipboard content (see §1.7)
S Replace from cursor to end of line with clipboard content (see §1.7)
Y Copy from the cursor position to the end of the line, same as y$
H To the first non-blank character of the line, same as ^
L To the last character of the line, same as $
U Redo, same as Ctrl-r
; Enter command line mode, same as :
q Quit current window (with special handling for diff/fugitive/quickfix)
Shift+q Quit vim, same as :qa
t Recording, same as the original q (normal and visual mode)
j Move down one display line (gj), works on wrapped lines
k Move up one display line (gk), works on wrapped lines
f Search 1 char to jump with hints (stargate)
F Search 2 consecutive chars to jump with hints (stargate)
gs Select words/regions for multi-cursor editing (vim-visual-multi)
The following remaps work in both Insert mode and Command-line mode:
Ctrl+p Move up (Up)
Ctrl+n Move down (Down)
Ctrl+b Move left (Left)
Ctrl+f Move right (Right)
Ctrl+a Jump to start (Home)
Ctrl+e Jump to end (End)
Ctrl+h Backspace (BackSpace)
Ctrl+d Delete forward (Del)
F1 Open CtrlSF search prompt
F2 Toggle CtrlSF search window
F3 Open a terminal at the bottom
F4 Toggle the global terminal at the bottom
F5 Toggle the global terminal on the right
Leader+o Open a new buffer with given file path in current window
[+b Jump to previous buffer
]+b Jump to next buffer
Leader+Leader+s Open a horizontal split with given file path in current window
Leader+Leader+v Open a vertical split with given file path in current window
Ctrl+h Jump to the left split
Ctrl+j Jump to the below split
Ctrl+k Jump to the above split
Ctrl+l Jump to the right split
Leader+z Toggle zoom
Leader+Leader+t Open a tab with given file path in current window
[+t Jump to previous tab
]+t Jump to next tab
Leader+1~9 Jump to the 1~9 tab
Leader+[ Jump to first tab
Leader+] Jump to last tab
Pressing * or # highlights all occurrences of the word under cursor without moving. Press again to jump normally.
* Highlight current word without moving (press again to jump)
g* Same as *, partial match
# Same as *, search backward
g# Same as g*, search backward
s{textobj} Replace a text object with clipboard content (e.g. siw to replace current word)
ss Replace entire current line with clipboard content
S Replace from cursor to end of line with clipboard content
K Hover documentation for symbol under cursor
gh Show hover in popup
gd Go to definition (fallback to ctags if LSP fails)
gc Go to declaration
gt Go to type definition
gi Go to implementation
gr Show references
Leader+gd Peek definition
Leader+gc Peek declaration
Leader+gt Peek type definition
Leader+gi Peek implementation
Leader+gr Peek references
Leader+rn Rename symbol
[d Previous diagnostic
]d Next diagnostic
[D First diagnostic
]D Last diagnostic
Leader+gh Show current line diagnostics (popup)
Leader+d Show/hide current buffer diagnostics (location list)
Files are auto-formatted on save via LSP. Completion is enabled by default — LSP-powered suggestions appear automatically as you type. K looks up the word under the cursor: :Man by default, :LspHover in LSP-enabled filetypes, and :help in Vim/help files.
gs Find symbol under cursor (cscope)
gD Find global definition (cscope, fallback to ctags on failure)
gR Find callers (cscope)
g] Jump to the tag under cursor, listing all matches in quickfix
Cscope supports c, d, e, f, g, i, s, t query types, with results in quickfix.
Requires cscope and gtags-cscope database (auto-generated by gutentags).
Ctrl+p Search files
Leader+b Search buffers (C-d to delete, Enter to open)
Leader+t Search buffer tags
Leader+p Search project tags
Leader+f Search function in buffer
Leader+e Search line in buffer
These are standard Vim built-in keys enhanced by FastFold for performance:
za When on a closed fold, open it. When on an open fold, close it and set 'foldenable'
zc Close one fold under the cursor
zo Open one fold under the cursor
zR Open all folds
zM Close all folds
zuz Manually update all folds (FastFold)
m[a-zA-Z] Toggle mark and display it in the leftmost column
m, Place the next available mark
m. If no mark on line, place the next available mark. Otherwise, remove (first) existing mark
dm[a-zA-Z] Delete mark[a-zA-Z]
m- Delete all marks in current line
m<Space> Delete all marks in current buffer
'[a-zA-Z] Jump to the mark
]` / [` Jump to next / previous mark
`] / `[ Jump by alphabetical order to next / previous mark
m/ View all marks in Location List
m[0-9] Toggle the corresponding marker !@#$%^&*()
m<S-[0-9]> Remove all markers of the same type
m<BS> Remove all markers
]- Jump to next line having a marker of the same type
[- Jump to prev line having a marker of the same type
]= Jump to next line having a marker of any type
[= Jump to prev line having a marker of any type
m? Open location list and display markers from current buffer
:SignatureToggle Show/hide marks without deleting them
:SignatureRefresh Re-sync marks and signs if they go out of sync
- Open file directory in current window
~ Open project root or home directory in current window
<CR> Enter directory or open file
o Open in current window (edit)
a Open in horizontal split
i Open in vertical split
t Open in new tab
- Go up one directory
A/I/O Disabled (use a/i/o instead)
x Add files to arglist
R Reload directory view
:Shdo Generate shell script from lines (e.g., :%Shdo)
Leader+a Search current word in current directory
ys+textobj+surroundA Add surround A for the region of textobj
yss+surroundA Add surround A for current line
ds+surroundA Delete surround A
cs+surroundA+surroundB Change surround A to B
F3 Open a terminal buffer
F4 Toggle the global terminal at the bottom
F5 Toggle the global terminal on the right
F3 opens a new terminal at the bottom. F4 and F5 toggle the single global terminal — F4 shows it at the bottom (20 rows), F5 on the right (half the width). While visible, either key hides it; while hidden, each key reopens it in its own position. It is shared across all tabs: hiding does not kill the job, and the same terminal (history included) reopens in whatever tab you are in.
Use <Ctrl-\><Ctrl-n> to switch from terminal mode to normal mode. In normal mode, <ScrollWheelUp> and <ScrollWheelDown> scroll the terminal buffer.
Leader+ws Save session
Leader+rs Remove session (asks for confirmation; no-op when no session exists)
Sessions are saved to ~/.cache/vim/sessions/. On Vim startup, a session is automatically restored from this directory.
Viminfo is per-project: command/search history, registers, the jumplist and file marks are stored in ~/.cache/vim/viminfo/<project-root-flattened>.viminfo (project root detected by walking up from the startup directory for .git/.root/.hg/... markers, falling back to ~), so histories do not leak between projects.
'. Jump to last changes
'' To the position before the latest jump, or where the last "m'" or "m" + backtick command was given
Ctrl+o Go to [count] Older cursor position in jump list
Ctrl+i Go to [count] newer cursor position in jump list
Ctrl+^ Edit the alternate file. Mostly the alternate file is the previously edited file
cod Toggle diff
cop Toggle paste (auto-disabled on leaving insert mode)
col Toggle list
con Clear search highlight
Leader+cr Change project root (manual only, no auto-chdir on file open)
Leader+space Strip trailing whitespace
Leader+Leader+space Strip trailing whitespace + \\r (DOS newlines)
Leader+q Toggle quickfix
Leader+l Toggle location list
In quickfix/location windows (ack-style mappings):
o/Enter— Open entry (file + line)go— Open in horizontal splitgO— Open and focus new windowt— Open in new tabT— Open in new tab (keep quickfix focused)q— Close quickfix window
Quickfix windows auto-resize to fit content (max 10 lines), auto-close when empty, and are placed at the bottom.
Note: gdefault is set, so :s performs global substitution (all matches per line) by default. The jumplist is persisted per project via the per-project viminfo. jumpoptions+=stack makes the jumplist behave like the tagstack.
New .sh and .py files get a shebang line automatically inserted:
.sh→#!/usr/bin/env bash.py→#!/usr/bin/env python3
% Go forward to next matching word (cycles back from close to open)
g% Go backward to previous matching word
[% Go to previous outer open word (start of surrounding block)
]% Go to next surrounding close word (end of surrounding block)
z% Go inside nearest inner contained block
i% Inside of any block (text object)
a% Around any block (text object)
Lexima automatically closes pairs: (), [], {}, "", '' and backtick pairs. Backspace inside an empty pair deletes both characters. Enter inside {} auto-indents and creates a closing brace. In vim files, " is not auto-paired (since " is the comment leader).
Ctrl+l Expand snippet
Tab Jump to next placeholder
Shift+Tab Jump to previous placeholder
Ctrl+x Ctrl+p Fuzzy file path completion (fzf)
Ctrl+x Ctrl+l Fuzzy line completion (fzf)
Ctrl+x Ctrl+b Fuzzy buffer line completion (fzf)
Ctrl+x Ctrl+f Built-in filename completion
Ctrl+x Ctrl+n Built-in keyword completion
Ctrl+x Ctrl+o Built-in omni completion
Ctrl+x Ctrl+] Tag completion (fallback when LSP is slow/unavailable)
s Replace selected text with clipboard content
; Enter command line mode, same as :
< Decrease indent, keep selection
> Increase indent, keep selection
* Search selected text forward (standard vim behavior, enhanced by vim-asterisk)
# Search selected text backward (standard vim behavior, enhanced by vim-asterisk)
# '\r' standard for newline
s{textobj} Replace a text object with clipboard content (e.g. siw)
ss Replace entire current line with clipboard content
S Replace from cursor to end of line with clipboard content
f Search 1 character to jump with hints (stargate)
F Search 2 consecutive characters to jump with hints (stargate)
Leader+a Search selected text in current directory
S+surroundA Add surround A for selected text (vim-surround built-in)
Ctrl+p Previous command
Ctrl+n Next command
Ctrl+a Jump to the begin of the command line
Ctrl+e Jump to the end of the command line
1. git for vim: vim-fugitive
" Run an arbitrary git command. Similar to :!git [args] but chdir to the repository tree first.
:Git [args]
" Short alias for :Git
:G [args]:Git status
:Git diff
:Git commit
:Git log
:Git blame
:Git pull
:Git push" Stage file (git add)
:Gwrite
" Stage and quit
:Gwq
" Delete file from git and buffer
:GDelete
" Delete from git, keep buffer
:GRemove
" Rename / move file
:GMove {dest}
" Blame current file in a scroll-bound split
:Git blame" Diff against index (staging area)
:Gdiffsplit
" Diff against HEAD (last commit)
:Gdiffsplit HEAD
" Always vertical
:Gvdiffsplit" git-log into quickfix list
:Gclog
" git-log into location list
:Gllog
" git-grep into quickfix list
:Ggrep [args]
" Browse file/commit in GitHub
:GBrowse
" Copy URL to clipboard
:GBrowse!In the :Git status buffer:
s— Stage fileu— Unstage file-— Stage/unstage toggleX— Discard changes=— Toggle inline diffcc— Commitca— Amend last commitcf— Fixup commitcs— Squash commitcrc— Revert commitcoo— Checkout filedd—:Gdiffsplitdv—:Gvdiffsplitgq— Close status window
More help: :h fugitive.txt or https://github.com/tpope/vim-fugitive#screencasts
2. Git commit browser: gv.vim
" Open git commit browser
:GV
" List commits affecting current file only
:GV!
" Fill location list with revisions of current file
:GV?Leader+gg Open git status
Leader+gl Git commit browser for current file (GV!)
Leader+gL Open git commit browser (GV)
Leader+gd Vertical diff against index
Leader+gD Diff entire project against index
Leader+gb Git blame
Leader+gb/Leader+gl/Leader+gLalso work in Visual mode to blame or browse commits for the selected lines.
3. Git diff gutter: vim-gitgutter
[h / ]h Jump to previous/next hunk
Leader+hp Preview current hunk
Leader+hs Stage current hunk
Leader+hr Undo current hunk
Leader+hS Stage entire file
Leader+hR Discard all changes in file
Leader+hq Load hunks into quickfix (current file)
Leader+hQ Load hunks into quickfix (all files)
" Like :wall, but writes all windows rather than all buffers
:W
" Write all modified buffers
:wall
" Write file with sudo privileges
:SudoWrite
" Edit file with sudo
:SudoEdit {file}
" Delete file from disk and buffer
:Delete
" Delete file from disk, keep buffer
:Remove
" Rename / move file
:Rename {dest}
" Copy file
:Copy {dest}
" Change permissions
:Chmod {mode}
" Create directory (incl. parents)
:Mkdir {dir}
" Mkdir on its own creates the current file's parent dir
" Find files (results in quickfix)
:Cfind {args}" Search recursively in current directory for the pattern
" Jump to the first result unless ! is given.
:CtrlSF[!] [PATTERN] [path]
" Reopen CtrlSF window
:CtrlSFOpen
" Close CtrlSF window
:CtrlSFClose" Generate tags for current file
:GutentagsUpdate
" Generate tags for current project
:GutentagsUpdate!If GNU Global (gtags/global) and Pygments (pygmentize) are installed,
gutentags also generates the GTAGS/GRTAGS/GPATH databases in
~/.cache/vim/tags/<project>/. GNU Global provides native parsers for C/C++/Java,
and falls back to Pygments for all other languages (Python, Go, Rust,
JavaScript, etc.). The gtags database is queried with the :cs commands, or
directly with the global CLI.
" Search files
:Files [QUERY]
" Search git-tracked files
:GFiles [QUERY] " or :GitFiles
:GFiles? " show git status
" Search buffers (C-d to delete, Enter to open)
:Buffers [QUERY]
" Search lines in loaded buffers
:Lines [QUERY]
" Search lines in current buffer
:BLines [QUERY]
" Search tags in the project
:Tags [QUERY]
" Search buffer tags
:BTags [QUERY]
" Interactive grep (ripgrep)
:Rg [QUERY] " or :RG for full-screen results
" Search with ag (Silver Searcher)
:Ag [QUERY]
" Search file history
:History [QUERY]
" Search command history
:History:
" Search search history
:History/
" Search marks
:Marks
" Search buffer-local marks
:BMarks
" Search jumps
:Jumps
" Search changes
:Changes
" Search help tags
:Helptags [QUERY]
" Search windows
:Windows
" Search git commits (current file)
:Commits [QUERY] " :BCommits for buffer commits
" Search commands
:Commands
" Search key mappings
:Maps
" Search filetypes
:Filetypes
" Search snippets (UltiSnips)
:Snippets
" Search colorschemes
:Colors
" Search files via locate
:Locate [QUERY]" Keep only matching entries in qf/loc list
:Keep {pattern}
" Remove matching entries
:Reject {pattern}
" Save current qf/loc list by name
:SaveList {name}
" Load named list
:LoadList {name}
" Execute command on every file in list
:Dofile {cmd}
" Execute command on every line in list
:Doline {cmd}" Start/update session in ~/.cache/vim/sessions/
:Obsession {file}
" Toggle pause/resume session tracking
:Obsession
" Stop and delete session file
:Obsession!" Symbol search across entire workspace
:LspSymbolSearch [query]
" Show outline of current file
:LspOutline
" Show symbols in popup
:LspDocumentSymbol
" Switch between source and header
:LspSwitchSourceHeader
" Show/server status
:LspShowAllServers
" Workspace management
:LspWorkspaceAddFolder {folder}
:LspWorkspaceRemoveFolder {folder}
:LspWorkspaceListFolders- Indentation convention — monkey-vim applies indent settings per filetype:
| Filetype | Style | Width |
|---|---|---|
c, cpp, go, sh, vim, sql |
Hard tab (noexpandtab) |
4 |
zig, rust, python, markdown |
Spaces (expandtab) |
4 |
javascript, typescript, lua, yaml, json |
Spaces (expandtab) |
2 |
The global default is 4-width hard tabs. To customize, override the FileType autocmds in your own vimrc after sourcing monkey-vim's.
- Vim clipboard integration
monkey-vim sets clipboard=unnamed,unnamedplus so vim's yank/delete automatically syncs to the system clipboard. Copied text persists in the system clipboard after vim exits (the system clipboard is owned by the display server / Wayland compositor / terminal, not by vim).
Depending on the environment, yanks reach the system clipboard through different routes (evaluated in this order at startup):
| Environment (checked in this order) | Route |
|---|---|
SSH and OSC 52 usable — no tmux, or tmux with set-clipboard on |
OSC 52 escape sequence → local clipboard |
| A display server is available (Wayland/X11, macOS/WSLg, or Wayland/X11 detected over SSH) and not a physical console | GUI clipboard |
No display server and inside tmux — e.g. a non-SSH kmscon/tty, or SSH with set-clipboard off |
tmux buffer (tmux load-buffer -w) |
| Older Vim without the provider feature | Provider routes skipped — GUI clipboard only with a display server; with none, no route is available and the clipboard does not sync |
Notes: the OSC 52 route requires a terminal with OSC 52 support and Vim ≥ 9.1.1984 (the one-click installer builds a current Vim). Inside tmux, set-clipboard on is required so paste queries don't block.
If you use a standalone clipboard manager (optional):
| Tool | Platform | Purpose |
|---|---|---|
| parcellite | X11 | Lightweight clipboard manager with persistent history |
| cliphist | Wayland | Clipboard history for wlroots-based compositors |
| Built-in | macOS/WSL | System clipboard persists by default — no extra tool needed |
Build Vim from source for the latest version with full features: GTK3 GUI, Wayland/X11 support, and Lua/Python3/Perl/Ruby integration. Pick the display server you use: Wayland (listed first), X11 & Wayland, or kmscon / text console.
Note: Vim's Linux GUI is GTK-based — there is no Qt version, so the GTK3 packages below are required even on KDE (or any other Qt-based desktop). GTK3 apps run fine on any desktop environment.
The
gpmpackages enable mouse support on the Linux text console (TTY), not on the desktop. Harmless to include.Optional CLI tools:
wl-clipboard(Wayland, provideswl-copy/wl-paste),xcliporxsel(X11). Vim has built-in clipboard support via--with-wayland/--with-x, so these are only needed for command-line clipboard access outside Vim.
Wayland:
sudo apt-get install libgtk-3-dev \
libwayland-dev \
libcairo2-dev \
libgpm-dev \
libncurses-dev \
python3-dev \
lua5.4 \
liblua5.4-dev \
perl \
libperl-dev \
ruby \
ruby-devX11 & Wayland:
sudo apt-get install libgtk-3-dev \
libx11-dev \
libxt-dev \
libxpm-dev \
libwayland-dev \
libcairo2-dev \
libgpm-dev \
libncurses-dev \
python3-dev \
lua5.4 \
liblua5.4-dev \
perl \
libperl-dev \
ruby \
ruby-devWayland:
sudo zypper install gtk3-devel \
wayland-devel \
cairo-devel \
gpm-devel \
ncurses-devel \
python-devel \
python3-devel \
ruby-devel \
lua-develX11 & Wayland:
sudo zypper install gtk3-devel \
wayland-devel \
xorg-x11-devel \
libXpm-devel \
libXt-devel \
cairo-devel \
gpm-devel \
ncurses-devel \
python-devel \
python3-devel \
ruby-devel \
lua-develEnable EPEL first:
sudo dnf install epel-release. Thegtk3-develpackage requires CentOS 8+ / EPEL 8+; it is not available on CentOS 7.lua-develrequires CRB (CodeReady Builder) repository:sudo dnf config-manager --set-enabled crb(CentOS 9) orsudo dnf config-manager --set-enabled powertools(CentOS 8).
Wayland:
sudo dnf install gtk3-devel \
wayland-devel \
cairo-devel \
gpm-devel \
ncurses-devel \
python-devel \
python3-devel \
ruby-devel \
lua-devel \
perl \
perl-devel \
perl-ExtUtils-ParseXS \
perl-ExtUtils-CBuilder \
perl-ExtUtils-EmbedX11 & Wayland:
sudo dnf install gtk3-devel \
wayland-devel \
libX11-devel \
libXpm-devel \
libXt-devel \
cairo-devel \
gpm-devel \
ncurses-devel \
python-devel \
python3-devel \
ruby-devel \
lua-devel \
perl \
perl-devel \
perl-ExtUtils-ParseXS \
perl-ExtUtils-CBuilder \
perl-ExtUtils-EmbedWayland:
sudo pacman -S gtk3 \
wayland \
gpm \
ncurses \
lua \
perl \
python \
rubyX11 & Wayland:
sudo pacman -S gtk3 \
wayland \
libx11 \
libxt \
libxpm \
gpm \
ncurses \
lua \
perl \
python \
rubyMac (terminal build, macOS system clipboard via Cocoa)
brew install python3 \
ruby \
luaTerminal Vim on macOS gets the system clipboard from the Darwin/Cocoa (AppKit) feature, which is enabled by default — do not pass
--disable-darwin. Since no GTK/Motif/Athena dev libraries are installed, build with--enable-gui=no(see mac under "Compile and install" below), not--enable-gui=auto.
./configure --with-features=huge \
--enable-gui=gtk3 \
--enable-gpm \
--with-wayland \
--enable-python3interp \
--enable-luainterp \
--enable-perlinterp \
--enable-rubyinterp \
--enable-multibyte \
--enable-terminal \
--enable-fontset \
--enable-cscope \
--enable-fail-if-missing
make
sudo make installThe GTK3 GUI auto-detects the Wayland backend at runtime; you can force it with
export GDK_BACKEND=wayland.--with-waylandenables native Wayland support (+wayland,+wayland_clipboard) for terminal Vim, so clipboard access works even without the GUI.
./configure --with-features=huge \
--enable-gui=gtk3 \
--enable-gpm \
--with-x \
--with-wayland \
--enable-python3interp \
--enable-luainterp \
--enable-perlinterp \
--enable-rubyinterp \
--enable-multibyte \
--enable-terminal \
--enable-fontset \
--enable-cscope \
--enable-fail-if-missing
make
sudo make install
--with-xadds X11 support (clipboard, drag & drop);--with-waylandenables native Wayland support (+wayland,+wayland_clipboard). A single GTK3 build runs on both Wayland and X11 by auto-detecting the display server at runtime. Use this if you need both — e.g., WSLg (no Wayland clipboard), where clipboard goes through XWayland but display is Wayland.GTK3 vs GTK4. On a regular Linux desktop you may build with GTK4 instead: install
libgtk-4-dev(Debian/Ubuntu),gtk4-devel(openSUSE/CentOS) orgtk4(Arch), and pass--enable-gui=gtk4. Do not use GTK4 under WSL (WSLg). A GTK4 build drops X11 support entirely (--enable-gui=gtk4forces--without-x), so it has no+xterm_clipboard; the only remaining clipboard feature is+wayland_clipboard, which speaks the Waylanddata-controlprotocol (zwlr-data-control-unstable-v1/ext-data-control-v1). WSLg's compositor does not implement that protocol — its clipboard is relayed to Windows over RDP and exposed to Linux apps through XWayland — so a GTK4 build under WSLg ends up with no working system clipboard. On WSL, keep GTK3 with--with-x(the "X11 & Wayland" build above), which reaches the clipboard through XWayland.
./configure --with-features=huge \
--enable-gui=no \
--disable-gpm \
--enable-python3interp \
--enable-luainterp \
--enable-perlinterp \
--enable-rubyinterp \
--enable-multibyte \
--enable-terminal \
--enable-fontset \
--enable-cscope \
--enable-fail-if-missing
make
sudo make installOn macOS the
"+/"*registers come from the Darwin/Cocoa (AppKit) feature, enabled by default — keep it (no--disable-darwin), and--enable-gui=nojust makes the build terminal-only.--disable-gpmis required: gpm (the Linux console-mouse library) doesn't exist on macOS and--enable-fail-if-missingwould abort configure.
kmscon / text console (no GUI)
./configure --with-features=huge \
--enable-gui=no \
--enable-gpm \
--with-osc52 \
--enable-python3interp \
--enable-luainterp \
--enable-perlinterp \
--enable-rubyinterp \
--enable-multibyte \
--enable-terminal \
--enable-fontset \
--enable-cscope \
--enable-fail-if-missing
make
sudo make installOn a console-only machine, build without GUI libraries — drop
--with-wayland/--with-xand thelibgtk-3-dev/ Wayland / X11 packages.--enable-gpmkeeps console mouse support, and--enable-terminalcovers terminal mode.Without
--with-waylandor--with-x, Vim has no system clipboard integration. The"*and"+registers are unavailable; copy/paste is limited to internal Vim registers ("","0–"9, etc.).
--with-osc52adds the OSC 52 clipboard provider (+clipboard_provider): yanks are sent to the terminal emulator, which writes the system clipboard. It thus works over ssh (e.g., into a headless box from Windows Terminal / iTerm2) and in desktop terminal emulators even without any GUI/X11 support compiled in; on a raw tty/kmscon console it is a no-op, since nothing parses the escape sequence there.
Put this in your bashrc:
export MANPAGER="env MAN_PN=1 vim -R +MANPAGER -"