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

11

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

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

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

tl; dr

colocar bind '"jk":vi-movement-mode'no seu .bashrcarquivo depois set -o vi:)

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

consulte a resposta de @ grochmal para obter uma explicação mais detalhada

mbigras
fonte
1
O que você quer dizer com remapeamento para jk? Essa tecla é especial no seu teclado?
Stephen Harris
consulte editar
mbigras
Para o seu primeiro, .bashrcnormalmente é chamado em todos os shell (por exemplo, se você sair vi), mas .bash_profileé chamado apenas em shells de login. Então .bashrcé o lugar certo para set -o vi. Eu não tenho uma resposta para a sua segunda pergunta revisada :-(
Stephen Harris
Como você está iniciando seu shell bash? Aqui está uma boa explicação da diferença entre .bashrc e .bash_profile
the_velour_fog
set -o vientra .bashrc, consulte Por que meu ~ / .bash_profile não funciona?
Gilles 'SO- stop be evil'

Respostas:

10

TL; DR

O Bash tem uma funcionalidade semelhante à zshdo bindkeymeio bind, mas não possui vários vimodos como zsh. Depois que set -o vivocê pode fazer:

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

que é o equivalente zshabindkey -M <all vi modes> jk vi-movement-mode

As vi-movement-modefunções são originárias inputrc(veja /etc/inputrcuma lista delas).

Texto completo

Como Stephen Harris aponta em seu comentário:

  • .bashrcé chamado por bashsempre (e principalmente não por outras conchas).

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

Várias distros vêm com um .bash_profileesqueleto com a seguinte aparência:

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

Qual é um bom conteúdo, .bash_profilepois você pode simplesmente esquecer que ele existe.

Agora, para mapear jka Escna sessão shell, que 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 a kseguir e deve chamar o mapeamento (ou que você digita outra chave e o mapeamento não deve ser acionado). Como um adendo, isso é controlado pelo :set timeoutlen=<miliseconds>Vim (consulte :h timeoutlen).

Vários shell ou X11 não têm esse controle de tempo limite e não permitem mapeamentos de caracteres múltiplos. Somente o mapeamento de uma única chave é permitido (mas consulte 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 todo o poder de emacs.


suporte zsh

zshrealmente suporta o tempo limite do mapa. E você pode usar o seguinte para mapear jkpara <esc>:

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

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

No entanto, eu aconselho contra isso. Eu uso vime na zshmaioria das vezes. Eu tenho inoremap jk <esc>no meu vimrce eu tentei usar a bindkeycombinação acima. zshaguarda muito tempo para imprimir jao usá-lo, e isso me incomodou muito.


suporte do bash

bashsuporta readline bind. Acredito que bashpossa ser compilado sem, readilneportanto, pode haver alguns sistemas raros que possuem o bash que não suportam bind(fique atento). Para mapear jka <esc>em bashque você precisa fazer:

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

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

Novamente, isso torna a digitação jbastante irritante. Mas de alguma forma menos irritante do que a zshsolução na minha máquina (provavelmente o tempo limite padrão é mais curto).


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

O motivo para remapear a Esctecla é que ela fica bem distante do teclado, e digitar leva tempo. Um truque que pode ser emprestado dos emacscaras é remapear, CapsLockjá que é uma chave inútil. emacscaras remapear para Ctrlmas vamos remapear para Esc.

Vamos usar xev -event keyboardpara verificar o código-chave de 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 keycode 66 e Esca função é chamada "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 acima deve ser feito nesta ordem. Agora, toda vez que você pressiona CapsLock, funciona como uma Escchave.


A parte complicada é onde definir isso. Um arquivo ~/.Xmodmapcom 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 por simplicidade), mas vi aqueles que não respeitam vários ~/X*arquivos. Para tais 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, ~/.xinitrcmas se um gerente de exibição não o respeitar .Xmodmap, definitivamente não o respeitará ~/.xnintrc.)

Nota extra: Isso só remapeia CapsLocka Escem uma sessão X11, portanto, o mapa só irá funcionar em emuladores de terminal. O real ttynão verá o mapa.

Referências e leitura extra:

grochmal
fonte
Obrigado pela explicação detalhada. Você gostaria de ilustrar o mesmo processo, exceto o mapeamento em jkvez de CapsLock? Coloquei na minha máquina osx; no entanto, eu não tê-lo para o resto do fim de semana e eu não me lembro como eu fiz isso :)
mbigras
@mbigras - Você tem certeza que fez isso no bash? O Bash não possui mapas ambíguos. Eu sei de uma maneira de fazê-lo em zsh: bindkey -v; bindkey -s jk \\e. Mas isso é algo que vai voltar e mordê-lo de volta quando você precisa jk, porque o temporizador não é configurável e você não tem <leader>no zsh.
grochmal
Eu definitivamente fiz isso zshe não bash, não é possível no bash?
mbigras
@mbigras - Espere, eu estava errado! Lendo man bash, achei bindesse trabalho bem parecido com zsho bindkey. Vou atualizar a resposta. Lá vai você, estou usando zshdemais.
grochmal
2
@ Jason - Ei, este é o Vi SE, aqui todos escrevem uma palavra ALL CAPS com: "type word" <Esc> viwU :). Nenhuma conclusão necessária
grochmal
2

Obrigado, pelas respostas anteriores, eu uso isso no meu ~ / .zshrc para atalhos do tipo vi no meu terminal. Espero que ajude alguém.

bindkey -v
bindkey 'jk' vi-cmd-mode
om2c0de
fonte
Eu vim aqui procurando uma resposta que funcione para ligar a tecla '^ G' para entrar no "modo normal" no zsh ativado por vi, e este é o único que funcionou.
Dalker 11/01