Git Product home page Git Product logo

zsh-vi-mode's Introduction

vi-mode โ†’~ zsh

๐Ÿ’ป A better and friendly vi(vim) mode plugin for ZSH.


โš’๏ธ Zsh Vi Mode โš’๏ธ

ZSH plugin for Agnosticism.

Donate (GitHub Sponsor) Release Version License: MIT Donate (Liberapay) Donate (Patreon) Donate (Ko-fi)

Built with โค๏ธŽ by jeffreytse and contributors

Zsh Vi-mode Demo

๐Ÿค” 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.).
  • โš™๏ธ Better functionality in command mode (In progress).
  • ๐Ÿช€ Repeating command such as 10p and 4fa (In progress).
  • ๐Ÿ“’ System clipboard (In progress).

๐Ÿ’ผ 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";
        }
      ];
    };
  };
};

Using Fig

Fig adds apps, shortcuts, and autocomplete to your existing terminal.

Install zsh-vi-mode in just one click.

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
  • ...

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 that 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.

zsh-vi-mode's People

Contributors

ansonyeung avatar blucey avatar c-uo avatar dm9pzcaq avatar eleanor-clifford avatar fengstats avatar gotgenes avatar ibayramli avatar jeffreytse avatar kevintraver avatar kuzy000 avatar kyleondy avatar mahmoudsaeed avatar mauriciokuyama avatar medv avatar michaelorr avatar milesfrain avatar pschmitt avatar rbozan avatar robertek avatar scresante avatar shun-shobon avatar tetov avatar toh995 avatar verydamptowel avatar weirongxu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zsh-vi-mode's Issues

Can't enter normal mode again when using key combo `c<key>` to change content

Strokubg a prefix key like c and slightly waiting for a second will cause this plugin stuck, because it called an original widget and didn't trigger changing the internal mode ZVM_MODE and updating cursor style.

Reproduce:

  • Stroke Esc to enter normal mode.
  • Stroke c and slightly wait for a second.
  • Stroke w or iw or others.
  • It is stuck in insert mode and the cursor shape is no changed.

Partial history search from "zsh-autosuggestions" is overidden

I use zsh-autosuggestions for auto-complete which provides a very neat partial search capability. However, with the installation of zsh-vi-mode, partial search no longer works and was forcefully replaced with jumping among historical commands.

Steps to reproduce:

  • run 2 commands such as test working 1 and test not working 2
  • when zsh-vi-mode is not installed, typing test and pressing up/down arrow will circle historical commands that start with test
  • when zsh-vi-mode is installed, typing test and pressing up/down arrow will just jump to the previous/next command

Is there a way for me to get the best of both world here? Possible solutions:

  • Support partial search in this plugin
  • Find a way to use the existing arrow key behaviour from terminal or other plugin
  • Give the option to turn off search implemented by this plugin

'dw' deletes first character of the next word

Hi,

thanks for this awesome plugin, I love the cursor transformation in different modes and increased visual feedback in visual mode. :-)

I found an oddity that appears to be a bug. I've tried to look into it myself, but zsh-vi-mode.zsh is a bit too much for my zsh scripting skills (although it is very well commented).

Sample string: "apple orange"

When typing dw at the beginning of the word apple, zsh-vi-mode also removes the o orange. This is unexpected, both default vi-mode in zsh and also vim/vi only remove up until the next word (including whitespace), not the beginning of the next word.

de as a workaround doesn't work, because it leaves a whitespace which dw usually would remove as well.

TL;DR

Input

`apple orange"

Action

dw while cursor is on a of apple

Expected Result

orange

Actual Result

range

AUR packages

First of all, I just discovered this plugin and love it.

Since I don't use a plugin manager for zsh and didn't want to pull regularly, I created the AUR packages zsh-vi-mode and zsh-vi-mode-git

Maybe you could add this to the README? It currently installs to /usr/share/zsh/plugins/zsh-vi-mode/

And let me know if you'd rather maintain the packages yourself

Cursor style maintained across terminals

With TMux the cursor style is changed across all terminals.

Ideally I would love to be able to have a block style outside of the shell. So even if I was in insert mode with a pipe, when I go into vim for example I'd like it to go back to a block. Similarly if I go to a different terminal I'd like it to be independent, although I don't know how feasible that is.

Add an option for disabling cursor style

This feature supports to disable the cursor style update, so that this plugin will not update the cursor style when the ZVM_CURSOR_STYLE_ENABLED variable value is false, the default value is true.

Interference with `fzf`'s Ctrl+R

Hi @jeffreytse , thanks for a great plugin. I love it!

Any chance you can chime in on why this seems to interfere with my ability to use fzf's Ctrl+R for history search? For example, without your plugin:

โฏ
โˆผ   < 12/12 +S                                  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ–ถ    14  cd ~                                   โ”‚    14  cd ~                                                          โ”‚
     13  exit                                   โ”‚                                                                      โ”‚
     12  git smu                                โ”‚                                                                      โ”‚
     11  lla submodules/pythonrc                โ”‚                                                                      โ”‚
     10  gsmurr                                 โ”‚                                                                      โ”‚
      9  gsmu                                   โ”‚                                                                      โ”‚
      8  git submodule update                   โ”‚                                                                      โ”‚
      6  lla submodules                         โ”‚                                                                      โ”‚
      5  lla                                    โ”‚                                                                      โ”‚
      4  ci                                     โ”‚                                                                      โ”‚
      2  env|grep PY                            โ”‚                                                                      โ”‚
      1  env                                    โ”‚                                                                      

whilst with your plugin:

โฏ
bck-i-search: _

[BUG] output disapears

Hi,

Thanks for this great plugins. I found this plugin very useful, but I realized the output will disappear. And I have no idea why this would happen.

For the reference. I am using my Dotfiles. During testing, I comment out these lines and leave only antigen specific config for testing.

I also tried another theme, but it still happens. The screenshots are taken and it happens in a second.

Screen Shot 2021-01-27 at 3 17 48 AM

Screen Shot 2021-01-27 at 3 17 58 AM

[BUG] Cannot exit normal mode with `a` or `i`

Problem description

I realized exit normal mode in zsh-vi-mode breaks recently. I cannot use a or i to enter insertion mode again. Are you aware anything like that?

I observed this behavior works at commit d7d6fba but breaks at df675da.

my zsh version: zsh 5.8 (x86_64-apple-darwin19.6.0)

Reproduce with my current environment setup with the following steps.

  1. Clone
bash <(curl -s https://raw.githubusercontent.com/ztlevi/Dotfiles/master/bootstrap.sh)
cd ~/Dotfiles
export ZDOTDIR=$HOME/Dotfiles/shell/zsh
  1. Comment out
    these lines in my zsh
    config.

  2. Add antigen bundle jeffreytse/zsh-vi-mode in $HOME/Dotfiles/shell/zsh/bundles.zsh

  3. ./deploy shell/zsh then start a new zsh in the current terminal

Start zsh in normal mode

Atm when zsh is initialised with the plugin, it automatically goes to insert mode. It kinda make sense in a command-line context but just wondering if it's possible to start zsh with the normal mode which matches Vim's behaviour better.

zsh-vi-mode overrides word separator

By default (if I disable this plugin) zsh will treat each directory in the path /home/hubro/Dropbox/Config as separate words, so when I press Ctrl+w repeatedly, it will first delete "Config", then the "/", then "Dropbox" and so on.

When using zsh-vi-mode, pressing Ctrl+w will remove the entire path, treating it as one long word.

To test, type "cd foo/bar/baz" into the terminal and press Ctrl+w. Then, run zsh without plugins (zsh -f) and repeat the test.

I think zsh-vi-mode should keep the default, or at least provide a way to configure word separators. If this is already possible, it should be documented in the README.

Support line initial mode

Add an option ZVM_LINE_INIT_MODE to support setting the command line mode, you can control the vi mode of each new command line as below:

  • ZVM_LINE_INIT_MODE= : Empty for keeping last vi mode (The first command line is INSERT mode and this is the default).
  • ZVM_LINE_INIT_MODE=$ZVM_MODE_INSERT : Always insert mode.
  • ZVM_LINE_INIT_MODE=$ZVM_MODE_NORMAL : Always normal mode.

clipboard workaround

While we wait for final solution you can patch zsh-vi-mode plugin if it's deal breaker for you.

For those not very familiar with bash just find plugin file ~/.oh-my-zsh/custom/plugins/zsh-vi-mode/zsh-vi-mode.zsh and then function zvm_yank(); In my case for windows wsl2 ubuntu20 it's like so:

image

brutal, but does the job.

Can't leave insert mode after typing S from normal mode

When in normal mode, then typing S, this plugin clears the line and puts the user in insert mode, consistent with behavior described in Vim.

["x]S                   Delete [count] lines [into register x] and start                                                                        
                        insert.  Synonym for "cc" linewise.      

However, at this point, it does not seem to be possible to exit insert mode. The user is forced to hit Enter to get a new prompt. This prompt will actually start in normal mode, which is also unexpected.

I do not observe this behavior when using cc from normal mode. Like S, cc will clear the line's contents and put me in insert mode, however, I am able to hit Esc and get back to normal mode, as expected.

ZVM_VI_ESCAPE_BINDKEY not adding pressed key after timeout

Hello,

Firstly, thanks for the amazing plug-in!
I've just pulled the latest version and I'm running into an issue with my escape bindkey ("jk").

Currently in insert mode if I press "j" nothing happens, no matter how long I wait.
The expected behaviour though should be that "j" appears in the console after the time specified by VIM_KEYTIMEOUT passes, just like in vim.

Cheers,
kk

Can't disable custom cursor

Since the custom cursor currently interferes with applications launched in the terminal like SSH and Vim, I want to disable it.

Here is my relevant Zsh config:

#                                                                               
# Antigen plugin manager                                                        
#                                                                               
# This block of config works automatically with the "antigen-git" AUR package   
# on Arch and with the "antigen" homebrew package on macOS.                     
#                                                                               
                                                                                
# Possible init script locations                                                
ANTIGEN_INIT_SCRIPT=(                                                           
    "/usr/share/zsh/share/antigen.zsh"                                          
    "/usr/local/share/antigen/antigen.zsh"                                      
)                                                                               
                                                                                
for ANTIGEN_INIT_SCRIPT_PATH in "${ANTIGEN_INIT_SCRIPT[@]}"; do                 
    if [[ -f "$ANTIGEN_INIT_SCRIPT_PATH" ]]; then                               
        source "$ANTIGEN_INIT_SCRIPT_PATH"                                      
                                                                                
        antigen bundle jeffreytse/zsh-vi-mode                                   
        antigen apply                                                           
                                                                                
        # Configure zsh-vi-mode                                                 
        ZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BLINKING_BEAM                        
        ZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK                                
        ZVM_CURSOR_STYLE_ENABLED=false                                          
                                                                                
        echo "Antigen initialized"                                              
        break                                                                   
    fi                                                                          
done                                                                            
                                                                                
unset ANTIGEN_INIT_SCRIPT                                                       
unset ANTIGEN_INIT_SCRIPT_PATH

As you see, I have set ZVM_CURSOR_STYLE_ENABLED=false, but the custom cursor feature is still enabled.

I have tried exporting the variable, and I have tried placing it before antigen apply, neither work. Even setting it to false manually in the terminal doesn't work.

Can't use c<count>, d<count>

zsh-vi-mode does not seem to take <count> after c or d and before <motion>, such as c2w or d2w. It only seems to accept a count before c or d.

Cursor in insert mode is forced to be vertical line.

I always had box cursor and I don't like to have it another way. Since using this plugin, it forces my cursor to be vertical line instead of box (box is in normal mode only - exactly opposite that I want it to be).

Any chance to add an option to set it?

Pasting in normal mode breaks

Not sure exactly when this started happening, but pasting breaks in subtle ways.

image

Here I've entered normal mode, and hit p. This pasted the contents of the buffer below my prompt. I cannot navigate to this content, and hitting dd to delete the line only deleted a single character at the end of that pasted contented.

If I type content in insert mode and then delete the line, my inserted content is deleted and the content that was pasted moves up into the correct position and is delete-able.

This is on the latest content but is reproduce-able a couple of commits back to feat: provide a mechanism to execute extra commands

incompatible with fzf

First of all, let me say that it is a really nice plugin! Thank you!

But I found out that it is not compatible with some fzf features like the backward search. Which is really a bummer for me.

If I should provide some more infos like log files, my configuration etc. please let me know. I don't really know what could help you.

due to many collisions introduce turn on/off switch

we should have this switch

ecosystem is like:

bindkey -M emacs '\eOQ\eOQ' one-wiget-from-.oh-my-zsh
bindkey -M vicmd '\eOQ\eOQ' one-wiget-from-.oh-my-zsh
bindkey -M viins '\eOQ\eOQ' one-wiget-from-.oh-my-zsh 

do now i have to create bindings for all my widgets like?

zvm_bindkey vicmd '\eOQ\eOQ' one-wiget-from-.oh-my-zsh
zvm_bindkey viins '\eOQ\eOQ' one-wiget-from-.oh-my-zsh 

Key combo "Esc k" when already in normal mode scrolls up infinitely

From insert mode, pressing "Esc k" works as expected. You leave insert mode into normal mode and scroll back in history once.

However, if you are already in normal mode, pressing "Esc k" will start scrolling upwards indefinitely, as if I was holding down "k". I have to press Ctrl+c to stop it.

Here is my Zsh config (shell-setup.sh only contains aliases):

HISTFILE=~/.histfile
HISTSIZE=10000
SAVEHIST=10000
KEYTIMEOUT=1
setopt SHARE_HISTORY nomatch notify
#bindkey -v
bindkey '^R' history-incremental-search-backward

fpath=(~/Dropbox/Config/zsh-completions $fpath)


#
# Completion config
#

zstyle ':completion:*' completer _expand _complete _ignored _correct _approximate
zstyle ':completion:*' max-errors 2
zstyle :compinstall filename '/home/tomas/.zshrc'

autoload -Uz compinit
compinit

#
# Antigen plugin manager
#
# This block of config works automatically with the "antigen-git" AUR package
# on Arch and with the "antigen" homebrew package on macOS.
#

# Possible init script locations
ANTIGEN_INIT_SCRIPT=(
    "/usr/share/zsh/share/antigen.zsh"
    "/usr/local/share/antigen/antigen.zsh"
)

for ANTIGEN_INIT_SCRIPT_PATH in "${ANTIGEN_INIT_SCRIPT[@]}"; do
    if [[ -f "$ANTIGEN_INIT_SCRIPT_PATH" ]]; then
        source "$ANTIGEN_INIT_SCRIPT_PATH"

        antigen bundle jeffreytse/zsh-vi-mode

        #NVM_NO_USE=true
        #NVM_AUTO_USE=true
        ##NVM_LAZY_LOAD=true
        #antigen bundle lukechilds/zsh-nvm

        antigen apply

        # Configure zsh-vi-mode
        ZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BLINKING_BEAM
        ZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK
        #ZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BLINKING_BLOCK
        #ZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK
        #ZVM_CURSOR_STYLE_ENABLED=false

        break
    fi
done

unset ANTIGEN_INIT_SCRIPT
unset ANTIGEN_INIT_SCRIPT_PATH

#
# Kubectl completion
#
#if which kubectl &>/dev/null; then
#    eval "$(kubectl completion zsh 2>/dev/null)"
#fi

#
# Shell init script
#
SHELL_SETUP="$HOME/Dropbox/Config/shell-setup.zsh"
[[ -f "$SHELL_SETUP" ]] && source "$SHELL_SETUP"
unset SHELL_SETUP

#
# Pyenv
#
if which pyenv &>/dev/null; then
    eval "$(pyenv init - --no-rehash)"
    eval "$(pyenv virtualenv-init - --no-rehash)"
fi

#
# NVM (Node Version Manager)
#
NVM_INIT_SCRIPT="/usr/share/nvm/init-nvm.sh"
if [[ -f "$NVM_INIT_SCRIPT" ]]; then
    source "$NVM_INIT_SCRIPT" --no-use
    #source "$NVM_INIT_SCRIPT"
fi

#
# Starship
#
if which starship &>/dev/null; then
    eval "$(starship init zsh)"
fi

#
# Direnv (https://direnv.net/)
#
if which direnv &>/dev/null; then
    eval "$(direnv hook zsh)"
fi

#
# Broot
#
if which broot &>/dev/null; then
    source /home/tomas/.config/broot/launcher/bash/br
fi

#
# Allow parent to initialize shell
#
# This is awesome for opening terminals in VSCode.
#
if [[ -n $ZSH_INIT_COMMAND ]]; then
    echo "Running: $ZSH_INIT_COMMAND"
    eval "$ZSH_INIT_COMMAND"
fi

#
# Syntax highlighting
#
SYNTAX_HIGHLIGHTING_INIT="/usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
if [[ -f "$SYNTAX_HIGHLIGHTING_INIT" ]]; then
    source "$SYNTAX_HIGHLIGHTING_INIT"
fi

I have tried disabling Starship and syntax highlighting, but that doesn't make any difference.

Surround not working

I cloned and sourced the plugin:

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

Incrementation/decrementation works (<C-a>/<C-x>), but surround (e.g. yse") doesn't.
I tried it with visual selection and with motions. Am I doing something wrong?

Using a to enter insert mode from empty command line triggers terminal bell

When the command line is empty, after entering normal mode with Esc, pressing a to enter insert mode triggers the terminal bell.

bell

Note that using i or A to enter insert mode does not cause the terminal bell to fire. Using a to enter insert mode when the command line has at least one character will also not trigger the terminal bell.

Unsupported grep -P option on Mac OS

Hi,
Thanks for authoring this plugin.
Mac OS uses BSD grep rather than GNU grep. Because of this, grep's -P, --perl-regexp option is not available on Mac OS . This causes a bunch of error lines to be output every time you start a new shell with this plugin enabled:
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]

Here are a few options to support Mac OS:

  • Option #1: Use grep option -E, --extended-regexp rather than -P, --perl-regexp.
  • Option #2: Check for MacOS and if so use perl instead of grep. See stackoverflow.com for details on converting a grep call to a perl equivalent.

I'll look into this further when I get a chance.

My OS:

~ sw_vers
ProductName:	macOS
ProductVersion:	11.1
BuildVersion:	20C69

Add ys normal mode mapping for surround

This is a feature request to support ys<motion/text object><surround character> in normal mode to surround <text object> with <character>. It is similar to ys from visual selection mode. The description from surround.vim:

ys takes a valid Vim motion or text object as the first object, and wraps                                                                                                                       
it using the second argument as with cs.  (It's a stretch, but a good                                                                                                                           
mnemonic for "ys" is "you surround".)                                                                                                                                                           
                                                                                                                                                                                              
Old text                  Command     New text                                                                                                                                                
Hello w*orld!             ysiw)       Hello (world)!

[In the example above, the * denotes the position of the cursor.]

Right now the workaround from normal mode is to enter v<text object>ys<character>. This feature would cut down on a few keypresses. It would also help those users who have gotten used to this normal mode mapping from surround.vim.

Thanks for considering this request!

Home and Insert keys enter normal mode

When I press home & insert keys I enter normal mode instead of jumping ^ or $.

I checked regular bindkey -v and they seem to work, so I suspect somehow this plugin does some overrides.

If this is intended, behavior option would still be preferred.

`dw` or `yw` includes the newline character from the Normal Mode

Reproduce

  1. Input the the below content:
friend
basket
base
  1. Move the cursor to the the letter i of friend
  2. Stroke dw from the Normal Mode

Result

We get the below result:

frbasket
base

But we should get the result:

fr
basket
base

The same situation is existed on yw

Cursor insert mode style affects other applications

I enjoy using these cursor styles to clearly distinguish between normal mode and insert mode:

ZVM_INSERT_MODE_CURSOR=$ZVM_CURSOR_BLINKING_BEAM
ZVM_NORMAL_MODE_CURSOR=$ZVM_CURSOR_BLOCK

However, the insert mode cursor style is inherited by other applications, and those applications don't handle switching between cursor styles when switching modes, which makes the cursor permanently stay in the insert mode style until the application is exited.

For example, try starting Vim from the terminal, or simply start bash. Inside vim or bash, the insert mode cursor is permanently active, even when switching to normal mode. This is extremely distracting.

I wish zsh-vi-mode would "reset" the cursor style to default before executing a command, then set the custom style again when the command exits. This way applications like vim, bash, python and any other interactive CLI application would not be affected by it.

(Put a different way, temporarily set ZVM_CURSOR_STYLE_ENABLED=false while a process is running in the terminal)

problems in vim built-in terminal when vim is opened in tmux

When I use the plugin in vim built-in termimal in tmux, every character I typed was followed by an extra "6 ", and there is an extra "q" at end.

To produce:

  1. create and enter a new tmux session by tmux
  2. open vim by vim -u NONE
  3. open terminal by :term
  4. enter zsh shell by zsh
  5. type any character

keybindings seem to conflict with fzf's

hi, thanks for creating this wonderful plugin. I am having trouble getting it working with fzf. My .zshrc file looks like this:

...


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

# fzf
source /usr/share/doc/fzf/examples/key-bindings.zsh
source /usr/share/doc/fzf/examples/completion.zsh

if I comment out ZVM, fzf will work, and if I comment out fzf, ZVM will work. I also tried switching order and same situation. Any ideas how to get these two plugins working in harmony? Thanks.

Add spec for test

It builds a safety net against errors, especially useful for refactoring. If we donโ€™t have a test suite then to touch the code is frightening, because of the fear of something breaking, having tests increases the confidence.

[Bug] Conflict with oh my zsh sudo plugin

zinit snippet OMZ::plugins/sudo/sudo.plugin.zsh

sudo plugin makes you can just double click esc to auto add a sudo to the start of a line.

But this plugin works well with zsh's default vi mode

last commit breaks the plugin

commit 88db808 introduces changes that breaks the whole plugin. Outputs true on each shell initialization (breaking the prompt) and erroring when changing mode, making the plugin unusable.

local cat alias breaks `d` in normal mode

I've got cat aliased to bat locally, and it seems that cat is used internally to parse keys using the -v key which isn't supported by bat.

image

ref:

key=$(echo "${key}" | cat -v)

Not sure if this is workable as I know it's not really standard to expect cat to be aliased. Maybe if you go for /usr/bin/cat, but then that might make it harder to support other systems...

I think I could work around by using a function that checks for valid bat args and if it finds something that won't work with bat then defer to cat.

read-only variable: ZVM_NAME

What does this mean?

~/.zsh-vi-mode/zsh-vi-mode.zsh:100: read-only variable: ZVM_NAME

How can I avoid this message upon shell startup?

Different results when typing cw depending on interval between keypresses

I'm observing an one extra word deleted when using cw (or [count]cw or c[count]w) if typing the sequence of keys rapidly.

For the line

echo 1 2 3 4 5

Enter normal mode and place the mouse over 1.

If the user types c, waits a half a second, then types w, it will delete 1 and place the cursor after where the 1 was

echo | 2 3 4 5

This is the expected behavior.

If, however, the user quickly types cw, it will delete 1 2 and place the cursor after where the 2 was

echo | 3 4 5

That is, an additional word will get deleted.

This behavior is consistent for whatever [count] is provided, too. For example, for 2cw typed quickly, it will instead delete three words 1 2 3 instead of 1 2.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.