¿Cómo personalizo el modo vim de zsh?

25

Ok, entonces finalmente hice el gran cambio. En mi .zshenv, cambié mi EDITOR:

export EDITOR=vim

Tengo un par de preguntas que tengo que son tan pequeñas que no quería comenzar preguntas separadas para ellas. Aquí están:

  1. ¿Cómo obtengo zsh para distinguir entre el modo de inserción y el modo de comando como en vim? Preferiblemente, esto cambiaría el cursor de un subrayado a un bloque como en vim, pero mostrar texto en la parte inferior también funcionaría.

  2. ¿Cómo consigo que actúe más como vim? Por ejemplo, prefiero que esté en modo comando por defecto y no salir después de un comando.

Jason Baker
fuente
//, ¿Has tenido algún comportamiento extraño con las ediciones de línea de comandos? Me he encontrado con el ~personaje que se inserta cuando presiono la Deletetecla zsh. Hice una pregunta sobre ello aquí: superuser.com/questions/997593/...
Nathan Basanese

Respuestas:

25

1. ) (ver http://zshwiki.org/home/examples/zlewidgets y http://pthree.org/2009/03/28/add-vim-editing-mode-to-your-zsh-prompt/ ) :

función 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

Dónde:

2. ) sospecho que tienes que escribir otro widget de zsh para hacerlo, inspírate con el primero de los dos enlaces para el primer problema.

akira
fuente
22

La solución de akira tiene el siguiente problema cuando se utilizan indicaciones de varias líneas: cuando se pasa del modo ins al modo cmd, el redibujo de la solicitud hace que se eliminen pocas líneas de la salida anterior (y la nueva solicitud se muestra algunas líneas arriba). La cantidad de líneas depende de cuántas líneas tenga en su solicitud.

La forma de lidiar con eso es usar zle-line-finish, sin usar zle reset-promptallí. Un ejemplo:

# perform parameter expansion/command substitution in prompt
setopt PROMPT_SUBST

vim_ins_mode="[INS]"
vim_cmd_mode="[CMD]"
vim_mode=$vim_ins_mode

function zle-keymap-select {
  vim_mode="${${KEYMAP/vicmd/${vim_cmd_mode}}/(main|viins)/${vim_ins_mode}}"
  zle reset-prompt
}
zle -N zle-keymap-select

function zle-line-finish {
  vim_mode=$vim_ins_mode
}
zle -N zle-line-finish

Y luego puede agregarlo a su indicador derecho, por ejemplo:

RPROMPT='${vim_mode}'

Esto es directamente de mi publicación de blog al respecto:

Paweł Gościcki
fuente
Esta respuesta debería obtener muchos votos. Esta es la primera vez que veo esta solución, y funciona donde los demás no. Pasé una hora jugando con el zle-line-initwidget en vano. ¡Lo cambió para que coincida con lo que Pawel proporcionó y el bingo!
Colin R
¡Gracias! Todavía no es 100% a prueba de balas: de vez en cuando experimento una situación en la que se eliminan algunas líneas de mi salida anterior, pero ocurre tan raramente que simplemente lo ignoro.
Paweł Gościcki
1
RPROMPT2también debe configurarse para que el estado se muestre en líneas de continuación. Además, al usar esto, es posible que desee hacerlo setopt transient_rpromptpara que no se muestren los modos de las líneas aceptadas previamente.
qqx
Una cosa que todavía falta: si vuelvo al modo emacs ( bindkey -e), todavía se muestra [INS].
Daniel
1
@cheflo puedes ver mi versión actual de esta configuración aquí: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - tal vez eso te ayude
Paweł Gościcki
5
zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

estas dos líneas aseguran que comience en modo comando

Tranquilidad
fuente
No funciona, zsh comienza en modo de inserción de todos modos
calvas
0

Lo siguiente lo configurará con un cursor modificado y un mensaje que muestra en qué modo se encuentra. Puede cambiar DEFAULT_VI_MODEa cualquiera viinso vicmd. Simplemente pegue el siguiente en un nuevo .zshrcpara comenzar:

# Prefer vi shortcuts
bindkey -v
DEFAULT_VI_MODE=viins
KEYTIMEOUT=1

__set_cursor() {
    local style
    case $1 in
        reset) style=0;; # The terminal emulator's default
        blink-block) style=1;;
        block) style=2;;
        blink-underline) style=3;;
        underline) style=4;;
        blink-vertical-line) style=5;;
        vertical-line) style=6;;
    esac

    [ $style -ge 0 ] && print -n -- "\e[${style} q"
}

# Set your desired cursors here...
__set_vi_mode_cursor() {
    case $KEYMAP in
        vicmd)
          __set_cursor block
          ;;
        main|viins)
          __set_cursor vertical-line
          ;;
    esac
}

__get_vi_mode() {
    local mode
    case $KEYMAP in
        vicmd)
          mode=NORMAL
          ;;
        main|viins)
          mode=INSERT
          ;;
    esac
    print -n -- $mode
}

zle-keymap-select() {
    __set_vi_mode_cursor
    zle reset-prompt
}

zle-line-init() {
    zle -K $DEFAULT_VI_MODE
}

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

# Optional: allows you to open the in-progress command inside of $EDITOR
autoload -Uz edit-command-line
bindkey -M vicmd 'v' edit-command-line
zle -N edit-command-line

# PROMPT_SUBST enables functions and variables to re-run everytime the prompt
# is rendered
setopt PROMPT_SUBST

# Single quotes are important so that function is not run immediately and saved
# in the variable
RPROMPT='$(__get_vi_mode)'

Nota: Solo probé esto en Terminal.app (2.7.3) en MacOS (10.12.6) con zsh (5.3.1). Además, si alguna vez agrega edit-command-line, el modo también se establecerá correctamente.

casr
fuente