zsh-vi-mode

jeffreytseMIT活跃维护

给 ZSH 加上更顺手的 vi/vim 模式,支持文本对象、环绕操作和系统剪贴板,让终端命令行编辑像在 vim 里一样高效。

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

v0.12.0发布于 2025-09-16 06:23 UTC4,485star157fork同步于 2026-11-11 05:36 UTC

怎么上手

由 README 提炼,执行前请确认
git clone https://github.com/jeffreytse/zsh-vi-mode.git $HOME/.zsh-vi-mode
source $HOME/.zsh-vi-mode/zsh-vi-mode.plugin.zsh
硬件要求按 README 说明

README 未说明,仅要求 ZSH >= 5.1.0

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

纯 Zsh 脚本实现的 vi/vim 模式插件,让 Zsh 命令行编辑接近原生 Vim 体验

给 ZSH 加上更顺手的 vi/vim 模式,支持文本对象、环绕操作和系统剪贴板,让终端命令行编辑像在 vim 里一样高效。

核心能力

  • 纯 Zsh 脚本实现,无任何第三方依赖
  • 用块状/竖线光标区分普通与插入模式
  • 支持文本对象、f/t 跳转与 10p 等计数重复命令
  • 提供 surround 增删改与 ctrl-a/ctrl-x 关键字增减
  • gx 打开光标下 URL 或路径,vv 调用外部编辑器

容易踩的坑

需在 .zshrc 中 source 插件文件才会生效;作为 Oh My Zsh 插件时必须在 source oh-my-zsh.sh 之前加入 plugins;surround 等按键序列需快速连按,否则会超时,可用 ZVM_KEYTIMEOUT 调整

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v0.12.0
  1. v0.12.0最新正式版2025-09-16 · 2025-09-16 06:23 UTC

    🚀 Release v0.12.0

    After almost two years since the last release, this version delivers long-awaited updates with new features, multiple bug fixes, important improvements, and documentation updates. It represents a significant refresh and is highly recommended for all users.

    ✨ Features

    • Open under cursor: Added support for opening the URL or file path under the cursor with gx (557c34b)
    • System clipboard integration: Added support for system clipboard (0da7e22)

    🐛 Bug Fixes

    • Fixed [cdy]G and [cdy]gg not working when editing multi-line commands (#106) (22a6773)
    • Fixed weird behavior when pressing Esc after [cdy] (#295) (757a2fe)
    • Fixed potential local variable leakage (a9377ba)
    • Fixed repeat command issues:
      • 3. didn’t repeat the last change correctly (fc4f202)
      • 3p / 3P pasted only once instead of multiple times (eb83e95)
    • Fixed return code propagation issue (35fc87b)
    • Fixed quoting for paths with spaces in plugin sources (1a0d203)
    • Fixed missing prefix_keys setting that caused full keymap scans (fa5e6fc)
    • Fixed quoting of temp file names containing spaces (b115c13)
    • Fixed incorrect cursor style handling in zvm_cursor_style (18c6506)
    • Fixed variable name typo zsh_frameworks in zvm_system_report (3f639a5)
    • Fixed wrong variable name in zvm_viins_undo (should be ZVM_VI_INSERT_MODE_LEGACY_UNDO) (18ff536)
    • Compatibility Fixes:
      • Cursor style compatibility with custom VIMRUNTIME variable (#327) (808579b)
      • WezTerm cursor compatibility (#259) (cd730cd)
      • Fixed case branch syntax error with escape \ (#276) (d35c0b4)

    📚 Documentation

    • Updated README with new features (bbfae4e)
    • Added installation instructions for Zim (#278) (287efa1)
    • Fixed Nix home-manager plugin usage instructions (#271, #270) (7cf6fd1, 4680766)

    🛠 Chores

    • Added notes for system clipboard integration (9a5c424)
    • Added comments and adjusted function order (d2ce966, 748c3df)
    • Removed unused code blocks and variables (f3b7fce, 172a614)
    • Ensured consistent behavior of repeating insertion, matching native Vim behavior (a925a34)

    🔑 Highlights

    This release mainly introduces:

    • System clipboard support
    • gx to open URLs and file paths under the cursor
    • Numerous bug fixes improving repeat commands, cursor styles, and compatibility

    👉 We recommend upgrading to this version for the best experience.

    Full Changelog: https://github.com/jeffreytse/zsh-vi-mode/compare/v0.11.0...v0.12.0

  2. v0.11.02023-11-06 · 2023-11-06 09:49 UTC
    查看更新说明

    🎉 Hello world, I'm a new release for better work!

    • Added support for foot terminal (#233).
    • Fixed above lines were eaten issue (#234).
    • Fixed custom escape keys breaks CTRL-r history search (#145).
    • Fixed selecting a surrounded text object doesn't work (#236).
    • Fixed changing modes don't trigger an auto prompt reset (#243).
    • Fixed incorrect ZVM_MODE value after initialization.
    • Fixed session starts in normal mode (#245).

    This release provides important updates and bug fixes. Welcome to update to this version! Hooray! Thanks for your supports! 💯

  3. v0.10.02023-07-17 · 2023-07-17 10:09 UTC
    查看更新说明

    🎉 Hello world, I'm a new release for better work!

    • Fixed commands not found in zvm_config (#206).
    • Fixed visual mode stuck after typing x (#207).
    • Fixed vioppend mode does not exit correctly (#208).
    • Fixed d^ deletes current character (#211).
    • Fixed visual replacement doesn't work normally (#212).
    • Changed replace selection function name.
    • Fixed unexpected behavior of c[wWeE] (#161).
    • Fixed unexpected behavior of [cdy]<esc> (#215).
    • Fixed preventing terminal from deleting previous line on ESC (#180).
    • Fixed actions like dt' or ct" don't work (#218).
    • Fixed regression in prompt resetting (#219).
    • Fixed . command doesn't work as expected behavior (#226).
    • Fixed repeat action in normal mode chomps lines above (#181).
    • Fixed switching modes make above line chomped (#229).
    • Fixed zsh-syntax-highlighting was broken (#228).
    • Fixed switching modes doesn't change prompt indicator (#230).
    • Fixed switching keywords on 3-letter month wrongly (#227).
    • Fixed NEX read engine doesn't correctly handle - (#220).
    • Added system report support by zvm_system_report.
    • Better version information by zvm_version.

    This release provides important updates and bug fixes. Welcome to update to this version! Hooray! Thanks for your supports! 💯

  4. v0.9.02022-10-29 · 2022-10-29 12:15 UTC
    查看更新说明

    🎉 Hello world, I'm a new release for better work!

    • Supported home, end and delete keys (#138).
    • Updated zinit url of the document guide (#139).
    • Added note about timeouts in surround guide (#140).
    • Fixed escape cmd line flags of ZVM_VI_EDITOR (#143).
    • Fixed temp dir creation was corrupted (#146).
    • Updated ZSH plugin standard URL of the document guide (#147).
    • Added installation instructions for Nix users (#155).
    • Fixed typo in head document (#157).
    • Fixed no remember cursor style in tmux (#163).
    • Used $ZSH_CUSTOM variable in Oh My ZSH (#166).
    • Perfected initialize commands arrays only if unset (#172).
    • Added Fig as an installation method to the README (#183).
    • Updated README.md for Homebrew (#184).
    • Fixed completion display bug with tmux/IntelliJ (#191).

    This release provides important updates and bug fixes. Welcome to update to this version!

  5. v0.8.52021-10-23 · 2021-10-23 15:54 UTC
    查看更新说明

    🎉 Hello world, I'm a new release for better work!

    1. Fix stroking ESC and other keys rapidly not working (#111).
    2. Support to configure the initialization mode (#113).
    3. Support to config by a unified function (#115).
    4. Fix cursor color isn't restored correctly (#121).
    5. Better postponing reset-prompt.
    6. Fix characters are hidden weirdly in IntelliJ terminal (#120).
    7. Fix characters are hidden weirdly under replace mode.
    8. Fix zsh completion menu was corrupted (#122).
    9. Fix prompt line got eaten on certain actions (#124).
    10. Fix editing command line by editor not working (#129).
    11. Support to custom user default cursor (#131).

    This release provides important updates and bug fixes. Welcome to update to this version!

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    ⚒️ Zsh Vi Mode ⚒️

    🧙 Check out my new project — Grimoire: a free, open-source package manager for best practices — 1000+ skills across 26 domains (engineering, law, finance, design, health, and more), each sourced from a real institution or study. Install once, and your AI routes to the right skill automatically. ⭐ Star it if you find it useful!

    🤔 Why ZVM?

    Maybe you have experienced the default Vi mode in Zsh, after turning on the default Vi mode, you gradually found that it had many problems, some features were not perfect or non-existent, and some behaviors even were different from the native Vi(Vim) mode.

    Although the default Vi mode was a bit embarrassing and unpleasant, you kept on using it and gradually lost your interest on it after using for a period of time. Eventually, you disappointedly gave up.

    You never think of the Vi mode for a long time, one day you accidentally discovered this plugin, you read here and realize that this plugin is to solve the above problems and make you fall in love to Vi mode again. A smile suddenly appeared on your face like regaining a good life.

    If winter comes, can spring be far behind?

    ✨ Features

    • 🌟 Pure Zsh's script without any third-party dependencies.
    • 🎉 Better experience with the near-native vi(vim) mode.
    • ⌛ Lower delay and better response (Mode switching speed, etc.).
    • ✏️ Mode indication with different cursor styles.
    • 🧮 Cursor movement (Navigation).
    • 📝 Insert & Replace (Insert mode).
    • 💡 Text Objects (A word, inner word, etc.).
    • 🔎 Searching history.
    • ❇️ Undo, Redo, Cut, Copy, Paste, and Delete.
    • 🪐 Better surrounds functionality (Add, Replace, Delete, Move Around, and Highlight).
    • 🧽 Switch keywords (Increase/Decrease Number, Boolean, Weekday, Month, etc.).
    • ⚙️ Open under cursor URL or file path with charming gx.
    • 🖋️ Edit current command line in an external editor with vv.
    • 🪀 Repeating command such as 10p and 4fa.
    • 📒 System clipboard integration (Copy/Paste).

    💼 Requirements

    ZSH: >= 5.1.0

    🛠️ Installation

    Using Antigen

    Bundle zsh-vi-mode in your .zshrc

    antigen bundle jeffreytse/zsh-vi-mode
    
    Using zplug

    Load zsh-vi-mode as a plugin in your .zshrc

    zplug "jeffreytse/zsh-vi-mode"
    
    Using zgen

    Include the load command in your .zshrc

    zgen load jeffreytse/zsh-vi-mode
    
    Using zinit

    Include the load command in your .zshrc

    zinit ice depth=1
    zinit light jeffreytse/zsh-vi-mode
    

    Note: the use of depth=1 ice is optional, other types of ice are neither recommended nor officially supported by this plugin.

    As an Oh My Zsh! custom plugin

    Clone zsh-vi-mode into your custom plugins repo

    git clone https://github.com/jeffreytse/zsh-vi-mode \
      $ZSH_CUSTOM/plugins/zsh-vi-mode
    

    Then load as a plugin in your .zshrc

    plugins+=(zsh-vi-mode)
    

    Keep in mind that plugins need to be added before oh-my-zsh.sh is sourced.

    Using Antibody

    Add zsh-vi-mode to your plugins file (e.g. ~/.zsh_plugins.txt)

    jeffreytse/zsh-vi-mode
    
    Using Zap

    Load zsh-vi-mode as a plugin in your .zshrc

    plug "jeffreytse/zsh-vi-mode"
    
    Using Zim

    Load zsh-vi-mode as a plugin in your .zimrc

    zmodule jeffreytse/zsh-vi-mode
    
    Using Homebrew

    For Homebrew users, you can install it through the following command

    brew install zsh-vi-mode
    

    Then source it in your .zshrc (or .bashrc)

    source $(brew --prefix)/opt/zsh-vi-mode/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh
    
    Arch Linux (AUR)

    For Arch Linux users, you can install it through the following command

    yay -S zsh-vi-mode
    

    or the latest update (unstable)

    yay -S zsh-vi-mode-git
    

    Then source it in your .zshrc (or .bashrc)

    source /usr/share/zsh/plugins/zsh-vi-mode/zsh-vi-mode.plugin.zsh
    
    Nix

    For users of Nix, as of e7e3480530b34a9fe8cb52963ec2cf66e6707e15 you can source the plugin through the following configuration

    programs = {
      zsh = {
        interactiveShellInit = ''
          source ${pkgs.zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh
        '';
      };
    };
    

    Or if you prefer home-manager:

    home-manager.users.[your username] = { pkgs, ... }: {
      programs = {
        zsh = {
          initExtra = ''
            source ${pkgs.zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh
          '';
        };
      };
    };
    

    You can also use home-manager's built-in "plugin" feature:

    home-manager.users.[your username] = { pkgs, ... }: {
      programs = {
        zsh = {
          plugins = [
            {
              name = "vi-mode";
              src = pkgs.zsh-vi-mode;
              file = "share/zsh-vi-mode/zsh-vi-mode.plugin.zsh";
            }
          ];
        };
      };
    };
    
    Gentoo Linux

    Available in dm9pZCAq overlay

    eselect repository enable dm9pZCAq
    emerge --sync dm9pZCAq
    emerge app-shells/zsh-vi-mode
    

    Then source it in your .zshrc (or .bashrc)

    source /usr/share/zsh/site-contrib/zsh-vi-mode/zsh-vi-mode.plugin.zsh
    
    Manually

    Clone this repository somewhere ($HOME/.zsh-vi-mode for example)

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

    Then source it in your .zshrc (or .bashrc)

    source $HOME/.zsh-vi-mode/zsh-vi-mode.plugin.zsh
    

    Packaging Status

    Packaging status

    📚 Usage

    Use ESC or CTRL-[ to enter Normal mode.

    But some people may like the custom escape key such as jj, jk and so on, if you want to custom the escape key, you can learn more from here.

    History

    • ctrl-p : Previous command in history
    • ctrl-n : Next command in history
    • / : Search backward in history
    • n : Repeat the last /

    Mode indicators

    Normal mode is indicated with block style cursor, and Insert mode with beam style cursor by default.

    Vim edition

    In Normal mode you can use vv to edit current command line in an editor (e.g. vi/vim/nvim...), because it is bound to the Visual mode.

    You can change the editor by ZVM_VI_EDITOR option, by default it is $EDITOR.

    Movement

    • $ : To the end of the line
    • ^ : To the first non-blank character of the line
    • 0 : To the first character of the line
    • w : [count] words forward
    • W : [count] WORDS forward
    • e : Forward to the end of word [count] inclusive
    • E : Forward to the end of WORD [count] inclusive
    • b : [count] words backward
    • B : [count] WORDS backward
    • t{char} : Till before [count]'th occurrence of {char} to the right
    • T{char} : Till before [count]'th occurrence of {char} to the left
    • f{char} : To [count]'th occurrence of {char} to the right
    • F{char} : To [count]'th occurrence of {char} to the left
    • ; : Repeat latest f, t, F or T [count] times
    • , : Repeat latest f, t, F or T in opposite direction

    Insertion

    • i : Insert text before the cursor
    • I : Insert text before the first character in the line
    • a : Append text after the cursor
    • A : Append text at the end of the line
    • o : Insert new command line below the current one
    • O : Insert new command line above the current one

    Surround

    There are 2 kinds of keybinding mode for surround operating, default is classic mode, you can choose the mode by setting ZVM_VI_SURROUND_BINDKEY option.

    1. classic mode (verb->s->surround)
    • S" : Add " for visual selection
    • ys" : Add " for visual selection
    • cs"' : Change " to '
    • ds" : Delete "
    1. s-prefix mode (s->verb->surround)
    • sa" : Add " for visual selection
    • sd" : Delete "
    • sr"' : Change " to '

    Note that key sequences must be pressed in fairly quick succession to avoid a timeout. You may extend this timeout with the ZVM_KEYTIMEOUT option.

    How to select surround text object?
    • vi" : Select the text object inside the quotes
    • va( : Select the text object including the brackets

    Then you can do any operation for the selection:

    1. Add surrounds for text object
    • vi" -> S[ or sa[ => "object" -> "[object]"
    • va" -> S[ or sa[ => "object" -> ["object"]
    1. Delete/Yank/Change text object
    • di( or vi( -> d
    • ca( or va( -> c
    • yi( or vi( -> y

    Increment and Decrement

    In normal mode, typing ctrl-a will increase to the next keyword, and typing ctrl-x will decrease to the next keyword. The keyword can be at the cursor, or to the right of the cursor (on the same line). The keyword could be as below:

    • Number (Decimal, Hexadecimal, Binary...)
    • Boolean (True or False, Yes or No, On or Off...)
    • Weekday (Sunday, Monday, Tuesday, Wednesday...)
    • Month (January, February, March, April, May...)
    • Operator (&&, ||, ++, --, ==, !==, and, or...)
    • ...

    For example:

    1. Increment
    • 9 => 10
    • aa99bb => aa100bb
    • aa100bc => aa101bc
    • 0xDe => 0xdf
    • 0Xdf => 0Xe0
    • 0b101 => 0b110
    • 0B11 => 0B101
    • true => false
    • yes => no
    • on => off
    • T => F
    • Fri => Sat
    • Oct => Nov
    • Monday => Tuesday
    • January => February
    • + => -
    • ++ => --
    • == => !=
    • !== => ===
    • && => ||
    • and => or
    • ...
    1. Decrement:
    • 100 => 99
    • aa100bb => aa99bb
    • 0 => -1
    • 0xdE0 => 0xDDF
    • 0xffFf0 => 0xfffef
    • 0xfffF0 => 0xFFFEF
    • 0x0 => 0xffffffffffffffff
    • 0Xf => 0Xe
    • 0b100 => 0b010
    • 0B100 => 0B011
    • True => False
    • On => Off
    • Sun => Sat
    • Jan => Dec
    • Monday => Sunday
    • August => July
    • / => *
    • ++ => --
    • == => !=
    • !== => ===
    • || => &&
    • or => and
    • ...

    System Clipboard

    zsh-vi-mode can integrate with your system clipboard. This feature is disabled by default. Therefore, you can't automatically copy to the system clipboard when you stroke yy, yw and so on, but only allowed to paste from it. If you want to enable this feature, you can set the option:

    Enable:

    ZVM_SYSTEM_CLIPBOARD_ENABLED=true
    

    Auto-detection:

    • macOS: pbcopy and pbpaste
    • Wayland: wl-copy and wl-paste -n
    • X11: xclip or xsel

    Override commands:

    ZVM_CLIPBOARD_COPY_CMD='xclip -selection clipboard'
    ZVM_CLIPBOARD_PASTE_CMD='xclip -selection clipboard -o'
    

    Keybindings:

    • Normal: gp paste clipboard after cursor, gP before cursor
    • Visual: gp/gP replace selection with clipboard

    Note: p/P keep using ZLE's CUTBUFFER; gp/gP use the system clipboard.

    Behavior:

    • When enabled, yanks/deletes/changes that set CUTBUFFER also copy to the system clipboard.

    WSL (Windows Subsystem for Linux):

    # Using Windows clipboard
    ZVM_SYSTEM_CLIPBOARD_ENABLED=true
    ZVM_CLIPBOARD_COPY_CMD='clip.exe'
    ZVM_CLIPBOARD_PASTE_CMD='powershell.exe -NoProfile -Command Get-Clipboard'
    

    or using win32yank:

    ZVM_CLIPBOARD_COPY_CMD='win32yank.exe -i --crlf'
    ZVM_CLIPBOARD_PASTE_CMD='win32yank.exe -o --lf'
    

    OSC 52 (Remote Clipboard)

    OSC 52 is an escape sequence that allows copying text to the clipboard over SSH or in tmux sessions without requiring X11 forwarding or other clipboard tools.

    Enable OSC 52:

    ZVM_SYSTEM_CLIPBOARD_ENABLED=true
    ZVM_CLIPBOARD_USE_OSC52=true
    

    By default, the plugin automatically detects if you're in a tmux session (via the $TMUX variable) and wraps the escape sequence accordingly. You can control this behavior:

    # Always use tmux wrapping (even if not in tmux)
    ZVM_CLIPBOARD_OSC52_TMUX=true
    
    # Never use tmux wrapping (even if in tmux)
    ZVM_CLIPBOARD_OSC52_TMUX=false
    
    # Auto-detect (default behavior, check $TMUX variable)
    ZVM_CLIPBOARD_OSC52_TMUX=
    

    Note: OSC 52 requires your terminal emulator and tmux (if used) to support clipboard integration. Most modern terminals support this feature.

    Open Under Cursor

    In Normal mode, you can use gx to open the URL or file path under the cursor.

    • If the word under the cursor is a URL (starting with http://, https://, ftp://, file://), it will open in your default web browser.
    • If the word under the cursor is a valid file or directory path, it will open with your system's default application for that file type.

    The plugin automatically detects whether the text under the cursor is a URL or a file path and opens it accordingly using your system's default opener:

    • macOS: open
    • Linux: xdg-open
    • Windows: You need to manually config, see below.

    You can override the default open command by setting the ZVM_OPEN_CMD option. Also, you can set the ZVM_OPEN_URL_CMD and ZVM_OPEN_FILE_CMD options to specify different commands for opening URLs and files respectively.

    Overriding commands example:

    # Override the default open command
    ZVM_OPEN_CMD='xdg-open'
    
    # Override the open command for URLs
    ZVM_OPEN_URL_CMD='firefox'
    
    # Override the open command for URLs on macOS
    ZVM_OPEN_URL_CMD='open -a "Safari"'
    
    # Override the open command for files
    ZVM_OPEN_FILE_CMD='code'  # Open files with Visual Studio Code
    
    # Override the open command for files on macOS
    ZVM_OPEN_FILE_CMD='open -a "Visual Studio Code"'
    
    # Override the open command for files on Windows
    ZVM_OPEN_FILE_CMD='powershell.exe -Command "Start-Process code"'
    
    # Override the open command for files on Windows using cmd
    ZVM_OPEN_FILE_CMD='start code'
    

    For Windows users, you can create a script for opening on Windows, for example, a script /usr/local/bin/xdg-open with content:

    #!/usr/bin/env bash
    
    # A Linux-like "xdg-open" command for WSL
    # Supports: http, https, ftp, ftps, file URLs, local files and directories
    
    if [ $# -eq 0 ]; then
      echo "Usage: open <file|dir|url>"
      exit 1
    fi
    
    for target in "$@"; do
      # If it is a URL (http, https, ftp, ftps, file)
      if [[ "$target" =~ ^(https?|ftps?|file):// ]]; then
        explorer.exe "$target"
        continue
      fi
    
      # Otherwise, treat as regular file or directory paths
      if [ -e "$target" ]; then
        win_path=$(wslpath -w "$target")
        explorer.exe "$win_path"
      else
        echo "open: $target not found"
      fi
    done
    

    And add executive permission:

    sudo chmod +x /usr/local/bin/xdg-open
    

    Then set the ZVM_OPEN_CMD option:

    ZVM_OPEN_CMD='/usr/local/bin/xdg-open'
    

    Or you can use cygstart if you are using Cygwin:

    ZVM_OPEN_CMD='cygstart'
    

    Or set the cygstart command as a alias as below:

    # Add a open alias to your .zshrc for Windows users
    open='cygstart'
    

    Custom Escape Key

    You can use below options to custom the escape key which could better match your flavor, such as jj or jk and so on.

    • ZVM_VI_ESCAPE_BINDKEY: The vi escape key in all modes (default is ^[ => ESC)
    • ZVM_VI_INSERT_ESCAPE_BINDKEY: The vi escape key in insert mode (default is $ZVM_VI_ESCAPE_BINDKEY)
    • ZVM_VI_VISUAL_ESCAPE_BINDKEY: The vi escape key in visual mode (default is $ZVM_VI_ESCAPE_BINDKEY)
    • ZVM_VI_OPPEND_ESCAPE_BINDKEY: The vi escape key in operator pending mode (default is $ZVM_VI_ESCAPE_BINDKEY)

    For example:

    # Only changing the escape key to `jk` in insert mode, we still
    # keep using the default keybindings `^[` in other modes
    ZVM_VI_INSERT_ESCAPE_BINDKEY=jk
    

    Readkey Engine

    This plugin has supported to choose the readkey engine for reading and processing the key events. It easy to do by the ZVM_READKEY_ENGINEoption, currently the below engines are supported:

    • ZVM_READKEY_ENGINE_NEX: It is a better readkey engine to replace ZLE (Beta).
    • ZVM_READKEY_ENGINE_ZLE: It is Zsh's default readkey engine (ZLE).
    • ZVM_READKEY_ENGINE_DEFAULT: It is the default engine of this plugin (It's the NEX engine now).

    The NEX is a better engine for reading and handling the key events than the Zsh's ZLE engine, currently the NEX engine is still at beta stage, you can change back to Zsh's ZLE engine if you want.

    For example:

    # Change to Zsh's default readkey engine
    ZVM_READKEY_ENGINE=$ZVM_READKEY_ENGINE_ZLE
    

    You can use ZVM_KEYTIMEOUT option to adjust the key input timeout for waiting for next key, default is 0.4 seconds.

    The escape key is a special case, it can be used standalone. NEX engine waits for a period after receiving the escape character, to determine whether it is standalone or part of an escape sequence. While waiting, additional key presses make the escape key behave as a meta key. If no other key presses come in, it is handled as a standalone escape.

    For the NEX engine, we can use ZVM_ESCAPE_KEYTIMEOUT option to adjust the waiting timeout for the escape key, default is 0.03 seconds.

    Configuration Function

    Since there are some config options relied to some variables defined in the plugin, however, some not. We need to provide an unified config entry function. The name of entry function is stored in an option called ZVM_CONFIG_FUNC and default value is zvm_config, you can change to others for fitting your flavor.

    If this config function exists, it will be called automatically, you can do some configurations in this aspect before you source this plugin. For example:

    function zvm_config() {
      ZVM_LINE_INIT_MODE=$ZVM_MODE_INSERT
      ZVM_VI_INSERT_ESCAPE_BINDKEY=jk
    }
    
    source ~/zsh-vi-mode.zsh
    

    Execute Extra Commands

    This plugin has provided a mechanism to execute extra commands, and now you have the below aspects for executing something:

    zvm_before_init_commands=()
    zvm_after_init_commands=()
    zvm_before_select_vi_mode_commands=()
    zvm_after_select_vi_mode_commands=()
    zvm_before_lazy_keybindings_commands=()
    zvm_after_lazy_keybindings_commands=()
    

    Since the default initialization mode, this plugin will overwrite the previous key bindings, this causes the key bindings of other plugins (i.e. fzf, zsh-autocomplete, etc.) to fail.

    You can solve the compatibility issue as below:

    # Append a command directly
    zvm_after_init_commands+=('[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh')
    

    or

    # Define an init function and append to zvm_after_init_commands
    function my_init() {
      [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
    }
    zvm_after_init_commands+=(my_init)
    

    or

    # The plugin will auto execute this zvm_after_init function
    function zvm_after_init() {
      [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
    }
    

    or if you are using the zinit:

    # For postponing loading `fzf`
    zinit ice lucid wait
    zinit snippet OMZP::fzf
    

    By default, the lazy keybindings feature is enabled, all the keybindings of normal and visual mode should be executed by the zvm_after_lazy_keybindings_commands. For example:

    # The plugin will auto execute this zvm_after_lazy_keybindings function
    function zvm_after_lazy_keybindings() {
      bindkey -M vicmd 's' your_normal_widget
      bindkey -M visual 'n' your_visual_widget
    }
    

    Custom widgets and keybindings

    This plugin has two functions for you to define custom widgets and keybindings. In case of unnecessary problems, it is better to use them, especially when you meet the key conflicts.

    To define a custom widget, you should:

    # If [your_custom_widget] were ignored, it will be the same with <your_custom_widget>
    zvm_define_widget <your_custom_widget> [your_custom_function]
    

    To define a keybinding, you should:

    zvm_bindkey <keymap> <keys> <widget>
    

    For example:

    # Your custom widget
    function my_custom_widget() {
      echo 'Hello, ZSH!'
    }
    
    # The plugin will auto execute this zvm_after_lazy_keybindings function
    function zvm_after_lazy_keybindings() {
      # Here we define the custom widget
      zvm_define_widget my_custom_widget
    
      # In normal mode, press Ctrl-E to invoke this widget
      zvm_bindkey vicmd '^E' my_custom_widget
    }
    

    Vi Mode Indicator

    This plugin has provided a ZVM_MODE variable for you to retrieve current vi mode and better show the indicator.

    And currently the below modes are supported:

    ZVM_MODE_NORMAL
    ZVM_MODE_INSERT
    ZVM_MODE_VISUAL
    ZVM_MODE_VISUAL_LINE
    ZVM_MODE_REPLACE
    

    For updating the vi mode indicator, we should add our commands to zvm_after_select_vi_mode_commands. For example:

    # The plugin will auto execute this zvm_after_select_vi_mode function
    function zvm_after_select_vi_mode() {
      case $ZVM_MODE in
        $ZVM_MODE_NORMAL)
          # Something you want to do...
        ;;
        $ZVM_MODE_INSERT)
          # Something you want to do...
        ;;
        $ZVM_MODE_VISUAL)
          # Something you want to do...
        ;;
        $ZVM_MODE_VISUAL_LINE)
          # Something you want to do...
        ;;
        $ZVM_MODE_REPLACE)
          # Something you want to do...
        ;;
      esac
    }
    

    Custom Cursor Style

    This plugin has provided some options for users to custom the cursor style for better terminal compatibility.

    • You can disable this feature by the ZVM_CURSOR_STYLE_ENABLED option (Default is true)
    # Disable the cursor style feature
    ZVM_CURSOR_STYLE_ENABLED=false
    
    • You can set your cursor style for different vi mode:
    # The prompt cursor in normal mode
    ZVM_NORMAL_MODE_CURSOR
    
    # The prompt cursor in insert mode
    ZVM_INSERT_MODE_CURSOR
    
    # The prompt cursor in visual mode
    ZVM_VISUAL_MODE_CURSOR
    
    # The prompt cursor in visual line mode
    ZVM_VISUAL_LINE_MODE_CURSOR
    
    # The prompt cursor in operator pending mode
    ZVM_OPPEND_MODE_CURSOR
    
    • And the below cursor styles are supported:
    ZVM_CURSOR_USER_DEFAULT
    ZVM_CURSOR_BLOCK
    ZVM_CURSOR_UNDERLINE
    ZVM_CURSOR_BEAM
    ZVM_CURSOR_BLINKING_BLOCK
    ZVM_CURSOR_BLINKING_UNDERLINE
    ZVM_CURSOR_BLINKING_BEAM
    
    • Custom your cursor style is easy as below:
    ZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BEAM
    ZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK
    ZVM_OPPEND_MODE_CURSOR=$ZVM_CURSOR_UNDERLINE
    
    • Also, custom your colorful cursor style as below:
    # The plugin will auto execute this zvm_config function
    zvm_config() {
      # Retrieve default cursor styles
      local ncur=$(zvm_cursor_style $ZVM_NORMAL_MODE_CURSOR)
      local icur=$(zvm_cursor_style $ZVM_INSERT_MODE_CURSOR)
    
      # Append your custom color for your cursor
      ZVM_INSERT_MODE_CURSOR=$icur'\e\e]12;red\a'
      ZVM_NORMAL_MODE_CURSOR=$ncur'\e\e]12;#008800\a'
    }
    

    We can use ZVM_TERM option to set the term type for plugin to handle terminal escape sequences, default is $TERM. It could be xterm-256color, alacritty-256color, st-256color, etc. It's important for some terminal emulators to show cursor properly.

    Highlight Behavior

    You can use ZVM_VI_HIGHLIGHT_BACKGROUND, ZVM_VI_HIGHLIGHT_FOREGROUND and ZVM_VI_HIGHLIGHT_EXTRASTYLE to change the highlight behaviors ( surrounds, visual-line, etc.), the color value could be a color name or a hex color value.

    For example:

    ZVM_VI_HIGHLIGHT_FOREGROUND=green             # Color name
    ZVM_VI_HIGHLIGHT_FOREGROUND=#008800           # Hex value
    ZVM_VI_HIGHLIGHT_BACKGROUND=red               # Color name
    ZVM_VI_HIGHLIGHT_BACKGROUND=#ff0000           # Hex value
    ZVM_VI_HIGHLIGHT_EXTRASTYLE=bold,underline    # bold and underline
    

    Command Line Initial Mode

    You can set the command line initial mode by the ZVM_LINE_INIT_MODE option.

    Currently the below modes are supported:

    • ZVM_MODE_LAST : Starting with last mode (Default).
    • ZVM_MODE_INSERT : Starting with insert mode.
    • ZVM_MODE_NORMAL : Starting with normal mode.

    For example:

    # Always starting with insert mode for each command line
    ZVM_LINE_INIT_MODE=$ZVM_MODE_INSERT
    

    Lazy Keybindings

    This plugin has supported the lazy keybindings feature, and it is enabled by default. To disable it, you can set the option ZVM_LAZY_KEYBINDINGS to false before this plugin is loaded. This feature will postpone all the keybindings of normal and visual mode to the first time you enter the normal mode.

    It can greatly improve the startup speed, especially you open the terminal and just want to execute a simple command.

    Initialization Mode

    In order to prevent various problems related to keybindings caused by the plugin sourcing sequence, and also keep the same functionality for this plugin, the initialization of this plugin was postponed to the first command line starting.

    However, almost all plugins are initialized when the script is sourced. Therefore, this plugin provides an option ZVM_INIT_MODE to change the initialization mode.

    For example:

    # Do the initialization when the script is sourced (i.e. Initialize instantly)
    ZVM_INIT_MODE=sourcing
    

    💎 Credits

    • Zsh - A powerful shell that operates as both an interactive shell and as a scripting language interpreter.
    • Oh-My-Zsh - A delightful, open source, community-driven framework for managing your ZSH configuration.
    • vim-surround - A vim plugin all about "surroundings": parentheses, brackets, quotes, XML tags, and more.
    • vim-sandwich - A set of operator and textobject plugins to add/delete/replace surroundings of a sandwiched textobject.

    🔫 Contributing

    Issues and Pull Requests are greatly appreciated. If you've never contributed to an open source project before I'm more than happy to walk you through how to create a pull request.

    You can start by opening an issue describing the problem that you're looking to resolve and we'll go from there.

    🌈 License

    This theme is licensed under the MIT license © Jeffrey Tse.