Як я можу змусити режим vi від zsh поводитись більше як режим vih bash?


24

Мені дуже подобається загальна швидкість zsh, але дві речі дратують чорт з мене.

  1. Мені доводиться чекати хвилину між натисканням на втечу та нахилом косою рисою, щоб дістатися до пошуку історії (якщо вона потрапляє на косу рису занадто швидко, це говорить 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). Ви можете виправити клавішу зворотної області таким чином:

`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/, але це обидва способи сказати втечу. Зміна працює чудово. Тепер, коли я граю з нею більш повно, схоже, що режим zsh v's смокче порівняно з bash (або, принаймні, не повністю налаштовано за замовчуванням). Одним із прикладів цього є той факт, що він переходить у режим вставки після історії пошуку. Я повинен повернутися в командний режим, щоб натиснути n, щоб знайти наступний елемент пошуку.
Час. Оуенс

1
Ну, я не знаю, чи є у вас інші приклади, але той, кого ви згадуєте, - це моя вина, а не zsh. =) Що трапилось - я зв'язав команду редактора vi-cmd режиму у режимі вставки vi - команда очікує, що оболонка вже перебуває у режимі cmd і поводиться відповідно. Нам потрібно написати команду редактора, яка спочатку викликає команду "введіть cmd режим", а потім виконує .vi-history-search-backward. Я напишу це та відредагую свою відповідь - перевірте пізніше сьогодні.
Маршалл Юбанкс

Гаразд, я оновив свою відповідь. Спробуй.
Маршалл Юбанкс

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

1
Дякую. Ці хаки (і такі, як wjv внизу теж), змушують режим 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 to Z Shell від Kiddle та ін., Еквівалентність ESC та META в клавіатурних палітурках обговорюється в бічній панелі глави 4 на стор. 78–79.


Дякую. Ці хаки (і ті, хто в маршалі вище) також перетворюють режим zsh від «майже непридатного» до «відмінного». Я створив обліковий запис суперпользователя, щоб я міг вас проголосувати. :-)
ctrueden

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