{"id":13442273,"url":"https://github.com/jeffreytse/zsh-vi-mode","last_synced_at":"2025-10-03T03:30:25.503Z","repository":{"id":37150184,"uuid":"320469278","full_name":"jeffreytse/zsh-vi-mode","owner":"jeffreytse","description":"💻 A better and friendly vi(vim) mode plugin for ZSH.","archived":false,"fork":false,"pushed_at":"2025-09-23T01:58:28.000Z","size":385,"stargazers_count":3975,"open_issues_count":120,"forks_count":135,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-09-23T03:39:40.981Z","etag":null,"topics":["antigen","awesome","clipboard","command-line-tool","keybinding","like","oh-my-zsh","productivity","shell","shell-scripts","surround","terminal","vi-keybinds","vim","zgen","zinit","zplug","zsh","zsh-plugin","zsh-plugins"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeffreytse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"jeffreytse","patreon":"jeffreytse","open_collective":null,"ko_fi":"jeffreytse","tidelift":null,"community_bridge":null,"liberapay":"jeffreytse","issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-12-11T04:44:28.000Z","updated_at":"2025-09-23T01:58:31.000Z","dependencies_parsed_at":"2024-03-14T02:46:36.466Z","dependency_job_id":"7968df10-9c5c-419f-ba50-0ceba02150a7","html_url":"https://github.com/jeffreytse/zsh-vi-mode","commit_stats":{"total_commits":312,"total_committers":28,"mean_commits":"11.142857142857142","dds":0.09294871794871795,"last_synced_commit":"287efa19ec492b2f24bb93d1f4eaac3049743a63"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/jeffreytse/zsh-vi-mode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreytse%2Fzsh-vi-mode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreytse%2Fzsh-vi-mode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreytse%2Fzsh-vi-mode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreytse%2Fzsh-vi-mode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeffreytse","download_url":"https://codeload.github.com/jeffreytse/zsh-vi-mode/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreytse%2Fzsh-vi-mode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276526561,"owners_count":25657892,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-23T02:00:09.130Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["antigen","awesome","clipboard","command-line-tool","keybinding","like","oh-my-zsh","productivity","shell","shell-scripts","surround","terminal","vi-keybinds","vim","zgen","zinit","zplug","zsh","zsh-plugin","zsh-plugins"],"created_at":"2024-07-31T03:01:43.760Z","updated_at":"2025-10-03T03:30:25.497Z","avatar_url":"https://github.com/jeffreytse.png","language":"Shell","funding_links":["https://github.com/sponsors/jeffreytse","https://patreon.com/jeffreytse","https://ko-fi.com/jeffreytse","https://liberapay.com/jeffreytse"],"categories":["HarmonyOS","Shell","Plugins","shell","Shells"],"sub_categories":["Windows Manager","ZSH on Windows"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/jeffreytse/zsh-vi-mode\"\u003e\n    \u003cimg alt=\"vi-mode →~ zsh\" src=\"https://user-images.githubusercontent.com/9413601/103399068-46bfcb80-4b7a-11eb-8741-86cff3d85a69.png\" width=\"600\"\u003e\n  \u003c/a\u003e\n  \u003cp\u003e 💻 A better and friendly vi(vim) mode plugin for ZSH.  \u003c/p\u003e\n\n  \u003cbr\u003e \u003ch1\u003e⚒️  Zsh Vi Mode ⚒️\u003c/h1\u003e\n\n\u003c/div\u003e\n\n\n\n\u003ch4 align=\"center\"\u003e\n  \u003ca href=\"https://www.zsh.org/\" target=\"_blank\"\u003e\u003ccode\u003eZSH\u003c/code\u003e\u003c/a\u003e plugin for Agnosticism.\n\u003c/h4\u003e\n\n\u003cp align=\"center\"\u003e\n\n  \u003ca href=\"https://github.com/sponsors/jeffreytse\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026link=\u0026color=greygreen\"\n      alt=\"Donate (GitHub Sponsor)\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://github.com/jeffreytse/zsh-vi-mode/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/jeffreytse/zsh-vi-mode?color=brightgreen\"\n      alt=\"Release Version\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-brightgreen.svg\"\n      alt=\"License: MIT\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://liberapay.com/jeffreytse\"\u003e\n    \u003cimg src=\"http://img.shields.io/liberapay/goal/jeffreytse.svg?logo=liberapay\"\n      alt=\"Donate (Liberapay)\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://patreon.com/jeffreytse\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/support-patreon-F96854.svg?style=flat-square\"\n      alt=\"Donate (Patreon)\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://ko-fi.com/jeffreytse\"\u003e\n    \u003cimg height=\"20\" src=\"https://www.ko-fi.com/img/githubbutton_sm.svg\"\n      alt=\"Donate (Ko-fi)\" /\u003e\n  \u003c/a\u003e\n\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch4\u003e\n    \u003ca href=\"#-features\"\u003eFeatures\u003c/a\u003e |\n    \u003ca href=\"#%EF%B8%8F-installation\"\u003eInstall\u003c/a\u003e |\n    \u003ca href=\"#-usage\"\u003eUsage\u003c/a\u003e |\n    \u003ca href=\"#-credits\"\u003eCredits\u003c/a\u003e |\n    \u003ca href=\"#-license\"\u003eLicense\u003c/a\u003e\n  \u003c/h4\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003csub\u003eBuilt with ❤︎ by\n  \u003ca href=\"https://jeffreytse.net\"\u003ejeffreytse\u003c/a\u003e and\n  \u003ca href=\"https://github.com/jeffreytse/zsh-vi-mode/graphs/contributors\"\u003econtributors \u003c/a\u003e\n\u003c/div\u003e\n\u003cbr\u003e\n\n\u003cimg alt=\"Zsh Vi-mode Demo\" src=\"https://user-images.githubusercontent.com/9413601/105746868-f3734a00-5f7a-11eb-8db5-22fcf50a171b.gif\" /\u003e\n\n## 🤔 Why ZVM?\n\nMaybe you have experienced the default Vi mode in Zsh, after turning on\nthe default Vi mode, you gradually found that it had many problems, some\nfeatures were not perfect or non-existent, and some behaviors even were\ndifferent from the native Vi(Vim) mode.\n\nAlthough the default Vi mode was a bit embarrassing and unpleasant, you\nkept on using it and gradually lost your interest on it after using for\na period of time. Eventually, you disappointedly gave up.\n\nYou never think of the Vi mode for a long time, one day you accidentally\ndiscovered this plugin, you read here and realize that this plugin is to\nsolve the above problems and make you fall in love to Vi mode again. A\nsmile suddenly appeared on your face like regaining a good life.\n\n\u003e If winter comes, can spring be far behind?\n\n\n## ✨ Features\n\n- 🌟 Pure Zsh's script without any third-party dependencies.\n- 🎉 Better experience with the near-native vi(vim) mode.\n- ⌛ Lower delay and better response (Mode switching speed, etc.).\n- ✏️  Mode indication with different cursor styles.\n- 🧮 Cursor movement (Navigation).\n- 📝 Insert \u0026 Replace (Insert mode).\n- 💡 Text Objects (A word, inner word, etc.).\n- 🔎 Searching history.\n- ❇️  Undo, Redo, Cut, Copy, Paste, and Delete.\n- 🪐 Better surrounds functionality (Add, Replace, Delete, Move Around, and Highlight).\n- 🧽 Switch keywords (Increase/Decrease Number, Boolean, Weekday, Month, etc.).\n- ⚙️  Open under cursor URL or file path with charming `gx`.\n- 🖋️ Edit current command line in an external editor with `vv`.\n- 🪀 Repeating command such as `10p` and `4fa`.\n- 📒 System clipboard integration (Copy/Paste).\n\n## 💼 Requirements\n\nZSH: \u003e= 5.1.0\n\n## 🛠️ Installation\n\n#### Using [Antigen](https://github.com/zsh-users/antigen)\n\nBundle `zsh-vi-mode` in your `.zshrc`\n\n```shell\nantigen bundle jeffreytse/zsh-vi-mode\n```\n\n#### Using [zplug](https://github.com/b4b4r07/zplug)\nLoad `zsh-vi-mode` as a plugin in your `.zshrc`\n\n```shell\nzplug \"jeffreytse/zsh-vi-mode\"\n```\n\n#### Using [zgen](https://github.com/tarjoilija/zgen)\n\nInclude the load command in your `.zshrc`\n\n```shell\nzgen load jeffreytse/zsh-vi-mode\n```\n\n#### Using [zinit](https://github.com/zdharma-continuum/zinit)\n\nInclude the load command in your `.zshrc`\n\n```shell\nzinit ice depth=1\nzinit light jeffreytse/zsh-vi-mode\n```\n\nNote: the use of `depth=1` ice is optional, other types of ice are neither\nrecommended nor officially supported by this plugin.\n\n#### As an [Oh My Zsh!](https://github.com/robbyrussell/oh-my-zsh) custom plugin\n\nClone `zsh-vi-mode` into your custom plugins repo\n\n```shell\ngit clone https://github.com/jeffreytse/zsh-vi-mode \\\n  $ZSH_CUSTOM/plugins/zsh-vi-mode\n```\nThen load as a plugin in your `.zshrc`\n\n```shell\nplugins+=(zsh-vi-mode)\n```\n\nKeep in mind that plugins need to be added before `oh-my-zsh.sh` is sourced.\n\n#### Using [Antibody](https://getantibody.github.io/)\n\nAdd `zsh-vi-mode` to your plugins file (e.g. `~/.zsh_plugins.txt`)\n\n```shell\njeffreytse/zsh-vi-mode\n```\n\n#### Using [Zap](https://github.com/zap-zsh/zap)\n\nLoad `zsh-vi-mode` as a plugin in your `.zshrc`\n\n```shell\nplug \"jeffreytse/zsh-vi-mode\"\n```\n\n#### Using [Zim](https://github.com/zimfw/zimfw)\n\nLoad `zsh-vi-mode` as a plugin in your `.zimrc`\n\n```shell\nzmodule jeffreytse/zsh-vi-mode\n```\n  \n#### Using [Homebrew](https://brew.sh/)\n\nFor Homebrew users, you can install it through the following command\n\n```shell\nbrew install zsh-vi-mode\n```\n\nThen source it in your `.zshrc` (or `.bashrc`)\n\n```shell\nsource $(brew --prefix)/opt/zsh-vi-mode/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh\n```\n\n#### Arch Linux (AUR)\n\nFor Arch Linux users, you can install it through the following command\n\n```shell\nyay -S zsh-vi-mode\n```\n\nor the latest update (unstable)\n\n```shell\nyay -S zsh-vi-mode-git\n```\n\nThen source it in your `.zshrc` (or `.bashrc`)\n\n```shell\nsource /usr/share/zsh/plugins/zsh-vi-mode/zsh-vi-mode.plugin.zsh\n```\n\n#### Nix\n\nFor users of Nix, as of [e7e3480530b34a9fe8cb52963ec2cf66e6707e15](https://github.com/NixOS/nixpkgs/commit/e7e3480530b34a9fe8cb52963ec2cf66e6707e15) you can source the plugin through the following configuration\n\n```nix\nprograms = {\n  zsh = {\n    interactiveShellInit = ''\n      source ${pkgs.zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh\n    '';\n  };\n};\n```\n  \nOr if you prefer `home-manager`:\n\n```nix\nhome-manager.users.[your username] = { pkgs, ... }: {\n  programs = {\n    zsh = {\n      initExtra = ''\n        source ${pkgs.zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh\n      '';\n    };\n  };\n};\n```\n\nYou can also use `home-manager`'s built-in \"plugin\" feature:\n\n```nix\nhome-manager.users.[your username] = { pkgs, ... }: {\n  programs = {\n    zsh = {\n      plugins = [\n        {\n          name = \"vi-mode\";\n          src = pkgs.zsh-vi-mode;\n          file = \"share/zsh-vi-mode/zsh-vi-mode.plugin.zsh\";\n        }\n      ];\n    };\n  };\n};\n```\n\n#### Using [Fig](https://fig.io)\n\nFig adds apps, shortcuts, and autocomplete to your existing terminal.\n\nInstall `zsh-vi-mode` in just one click.\n\n\u003ca href=\"https://fig.io/plugins/other/zsh-vi-mode\" target=\"_blank\"\u003e\u003cimg src=\"https://fig.io/badges/install-with-fig.svg\" /\u003e\u003c/a\u003e\n\n#### Gentoo Linux\n\nAvailable in [dm9pZCAq overlay](https://github.com/gentoo-mirror/dm9pZCAq)\n\n```shell\neselect repository enable dm9pZCAq\nemerge --sync dm9pZCAq\nemerge app-shells/zsh-vi-mode\n```\n\nThen source it in your `.zshrc` (or `.bashrc`)\n\n```shell\nsource /usr/share/zsh/site-contrib/zsh-vi-mode/zsh-vi-mode.plugin.zsh\n```\n\n#### Manually\n\nClone this repository somewhere (`$HOME/.zsh-vi-mode` for example)\n\n```shell\ngit clone https://github.com/jeffreytse/zsh-vi-mode.git $HOME/.zsh-vi-mode\n```\nThen source it in your `.zshrc` (or `.bashrc`)\n\n```shell\nsource $HOME/.zsh-vi-mode/zsh-vi-mode.plugin.zsh\n```\n\n## Packaging Status\n\n[![Packaging status](https://repology.org/badge/vertical-allrepos/zsh-vi-mode.svg)](https://repology.org/project/zsh-vi-mode/versions)\n\n## 📚 Usage\n\nUse `ESC` or `CTRL-[` to enter `Normal mode`.\n\nBut some people may like the custom escape key such as `jj`, `jk` and so on,\nif you want to custom the escape key, you can learn more from [here](#custom-escape-key).\n\nHistory\n-------\n\n- `ctrl-p` : Previous command in history\n- `ctrl-n` : Next command in history\n- `/`      : Search backward in history\n- `n`      : Repeat the last `/`\n\n\nMode indicators\n---------------\n\n`Normal mode` is indicated with block style cursor, and `Insert mode` with\nbeam style cursor by default.\n\nVim edition\n-----------\n\nIn `Normal mode` you can use `vv` to edit current command line in an editor\n(e.g. `vi`/`vim`/`nvim`...), because it is bound to the `Visual mode`.\n\nYou can change the editor by `ZVM_VI_EDITOR` option, by default it is\n`$EDITOR`.\n\nMovement\n--------\n\n- `$`   : To the end of the line\n- `^`   : To the first non-blank character of the line\n- `0`   : To the first character of the line\n- `w`   : [count] words forward\n- `W`   : [count] WORDS forward\n- `e`   : Forward to the end of word [count] inclusive\n- `E`   : Forward to the end of WORD [count] inclusive\n- `b`   : [count] words backward\n- `B`   : [count] WORDS backward\n- `t{char}`   : Till before [count]'th occurrence of {char} to the right\n- `T{char}`   : Till before [count]'th occurrence of {char} to the left\n- `f{char}`   : To [count]'th occurrence of {char} to the right\n- `F{char}`   : To [count]'th occurrence of {char} to the left\n- `;`   : Repeat latest f, t, F or T [count] times\n- `,`   : Repeat latest f, t, F or T in opposite direction\n\n\nInsertion\n---------\n\n- `i`   : Insert text before the cursor\n- `I`   : Insert text before the first character in the line\n- `a`   : Append text after the cursor\n- `A`   : Append text at the end of the line\n- `o`   : Insert new command line below the current one\n- `O`   : Insert new command line above the current one\n\nSurround\n--------\n\nThere are 2 kinds of keybinding mode for surround operating, default is\n`classic` mode, you can choose the mode by setting `ZVM_VI_SURROUND_BINDKEY`\noption.\n\n1. `classic` mode (verb-\u003es-\u003esurround)\n\n- `S\"`    : Add `\"` for visual selection\n- `ys\"`   : Add `\"` for visual selection\n- `cs\"'`  : Change `\"` to `'`\n- `ds\"`   : Delete `\"`\n\n 2. `s-prefix` mode (s-\u003everb-\u003esurround)\n- `sa\"`   : Add `\"` for visual selection\n- `sd\"`   : Delete `\"`\n- `sr\"'`  : Change `\"` to `'`\n\nNote that key sequences must be pressed in fairly quick succession to avoid a timeout. You may extend this timeout with the [`ZVM_KEYTIMEOUT` option](#readkey-engine).\n  \n#### How to select surround text object?\n\n- `vi\"`   : Select the text object inside the quotes\n- `va(`   : Select the text object including the brackets\n\nThen you can do any operation for the selection:\n\n1. Add surrounds for text object\n\n- `vi\"` -\u003e `S[` or `sa[` =\u003e `\"object\"` -\u003e `\"[object]\"`\n- `va\"` -\u003e `S[` or `sa[` =\u003e `\"object\"` -\u003e `[\"object\"]`\n\n2. Delete/Yank/Change text object\n\n- `di(` or `vi(` -\u003e `d`\n- `ca(` or `va(` -\u003e `c`\n- `yi(` or `vi(` -\u003e `y`\n\nIncrement and Decrement\n--------\n\nIn normal mode, typing `ctrl-a` will increase to the next keyword, and typing\n`ctrl-x` will decrease to the next keyword. The keyword can be at the cursor,\nor to the right of the cursor (on the same line). The keyword could be as\nbelow:\n\n- Number (Decimal, Hexadecimal, Binary...)\n- Boolean (True or False, Yes or No, On or Off...)\n- Weekday (Sunday, Monday, Tuesday, Wednesday...)\n- Month (January, February, March, April, May...)\n- Operator (\u0026\u0026, ||, ++, --, ==, !==, and, or...)\n- ...\n\nFor example:\n\n1. Increment\n\n- `9` =\u003e `10`\n- `aa99bb` =\u003e `aa100bb`\n- `aa100bc` =\u003e `aa101bc`\n- `0xDe` =\u003e `0xdf`\n- `0Xdf` =\u003e `0Xe0`\n- `0b101` =\u003e `0b110`\n- `0B11` =\u003e `0B101`\n- `true` =\u003e `false`\n- `yes` =\u003e `no`\n- `on` =\u003e `off`\n- `T` =\u003e `F`\n- `Fri` =\u003e `Sat`\n- `Oct` =\u003e `Nov`\n- `Monday` =\u003e `Tuesday`\n- `January` =\u003e `February`\n- `+` =\u003e `-`\n- `++` =\u003e `--`\n- `==` =\u003e `!=`\n- `!==` =\u003e `===`\n- `\u0026\u0026` =\u003e `||`\n- `and` =\u003e `or`\n- ...\n\n2. Decrement:\n\n- `100` =\u003e `99`\n- `aa100bb` =\u003e `aa99bb`\n- `0` =\u003e `-1`\n- `0xdE0` =\u003e `0xDDF`\n- `0xffFf0` =\u003e `0xfffef`\n- `0xfffF0` =\u003e `0xFFFEF`\n- `0x0` =\u003e `0xffffffffffffffff`\n- `0Xf` =\u003e `0Xe`\n- `0b100` =\u003e `0b010`\n- `0B100` =\u003e `0B011`\n- `True` =\u003e `False`\n- `On` =\u003e `Off`\n- `Sun` =\u003e `Sat`\n- `Jan` =\u003e `Dec`\n- `Monday` =\u003e `Sunday`\n- `August` =\u003e `July`\n- `/` =\u003e `*`\n- `++` =\u003e `--`\n- `==` =\u003e `!=`\n- `!==` =\u003e `===`\n- `||` =\u003e `\u0026\u0026`\n- `or` =\u003e `and`\n- ...\n\nSystem Clipboard\n--------\n\nzsh-vi-mode can integrate with your system clipboard. This feature is disabled\nby default. Therefore, you can't automatically copy to the system clipboard when\nyou stroke `yy`, `yw` and so on, but only allowed to paste from it. If you want\nto enable this feature, you can set the option:\n\nEnable:\n\n```zsh\nZVM_SYSTEM_CLIPBOARD_ENABLED=true\n```\n\nAuto-detection:\n\n- macOS: `pbcopy` and `pbpaste`\n- Wayland: `wl-copy` and `wl-paste -n`\n- X11: `xclip` or `xsel`\n\nOverride commands:\n\n```zsh\nZVM_CLIPBOARD_COPY_CMD='xclip -selection clipboard'\nZVM_CLIPBOARD_PASTE_CMD='xclip -selection clipboard -o'\n```\n\nKeybindings:\n\n- Normal: `gp` paste clipboard after cursor, `gP` before cursor\n- Visual: `gp`/`gP` replace selection with clipboard\n\nNote: `p`/`P` keep using ZLE's CUTBUFFER; `gp`/`gP` use the system clipboard.\n\nBehavior:\n\n- When enabled, yanks/deletes/changes that set CUTBUFFER also copy to the system clipboard.\n\nWSL (Windows Subsystem for Linux):\n\n```zsh\n# Using Windows clipboard\nZVM_SYSTEM_CLIPBOARD_ENABLED=true\nZVM_CLIPBOARD_COPY_CMD='clip.exe'\nZVM_CLIPBOARD_PASTE_CMD='powershell.exe -NoProfile -Command Get-Clipboard'\n```\n\nor using win32yank:\n\n```zsh\nZVM_CLIPBOARD_COPY_CMD='win32yank.exe -i --crlf'\nZVM_CLIPBOARD_PASTE_CMD='win32yank.exe -o --lf'\n```\n\nOpen Under Cursor\n----------------\n\nIn `Normal mode`, you can use `gx` to open the URL or file path under the cursor.\n\n- If the word under the cursor is a URL (starting with `http://`, `https://`, `ftp://`, `file://`), it will open in your default web browser.\n- 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.\n\nThe 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:\n\n- **macOS**: `open`\n- **Linux**: `xdg-open`\n- **Windows**: You need to manually config, see below.\n\nYou can override the default open command by setting the `ZVM_OPEN_CMD` option.\nAlso, you can set the `ZVM_OPEN_URL_CMD` and `ZVM_OPEN_FILE_CMD` options to\nspecify different commands for opening URLs and files respectively.\n\nOverriding commands example:\n\n```zsh\n# Override the default open command\nZVM_OPEN_CMD='xdg-open'\n\n# Override the open command for URLs\nZVM_OPEN_URL_CMD='firefox'\n\n# Override the open command for URLs on macOS\nZVM_OPEN_URL_CMD='open -a \"Safari\"'\n\n# Override the open command for files\nZVM_OPEN_FILE_CMD='code'  # Open files with Visual Studio Code\n\n# Override the open command for files on macOS\nZVM_OPEN_FILE_CMD='open -a \"Visual Studio Code\"'\n\n# Override the open command for files on Windows\nZVM_OPEN_FILE_CMD='powershell.exe -Command \"Start-Process code\"'\n\n# Override the open command for files on Windows using cmd\nZVM_OPEN_FILE_CMD='start code'\n```\n\nFor Windows users, you can create a script for opening on Windows, for example,\na script `/usr/local/bin/xdg-open` with content:\n\n```sh\n#!/usr/bin/env bash\n\n# A Linux-like \"xdg-open\" command for WSL\n# Supports: http, https, ftp, ftps, file URLs, local files and directories\n\nif [ $# -eq 0 ]; then\n  echo \"Usage: open \u003cfile|dir|url\u003e\"\n  exit 1\nfi\n\nfor target in \"$@\"; do\n  # If it is a URL (http, https, ftp, ftps, file)\n  if [[ \"$target\" =~ ^(https?|ftps?|file):// ]]; then\n    explorer.exe \"$target\"\n    continue\n  fi\n\n  # Otherwise, treat as regular file or directory paths\n  if [ -e \"$target\" ]; then\n    win_path=$(wslpath -w \"$target\")\n    explorer.exe \"$win_path\"\n  else\n    echo \"open: $target not found\"\n  fi\ndone\n```\n\nAnd add executive permission:\n\n```sh\nsudo chmod +x /usr/local/bin/xdg-open\n```\n\nThen set the `ZVM_OPEN_CMD` option:\n\n```zsh\nZVM_OPEN_CMD='/usr/local/bin/xdg-open'\n```\n\nOr you can use `cygstart` if you are using Cygwin:\n\n```zsh\nZVM_OPEN_CMD='cygstart'\n```\n\nOr set the `cygstart` command as a alias as below:\n\n```zsh\n# Add a open alias to your .zshrc for Windows users\nopen='cygstart'\n```\n\nCustom Escape Key\n--------\n\nYou can use below options to custom the escape key which could better match\nyour flavor, such as `jj` or `jk` and so on.\n\n- `ZVM_VI_ESCAPE_BINDKEY`: The vi escape key in all modes (default is `^[`\n  =\u003e `ESC`)\n- `ZVM_VI_INSERT_ESCAPE_BINDKEY`: The vi escape key in insert mode (default\n  is `$ZVM_VI_ESCAPE_BINDKEY`)\n- `ZVM_VI_VISUAL_ESCAPE_BINDKEY`: The vi escape key in visual mode (default\n  is `$ZVM_VI_ESCAPE_BINDKEY`)\n- `ZVM_VI_OPPEND_ESCAPE_BINDKEY`: The vi escape key in operator pending mode\n  (default is `$ZVM_VI_ESCAPE_BINDKEY`)\n\nFor example:\n\n```zsh\n# Only changing the escape key to `jk` in insert mode, we still\n# keep using the default keybindings `^[` in other modes\nZVM_VI_INSERT_ESCAPE_BINDKEY=jk\n```\n\nReadkey Engine\n--------\n\nThis plugin has supported to choose the readkey engine for reading and\nprocessing the key events. It easy to do by the `ZVM_READKEY_ENGINE`option,\ncurrently the below engines are supported:\n\n- `ZVM_READKEY_ENGINE_NEX`: It is a better readkey engine to replace ZLE (Beta).\n- `ZVM_READKEY_ENGINE_ZLE`: It is Zsh's default readkey engine (ZLE).\n- `ZVM_READKEY_ENGINE_DEFAULT`: It is the default engine of this plugin\n  (It's the NEX engine now).\n\nThe NEX is a better engine for reading and handling the key events than the\nZsh's ZLE engine, currently the NEX engine is still at beta stage, you can\nchange back to Zsh's ZLE engine if you want.\n\nFor example:\n\n```zsh\n# Change to Zsh's default readkey engine\nZVM_READKEY_ENGINE=$ZVM_READKEY_ENGINE_ZLE\n```\n\nYou can use `ZVM_KEYTIMEOUT` option to adjust the key input timeout for\nwaiting for next key, default is `0.4` seconds.\n\nThe escape key is a special case, it can be used standalone. NEX engine\nwaits for a period after receiving the escape character, to determine\nwhether it is standalone or part of an escape sequence. While waiting,\nadditional key presses make the escape key behave as a meta key. If no\nother key presses come in, it is handled as a standalone escape.\n\nFor the NEX engine, we can use `ZVM_ESCAPE_KEYTIMEOUT` option to adjust\nthe waiting timeout for the escape key, default is `0.03` seconds.\n\nConfiguration Function\n--------\n\nSince there are some config options relied to some variables defined in\nthe plugin, however, some not. We need to provide an unified config entry\nfunction. The name of entry function is stored in an option called\n`ZVM_CONFIG_FUNC` and default value is `zvm_config`, you can change to\nothers for fitting your flavor.\n\nIf this config function exists, it will be called automatically, you can\ndo some configurations in this aspect before you source this plugin. For\nexample:\n\n```zsh\nfunction zvm_config() {\n  ZVM_LINE_INIT_MODE=$ZVM_MODE_INSERT\n  ZVM_VI_INSERT_ESCAPE_BINDKEY=jk\n}\n\nsource ~/zsh-vi-mode.zsh\n```\n\nExecute Extra Commands\n--------\n\nThis plugin has provided a mechanism to execute extra commands, and now\nyou have the below aspects for executing something:\n\n```zsh\nzvm_before_init_commands=()\nzvm_after_init_commands=()\nzvm_before_select_vi_mode_commands=()\nzvm_after_select_vi_mode_commands=()\nzvm_before_lazy_keybindings_commands=()\nzvm_after_lazy_keybindings_commands=()\n```\n\nSince the default [initialization mode](#initialization-mode), this plugin\nwill overwrite the previous key bindings, this causes the key bindings of\nother plugins (i.e. `fzf`, `zsh-autocomplete`, etc.) to fail.\n\nYou can solve the compatibility issue as below:\n\n```zsh\n# Append a command directly\nzvm_after_init_commands+=('[ -f ~/.fzf.zsh ] \u0026\u0026 source ~/.fzf.zsh')\n```\n\nor\n\n```zsh\n# Define an init function and append to zvm_after_init_commands\nfunction my_init() {\n  [ -f ~/.fzf.zsh ] \u0026\u0026 source ~/.fzf.zsh\n}\nzvm_after_init_commands+=(my_init)\n```\n\nor\n\n```zsh\n# The plugin will auto execute this zvm_after_init function\nfunction zvm_after_init() {\n  [ -f ~/.fzf.zsh ] \u0026\u0026 source ~/.fzf.zsh\n}\n```\n\nor if you are using the `zinit`:\n\n```zsh\n# For postponing loading `fzf`\nzinit ice lucid wait\nzinit snippet OMZP::fzf\n```\n\nBy default, [the lazy keybindings feature](#lazy-keybindings) is enabled, all\nthe keybindings of `normal` and `visual` mode should be executed by the\n`zvm_after_lazy_keybindings_commands`. For example:\n\n```zsh\n# The plugin will auto execute this zvm_after_lazy_keybindings function\nfunction zvm_after_lazy_keybindings() {\n  bindkey -M vicmd 's' your_normal_widget\n  bindkey -M visual 'n' your_visual_widget\n}\n```\n\nCustom widgets and keybindings\n--------\n\nThis plugin has two functions for you to define custom widgets and keybindings.\nIn case of unnecessary problems, it is better to use them, especially when you\nmeet the key conflicts.\n\nTo define a custom widget, you should:\n\n```zsh\n# If [your_custom_widget] were ignored, it will be the same with \u003cyour_custom_widget\u003e\nzvm_define_widget \u003cyour_custom_widget\u003e [your_custom_function]\n```\n\nTo define a keybinding, you should:\n\n```zsh\nzvm_bindkey \u003ckeymap\u003e \u003ckeys\u003e \u003cwidget\u003e\n```\n\nFor example:\n\n```zsh\n# Your custom widget\nfunction my_custom_widget() {\n  echo 'Hello, ZSH!'\n}\n\n# The plugin will auto execute this zvm_after_lazy_keybindings function\nfunction zvm_after_lazy_keybindings() {\n  # Here we define the custom widget\n  zvm_define_widget my_custom_widget\n\n  # In normal mode, press Ctrl-E to invoke this widget\n  zvm_bindkey vicmd '^E' my_custom_widget\n}\n```\n\nVi Mode Indicator\n--------\n\nThis plugin has provided a `ZVM_MODE` variable for you to retrieve\ncurrent vi mode and better show the indicator.\n\nAnd currently the below modes are supported:\n\n```zsh\nZVM_MODE_NORMAL\nZVM_MODE_INSERT\nZVM_MODE_VISUAL\nZVM_MODE_VISUAL_LINE\nZVM_MODE_REPLACE\n```\n\nFor updating the vi mode indicator, we should add our commands to \n`zvm_after_select_vi_mode_commands`. For example:\n\n```zsh\n# The plugin will auto execute this zvm_after_select_vi_mode function\nfunction zvm_after_select_vi_mode() {\n  case $ZVM_MODE in\n    $ZVM_MODE_NORMAL)\n      # Something you want to do...\n    ;;\n    $ZVM_MODE_INSERT)\n      # Something you want to do...\n    ;;\n    $ZVM_MODE_VISUAL)\n      # Something you want to do...\n    ;;\n    $ZVM_MODE_VISUAL_LINE)\n      # Something you want to do...\n    ;;\n    $ZVM_MODE_REPLACE)\n      # Something you want to do...\n    ;;\n  esac\n}\n```\n\nCustom Cursor Style\n--------\n\nThis plugin has provided some options for users to custom the cursor\nstyle for better terminal compatibility.\n\n- You can disable this feature by the `ZVM_CURSOR_STYLE_ENABLED`\n  option (Default is `true`)\n\n```zsh\n# Disable the cursor style feature\nZVM_CURSOR_STYLE_ENABLED=false\n```\n\n- You can set your cursor style for different vi mode:\n\n```zsh\n# The prompt cursor in normal mode\nZVM_NORMAL_MODE_CURSOR\n\n# The prompt cursor in insert mode\nZVM_INSERT_MODE_CURSOR\n\n# The prompt cursor in visual mode\nZVM_VISUAL_MODE_CURSOR\n\n# The prompt cursor in visual line mode\nZVM_VISUAL_LINE_MODE_CURSOR\n\n# The prompt cursor in operator pending mode\nZVM_OPPEND_MODE_CURSOR\n```\n\n- And the below cursor styles are supported:\n\n```zsh\nZVM_CURSOR_USER_DEFAULT\nZVM_CURSOR_BLOCK\nZVM_CURSOR_UNDERLINE\nZVM_CURSOR_BEAM\nZVM_CURSOR_BLINKING_BLOCK\nZVM_CURSOR_BLINKING_UNDERLINE\nZVM_CURSOR_BLINKING_BEAM\n```\n\n- Custom your cursor style is easy as below:\n\n```zsh\nZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BEAM\nZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK\nZVM_OPPEND_MODE_CURSOR=$ZVM_CURSOR_UNDERLINE\n```\n\n- Also, custom your colorful cursor style as below:\n\n```zsh\n# The plugin will auto execute this zvm_config function\nzvm_config() {\n  # Retrieve default cursor styles\n  local ncur=$(zvm_cursor_style $ZVM_NORMAL_MODE_CURSOR)\n  local icur=$(zvm_cursor_style $ZVM_INSERT_MODE_CURSOR)\n\n  # Append your custom color for your cursor\n  ZVM_INSERT_MODE_CURSOR=$icur'\\e\\e]12;red\\a'\n  ZVM_NORMAL_MODE_CURSOR=$ncur'\\e\\e]12;#008800\\a'\n}\n```\n\nWe can use `ZVM_TERM` option to set the term type for plugin to handle\nterminal escape sequences, default is `$TERM`. It could be `xterm-256color`,\n`alacritty-256color`, `st-256color`, etc. It's important for some\nterminal emulators to show cursor properly.\n\nHighlight Behavior\n--------\n\nYou can use `ZVM_VI_HIGHLIGHT_BACKGROUND`, `ZVM_VI_HIGHLIGHT_FOREGROUND`\nand `ZVM_VI_HIGHLIGHT_EXTRASTYLE` to change the highlight behaviors (\nsurrounds, visual-line, etc.), the color value could be _a color name_ or\n_a hex color value_.\n\nFor example:\n\n```zsh\nZVM_VI_HIGHLIGHT_FOREGROUND=green             # Color name\nZVM_VI_HIGHLIGHT_FOREGROUND=#008800           # Hex value\nZVM_VI_HIGHLIGHT_BACKGROUND=red               # Color name\nZVM_VI_HIGHLIGHT_BACKGROUND=#ff0000           # Hex value\nZVM_VI_HIGHLIGHT_EXTRASTYLE=bold,underline    # bold and underline\n```\n\nCommand Line Initial Mode\n--------\n\nYou can set the command line initial mode by the `ZVM_LINE_INIT_MODE`\noption.\n\nCurrently the below modes are supported:\n\n- `ZVM_MODE_LAST`   : Starting with last mode (Default).\n- `ZVM_MODE_INSERT` : Starting with insert mode.\n- `ZVM_MODE_NORMAL` : Starting with normal mode.\n\nFor example:\n\n```zsh\n# Always starting with insert mode for each command line\nZVM_LINE_INIT_MODE=$ZVM_MODE_INSERT\n```\n\nLazy Keybindings\n--------\n\nThis plugin has supported the lazy keybindings feature, and it is enabled\nby default. To disable it, you can set the option `ZVM_LAZY_KEYBINDINGS`\nto `false` before this plugin is loaded. This feature will postpone all\nthe keybindings of `normal` and `visual` mode to the first time you enter\nthe normal mode.\n\nIt can greatly improve the startup speed, especially you open the terminal\nand just want to execute a simple command.\n\nInitialization Mode\n--------\n\nIn order to prevent various problems related to keybindings caused by the\nplugin sourcing sequence, and also keep the same functionality for this\nplugin, the initialization of this plugin was postponed to the first\ncommand line starting.\n\nHowever, almost all plugins are initialized when the script is sourced.\nTherefore, this plugin provides an option `ZVM_INIT_MODE` to change the\ninitialization mode.\n\nFor example:\n\n```zsh\n# Do the initialization when the script is sourced (i.e. Initialize instantly)\nZVM_INIT_MODE=sourcing\n```\n\n## 💎 Credits\n\n- [Zsh](https://www.zsh.org/) - A powerful shell that operates as both an interactive shell and as a scripting language interpreter.\n- [Oh-My-Zsh](https://github.com/ohmyzsh/ohmyzsh) - A delightful, open source, community-driven framework for managing your ZSH configuration.\n- [vim-surround](https://github.com/tpope/vim-surround) - A vim plugin all about \"surroundings\": parentheses, brackets, quotes, XML tags, and more.\n- [vim-sandwich](https://github.com/machakann/vim-sandwich) - A set of operator and textobject plugins to add/delete/replace surroundings of a sandwiched textobject.\n\n## 🔫 Contributing\n\nIssues 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.\n\nYou can start by [opening an issue](https://github.com/jeffreytse/zsh-vi-mode/issues/new) describing the problem that you're looking to resolve and we'll go from there.\n\n## 🌈 License\n\nThis theme is licensed under the [MIT license](https://opensource.org/licenses/mit-license.php) © Jeffrey Tse.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffreytse%2Fzsh-vi-mode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeffreytse%2Fzsh-vi-mode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffreytse%2Fzsh-vi-mode/lists"}