Jak mogę sprawić, aby tryb vi zsh działał bardziej jak tryb vi bash?

24

Naprawdę podoba mi się ogólna prędkość Zsh, ale dwie rzeczy mnie denerwują.

  1. Muszę poczekać chwilę między uderzeniem w ucieczkę a uderzeniem w ukośnik, aby przejść do wyszukiwania historii (jeśli uderzy zbyt szybko, napisane jest zsh: do you wish to see all 514 possibilities (172 lines))
  2. Po wejściu w tryb wstawiania z powodu uderzenia alub Anie mogę cofnąć się do miejsca, w którym wszedłem w tryb wstawiania.

Wiem, że 2 jest jak klasyczna vi, ale bardziej podoba mi się styl vim.

Chas. Owens
źródło
Jeśli ktoś napotyka bardzo irytujący problem podwójnego ucieczki, powodujący konieczność idwukrotnego naciśnięcia przycisku, aby wrócić do trybu wstawiania, zdecydowanie polecam poprawkę!
cchamberlain
Istnieje również dobre podsumowanie tutaj: dougblack.io/words/zsh-vi-mode.html
jackcogdill

Odpowiedzi:

22

(1). Z jakiegoś powodu bindkey zachowuje się dziwnie, jeśli chodzi o „/”: <esc>po którym następuje szybkie /interpretowanie jako <esc-/>. (Obserwowałem to zachowanie innego dnia; nie jestem do końca pewien, co je powoduje). Nie wiem, czy to błąd, czy funkcja, a jeśli jest to funkcja, jeśli można ją wyłączyć, ale można dość łatwo obejść ten problem .

Ta kombinacja klawiszy prawdopodobnie jest związana _history-complete-older, co generuje niepożądany wynik - możesz użyć, bindkey -Laby sprawdzić, czy tak jest.

W każdym razie, jeśli nie masz nic przeciwko poświęceniu rzeczywistego <esc-/> (wciśniętego razem, jako akordu) wiązania, możesz ponownie powiązać je z poleceniem wyszukiwania historii w trybie vi, aby pisanie <esc>poprzedzone działało /tak samo przy każdym pisaniu prędkość. =)

Ponieważ będzie to traktowane jako akord, nie będzie miało wpływu na wejście w tryb komend vi, więc musimy upewnić się, że to się stanie najpierw. Najpierw musisz zdefiniować funkcję; umieść go gdzieś w swoim, fpathjeśli go używasz, lub umieść go w .zshrc w przeciwnym razie:

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

Reszta idzie w twoim .zshrc w obu kierunkach:

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

Powinno być dobrze.

(2). Możesz naprawić klawisz Backspace w następujący sposób:

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

Ponadto, jeśli chcesz mieć podobne zachowanie dla innych poleceń w stylu vi:

bindkey "^W" backward-kill-word 
bindkey "^H" backward-delete-char      # Control-h also deletes the previous char
bindkey "^U" backward-kill-line            
Marshall Eubanks
źródło
To pod ^[/nie \e/, ale te są zarówno ważne sposoby mówiąc ucieczki. Zmiana działa idealnie. Teraz, gdy gram z tym bardziej kompletnie, wygląda na to, że tryb vi zsh jest do bani w porównaniu do basha (lub przynajmniej nie jest w pełni skonfigurowany domyślnie). Jednym z przykładów jest to, że po historii wyszukiwania powoduje przejście do trybu wstawiania. Muszę wrócić do trybu poleceń, aby nacisnąć n, aby znaleźć następny szukany element.
Chas. Owens
1
Nie wiem, czy masz jakieś inne przykłady, ale ten, o którym wspominasz, to moja wina, a nie zsh. =) To, co się stało, jest związane z poleceniem edytora trybu vi-cmd w trybie wstawiania vi - polecenie oczekuje, że powłoka już działa w trybie cmd i odpowiednio się zachowuje. Musimy napisać polecenie edytora, które najpierw wywołuje polecenie „wejdź w tryb cmd”, a następnie wykonuje polecenie .vi-history-search-backward. Napiszę i zredaguję swoją odpowiedź - sprawdź później.
Marshall Eubanks
OK, zaktualizowałem swoją odpowiedź. Wypróbuj to.
Marshall Eubanks
W odniesieniu do (2), kiedy robię bindkey | grep <searchterm>dla któregokolwiek z terminów, wszystkie są poprzedzone przez vi-. Czy muszę skonfigurować bindkeypolecenia, które nie mają przedrostka vi-?
adam_0
1
Dziękuję Ci. Te hacki (i te z wjv poniżej) powodują, że tryb vi zsh zmienia się z prawie nieużytecznego w doskonały. Utworzyłem konto administratora, aby móc zagłosować. :-)
ctrueden
14

Zajmę się tylko pytaniem (1).

Twój problem to KEYTIMEOUT. Cytuję z zshzle (1):

Gdy ZLE odczytuje polecenie z terminala, może odczytać sekwencję powiązaną z jakimś poleceniem, a także przedrostek dłuższego łańcucha. W takim przypadku ZLE poczeka pewien czas, aby sprawdzić, czy zostanie wpisanych więcej znaków, a jeśli nie (lub nie pasują one do żadnego dłuższego ciągu), wykona wiązanie. Limit czasu jest zdefiniowany przez parametr KEYTIMEOUT; jego domyślna wartość to 0,4 sekundy. Nie ma limitu czasu, jeśli ciąg prefiksu nie jest związany z poleceniem.

Te 0,4 s to opóźnienie występujące po uderzeniu w ESC. Rozwiązaniem jest ustawienie KEYTIMEOUT aż do 0,01 s w jednym z plików startowych powłoki:

export KEYTIMEOUT=1

Niestety ma to efekt domina: inne rzeczy zaczynają się dziać źle…

Po pierwsze, występuje teraz problem w trybie komend vi: Wpisanie ESC powoduje zawieszenie się kursora, a następnie którykolwiek z wpisanych znaków zostanie połknięty. Wynika to z faktu, że ESC nie jest domyślnie powiązany z niczym w trybie komend vi, ale istnieją widżety wieloznakowe, które zaczynają się od ESC (klawisze kursora!). Więc kiedy wciśniesz ESC, ZLE czeka na następną postać… a następnie ją pochłania.

Rozwiązaniem jest powiązanie ESC z czymś w trybie poleceń, co zapewnia, że coś zostanie przekazane do ZLE po centisekundach $ KEYTIMEOUT. Teraz możemy utrzymywać wiązania zaczynające się od ESC w trybie poleceń bez tych złych efektów. Wiążę ESC z postacią dzwonka, co wydaje mi się mniej inwazyjne niż samodzielne wstawianie (a moja skorupa jest wyciszona):

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

Aktualizacja 2017:

Od tego czasu znalazłem jeszcze lepsze rozwiązanie dla wiązania ESC - undefined-keywidgetu. Nie jestem pewien, czy ten widget był dostępny w Zsh, kiedy pierwotnie napisałem tę odpowiedź.

bindkey -M vicmd '^[' undefined-key

Następny problem: Domyślnie istnieją dwa widżety z dwoma kluczami, zaczynające się od ^ X w trybie wstawiania vi; stają się one bezużyteczne, jeśli $ KEYTIMEOUT jest ustawiony do końca. To, co robię, to unbindowanie ^ X w trybie wstawiania vi (domyślnie jest to automatyczne wstawianie); pozwala to dwóm kluczowym widżetom kontynuować pracę.

bindkey -rM viins '^X'

Tracisz wiązanie do samodzielnego wstawiania, ale możesz oczywiście powiązać je z czymś innym. (Nie mam, bo nie mam z tego pożytku.)

Ostatni problem (do tej pory znalazłem): Są pewne domyślne skróty klawiszowe, które „tracimy” z powodu ustawienia $ KEYTIMEOUT w dół, to znaczy: te zaczynające się od ESC w trybie wstawiania vi, które nie są klawiszami kursora. Osobiście wiążę je ponownie, aby zacząć od ^ X:

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

Aktualizacja 2018:

Okazuje się, że cała sekcja powyżej (po „Aktualizacji 2017”) niekoniecznie jest wymagana. Możliwe jest ustawienie klawisza META tak, aby był równoważny klawiszowi ESC w mapowaniu klawiatury za pomocą:

bindkey -mv

Jest zatem możliwe, aby nie cofać wiązania ^ X i uzyskać dostęp do skrótów klawiszowych rozpoczynających się w ESC, naciskając zamiast tego META jako lidera (ALT lub OPT na nowoczesnych klawiaturach).

Jeśli masz dostęp do książki From Bash to Z Shell autorstwa Kiddle i wsp., Równoważność ESC i META w skrótach klawiszowych omówiono w pasku bocznym rozdziału 4 na str. 78–79.

wjv
źródło
Dziękuję Ci. Te włamania (i powyższe także marshaul) powodują, że tryb vi zsh zmienia się z prawie bezużytecznego w doskonały. Utworzyłem konto administratora, aby móc zagłosować. :-)
ctrueden
1
Dzięki! Trochę niepokoi mnie to, że po tak długim czasie nadal potrzebujemy tego, co jest w zasadzie hackem i obejściem, aby uczynić rdzeń funkcji zsh użytecznym!
wjv