使 zsh 中的 `Ctrl + W` 和 `Ctrl + Alt + H` 的行為與 bash 中的相同

使 zsh 中的 `Ctrl + W` 和 `Ctrl + Alt + H` 的行為與 bash 中的相同

在 bash 中的行為是這樣的:

  • Ctrl+W刪除遊標後面的單字直到下一個空格
  • Ctrl+ Alt+H刪除遊標後面的單字直到下一個分隔字符,如, .,,等。-/

在+和zsh++中,其行為類似.CtrlWCtrlAltHbash

我想要與 中相同的行為bash

答案1

無論 中包含什麼內容$WORDCHARS,這都會執行您想要的操作,並使被刪除的單字可用於yank

# Create a new widget.
zle -N backward-kill-space-word
backward-kill-space-word() {
  # Inform the line editor that this widget will kill text.
  zle -f kill

  # Set $WORDCHARS for this command only. 
  WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' zle .backward-kill-word
}

# See comments above.
zle -N backward-kill-bash-word
backward-kill-bash-word() {
  zle -f kill
  WORDCHARS='' zle .backward-kill-word
}

# Bind the widgets to keys.
bindkey   '^W' backward-kill-space-word
bindkey '^[^H' backward-kill-bash-word

或者,我發布了一個插件名為zsh-edit,它附帶了這些鍵綁定的更複雜版本。

答案2

您可以使用變數設定被視為單字一部分的特殊字元WORDCHARS。這會影響以下方式刪除單字的方式Ctrl + W

WORDCHARS='~!#$%^&*(){}[]<>?.+;-_/\|=@`'

不過它也有影響Ctrl + Alt + H。我們希望此行為僅適用於Ctrl + W.但我們可以使用一個技巧。讓我解釋:

您可以將組合鍵重新綁定到不同的功能(請參閱man zshzle)。有兩個函數實際上具有相同的行為:

  • 向後刪除單字
  • 向後殺字

您也可以使用 重新定義這些函數zle -N <func>。我不完全確定它是如何工作的,但是如果你閱讀程式碼你就會明白,無論如何,它確實有效。

預設情況下,Ctrl + WCtrl + Alt + H都映射到backward-kill-word.所以我們可以重新定義backward-delete-word然後將其綁定到Ctrl + W

# Make `Ctrl + W` behave like it does in Bash, deleting words separated by
# spaces. We do this by redefining the `backward-delete-word` function and bind
# that to `Ctrl + W`.
SPACE_WORDCHARS='~!#$%^&*(){}[]<>?.+;-_/\|=@`'
backward-delete-word() WORDCHARS=$SPACE_WORDCHARS zle .$WIDGET
zle -N backward-delete-word
bindkey "^W" backward-delete-word

是的,現在刪除比!Ctrl + W更大的單字。Ctrl + Alt + H

編輯:

非常遺憾的是,我現在發現這種方法缺乏一些功能,當您刪除一個單字時,它不會被拉到貼上緩衝區(Ctrl + Y)。還沒找到解決方案..

答案3

我最終透過這些綁定找到了我想要的行為:

# Configures bindings for jumping/deleting full and sub-words, similar to
# the keybindings in bash.

# Jumping:
# Alt + B                Backward sub-word
# Ctrl + Alt + B         Backward full-word
# Alt + F                Forward sub-word
# Ctrl + Alt + F         Forward full-word

# Deleting:
# Ctrl + W               Backward delete full-word
# Ctrl + Alt + H         Backward delete sub-word
# Alt + D                Forward delete sub-word
# Ctrl + Alt + D         Forward delete full-word

# Which characters, besides letters and numbers, that are jumped over by a
# full-word jump:
FULLWORDCHARS="*?_-.,[]~=/&:;!#$%^(){}<>'\""

backward-full-word() { WORDCHARS=$FULLWORDCHARS zle .backward-word ; }
backward-sub-word() { WORDCHARS="" zle .backward-word ; }
forward-full-word() { WORDCHARS=$FULLWORDCHARS zle .forward-word ; }
backward-kill-full-word() { WORDCHARS=$FULLWORDCHARS zle .backward-kill-word ; }
backward-kill-sub-word() { WORDCHARS="" zle .backward-kill-word ; }
forward-kill-full-word() { WORDCHARS=$FULLWORDCHARS zle .kill-word ; }
forward-kill-sub-word() { WORDCHARS="" zle .kill-word ; }

zle -N backward-full-word
zle -N backward-sub-word
zle -N forward-full-word
zle -N backward-kill-full-word
zle -N backward-kill-sub-word
zle -N forward-kill-full-word
zle -N forward-kill-sub-word

# For `forward-sub-word` we use the built-in `emacs-forward-word` widget,
# because that simulates bash behavior.
zle -A emacs-forward-word forward-sub-word

bindkey "^[b" backward-sub-word
bindkey "^[^b" backward-full-word
bindkey "^[f" forward-sub-word
bindkey "^[^f" forward-full-word
bindkey "^[^h" backward-kill-sub-word
bindkey "^w" backward-kill-full-word
bindkey "^[d" forward-kill-sub-word
bindkey "^[^d" forward-kill-full-word

相關內容