Come posso fare in modo che la modalità vi di zsh si comporti più come la modalità vi di bash?


24

Mi piace molto la velocità generale di zsh, ma due cose mi danno fastidio.

  1. Devo colpire un momento tra colpire la fuga e colpire la barra per arrivare alla ricerca della cronologia (se colpisce la barra troppo rapidamente dice zsh: do you wish to see all 514 possibilities (172 lines))
  2. Dopo aver inserito la modalità di inserimento a causa del colpo ao A, non riesco a tornare indietro oltre il punto in cui sono entrato nella modalità di inserimento.

So che 2 è come il classico vi, ma mi piace di più lo stile vim.


Se qualcuno si imbatte nel fastidioso problema della doppia fuga che ti costringe a colpire idue volte per tornare alla modalità di inserimento, consiglio vivamente questa correzione!
cchamberlain,

C'è anche un buon riassunto qui: dougblack.io/words/zsh-vi-mode.html
jackcogdill

Risposte:


22

(1). Per qualche motivo, bindkey si comporta in modo strano quando si tratta di "/": <esc>seguito rapidamente da /viene interpretato come <esc-/>. (Ho osservato questo comportamento l'altro giorno; non sono del tutto sicuro di cosa lo causi.) Non so se si tratta di un bug o di una funzionalità e se è una funzionalità se può essere disabilitata, ma puoi aggirare abbastanza facilmente .

Questa combinazione di tasti è probabilmente legata a _history-complete-older, che sta generando il risultato indesiderato - puoi usare bindkey -Lper vedere se questo è il caso.

In ogni caso, se non ti dispiace sacrificare il legame effettivo <esc-/> (premuto insieme, come un accordo), puoi ricollegarlo al comando di ricerca della cronologia vi-mode, in modo che la digitazione <esc>seguita /faccia la stessa cosa in qualsiasi battitura velocità. =)

Dato che questo sarà trattato come un accordo, non avrà l'effetto di entrare prima nella modalità di comando vi, quindi dovremo assicurarci che ciò accada per primo. Innanzitutto, è necessario definire una funzione; mettilo da qualche parte nel tuo fpathse lo usi, o mettilo nel tuo .zshrc altrimenti:

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

Il resto va nel tuo .zshrc in entrambi i modi:

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

Dovrebbe essere buono per andare.

(2). È possibile correggere la chiave backspace come segue:

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

Inoltre, se si desidera un comportamento simile per altri comandi in stile vi:

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

E 'stato sotto ^[/non \e/, ma questi sono entrambi i modi validi di dire fuga. Il cambiamento funziona perfettamente. Ora che ci sto giocando più completamente, sembra che la modalità vi di zsh faccia schifo rispetto a quella di bash (o almeno non è completamente configurata di default). Un esempio di ciò è il fatto che ti porta in modalità inserimento dopo la cronologia delle ricerche. Devo tornare alla modalità di comando per premere n per trovare l'elemento di ricerca successivo.
Chas. Owens,

1
Beh, non so se hai altri esempi, ma quello che hai citato è colpa mia, non di zsh. =) Quello che è successo è che ho associato un comando dell'editor in modalità vi-cmd in modalità di inserimento vi - il comando prevede che la shell sia già passata in modalità cmd e si comporta di conseguenza. Dobbiamo scrivere un comando dell'editor che prima chiama il comando "enter cmd mode", quindi viene eseguito .vi-history-search-backward. Lo scrivo e modifico la mia risposta - ricontrolla più tardi oggi.
Marshall Eubanks,

OK, ho aggiornato la mia risposta. Provalo.
Marshall Eubanks,

Per quanto riguarda (2), quando lo faccio bindkey | grep <searchterm>per uno qualsiasi dei termini, sono tutti preceduti da vi-. Devo impostare bindkeycomandi che non hanno il prefisso vi-?
adam_0,

1
Grazie. Questi hack (e anche quelli di wjv qui sotto) fanno passare la modalità vi di zsh da quasi inutilizzabile a eccellente. Ho creato un account superutente per poterti votare. :-)
ctrueden,

14

Affronterò solo la domanda (1).

Il tuo problema è KEYTIMEOUT. Cito da zshzle (1):

Quando ZLE legge un comando dal terminale, può leggere una sequenza associata a un comando ed è anche un prefisso di una stringa associata più lunga. In questo caso ZLE attenderà un certo tempo per vedere se vengono digitati più caratteri e in caso contrario (o se non corrispondono più a una stringa) eseguirà l'associazione. Questo timeout è definito dal parametro KEYTIMEOUT; il suo valore predefinito è 0,4 sec. Non vi è alcun timeout se la stringa prefisso non è essa stessa associata a un comando.

Quel 0.4s è il ritardo che stai riscontrando dopo aver colpito ESC. La correzione è impostare KEYTIMEOUT fino a 0,01s in uno dei file di avvio della shell:

export KEYTIMEOUT=1

Sfortunatamente questo ha un effetto a catena: altre cose iniziano a sbagliare ...

Innanzitutto, ora esiste un problema nella modalità di comando vi: digitando ESC si blocca il cursore, quindi viene ingoiato il carattere che si digita successivamente. Questo perché ESC non è associato a nulla per impostazione predefinita nella modalità di comando vi, tuttavia ci sono widget multi-carattere che iniziano con ESC (tasti cursore!). Quindi quando premi ESC, ZLE aspetta il personaggio successivo ... e poi lo consuma.

La correzione è di associare ESC a qualcosa in modalità comando, assicurando così che qualcosa venga passato a ZLE dopo $ KEYTIMEOUT centisecondi. Ora possiamo mantenere i binding iniziando con ESC in modalità comando senza questi effetti negativi. Lego ESC al carattere di campana, che trovo ancora meno invadente di auto-inserimento (e la mia shell è messa a tacere):

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

Aggiornamento 2017:

Da allora ho trovato una soluzione ancora migliore per associare ESC: il undefined-keywidget. Non sono sicuro che questo widget fosse disponibile in zsh quando originariamente ho scritto questa risposta.

bindkey -M vicmd '^[' undefined-key

Problema successivo: per impostazione predefinita ci sono alcuni widget a due tasti che iniziano in ^ X nella modalità di inserimento vi; questi diventano inutilizzabili se $ KEYTIMEOUT è impostato al minimo. Quello che faccio è separare ^ X nella modalità di inserimento vi (è auto-inserimento di default); ciò consente a quei widget a due tasti di continuare a funzionare.

bindkey -rM viins '^X'

Si perde l'associazione per l'autoinserimento, ma è possibile associarlo a qualcos'altro ovviamente. (Non lo so, dal momento che non ne ho bisogno.)

L'ultimo problema (l'ho trovato finora): ci sono alcune rimanenti combinazioni di tasti predefinite che "perdiamo" a causa dell'impostazione di $ KEYTIMEOUT verso il basso, vale a dire: quelle che iniziano con ESC in modalità di inserimento vi che non sono tasti cursore. Personalmente li rilevo per iniziare invece con ^ X:

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

Aggiornamento 2018:

Si scopre che l'intera sezione sopra (dopo "Aggiornamento 2017") non è necessariamente richiesta. È possibile impostare il tasto META in modo che sia equivalente a ESC nelle mappature della tastiera usando:

bindkey -mv

È quindi possibile non separare ^ X e accedere alle combinazioni di tasti che iniziano in ESC premendo invece META come leader (ALT o OPT sulle tastiere moderne).

Se hai accesso al libro From Bash to Z Shell di Kiddle et al., L'equivalenza di ESC e META nelle combinazioni di tasti è discussa nella barra laterale del capitolo 4 alle pagine 78–79.


Grazie. Questi hack (e anche quelli di marshaul sopra) fanno passare la modalità vi di zsh da quasi inutilizzabile a eccellente. Ho creato un account superutente per poterti votare. :-)
ctrueden,

1
Grazie! Trovo un po 'preoccupante che, dopo tutto questo tempo, abbiamo ancora bisogno di ciò che è essenzialmente un hack e una soluzione alternativa per rendere utilizzabile un po' di funzionalità zsh!
wjv,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.