Wie kann ich dafür sorgen, dass sich der vi-Modus von zsh mehr wie der vi-Modus von bash verhält?

24

Ich mag die allgemeine Geschwindigkeit von zsh sehr, aber zwei Dinge nerven mich.

  1. Ich habe zu schlagen warten Sie einen Moment zwischen Flucht schlagen und Slash auf die Geschichte Suche zu erhalten schlagen (wenn es zu schnell getroffen Slash es sagt zsh: do you wish to see all 514 possibilities (172 lines))
  2. Nach dem Aufrufen des Einfügemodus durch Drücken von aoder Akann ich den Punkt, an dem ich den Einfügemodus aufgerufen habe , nicht mehr rückgängig machen.

Ich weiß, dass 2 wie klassisches vi ist, aber ich mag den Vim-Stil besser.

Chas. Owens
quelle
Wenn jemand auf das ärgerliche Problem der doppelten Fluchtung stößt, bei dem Sie izweimal drücken müssen, um in den Einfügemodus zurückzukehren, kann ich dieses Update wärmstens empfehlen !
Cchamberlain
Hier gibt es auch eine gute Zusammenfassung: dougblack.io/words/zsh-vi-mode.html
jackcogdill

Antworten:

22

(1). Aus irgendeinem Grund verhält sich bindkey merkwürdig, wenn es um "/" geht: <esc>gefolgt von /wird interpretiert als <esc-/>. (Ich habe dieses Verhalten neulich beobachtet; ich bin mir nicht ganz sicher, was es verursacht.) Ich weiß nicht, ob es sich um einen Fehler oder eine Funktion handelt und ob es sich um eine Funktion handelt, die deaktiviert werden kann, aber Sie können es ziemlich einfach umgehen .

Diese Tastenkombination ist wahrscheinlich an gebunden _history-complete-older, was zu dem unerwünschten Ergebnis führt - Sie können sie verwenden, um bindkey -Lzu sehen, ob dies der Fall ist.

Jedenfalls, wenn Sie nichts dagegen haben die Einbußen bei tatsächlichen <esc-/> (zusammengedrückt, als Akkord) zu binden, können Sie sich erneut binden sie an den vi-Modus Geschichte Suchbefehl, so dass die Eingabe <esc>anschließend /macht das Gleiche zu jeder Typisierung Geschwindigkeit. =)

Da dies als Akkord behandelt wird, wird der vi-Befehlsmodus nicht zuerst aufgerufen. Wir müssen also sicherstellen, dass dies zuerst geschieht. Zunächst müssen Sie eine Funktion definieren. fpathPlatziere es irgendwo in deinem, wenn du das benutzt, oder platziere es anders in deinem .zshrc:

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

Der Rest geht in Ihre .zshrc-Richtung:

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

Sollte gut zu gehen sein.

(2). Sie können die Rücktaste wie folgt korrigieren:

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

Wenn Sie ein ähnliches Verhalten für andere vi-Befehle wünschen:

bindkey "^W" backward-kill-word 
bindkey "^H" backward-delete-char      # Control-h also deletes the previous char
bindkey "^U" backward-kill-line            
Marshall Eubanks
quelle
Es war unter ^[/nicht \e/, aber das sind beide gültige Möglichkeiten, Flucht zu sagen. Die Änderung funktioniert einwandfrei. Jetzt, da ich etwas ausführlicher damit spiele, sieht es so aus, als ob der vi-Modus von zsh im Vergleich zu bash nicht funktioniert (oder zumindest nicht vollständig konfiguriert ist). Ein Beispiel hierfür ist die Tatsache, dass Sie nach dem Suchverlauf in den Einfügemodus versetzt werden. Ich muss in den Befehlsmodus zurückkehren, um n zu drücken und den nächsten Suchbegriff zu finden.
Chas. Owens
1
Nun, ich weiß nicht, ob Sie andere Beispiele haben, aber das, das Sie erwähnen, ist meine Schuld, nicht die von zsh. =) Was passiert ist, ist, dass ich einen vi-cmd-Modus-Editor-Befehl im vi-Einfügemodus gebunden habe - der Befehl erwartet, dass die Shell bereits im cmd-Modus ausgeführt wird, und verhält sich dementsprechend. Wir müssen einen Editor-Befehl schreiben, der zuerst den Befehl "enter cmd mode" aufruft und dann ausführt .vi-history-search-backward. Ich schreibe es und bearbeite meine Antwort - versuche es später noch einmal.
Marshall Eubanks
OK, ich habe meine Antwort aktualisiert. Versuch es.
Marshall Eubanks
In Bezug auf (2), wenn ich bindkey | grep <searchterm>für einen der Begriffe mache , sind sie alle mit einem Präfix versehen vi-. Muss ich bindkeyBefehle einrichten , denen kein Präfix vorangestellt ist vi-?
adam_0
1
Vielen Dank. Diese Hacks (und auch die von wjv unten) machen den vi-Modus von zsh fast unbrauchbar bis exzellent. Ich habe ein Superuser-Konto erstellt, damit ich Sie abstimmen kann. :-)
ctrueden
14

Ich werde nur Frage (1) ansprechen.

Ihr Problem ist KEYTIMEOUT. Ich zitiere aus zshzle (1):

Wenn ZLE einen Befehl vom Terminal liest, liest es möglicherweise eine Sequenz, die an einen Befehl gebunden ist und auch ein Präfix einer länger gebundenen Zeichenfolge ist. In diesem Fall wartet ZLE eine bestimmte Zeit, um zu sehen, ob weitere Zeichen eingegeben wurden. Wenn dies nicht der Fall ist (oder wenn sie nicht mehr mit einer Zeichenfolge übereinstimmen), wird die Bindung ausgeführt. Dieses Zeitlimit wird durch den Parameter KEYTIMEOUT definiert. Die Standardeinstellung ist 0,4 Sekunden. Es tritt keine Zeitüberschreitung auf, wenn die Präfixzeichenfolge selbst nicht an einen Befehl gebunden ist.

Diese 0,4s ist die Verzögerung, die Sie erfahren, nachdem Sie ESC geschlagen haben. Das Update besteht darin, KEYTIMEOUT in einer der Shell-Startdateien auf 0,01 Sekunden zu setzen:

export KEYTIMEOUT=1

Leider hat dies einen negativen Effekt: Andere Dinge laufen schief ...

Erstens gibt es jetzt ein Problem im vi-Befehlsmodus: Wenn Sie ESC eingeben, bleibt der Cursor hängen, und jedes Zeichen, das Sie als Nächstes eingeben, wird verschluckt. Dies liegt daran, dass ESC im vi-Befehlsmodus standardmäßig an nichts gebunden ist, es jedoch Widgets mit mehreren Zeichen gibt, die mit ESC beginnen (Cursortasten!). Wenn Sie also ESC drücken, wartet ZLE auf das nächste Zeichen ... und verbraucht es dann.

Der Fix besteht darin, ESC an etwas im Befehlsmodus zu binden und so sicherzustellen, dass das etwas nach $ KEYTIMEOUT Zentisekunden an ZLE übergeben wird. Jetzt können wir Bindungen, die mit ESC beginnen, im Befehlsmodus beibehalten, ohne diese negativen Auswirkungen. Ich binde ESC an die Glocke, die ich noch weniger aufdringlich finde als die Selbsteinfügung (und meine Shell wird stummgeschaltet):

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

Update 2017:

Ich habe seitdem eine noch bessere Lösung für das Binden von ESC gefunden - das undefined-keyWidget. Ich bin nicht sicher, ob dieses Widget in zsh verfügbar war, als ich diese Antwort ursprünglich schrieb.

bindkey -M vicmd '^[' undefined-key

Nächstes Problem: Es gibt standardmäßig einige Zwei-Tasten-Widgets, die im vi-Einfügemodus in ^ X beginnen. Diese werden unbrauchbar, wenn $ KEYTIMEOUT ganz nach unten gesetzt ist. Was ich tue, ist das Aufheben der Bindung von ^ X im vi-Einfügemodus (standardmäßig ist es das Einfügen selbst). Auf diese Weise können diese Zwei-Schlüssel-Widgets weiterarbeiten.

bindkey -rM viins '^X'

Sie verlieren die Bindung für die Selbsteinfügung, aber Sie können sie natürlich auch an etwas anderes binden. (Ich nicht, da ich nichts dafür habe.)

Das letzte Problem (das ich bis jetzt gefunden habe): Es gibt einige verbleibende Standard-Tastaturbelegungen, die wir "verlieren", weil wir $ KEYTIMEOUT ganz nach unten setzen: diejenigen, die mit ESC im vi-Einfügemodus beginnen und keine Cursortasten sind. Ich binde sie persönlich neu, um stattdessen mit ^ X zu beginnen:

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

Update 2018:

Es stellt sich heraus, dass der gesamte obige Abschnitt (nach „Update 2017“) nicht unbedingt erforderlich ist. Es ist möglich, die META-Taste in Tastaturzuordnungen so einzustellen, dass sie der ESC-Taste entspricht:

bindkey -mv

Es ist daher möglich , ^ X nicht zu lösen und auf die Tastenkombinationen zuzugreifen, die in ESC beginnen, indem Sie stattdessen META als Führungslinie drücken (ALT oder OPT auf modernen Tastaturen).

Wenn Sie Zugriff auf das Buch From Bash to Z Shell von Kiddle et al. Haben , wird die Äquivalenz von ESC und META in Tastenkombinationen in der Seitenleiste von Kapitel 4 auf S. 78–79 erläutert.

wjv
quelle
Vielen Dank. Diese Hacks (und auch die von Marshaul oben) bewirken, dass der vi-Modus von zsh von nahezu unbrauchbar auf exzellent wechselt. Ich habe ein Superuser-Konto erstellt, damit ich Sie abstimmen kann. :-)
ctrueden
1
Vielen Dank! Ich finde es ein wenig besorgniserregend, dass wir nach all der Zeit immer noch einen Hack und eine Problemumgehung benötigen, um ein Kernstück der zsh-Funktionalität nutzbar zu machen!
wjv