hacer mi modo de presentación de solicitud de zsh en modo vi

44

Yo uso bindkey -v(para bash-ers set -o vi, creo que también funciona en zsh) o el modo vi (m). pero me molesta que no tenga ninguna señal visual para decirme si estoy en modo de inserción o en modo de comando. ¿Alguien sabe cómo puedo hacer que mi mensaje muestre el modo?

xenoterracida
fuente

Respuestas:

25

Encontré esto a través de SU . Aquí está el ejemplo básico, aunque todavía lo estoy personalizando para mí:

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

Lo explicaría, excepto que todavía no lo entiendo

xenoterracida
fuente
1
Intenté este enfoque pero encontré un problema. Si hace algo como CTRL+Cmientras está en modo vi-command, la solicitud se reiniciará, pero indicará que está en modo comando cuando realmente esté en modo insert. zle-line-initsiempre debe cambiar el indicador al modo de inserción. Por alguna razón, $KEYMAPno se actualiza correctamente cuando se llama a zle-line-init.
Patrick
2
zle reset-promptborrará 1 (o más) líneas sobre el mensaje (si su mensaje es multilínea) al volver a dibujar :( Esto es un espectáculo para mí.
Paweł Gościcki
@ PawełGościcki parece ser un problema cuando tienes dos o más líneas de PS1.
Metaphox
@Metaphox Lo sé, por eso he dicho "(si su mensaje es multilínea)". ¿Alguna solución para eso?
Paweł Gościcki
@ PawełGościcki aww lo siento, de alguna manera me salteé las palabras entre paréntesis, mala costumbre. No, no encontré una solución para eso. ¿En qué plataforma estás? Me preguntaba si esto es específico de OS X.
Metaphox
18

Ya has encontrado zle-keymap-selectcuál se ejecuta cada vez que cambia el modo. Puede usarlo para configurar algún otro indicador visual que no sea el indicador, según lo que su terminal lo admita (y su gusto en la pantalla del indicador de modo, por supuesto).

Hay una capacidad estándar de terminfo para cambiar la forma del cursor. Sin embargo, algunos terminales muestran el mismo cursor en ambos modos. La noción de Xterm de un cursor menos visible es hacer que parpadee (y esto debe habilitarse con el -bcargumento o cursorBlinkrecurso de la línea 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
}

Con algunos terminales, también puede cambiar el color del cursor con print -n '\e]12;pink\a'(por nombre de color) o print -n '\e]12;#abcdef\a'(por especificación RGB). Estas secuencias se describen en la documentación de xterm, en el ctlseqsarchivo; Los emuladores de terminal modernos suelen emular xterm, aunque es posible que no admitan todas sus características.

Gilles 'SO- deja de ser malvado'
fuente
Por alguna razón, mainen KEYMAPlugar de viinsno entiendo , no estoy seguro de por qué.
Graeme
1
@Graeme maines un alias para viinso emacsdependiendo de si zsh pensó que su editor favorito era vi o no cuando comenzó. Pensé que lo usaría viinscuando volviera a cambiar el modo vicmd, pero parece que lo usa en su mainlugar. Actualizado.
Gilles 'SO- deja de ser malvado'
1
Todavía necesita duplicar zle-line-init(o cualquier otra alternativa) ya zle-keymap-selectque no se le llama si presionar enter cambia el mapa de teclas.
Graeme
9

Para las personas que tienen problemas al usar reset-prompt con mensajes multilínea, esto funcionó para mí: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html En combinación con https: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-line Terminé haciendo:

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
fuente
5

puedes probar VimMode

Hemant
fuente
44
Esperaba algo un poco menos ligado y un poco más explicativo. Me gusta saber cómo funcionan las cosas.
xenoterracide
1
En realidad está todo ahí. Mire los comentarios, las funciones y cómo están vinculados a los eventos de cambio de modo.
Martin
5

Esto es lo que uso para cambiar el cursor entre la forma 'Bloque' y 'Viga' en zsh:

(Probado con Termite , gnome-terminal y 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
fuente
Esto solo funcionará en terminales y emuladores de terminal que entiendan DECSCUSR.
JdeBP
1
Me gusta esto. Me preocupa que escribir en preexec pueda interactuar con otros usos, así que lo modifiqué un poco para usarlo add-zsh-hookasí: gist.github.com/MatrixManAtYrService/…
MatrixManAtYrService
4

Otra solución para cambiar la forma del cursor entre I-beam y block (para subrayado, uso \033[4 q). Agrega esto a tu ~/.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 de https://bbs.archlinux.org/viewtopic.php?id=95078 . Probado en gnome-terminal 3.22.


Actualizar

Aquí se puede encontrar otra solución para cambiar las formas del cursor . Aparentemente, este funciona para iTerm2, que no tengo los medios para probar, pero lo agrego aquí en caso de que sea útil para otra persona. La adición final a tu ~/.zshrcsería

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
fuente
1
Confirmé que el script actualizado para iTerm2 realmente funcionó.
Jason Denney
El primer script solo funcionará en terminales y emuladores de terminal que entiendan DECSCUSR.
JdeBP
Esta es una solución realmente elegante que no
abarrota
3

Actualmente estoy usando Zsh con el tema Bullet Train . Siguiendo el ejemplo dado por la respuesta de Sebastian Blask , terminé con el siguiente código

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

Esto solo cambiará $ por defecto a las letras N al modo normal e I al modo de inserción.

Esta imagen es un ejemplo cuando en modo normal presiono Ctrl+ C:

ingrese la descripción de la imagen aquí

Luciano Almeida
fuente
2

Aquí hay otra versión, basada en la publicación de Sebastian Blask . Se pretendía que fuera lo menos intrusivo posible, ya que todas las otras soluciones que pude encontrar utilizaron líneas adicionales, estado a la derecha o caracteres agregados.

Esto simplemente cambia el color de $blanco a rojo cuando el modo normal está habilitado. Edite el aviso a su gusto

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
fuente
2

Una versión para oh-my-zshusuarios

Hay un complemento para oh-my-zshllamado vi-modeque se puede encontrar aquí:

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

Utilizo Antigen para administrar mis complementos, por lo que incluirlo fue tan simple como agregar esto a mi .zshrc:

antigen bundle vi-mode
Jonathan Landrum
fuente
1

El complemento zsh-vim-mode puede mostrar un indicador para los modos de inserción, comando, búsqueda, reemplazo y visual. Utiliza la técnica básica de otras respuestas para conectarse a los diversos enlaces ZLE (zle-keymap-select, zle-isearch-update, etc.). Comprueba el [[ $ZLE_STATE = *overwrite* ]]modo de reemplazo. Comprueba $REGION_ACTIVEpara identificar el modo visual.

La lógica se complica por algunas peculiaridades de cómo ZSH dispara eventos al salir del modo de búsqueda.

Otra buena característica del módulo es la capacidad de cambiar la forma y el color del cursor según el modo. Por ejemplo, puede usar una barra vertical en modo INSERTAR y un subrayado parpadeante en modo BÚSQUEDA.

Tim Smith
fuente
Este complemento es genial.
jdhao