Как сделать так, чтобы режим vi в zsh вел себя как режим vi в bash?


24

Мне действительно нравится общая скорость zsh, но две вещи меня раздражают.

  1. Мне нужно подождать мгновение между нажатием клавиши «escape» и «косой чертой», чтобы перейти к поиску в истории (если он слишком быстро ударит по слешу zsh: do you wish to see all 514 possibilities (172 lines))
  2. После входа в режим вставки из-за нажатия aили A, я не могу вернуться назад после точки, в которой я вошел в режим вставки.

Я знаю, что 2 похожа на классический vi, но мне больше нравится стиль vim.


Если кто-то сталкивается с очень раздражающей проблемой двойного побега, из-за которой вам приходится iдважды нажимать, чтобы вернуться в режим вставки, я очень рекомендую это исправление!
cchamberlain

Здесь также есть хорошее резюме: dougblack.io/words/zsh-vi-mode.html
jackcogdill

Ответы:


22

(1). По какой-то причине bindkey ведет себя странно, когда дело доходит до "/": <esc>после чего быстро /интерпретируется как <esc-/>. (Я наблюдал это поведение на днях; не совсем уверен, что его вызывает.) Я не знаю, является ли это ошибкой или функцией, и если это функция, если ее можно отключить, но вы можете обойти ее довольно легко ,

С этим ключевым сочетанием, вероятно, связано _history-complete-older, что приводит к нежелательному результату - вы можете использовать, bindkey -Lчтобы увидеть, если это так.

В любом случае, если вы не возражаете пожертвовать фактической <esc-/> (спрессованной, как аккорд) связью, вы можете перепривязать ее к команде поиска истории vi-mode, так что при вводе с <esc>последующим вводом /выполняется то же самое при любой типизации. скорость. знак равно

Так как это будет восприниматься как аккорд, оно не будет иметь эффекта при первом входе в командный режим vi, поэтому сначала нужно убедиться, что это произойдет. Во-первых, вам нужно определить функцию; поместите это где-нибудь в свой, fpathесли вы используете это, или поместите в свой .zshrc в противном случае:

vi-search-fix() {
zle vi-cmd-mode
zle .vi-history-search-backward
}

Остальное идет в вашем .zshrc в любом случае:

autoload vi-search-fix
zle -N vi-search-fix
bindkey -M viins '\e/' vi-search-fix

Должно быть хорошо идти.

(2). Вы можете исправить клавишу Backspace следующим образом:

`bindkey "^?" backward-delete-char`

Также, если вы хотите подобное поведение для других команд в стиле vi:

bindkey "^W" backward-kill-word 
bindkey "^H" backward-delete-char      # Control-h also deletes the previous char
bindkey "^U" backward-kill-line            

Это было ^[/не под \e/, но это и то, и другое - правильный способ сказать побег. Изменение работает отлично. Теперь, когда я играю с ним более полно, похоже, что режим vi в zsh отстой по сравнению с режимом bash (или, по крайней мере, не полностью настроен по умолчанию). Одним из примеров этого является тот факт, что он переводит вас в режим вставки после истории поиска. Я должен вернуться в командный режим, чтобы нажать n, чтобы найти следующий элемент поиска.
час. Оуэнс

1
Ну, я не знаю, есть ли у вас другие примеры, но вы упомянули мою, а не зш. =) Что случилось, я связал команду редактора режима vi-cmd в режиме вставки vi - команда ожидает, что оболочка уже находится в режиме cmd, и ведет себя соответственно. Нам нужно написать команду редактора, которая сначала вызывает команду «enter cmd mode», а затем выполняет .vi-history-search-backward. Я напишу это и отредактирую свой ответ - проверьте позже сегодня.
Маршалл Юбэнкс

ОК, я обновил свой ответ. Попробуйте это.
Маршалл Юбэнкс

Что касается (2), когда я делаю bindkey | grep <searchterm>для любого из терминов, все они имеют префикс vi-. Нужно ли настраивать bindkeyкоманды без префикса vi-?
adam_0

1
Спасибо. Эти хаки (и хаки из wjv ниже) делают режим vi в zsh практически бесполезным и превосходным. Я создал учетную запись суперпользователя, чтобы я мог голосовать за вас. :-)
ctrueden

14

Я собираюсь ответить только на вопрос (1).

Ваша проблема - KEYTIMEOUT. Я цитирую из zshzle (1):

Когда ZLE читает команду из терминала, он может прочитать последовательность, которая привязана к какой-либо команде и также является префиксом строки с более длинной привязкой. В этом случае ZLE будет ждать определенное время, чтобы увидеть, набрано ли больше символов, и если нет (или они не соответствуют более длинной строке), то выполнит связывание. Это время ожидания определяется параметром KEYTIMEOUT; его значение по умолчанию составляет 0,4 сек. Тайм-аут не существует, если строка префикса сама не привязана к команде.

Эти 0,4 секунды - это задержка, которую вы испытываете после нажатия ESC. Исправление состоит в том, чтобы установить KEYTIMEOUT вплоть до 0,01 с в одном из файлов запуска оболочки:

export KEYTIMEOUT=1

К сожалению, это имеет эффект: другие вещи начинают работать неправильно ...

Во-первых, теперь есть проблема в командном режиме vi: ввод ESC приводит к зависанию курсора, а затем любой символ, который вы вводите следующим, проглатывается. Это связано с тем, что ESC по умолчанию не связан ни с чем в командном режиме vi, но есть многосимвольные виджеты, которые начинаются с ESC (клавиши курсора!). Поэтому, когда вы нажимаете ESC, ZLE ждет следующего символа ... и затем использует его.

Исправление состоит в том, чтобы привязать ESC к чему-либо в командном режиме, таким образом гарантируя, что что- то будет передано в ZLE через $ KEYTIMEOUT сантисекунды. Теперь мы можем поддерживать привязки, начиная с ESC, в командном режиме без этих вредных последствий. Я связываю ESC с персонажем колокольчика, который я считаю еще менее навязчивым, чем само вставка (и моя оболочка заставлена ​​замолчать):

bindkey -sM vicmd '^[' '^G'

Обновление 2017:

С тех пор я нашел еще лучшее решение для привязки ESC - undefined-keyвиджет. Я не уверен, был ли этот виджет доступен в zsh, когда я изначально писал этот ответ.

bindkey -M vicmd '^[' undefined-key

Следующая проблема: по умолчанию есть некоторые виджеты с двумя ключами, начинающиеся с ^ X в режиме вставки vi; они становятся непригодными для использования, если $ KEYTIMEOUT установлен полностью вниз. Что я делаю, так это отсоединяю ^ X в режиме вставки vi (по умолчанию это самостоятельная вставка); это позволяет этим двухключевым виджетам продолжать работать.

bindkey -rM viins '^X'

Вы теряете привязку для самостоятельной вставки, но, конечно, можете привязать ее к чему-то другому. (Не знаю, так как мне это не нужно.)

Последняя проблема (которую я нашел до сих пор): Есть некоторые оставшиеся по умолчанию комбинации клавиш, которые мы «теряем» из-за установки $ KEYTIMEOUT прямо вниз, то есть: те, которые начинаются с ESC в режиме вставки vi, которые не являются клавишами курсора. Я лично связываю их, чтобы начать с ^ X вместо этого:

bindkey -M viins '^X,' _history-complete-newer \
                 '^X/' _history-complete-older \
                 '^X`' _bash_complete-word

Обновление 2018:

Оказывается, весь приведенный выше раздел (после «Обновления 2017») не обязательно требуется. Можно установить ключ META эквивалентным ESC в отображениях клавиатуры, используя:

bindkey -mv

Следовательно, можно не отменять привязку ^ X и получить доступ к сочетаниям клавиш, начинающимся в ESC, нажав вместо этого META в качестве лидера (ALT или OPT на современных клавиатурах).

Если у вас есть доступ к книге « От Bash до Z Shell » Киддла и др., Эквивалентность ESC и META в привязках клавиш обсуждается в боковой панели главы 4 на стр. 78–79.


Спасибо. Эти хаки (и хиты из вышеупомянутого маршала) также делают режим vi в zsh практически бесполезным и превосходным. Я создал учетную запись суперпользователя, чтобы я мог голосовать за вас. :-)
ctrueden

1
Благодарность! Я немного волнуюсь, что после всего этого времени нам все еще нужно то, что по сути является хаком и обходным путем, чтобы сделать ядро ​​функциональности zsh пригодным для использования!
wjv
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.