Skip to content

0x1b2c/Veil

Repository files navigation

Veil

Veil

A Neovim GUI built for efficiency, not for cool.

Your Neovim config in proper macOS windows, in the tradition of MacVim. Instant startup with near-zero overhead, fast Metal rendering, fast multi-tab session loading. Designed for focus. No visual noise, no distractions.

Why another Neovim GUI?

Veil brings the MacVim workflow to Neovim: multiple independent windows in a single app, Cmd+` to switch between projects, Cmd+1/2/3 to jump to tabs. As a native macOS app instead of a terminal process, nearly all key sequences reach Neovim without being intercepted.

Vim is a tool built for focused, efficient work. Animations consume attention. Cursor effects, scroll easing, transition flourishes all pull your eyes away from what really matters: the text. Veil chooses to keep things quiet.

Features

  • MacVim-tradition multi-window: each window runs an independent Neovim, Cmd+N to create, Cmd+` to cycle.
  • Tabs: Neovim drives the tabline by default; opt into native macOS tabs with native_tabs = true.
  • Instant startup: sub-second cold start with fast multi-tab session loading.
  • Pixel-perfect Metal rendering: GPU-accelerated, with continuous box-drawing lines and programming ligature support.
  • Native macOS keyboard handling: most key sequences reach Neovim untouched; app shortcuts and Neovim keymaps both configurable. See KEYBOARD.md.
  • Per-window profiles: pick a different NVIM_APPNAME per window with Cmd+Shift+N.
  • Remote Neovim: connect to a remote Neovim over TCP, with local clipboard integration.
  • CJK ready: auto-fallback to matching CJK font variants with full IME support.

Veil screenshot

Requirements

  • macOS 14+
  • Neovim 0.10+ recommended (install via brew install neovim)

Veil uses your system-installed Neovim. No bundled binary, ~1 MB download. Veil finds nvim anywhere your interactive shell can access it, and caches the resolved path so only the first launch pays the detection cost.

Veil communicates with Neovim via its stable msgpack-RPC and ext_linegrid UI protocol, and works with any recent Neovim version. The RPC layer is heavily optimized with event batching for responsive rendering.

Install

Veil has two variants: the standard build, and a default-editor build that claims file associations on install (so double-clicking source files in Finder opens Veil).

Homebrew

brew tap 0x1b2c/veil
brew install --cask veil                  # standard
brew install --cask veil-default-editor   # claims file associations

This installs Veil.app to /Applications and symlinks the veil, gvim, and gvimdiff CLI commands to your Homebrew bin directory.

Manual

Download Veil.zip (standard) or Veil-default-editor.zip (claims file associations) from Releases, unzip, and move Veil.app to /Applications. Then remove the quarantine attribute so macOS doesn't block it:

xattr -cr /Applications/Veil.app

Build

Open Veil.xcodeproj in Xcode and run, or:

make                # Release build (arm-only, fast)
make debug          # Debug build
make test           # Run unit tests
make install        # Build + install to /Applications
make install-polite # Build + install + strip LSHandlerRank from /Applications/Veil.app
make zip            # Universal build + package as Veil-default-editor.zip
make zip-polite     # Universal build + package as Veil.zip (polite variant)
make clean          # Clean build artifacts
make lsp            # Generate buildServer.json for SourceKit-LSP

For Neovim/editor LSP support, run make lsp after cloning to generate buildServer.json (requires xcode-build-server).

Usage

Veil reads your existing Neovim configuration (~/.config/nvim/) for editor behavior. Veil's own settings (font, keyboard shortcuts, remote bookmarks, and a few other options) live in ~/.config/veil/veil.toml, separate from nvim's config. All fields are optional and have sensible defaults; see veil.sample.toml for the full reference. Changes take effect on the next new window.

Font

We recommend Maple Mono for its excellent CJK support and Nerd Font icons:

brew install font-maple-mono-nf-cn    # or font-maple-mono-nf without CJK

Set it in nvim:

vim.o.guifont = 'Maple Mono NF CN:h16'    -- or 'Maple Mono NF:h16' without CJK

Or in ~/.config/veil/veil.toml (recommended for remote nvim connections, where the remote machine's guifont rarely matches your local Mac):

[font]
family = "Maple Mono NF CN"    # or "Maple Mono NF" without CJK
size = 16.0

See FONT.md for precedence rules, the force option, and Nerd Font fallback details.

Keyboard

Veil's keybindings split into two categories: app shortcuts for Veil's own actions (new window, close tab, open settings, etc.) and Neovim keymaps for macOS-style shortcuts pre-bound to Neovim commands (cmd+s:w, cmd+1-9 → switch tabs, etc.). Both are configurable, and the Neovim keymaps can be disabled wholesale to free those keys for your own nvim mappings. See KEYBOARD.md for the full list and string format.

Quick reference:

Key Action
Cmd+N New window
Cmd+Shift+N New window with profile picker
Cmd+W Close tab (or window if only one tab)
Cmd+Shift+W Close window
Cmd+Q Quit Veil
Cmd+` Cycle windows
Cmd+1Cmd+9 Switch tab
Cmd+, Open settings (veil.toml)
Cmd+Ctrl+Shift+N Connect to remote nvim

Each of these stays at the granularity macOS users expect: Cmd+W closes one tab, Cmd+Shift+W closes the window, Cmd+Q quits the entire app. Unsaved-buffer prompts route through Neovim's :confirm qa.

Remote Neovim

Veil can connect to a Neovim instance running on a remote machine over TCP. Start Neovim on the remote host listening on localhost:

nvim --headless --listen 127.0.0.1:6666

Neovim's RPC protocol has no authentication, so always bind to 127.0.0.1 and use SSH tunneling. Never expose the listening port to the network directly.

Forward the port over SSH, then connect from Veil using Cmd+Ctrl+Shift+N:

# -L local_port:remote_host:remote_port
ssh -L 6666:127.0.0.1:6666 your-server

For a persistent setup, add to ~/.ssh/config:

Host dev-nvim
    HostName your-server
    # local_port remote_host:remote_port
    LocalForward 6666 127.0.0.1:6666

Then ssh dev-nvim automatically forwards the port. Use ssh -N dev-nvim to forward without opening a shell.

You can save frequently used connections in veil.toml:

[[remote]]
name = "Dev Server"
address = "127.0.0.1:6666"

[[remote]]
name = "Staging"
address = "127.0.0.1:6667"

I don't always code, but when I do, I code in production.

Clipboard integrates seamlessly with your local Mac. Yank/paste with + and * registers in the remote session operates on your local pasteboard.

Commands

Veil registers these commands in Neovim:

  • :VeilAppVersion show Veil and Neovim version info, and check for updates. Use :VeilAppVersion! to open in a scratch buffer for easy copying
  • :VeilAppDebugToggle show/hide an overlay with renderer info, frame time, grid size, font details, and more
  • :VeilAppDebugCopy copy the debug overlay info to the system clipboard

CLI

Veil ships CLI commands inside the app bundle: veil, plus gvim and gvimdiff as traditional aliases (gvimdiff is equivalent to veil -d). Symlink them to your PATH:

ln -s /Applications/Veil.app/Contents/bin/veil ~/.local/bin/veil
ln -s /Applications/Veil.app/Contents/bin/gvim ~/.local/bin/gvim
ln -s /Applications/Veil.app/Contents/bin/gvimdiff ~/.local/bin/gvimdiff

Then use it like nvim. All nvim flags and arguments are passed through transparently:

veil file.txt
gvim +42 file.txt               # open at line 42
gvim -p file1.txt file2.txt     # open in tabs
veil -d file1.txt file2.txt     # diff mode
gvimdiff file1.txt file2.txt    # same as veil -d

If Veil is already running, the CLI forwards arguments to the existing instance (opens a new window) instead of launching a second copy.

Multiple nvim configs

Each window can run a different Neovim configuration. Use NVIM_APPNAME from the CLI or Cmd+Shift+N from the GUI to select which config directory under ~/.config/ nvim uses:

NVIM_APPNAME=astronvim veil              # launch Veil with astronvim config
NVIM_APPNAME=nvim-nvchad gvim file.txt   # open file with NvChad config

Create shell aliases for configs you use often:

alias gvi='NVIM_APPNAME=nvim-nvchad gvim'
gvi file.txt                             # just works, fresh launch or new window

Background

MacVim introduced a workflow that set it apart from gVim: multiple independent windows in a single app, each with its own tabs, switching between projects instantly with Cmd+`. You could have three codebases open, Cmd+` between them, and Cmd+1/2/3 to jump to specific tabs within each one.

In the Neovim era, most GUI frontends followed the gVim model: you can open multiple instances, but each is a separate process with no way to Cmd+` between them. VimR was the exception, bringing the MacVim multi-window experience to Neovim, but its Redux architecture made startup and multi-tab session loading noticeably slow.

Veil carries this tradition forward: a minimal, fast wrapper that gives Neovim first-class macOS citizenship. Multiple windows as independent workspaces, intuitive tab switching with Cmd+1/2/3, and as a native app instead of a terminal process, nearly all key sequences reach Neovim without being intercepted.

Note: Neovide v0.16.0 also shipped macOS multi-window support within one day of Veil's first release, a fun coincidence. Neovide is an excellent choice if you prefer a cross-platform solution with visual effects. Veil focuses on being a minimal native macOS wrapper (~1 MB).

Acknowledgments

Thanks to VimR by Tae Won Ha. Veil learned a great deal from its implementation of the Neovim UI protocol, input handling, and macOS integration.

Box-drawing and block element rendering algorithms are ported from Ghostty (MIT License).

Glyph overflow strategy inspired by WezTerm: when a glyph (e.g. Nerd Font icon) is wider than its allocated cell, Veil renders it at full natural width if followed by a space, or shrinks it to fit otherwise.

License

MIT

About

Veil: A Neovim GUI built for efficiency, not for cool. Native macOS, Metal rendering, instant startup.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors