CLI tool
jeffreytse/zsh-vi-mode avatar
jeffreytse/zsh-vi-mode

zsh-vi-mode: thirteen install routes, one plugin file

💻 A better and friendly vi(vim) mode plugin for ZSH.

4,489 stars157 forksShellMIT

At a glance

What is it?
zsh-vi-mode swaps zsh's builtin vi editing for a pure zsh script with no third-party dependencies, and all thirteen documented install routes end by sourcing the same file, zsh-vi-mode.plugin.zsh.
Who is it for?
Worth a try on zsh 5.1.0 or newer if you gave up on the builtin vi mode and want text objects, surrounds and history search back. Match the source path to your package manager before touching .zshrc, since Homebrew, Arch and Gentoo drop the file into three different directories.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 118 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • jeffreytse/zsh-vi-mode4,489 ★ · +37
Star history
Repository2026-09-232026-11-14
jeffreytse/zsh-vi-mode4.5k4.5k

37 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Thirteen install routes end at one filename

Five prefixes, one script, and the same closing instruction every time. Homebrew installs the formula and leaves the file under the brew prefix in an opt/zsh-vi-mode directory, Arch Linux puts it in /usr/share/zsh/plugins/zsh-vi-mode, Gentoo in /usr/share/zsh/site-contrib/zsh-vi-mode, Nix resolves it through ${pkgs.zsh-vi-mode}, and a manual clone can sit anywhere, with $HOME/.zsh-vi-mode offered as the example. Each of those sections then ends with a source command, and a reader who copies the line from the wrong section ends up sourcing a file that is not there.

shell
brew install zsh-vi-mode
source $(brew --prefix)/opt/zsh-vi-mode/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh

Nothing in the install text tells you to check that the path exists first, and the filename itself carries no fallback, since zsh reports a missing source target and carries on.

A zsh plugin the README tells bash users to source

The requirements section asks for ZSH >= 5.1.0, and the first feature bullet calls the code a pure zsh script without any third-party dependencies. Both statements sit within a few lines of four install sections that end with the same parenthetical: source it in your `.zshrc` (or `.bashrc`). The parenthetical appears under Homebrew, under Arch, under Gentoo and under the manual clone.

shell
git clone https://github.com/jeffreytse/zsh-vi-mode.git $HOME/.zsh-vi-mode
source $HOME/.zsh-vi-mode/zsh-vi-mode.plugin.zsh

So a bash user following the text literally is pointed at a zsh plugin from a bash startup file, and no section says what that produces, what breaks, or how a bash user is meant to get the same keys. The version floor is a zsh floor: the plugin asks for ZSH 5.1.0 or newer and then offers a shell it does not target.

Oh My Zsh wants the plugin listed before its own shell file

Eight plugin managers get a one line loader each. Oh My Zsh is the fussiest, because the entry `plugins+=(zsh-vi-mode)` has to be added before `oh-my-zsh.sh` is sourced, and the repository is cloned into $ZSH_CUSTOM/plugins/zsh-vi-mode first. Zim reads `zmodule jeffreytse/zsh-vi-mode` from a .zimrc file, Antibody wants a bare repository line in a plugins file such as ~/.zsh_plugins.txt, and Zap, antigen, zplug, zgen and zinit each take a single call.

shell
antigen bundle jeffreytse/zsh-vi-mode
zplug "jeffreytse/zsh-vi-mode"
zgen load jeffreytse/zsh-vi-mode
zinit ice depth=1
zinit light jeffreytse/zsh-vi-mode

zinit has its own caveat attached: `depth=1` is optional, and other types of ice are neither recommended nor officially supported.

Two script files at the root and no keybinding table

The repository root holds `zsh-vi-mode.plugin.zsh` and `zsh-vi-mode.zsh` next to .github and the README, with no documentation directory, no completion file and no test suite at the top level. That shape matters, because the feature list runs to fifteen bullets and only three of them name concrete keys: gx opens a URL or a file path sitting under the cursor, vv hands the current command line to an external editor, and 10p and 4fa appear as examples of repeating a command.

Everything else is a category. Text objects cover a word and an inner word. Surrounds are listed as add, replace, delete, move around and highlight. Undo, redo, cut, copy, paste and delete arrive as one bundle, alongside history search, keyword switching for numbers, booleans, weekdays and months, and system clipboard integration.

Cursor shapes and a latency claim with no number

Two of the fifteen bullets promise feel rather than function. Mode switching is offered with lower delay and better response, and mode indication is offered through different cursor styles. No figure is attached to the switching speed claim in the feature list.

Near-native vi mode is the phrase used for the editing experience as a whole.

The AUR keeps two names for one plugin, one marked unstable

Arch carries a second package name. `yay -S zsh-vi-mode` installs the packaged build, and `yay -S zsh-vi-mode-git` is offered as the latest update and labelled unstable, which makes the choice between a known package and a moving branch an explicit one for anyone on that route.

shell
yay -S zsh-vi-mode
yay -S zsh-vi-mode-git

Gentoo has no package until an overlay is added, so the route takes three commands before the plugin is even on disk. Nix carries the package as of nixpkgs commit e7e3480530b34a9fe8cb52963ec2cf66e6707e15, and offers three variants: interactiveShellInit, home-manager initExtra, or the built-in plugins list, where the entry is named vi-mode, takes its source from pkgs.zsh-vi-mode, and points at the file share/zsh-vi-mode/zsh-vi-mode.plugin.zsh. Three names for one plugin again.

The branch moved after the newest tag was cut

The last push on the default branch master was 2026-07-19 and the repository is not archived, yet the newest tag v0.12.0 carries the date 2025-09-16 while v0.11.0 goes back to 2023-11-06. What that gap buys is unclear from the text, since the install sections pin no version for any of the thirteen routes, so what a user receives depends on which route was taken and how recently that route ran.

That distinction matters most on the two routes that follow the branch. A manual clone takes whatever master holds at the moment of the clone, while a Homebrew or Nix install stays on the packaged build until the package is refreshed. The unstable AUR package sits between them, tracking the branch without claiming to be anything else.

Nothing in the install steps clears the builtin vi binding

The reason the plugin exists is stated plainly at the top: after turning on the default vi mode, features turned out to be imperfect or non-existent, and some behaviours differed from native vi. What none of the install sections answers is what happens to a vi key binding that is already active in the shell when the plugin is sourced.

No route contains a step for switching the old binding off, and no route describes how to get it back afterwards. A user who wants vi editing only inside a few directories, rather than everywhere, has no supported configuration point for that either, since no environment variable or per-directory switch is named anywhere in the install or feature text.

Editorial conclusion

Worth a try on zsh 5.1.0 or newer if you gave up on the builtin vi mode and want text objects, surrounds and history search back. Match the source path to your package manager before touching .zshrc, since Homebrew, Arch and Gentoo drop the file into three different directories. Read the README's Usage section before committing, and note that the home-manager plugin entry is named vi-mode while sourcing a file named zsh-vi-mode.plugin.zsh.

Frequently asked questions

what is zsh vi mode

zsh-vi-mode is a pure zsh script that reworks the vi and vim mode built into zsh, with no third-party dependencies. It requires ZSH >= 5.1.0 and adds text objects, surrounds, history search, an external editor key and system clipboard integration.

install zsh vi mode

The install routes are Homebrew, the Arch AUR, Nix, Gentoo and a manual git clone, plus the antigen, zplug, zgen, zinit, Oh My Zsh, Antibody, Zap and Zim plugin managers. Every route ends by sourcing zsh-vi-mode.plugin.zsh, and the directory holding that file differs between package managers.

how to use zsh vi mode

The README has a Usage section linked from its header, and its feature list names gx for opening a URL or file path under the cursor, vv for editing the command line in an external editor, and 10p and 4fa as repeating command examples.

Official sources

  1. Issues
  2. jeffreytse/zsh-vi-mode on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jeffreytse-zsh-vi-mode.svg)](https://hysenlabs.com/projects/jeffreytse-zsh-vi-mode)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/jeffreytse-zsh-vi-mode.svg)](https://hysenlabs.com/projects/jeffreytse-zsh-vi-mode)

Was this useful?