Как сделать так, чтобы режим vi в zsh вел себя как режим vi в bash?
Мне действительно нравится общая скорость zsh, но две вещи меня раздражают.
- Мне нужно подождать мгновение между нажатием клавиши "escape" и "косой чертой", чтобы перейти к поиску истории
zsh: do you wish to see all 514 possibilities (172 lines)
) - После входа в режим вставки из-за удара
a
или жеA
Я не могу вернуться за точку, в которой я вошел в режим вставки.
Я знаю, что 2 похожа на классический vi, но мне больше нравится стиль vim.
3 ответа
(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
Я собираюсь ответить только на вопрос (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.
Я решил отменить завершение истории, чтобы устранить конфликт. Запустите следующее послеcompinit
связывает аккорд.
bindkey -M viins -r "^[/"
bindkey -M viins "^[." _history-complete-newer