Сделайте так, чтобы `Ctrl + W` и `Ctrl + Alt + H` в zsh вели себя так же, как в bash

Сделайте так, чтобы `Ctrl + W` и `Ctrl + Alt + H` в zsh вели себя так же, как в bash

В bash поведение такое:

  • Ctrl+ Wудаляет слово за курсором до следующего пробела
  • Ctrl+ Alt+ Hудаляет слово за курсором до следующего разделительного символа, например ., ,, , -, /и т. д.

В zshобоих случаях Ctrl+ Wи Ctrl+ Alt+ Hведут себя как последний в bash.

Я бы хотел такого же поведения, как в 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). И есть 2 функции, которые на самом деле ведут себя одинаково:

  • удалить-слово-назад
  • слово-убить-назад

Вы также можете переопределить эти функции с помощью zle -N <func>. Я не совсем уверен, как это работает, но вы получите представление, если прочитаете код, в любом случае, это делает свое дело.

По умолчанию Ctrl + Wи и Ctrl + 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

Связанный контент