Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround to use surrounds while keeping KEYTIMEOUT=1 #33

Closed
FreddieOliveira opened this issue Aug 11, 2020 · 9 comments
Closed

Workaround to use surrounds while keeping KEYTIMEOUT=1 #33

FreddieOliveira opened this issue Aug 11, 2020 · 9 comments

Comments

@FreddieOliveira
Copy link

This isn't actually a issue, it's more like an informative notice. All workarounds presented in the README.md has one or other drawback, but the one showed bellow adresses this issue flawless (or I think so).

The strategy is to remap the c, d and y keys to user defined widgets, thus removing its original bindings vi-delete, vi-change and vi-yank.

These widgets will then read the next character pressed and if its an s, it will call the surround widget, otherwise it will call the vi widget with the proper numeric-argument. One special attention must be given to repeated key commands, like cc, dd and yy, so it won't call our widget recursively.

Here's the code:

function change-hack() {
  read -k 1 option

  if [[ $option == 's' ]]; then
    zle -U Tcs
  elif [[ $option == 'c' ]]; then
    zle vi-change-whole-line
  else
    zle -U ${NUMERIC}Tvc$option
  fi
}

function delete-hack() {
  read -k 1 option

  if [[ $option == 's' ]]; then
    zle -U Tds
  elif [[ $option == 'd' ]]; then
    zle kill-whole-line
  else
    zle -U ${NUMERIC}Tvd$option
  fi
}

function yank-hack() {
  read -k 1 option

  if [[ $option == 's' ]]; then
    zle -U Tys
  elif [[ $option == 'y' ]]; then
    zle vi-yank-whole-line
  else
    zle -U ${NUMERIC}Tvy$option
  fi
}

zle -N change-hack
zle -N delete-hack
zle -N yank-hack
autoload -Uz surround
zle -N delete-surround surround
zle -N change-surround surround
zle -N add-surround surround
bindkey -M vicmd 'Tcs' change-surround
bindkey -M vicmd 'Tds' delete-surround
bindkey -M vicmd 'Tys' add-surround
bindkey -M vicmd 'Tvd' vi-delete
bindkey -M vicmd 'Tvc' vi-change
bindkey -M vicmd 'Tvy' vi-yank
bindkey -M vicmd 'c' change-hack
bindkey -M vicmd 'd' delete-hack
bindkey -M vicmd 'y' yank-hack
bindkey -M visual S add-surround

This workaround has two advantages over the others:

  1. The value of KEYTIMEOUT doesn't interfere on its working;
  2. You can press the first key and wait as much as desired to press the second key.

The only drawback is the ugly hack it is itself.

Note, however, that I came up with this yesterday night, so it wasn't tested throughout. Pls, let me know if something doesn't work.

@softmoth
Copy link
Owner

Thank you, Freddie! This is a nice hack. It is a little too hairy for me to want to put it in the plugin, but I think I could mention this issue in the README as another option for people to try.

@FreddieOliveira
Copy link
Author

Heey, happy new year!! 🎉

When I first wrote the code I wasn't sure if it would work correctly, but now after 5 months using it, I can say that it works perfectly! It's a bit shady to understand how it works, but it works. Hahaha

softmoth added a commit that referenced this issue Jan 1, 2021
@softmoth softmoth closed this as completed Jan 1, 2021
@korniychuk
Copy link

korniychuk commented May 3, 2022

@FreddieOliveira Thanks for your hack, it works! I have a question if you have a chance to read ...

Pls, let me know if something doesn't work.

Everything I use works well, except b key.
When I type <Esc>bb in INPUT mode, the first b moves the cursor to one word back (as expected), but then I end up in INPUT mode again, and the second b is typed as a char in INPUT mode.

If you have a chance, maybe you can try to reproduce it on your ZSH. If you could reproduce it, maybe you have any ideas on how to fix it ?

Thank you so much @FreddieOliveira for your solution.
@softmoth thanks for adding it to README, I found this topic there.

@FreddieOliveira
Copy link
Author

Hey @korniychuk, good to know it was helpful! I've been using this hack up to these days and never had any problems. I also couldn't reproduce your issue, probably it's another part of your code that's causing it. Could you share the whole file?

@softmoth
Copy link
Owner

softmoth commented May 5, 2022

@korniychuk It's not clear to me what you expect the behavior to be when typing <Esc>bb. What you describe is what I would expect to have happen.

@korniychuk
Copy link

Thank you for so quick response! And sorry for my delay. Tomorrow I'll try to find time to record a video reproducing the issue and prepare a minimal .zshrc to reproduce it.

@korniychuk
Copy link

@softmoth Thanks for your comment. Maybe I'm wrong, I'll try to explain.

Expected behavior:
I expect when I type <Esc>bb in INPUT mode, I'll be switched to NORMAL mode (<Esc>) and moved two words back/left (b pressed twice). This is VIM behavior.

Current behavior:

  1. If I do 1second delay between <Esc> and first b -> everything works fine. Mode is switched to NORMAL, cursor moves 2 words left.
  2. If I press <Esc> then bb without any delay between them -> cursor moves 1 word left, mode switches to INPUT again (this is the issue in my opinion) and second b is entered as a char in INPUT mode.

Demo:
https://cln.sh/FAf1gD

Shortest config to reproduce: .zshrc

export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="robbyrussell"

plugins=(zsh-vim-mode)

function change-hack() {
  read -k 1 option

  if [[ $option == 's' ]]; then
    zle -U Tcs
  elif [[ $option == 'c' ]]; then
    zle vi-change-whole-line
  else
    zle -U ${NUMERIC}Tvc$option
  fi
}

function delete-hack() {
  read -k 1 option

  if [[ $option == 's' ]]; then
    zle -U Tds
  elif [[ $option == 'd' ]]; then
    zle kill-whole-line
  else
    zle -U ${NUMERIC}Tvd$option
  fi
}

function yank-hack() {
  read -k 1 option

  if [[ $option == 's' ]]; then
    zle -U Tys
  elif [[ $option == 'y' ]]; then
    zle vi-yank-whole-line
  else
    zle -U ${NUMERIC}Tvy$option
  fi
}

zle -N change-hack
zle -N delete-hack
zle -N yank-hack
autoload -Uz surround
zle -N delete-surround surround
zle -N change-surround surround
zle -N add-surround surround
bindkey -M vicmd 'Tcs' change-surround
bindkey -M vicmd 'Tds' delete-surround
bindkey -M vicmd 'Tys' add-surround
bindkey -M vicmd 'Tvd' vi-delete
bindkey -M vicmd 'Tvc' vi-change
bindkey -M vicmd 'Tvy' vi-yank
bindkey -M vicmd 'c' change-hack
bindkey -M vicmd 'd' delete-hack
bindkey -M vicmd 'y' yank-hack
bindkey -M visual S add-surround

source $ZSH/oh-my-zsh.sh

@FreddieOliveira Maybe I'm mistaking and your hack just doesn't fix b command behavior ... However maybe you have any ideas how to fix the issue.

@softmoth
Copy link
Owner

softmoth commented May 7, 2022

@korniychuk Verify you've set KEYTIMEOUT=1. That's what this hack here is all about, but I don't see it in the .zshrc you posted. It should mean that if you wait just a millisecond or two between <Esc> and b, it will behave as you want.

But if KEYTIMEOUT is low and you're still hitting b too quickly, you can try removing b from VIM_MODE_ESC_PREFIXED_WANTED. By default, the Emacs-style binding for <Esc>b is added. If you don't use that, and it's tripping you up, you can remove it.

@korniychuk
Copy link

Wow! It works, removing b from VIM_MODE_ESC_PREFIXED_WANTED fixed this problem! I saw VIM_MODE_ESC_PREFIXED_WANTED in the README, but it looks like didn't understand its meaning right.

Thank you @softmoth ! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants