hlissner / zsh-autopair

Auto-close and delete matching delimiters in zsh
MIT License
509 stars 37 forks source link

autopair-close doesn't work #12

Closed mikheyev closed 4 years ago

mikheyev commented 7 years ago

I am running zsh 5.3, and can't seem to get the behavior in the example. When I type a quote, bracket or parenthesis by itself, a matching one appears at the end of the line. However, if I try to encapsulate existing text, nothing happens. I deleted everything from my .zshrc except zsh-autopair, and it still does not work.

hlissner commented 7 years ago

Could you provide steps to reproduce this? In particular, shed some light on what you mean by 'encapsulate existing text'.

There are checks in my plugin that prevents autopairing when the cursor isn't adjacent to whitespace, e.g. |text => { => {text, because in that case, I assume the user wants to autopair manually, maybe that's what you're referring to?

Or maybe you're having trouble with the zsh surround plugin? (Which lets you surround blocks with, say, ysiw" [wraps the inner word under the cursor in quotes], in much the way vim-surround does it in vim).

mikheyev commented 7 years ago

Sorry for the confusion (and late reply), the issue I have is with is indeed the zsh surround plugin. As far as I understand, if I type echo test => " the result should be echo "test", but what I actually get is echo test". Am I not activating it correctly somehow?

hlissner commented 7 years ago

That is the intended result. If i understood you correctly, zsh-autopair won't auto-surround text in the way you're suggesting. It does four things for you:

  1. It inserts matching pairs (when that pair isn't unbalanced and you're not next to a word character)

    e.g. echo | => " => echo "|"

  2. It skips over matching pairs:

    e.g. rm -f *.{|}" => } => rm -f *.{}|

  3. It auto-deletes pairs:

    e.g. echo "|" => backspace => echo |

  4. And only does all of the above when it makes sense to do so. i.e. when the pair is balanced. e.g.

    e.g. echo "|"" => backspace => echo |"" (doesn't aggressively eat up too many quotes)

    e.g. echo "test | => " => echo "test |" (only adds one "'s at the end, because it see's the first quote is unbalanced without it)

That's all.

However, if you use zsh-surround and exploit zsh's built-in vim-like command mode then you can do more sophisticated things. A quick peek at your dotfiles suggests you may not be a vim user. If vim's text objects and motion keys are alien to you, zsh-surround may be too complicated. Otherwise, read on:


First, we've got to ensure zsh-surround is set up properly (you can put this in your .zshenv or .zshrc):

# Ran into an issue where the surround module wasn't working if KEYTIMEOUT is <= 10.
# Specifically, (delete|change)-surround immediately abort into insert mode if
# KEYTIMEOUT <= 8, and if <= 10, then add-surround would do the same. At 11, all these
# issues vanish. Very strange!
export KEYTIMEOUT=15

## vi-mode ###############
bindkey -v                         # activate zsh vi mode
bindkey -M viins 'jk' vi-cmd-mode  # type jk quickly to get into command mode

# set up zsh-surround with vim keys
autoload -Uz surround
zle -N delete-surround surround
zle -N add-surround surround
zle -N change-surround surround
bindkey -a cs change-surround
bindkey -a ds delete-surround
bindkey -a ys add-surround
bindkey -M visual S add-surround

# sets up vimmish text-objects in zsh
autoload -U is-at-least
if is-at-least 5.0.8; then
    autoload -U select-quoted; zle -N select-quoted
    for m in visual viopp; do
        for c in {a,i}{\',\",\`}; do
            bindkey -M $m $c select-quoted
        done
    done
    autoload -U select-bracketed; zle -N select-bracketed
    for m in visual viopp; do
        for c in {a,i}${(s..)^:-'()[]{}<>bB'}; do
            bindkey -M $m $c select-bracketed
        done
    done
fi

What this allows me to do is to go into command mode (by pressing ESC, or typing jk; a custom shortcut I've added above) and:

echo test| => jkviw => echo [test] => S" => echo |"test"

  1. jk exits into command mode
  2. v enters visual (selection) mode
  3. iw selects "inner word"; since the cursor is on the word test, it selects that
  4. S" Surrounds the selection with quotes

Or even shorter:

echo test| => jkysiw" => echo "test"

  1. jk exits into command mode
  2. ysiw" Yank-Surrounds the inner word with quotes

Another example:

echo the quick brown fox| => jkv^w => echo [the quick brown fox] => S" => echo |"the quick brown fox"

  1. jk exits into command mode
  2. v enters visual (selection) mode
  3. ^ goes to the beginning of the line
  4. w jumps one "word" forward
  5. S" and surrounds the selection in quotes

Or you can delete pairs:

echo "hello world|" => jkds" => echo hello world|

  1. jk ...
  2. ds" delete the surrounding double quotes

Or change pairs:

echo "hello world|" => jkcs"' => echo 'hello world|'

  1. jk ...
  2. cs"' change surrounding double quotes into single quotes

There are a wide variety of motion keys like this. Being a vim user they come naturally to me, but I could see them being utterly nonsensical otherwise! In which case, sorry about that, haha.

mikheyev commented 7 years ago

Thank you for the very detailed reply! It is illuminating, and I might explore vim mode more, though I am an emacs user, typically. However, I can't get functionality 1 through 4 to work. Basically, the only thing that does is parenthesis and quote matching. You can see the autopair branch in my dotfiles has only autopair loaded, so it doesn't seem to be a matter of conflict with anything.

hlissner commented 7 years ago

Hmm, I suspect something is interfering (or unbinding) zsh-autopair's keybindings, as was the issue in #6 (with prezto's editor module). At first glance I don't see anything in your dotfiles that stand out as a potential culprit (and you seem to load prezto before loading autopair, so I'm not sure if that's the problem).

To test this, add AUTOPAIR_INHIBIT_INIT=1 to your zshrc (before you load autopair.zsh), then run autopair-init in the shell. If zsh-autopair works afterwards, then my hunch is right.

voyeg3r commented 7 years ago

In my case just placing source ... at the end of my zshrc solved "my problem" which was different. The plugin did not work.

hlissner commented 6 years ago

Is this still an issue? This plugin has seen a number of updates since, and things seem to be working fine so far in zsh 5.0.8+.

mikheyev commented 6 years ago

OK, just updated the plugin to the most current version and zsh to 5.0.2, but still doesn't work.

gHashTag commented 6 years ago

same +

laggardkernel commented 5 years ago

At last, I understood the | in the examples means the cursor, not a vertical bar. Then all my puzzles are solved. 😂

moriakijp commented 5 years ago

same +

hlissner commented 5 years ago

I still cannot reproduce this. @moriakijp @gHashTag @mikheyev If you are still experiencing his issue, are you able to reproduce it with a blank shell config?

hlissner commented 4 years ago

Anybody getting this issue in zsh 5.7.1? I have yet to reproduce it, and this plugin has worked for me since 5.0.2 in a vanilla config, zgen config, in a variety of terminals and OSes, so I'll close this.

If you have this problem, please disable the rest of your config and see if you can still reproduce it. Since this plugin rebinds keys it is very possible another plugin could interfere with it.

issenn commented 4 years ago

@hlissner
Doesn‘t work before bindkey -e