Вопрос или проблема
В bash поведение следующее:
- Ctrl+W удаляет слово за курсором до следующего пробела
- Ctrl+Alt+H удаляет слово за курсором до следующего разделительного символа, такого как
.
,,
,-
,/
и т.д.
В zsh
как Ctrl+W, так и Ctrl+Alt+H ведут себя, как последний в bash
.
Я бы хотел такое же поведение, как в bash
.
Это делает то, что вам нужно, независимо от того, что находится в $WORDCHARS
, и делает удаленные слова доступными для yank
:
# Создайте новый виджет.
zle -N backward-kill-space-word
backward-kill-space-word() {
# Сообщите редактору строк, что этот виджет будет удалять текст.
zle -f kill
# Установите $WORDCHARS только для этой команды.
WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' zle .backward-kill-word
}
# Смотрите комментарии выше.
zle -N backward-kill-bash-word
backward-kill-bash-word() {
zle -f kill
WORDCHARS='' zle .backward-kill-word
}
# Привяжите виджеты к клавишам.
bindkey '^W' backward-kill-space-word
bindkey '^[^H' backward-kill-bash-word
Кроме того, я выпустил плагин под названием zsh-edit
, который предлагает более сложные версии этих привязок клавиш.
Вы можете установить специальные символы, которые считаются частью слова, используя переменную WORDCHARS
. Это влияет на то, как слова удаляются командой Ctrl + W
:
WORDCHARS='~!#$%^&*(){}[]<>?.+;-_/\|=@`'
Однако это также влияет на Ctrl + Alt + H
. Мы хотим, чтобы это поведение применялось только к Ctrl + W
. Но есть трюк, который мы можем сделать. Позвольте мне объяснить:
Вы можете переназначить сочетания клавиш на разные функции (см. man zshzle
). И есть 2 функции, которые фактически имеют одинаковое поведение:
- backward-delete-word
- backward-kill-word
Вы также можете переопределить эти функции с помощью zle -N <func>
. Я не совсем уверен, как это работает, но вы получите представление, если прочитаете код, в любом случае это работает.
По умолчанию как Ctrl + W
, так и Ctrl + Alt + H
сопоставлены с backward-kill-word
. Поэтому мы можем переопределить backward-delete-word
и затем привязать его к Ctrl + W
:
# Сделаем так, чтобы `Ctrl + W` вел себя как в Bash, удаляя слова, разделенные
# пробелами. Мы делаем это, переопределяя функцию `backward-delete-word` и связываем
# ее с `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). Пока не нашел решения для этого..
Правильный ответ я нашел на Reddit: export WORDCHARS=${WORDCHARS/\/}
В итоге я нашел нужное поведение с этими привязками:
# Настраивает привязки клавиш для перехода/удаления полных и подслов, подобно
# привязкам клавиш в bash.
# Переходы:
# Alt + B Назад на подслово
# Ctrl + Alt + B Назад на полное слово
# Alt + F Вперед на подслово
# Ctrl + Alt + F Вперед на полное слово
# Удаление:
# Ctrl + W Назад удалить полное слово
# Ctrl + Alt + H Назад удалить подслово
# Alt + D Вперед удалить подслово
# Ctrl + Alt + D Вперед удалить полное слово
# Какие символы, кроме букв и цифр, перескакиваются при
# полном переходе на слово:
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
# Для `forward-sub-word` мы используем встроенный виджет `emacs-forward-word`,
# потому что он симулирует поведение bash.
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
.
Ответ или решение
Для реализации поведения клавиатурных сочетаний Ctrl + W
и Ctrl + Alt + H
в zsh так, как это происходит в bash, необходимо воспользоваться возможностями настройки клавиатурных сочетаний и функциональности zsh. В bash сочетание Ctrl + W
удаляет слово позади курсора до следующего пробела, а Ctrl + Alt + H
— до следующего разделительного символа, такого как точка, запятая или дефис. В zsh же эти команды по умолчанию обрабатываются одинаково, что, вероятно, не соотносится с вашими рабочими потребностями.
Теория
В zsh есть возможность изменять поведение клавиатурных сочетаний с помощью встроенного редактора командной строки zle и переменной окружения WORDCHARS. Эта переменная отвечает за определение символов, которые считаются частью слова. Вы можете создать пользовательские виджеты, которые определяют уникальное поведение для каждого клавиатурного сочетания.
Пример
Рассмотрим следующее решение для изменения поведения сочетаний Ctrl + W
и Ctrl + Alt + H
в zsh:
# Создание нового пользовательского виджета для удаления слова, как в bash.
zle -N backward-kill-space-word
backward-kill-space-word() {
zle -f kill
WORDCHARS='*?_-.[]~=/&!#$%^(){}<>' zle .backward-kill-word
}
# Создание виджета для удаления слова по bash поведению.
zle -N backward-kill-bash-word
backward-kill-bash-word() {
zle -f kill
WORDCHARS='' zle .backward-kill-word
}
# Привязка виджета к клавишам.
bindkey '^W' backward-kill-space-word
bindkey '^[^H' backward-kill-bash-word
Применение
-
Создание и настройка виджетов: В этих функциях мы используем встроенную команду zle для создания пользовательских команд, которые изменят поведение сочетаний
Ctrl + W
иCtrl + Alt + H
. В первом случаеWORDCHARS
устанавливается так, чтобы игнорировались разделительные символы, а во втором — чтобы они учитывались как пробелы. -
Назначение клавиш: После объявления функций, мы привязываем комбинации клавиш с помощью команды
bindkey
, тем самым настраивая необходимое поведение для каждой из них.
Этот подход обеспечивает, что Ctrl + W
будет удалять слова, разделённые пробелами, а Ctrl + Alt + H
— слова до следующего разделительного символа, как этого требует простая и интуитивно понятная работа в консоли. Real Time Transfer Protocol