fazer meu prompt do zsh mostrar o modo no modo vi

44

Eu uso bindkey -v(para bash-ers set -o vique também funcionam no zsh) ou vi (m). mas me incomoda que eu não tenha nenhuma dica visual para me dizer se estou no modo de inserção ou modo de comando. Alguém sabe como posso fazer meu prompt exibir o modo?

xenoterracida
fonte

Respostas:

25

Eu encontrei isso via SU . Aqui está o exemplo básico, embora eu ainda o esteja personalizando:

function zle-line-init zle-keymap-select {
    RPS1="${${KEYMAP/vicmd/-- NORMAL --}/(main|viins)/-- INSERT --}"
    RPS2=$RPS1
    zle reset-prompt
}

zle -N zle-line-init
zle -N zle-keymap-select

Eu explicaria, exceto que eu realmente não entendo ainda

xenoterracida
fonte
1
Eu tentei essa abordagem, mas encontrei um problema. Se você fizer algo como CTRL+Cno modo vi-command, o prompt será redefinido, mas indicará que você está no modo de comando quando estiver realmente no modo de inserção. zle-line-initdeve sempre mudar o indicador para inserir o modo. Por algum motivo, $KEYMAPnão é atualizado corretamente quando o zle-line-init é chamado.
21412 Patrick
2
zle reset-promptexcluirá 1 (ou mais) linhas acima o prompt (se o prompt é multilinha), quando redesenhar :( Este é um desmancha-prazeres para mim.
Paweł Gościcki
@ PawełGościcki parece ser um problema quando você tem duas ou mais linhas de PS1.
Metaphox
@ Metaphox eu sei, é por isso que eu disse "(se o seu prompt é multiline)". Alguma correção para isso?
Paweł Gościcki
@ PawełGościcki aww desculpe, de alguma forma pulei as palavras entre parênteses, mau hábito. Não, não encontrei uma solução para isso. Em que plataforma você está? Estava pensando se isso é específico para o OS X.
Metaphox
18

Você já encontrou o zle-keymap-selectque é executado sempre que o modo muda. Você pode usá-lo para definir outro indicador visual que não seja o prompt, dependendo do suporte do seu terminal (e do seu gosto no visor do indicador de modo, é claro).

Existe um recurso padrão terminfo para alterar a forma do cursor. No entanto, alguns terminais exibem o mesmo cursor nos dois modos. A noção do Xterm de um cursor menos visível é fazê-lo piscar (e isso deve ser ativado com o -bcargumento ou cursorBlinkrecurso da linha de comando ).

zle-keymap-select () {
  case $KEYMAP in
    vicmd) print -rn -- $terminfo[cvvis];; # block cursor
    viins|main) print -rn -- $terminfo[cnorm];; # less visible cursor
  esac
}

Em alguns terminais, você também pode alterar a cor do cursor com print -n '\e]12;pink\a'(por nome da cor) ou print -n '\e]12;#abcdef\a'(por especificação RGB). Essas sequências são descritas na documentação do xterm, no ctlseqsarquivo; emuladores de terminal modernos normalmente emulam o xterm, embora possam não suportar todos os seus recursos.

Gilles 'SO- parar de ser mau'
fonte
Por alguma razão, aposto mainem KEYMAPvez de viins, não sei por quê.
Graeme
1
@Graeme mainé um apelido para viinsou emacsdependendo do zsh pensar que seu editor favorito era vi ou não quando foi iniciado. Eu pensei que usaria viinsao mudar o modo de volta vicmd, mas parece que ele usa em seu mainlugar. Atualizada.
Gilles 'SO- stop being evil'
1
Você ainda precisa dobrar com zle-line-init(ou qualquer outra alternativa), pois zle-keymap-selectnão é chamado se pressionar enter altera o mapa de teclas.
Graeme
9

Para as pessoas que têm problemas ao usar o prompt de redefinição com prompts de múltiplas linhas, isso funcionou para mim: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html Em combinação com https: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-line Acabei fazendo:

terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]

function insert-mode () { echo "-- INSERT --" }
function normal-mode () { echo "-- NORMAL --" }

precmd () {
    # yes, I actually like to have a new line, then some stuff and then 
    # the input line
    print -rP "
[%D{%a, %d %b %Y, %H:%M:%S}] %n %{$fg[blue]%}%m%{$reset_color%}"

    # this is required for initial prompt and a problem I had with Ctrl+C or
    # Enter when in normal mode (a new line would come up in insert mode,
    # but normal mode would be indicated)
    PS1="%{$terminfo_down_sc$(insert-mode)$terminfo[rc]%}%~ $ "
}
function set-prompt () {
    case ${KEYMAP} in
      (vicmd)      VI_MODE="$(normal-mode)" ;;
      (main|viins) VI_MODE="$(insert-mode)" ;;
      (*)          VI_MODE="$(insert-mode)" ;;
    esac
    PS1="%{$terminfo_down_sc$VI_MODE$terminfo[rc]%}%~ $ "
}

function zle-line-init zle-keymap-select {
    set-prompt
    zle reset-prompt
}
preexec () { print -rn -- $terminfo[el]; }

zle -N zle-line-init
zle -N zle-keymap-select
Sebastian Blask
fonte
5

você pode experimentar o VimMode

Hemant
fonte
4
Eu esperava algo um pouco menos vinculativo e um pouco mais explicativo. Eu gosto de saber como as coisas funcionam.
Xenoterracide
1
Na verdade, está tudo lá. Veja os comentários sobre as funções e como elas estão vinculadas aos eventos de mudança de modo.
Martin
5

Isto é o que eu uso para alterar o cursor entre as formas 'Block' e 'Beam' no zsh:

(Testado com cupins , gnome-terminal e mate-terminal )

# vim mode config
# ---------------

# Activate vim mode.
bindkey -v

# Remove mode switching delay.
KEYTIMEOUT=5

# Change cursor shape for different vi modes.
function zle-keymap-select {
  if [[ ${KEYMAP} == vicmd ]] ||
     [[ $1 = 'block' ]]; then
    echo -ne '\e[1 q'

  elif [[ ${KEYMAP} == main ]] ||
       [[ ${KEYMAP} == viins ]] ||
       [[ ${KEYMAP} = '' ]] ||
       [[ $1 = 'beam' ]]; then
    echo -ne '\e[5 q'
  fi
}
zle -N zle-keymap-select

# Use beam shape cursor on startup.
echo -ne '\e[5 q'

# Use beam shape cursor for each new prompt.
preexec() {
   echo -ne '\e[5 q'
}
Rotareti
fonte
Isso funcionará apenas em terminais e emuladores de terminal que entendem DECSCUSR.
JdeBP
1
Eu gosto disso. Eu me preocupo que a escrita para interagir poder preexec com outros usos, então eu modifiquei um pouco para usar add-zsh-hookassim: gist.github.com/MatrixManAtYrService/...
MatrixManAtYrService
4

Outra solução para alterar a forma do cursor entre o feixe I e o bloco (para sublinhado, use \033[4 q). Adicione isso ao seu ~/.zshrc.

zle-keymap-select () {
if [ $KEYMAP = vicmd ]; then
    printf "\033[2 q"
else
    printf "\033[6 q"
fi
}
zle -N zle-keymap-select
zle-line-init () {
zle -K viins
printf "\033[6 q"
}
zle -N zle-line-init
bindkey -v

Modificado em https://bbs.archlinux.org/viewtopic.php?id=95078 . Testado no terminal gnome 3.22.


Atualizar

Ainda outra solução para alterar as formas do cursor pode ser encontrada aqui . Aparentemente, este funciona para o iTerm2, que não tenho como testar, mas adicioná-lo aqui, caso seja útil para outra pessoa. A adição final ao seu ~/.zshrcseria

function zle-keymap-select zle-line-init
{
    # change cursor shape in iTerm2
    case $KEYMAP in
        vicmd)      print -n -- "\E]50;CursorShape=0\C-G";;  # block cursor
        viins|main) print -n -- "\E]50;CursorShape=1\C-G";;  # line cursor
    esac

    zle reset-prompt
    zle -R
}

function zle-line-finish
{
    print -n -- "\E]50;CursorShape=0\C-G"  # block cursor
}

zle -N zle-line-init
zle -N zle-line-finish
zle -N zle-keymap-select
joelostblom
fonte
1
Confirmei que o script atualizado para o iTerm2 realmente funcionava.
Jason Denney
O primeiro script funcionará apenas em terminais e emuladores de terminal que entendem DECSCUSR.
JdeBP
Esta é uma solução muito elegante que não fiquem amontoados minha concha
tsturzl
3

Atualmente, estou usando o Zsh com o tema Bullet Train . Seguindo o exemplo da resposta de Sebastian Blask , acabei com o código abaixo

bindkey -v
KEYTIMEOUT=1

function zle-line-init zle-keymap-select {
    case ${KEYMAP} in
        (vicmd)      BULLETTRAIN_PROMPT_CHAR="N" ;;
        (main|viins) BULLETTRAIN_PROMPT_CHAR="I" ;;
        (*)          BULLETTRAIN_PROMPT_CHAR="I" ;;
    esac
    zle reset-prompt
}

zle -N zle-line-init
zle -N zle-keymap-select

Isso mudará apenas o padrão $ para as letras N para o modo normal e I para o modo de inserção.

Esta imagem é um exemplo quando, no modo normal, pressiono Ctrl+ C:

insira a descrição da imagem aqui

Luciano Almeida
fonte
2

Aqui está mais uma versão, baseada no post de Sebastian Blask . O objetivo era que fosse o menos intrusivo possível, pois todas as outras soluções que encontrei usavam linhas extras, status à direita ou caracteres adicionados.

Isso simplesmente muda a cor de $branco para vermelho quando o modo normal está ativado. Edite o prompt ao seu gosto

bindkey -v
function zle-line-init zle-keymap-select {
    case ${KEYMAP} in
        (vicmd)      PROMPT=$'%{\e[0;32m%}%~%{\e[0m%} %{\e[0;31m%}$%{\e[0m%} ' ;;
        (main|viins) PROMPT=$'%{\e[0;32m%}%~%{\e[0m%} $ ' ;;
        (*)          PROMPT=$'%{\e[0;32m%}%~%{\e[0m%} $ ' ;;
    esac
    zle reset-prompt
}

zle -N zle-line-init
zle -N zle-keymap-select
sealj553
fonte
2

Uma versão para oh-my-zshusuários

Existe um plugin oh-my-zshchamado vi-modeque pode ser encontrado aqui:

robbyrussell / oh-my-zsh / plugins / modo vi

Eu uso o Antigen para gerenciar meus plugins, então incluí-lo foi tão simples quanto adicionar isso ao meu .zshrc:

antigen bundle vi-mode
Jonathan Landrum
fonte
1

O plug - in zsh-vim-mode pode mostrar um indicador para os modos de inserção, comando, pesquisa, substituição e visual. Ele usa a técnica básica de outras respostas para conectar-se aos vários ganchos do ZLE (zle-keymap-select, zle-isearch-update, etc.). Ele verifica o [[ $ZLE_STATE = *overwrite* ]]modo de substituição. Verifica $REGION_ACTIVEpara identificar o modo visual.

A lógica é complicada por algumas peculiaridades de como o ZSH dispara eventos ao sair do modo isearch.

Outro recurso interessante do módulo é a capacidade de alterar a forma e a cor do cursor com base no modo. Por exemplo, você pode usar uma barra vertical no modo INSERT e um sublinhado piscando no modo SEARCH.

Tim Smith
fonte
Este plugin é ótimo.
jdhao 18/02