No modo bash vi, map jk para sair do modo de inserção

5

Estou usando uma nova instalação do Ubuntu 16.04, com o shell bash. Há duas coisas que quero fazer:

  1. Configure o modo vi para que eu possa ter movimentos semelhantes ao vim a partir do terminal
  2. saia do modo de inserção digitando jk

Eu li em outro post como isso pode ser feito com zsh , como posso fazer isso com bash ?

tl; dr

coloque bind '"jk":vi-movement-mode' no seu arquivo .bashrc depois de set -o vi :)

server@thinkpad:~$ tail -n 2 .bashrc
set -o vi
bind '"jk":vi-movement-mode'

por favor, veja a resposta de @ grochmal para uma explicação mais detalhada

    
por mbigras 14.08.2016 / 03:03

1 resposta

5

TL; DR

O Bash tem uma funcionalidade semelhante a zsh ' bindkey a bind , mas não tem vários modos vi como zsh . Depois de set -o vi , você pode fazer:

bind '"jk":vi-movement-mode'

que é o equivalente de zsh bindkey -M <all vi modes> jk vi-movement-mode

As funções vi-movement-mode vêm de inputrc (veja /etc/inputrc para uma lista delas).

Texto completo

Como Stephen Harris aponta em seu comentário:

  • .bashrc é chamado por bash sempre (e notavelmente não por outros shells).

  • .bash_profile é chamado apenas em shells de login (e novamente, somente bash).

Várias distros vêm com um esqueleto .bash_profile da seguinte forma:

# ~/.bash_profile
[[ -f ~/.bashrc ]] && . ~/.bashrc

Qual é um bom conteúdo para .bash_profile , pois você pode simplesmente esquecer que existe.

Agora, para mapear j k para Esc na sessão do shell, isso não é realmente possível. Quando você faz:

inoremap jk <esc>

No Vim, depois que você digita j , o Vim sabe que precisa esperar um pouco para ver se você digita k em seguida e ele deve chamar o mapeamento (ou que você digita outra chave e o mapeamento não deve ser acionado). Como um adendo, isso é controlado por :set timeoutlen=<miliseconds> no Vim (veja :h timeoutlen ).

Vários shell ou X11 não têm controle de timeout e não permitem vários mapeamentos de caracteres. Apenas um mapeamento de uma única chave é permitido (mas veja as notas de suporte abaixo).

set -o vi

Não lê .vimrc , apenas imita algumas combinações de teclas vi (nem mesmo vim ) que podem ser usadas no shell. O mesmo pode ser dito sobre -o emacs , ele não vem com o poder total de emacs .

suporte a zsh

zsh realmente suporta o tempo limite do mapa. E você pode usar o seguinte para mapear jk para <esc> :

bindkey -v  # instead of set -o vi
bindkey -e jk \e

(Isso precisará ir para ~/.zshrc não ~/.bashrc )

No entanto, eu aconselho contra isso. Eu uso vim e zsh na maioria das vezes. Eu tenho inoremap jk <esc> no meu vimrc e tentei usar a combinação bindkey acima. zsh espera muito tempo para imprimir j ao usá-lo, e isso me incomodou muito.

suporte ao bash

bash suporta readline bind . Eu acredito que bash pode ser compilado sem readilne , portanto, pode haver alguns sistemas raros que têm bash que não suportam bind (fique atento). Para mapear jk para <esc> em bash , você precisa fazer:

set -o vi
bind '"jk":"\e"'

(sim, isso é um duplo nível de citação, é necessário)

Novamente, isso torna a digitação j bem chata. Mas de alguma forma menos irritante do que a solução zsh na minha máquina (provavelmente o tempo limite padrão é menor).

Solução alternativa (para shells não bash e não zsh)

A razão para remapear a tecla Esc é que ela fica bem longe no teclado, e digitá-la leva tempo. Um truque que pode ser emprestado dos emacs guys é fazer o remapeamento de CapsLock , já que é uma chave inútil, de qualquer maneira. emacs guys remapam para Ctrl mas vamos remapear para Esc .

Vamos usar xev -event keyboard para verificar o código de tecla do CapsLock :

KeyPress event, serial 25, synthetic NO, window 0x1c00001,
    root 0x496, subw 0x0, time 8609026, (764,557), root:(765,576),
    state 0x0, keycode 66 (keysym 0xffe5, Caps_Lock), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

E para verificar a função de Esc :

KeyPress event, serial 25, synthetic NO, window 0x1c00001,
    root 0x496, subw 0x0, time 9488531, (571,525), root:(572,544),
    state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
    XLookupString gives 1 bytes: (1b) "
    XmbLookupString gives 1 bytes: (1b) "
    XFilterEvent returns: False

Muito bom, CapsLock é o código de tecla 66 e a função Esc é chamada de "Escape". Agora podemos fazer:

# diable caps lock
xmodmap -e "remove lock = Caps_Lock"
# make an Esc key from the keycode 66
xmodmap -e "keycode 66 = Escape"

O deve acima ser feito nesta ordem. Agora, toda vez que você apertar CapsLock , ele funciona como uma tecla Esc .

A parte complicada é onde definir isso. Um arquivo ~/.Xmodmap com o conteúdo:

remove lock = Caps_Lock
keycode 66 = Escape

Deve ser respeitado pela maioria das distros (na verdade, gerenciadores de exibição, mas estou dizendo distros pela simplicidade), mas eu vi aqueles que não respeitam vários arquivos ~/X* . Para essas distros você pode tentar algo como:

if [ "x" != "x$DISPLAY" ]; then
    xmodmap -e "remove lock = Caps_Lock"
    xmodmap -e "keycode 66 = Escape"
fi

No seu .bashrc .

(Em teoria, isso seria melhor colocado em ~/.xinitrc , mas se um gerenciador de exibição não respeitasse .Xmodmap , ele definitivamente não respeitaria ~/.xnintrc .)

Nota extra: Isso só remapeia CapsLock para Esc em uma sessão X11, portanto o mapa funcionará somente em emuladores de terminal. Os tty reais não verão o mapa.

Referências e leitura extra:

por 14.08.2016 / 23:47