Comment personnaliser le mode vim de zsh?

25

Ok, j'ai finalement fait le grand changement. Dans mon .zshenv, j'ai changé d'EDITEUR:

export EDITOR=vim

Il y a quelques questions que j'ai si mineures que je ne voulais pas leur poser de questions distinctes. Les voici:

  1. Comment obtenir zsh pour faire la distinction entre le mode d'insertion et le mode de commande comme dans vim? De préférence, cela changerait le curseur d'un soulignement en un bloc comme dans vim, mais l'affichage du texte en bas fonctionnerait également.

  2. Comment puis-je le faire agir plus comme vim? Par exemple, je préfère qu'il soit en mode commande par défaut et que je ne le quitte pas après une commande.

Jason Baker
la source
//, Avez-vous eu un comportement étrange avec des modifications en ligne de commande? J'ai rencontré le ~personnage inséré lorsque j'appuie sur la Deletetouche zsh. J'ai posé une question à ce sujet ici: superuser.com/questions/997593/…
Nathan Basanese

Réponses:

25

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

fonction 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

Où:

2. ) Je soupçonne que vous devez écrire un autre widget zsh pour ce faire, laissez-vous inspirer par le premier des deux liens pour le premier problème.

akira
la source
22

La solution d'Akira présente le problème suivant lors de l'utilisation d'invites multilignes: lors du passage du mode ins au mode cmd, le redessin d'invite entraîne la suppression de quelques lignes de la sortie précédente (et la nouvelle invite s'affiche quelques lignes ci-dessus). Le nombre de lignes dépend du nombre de lignes que vous avez dans votre invite.

La façon de gérer cela est d'utiliser zle-line-finish, sans l'utiliser zle reset-prompt. Un exemple:

# 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

Et puis vous pouvez l'ajouter à votre invite de droite, par exemple:

RPROMPT='${vim_mode}'

C'est directement de mon blog à ce sujet:

Paweł Gościcki
la source
Cette réponse devrait recueillir de nombreux votes. C'est la première fois que je vois cette solution, et elle fonctionne là où les autres ne le font pas. J'ai passé une heure à jouer avec le zle-line-initwidget en vain. Changé pour correspondre à ce que Pawel a fourni et au bingo!
Colin R
Merci! Ce n'est toujours pas à 100% à l'épreuve des balles - de temps en temps, je rencontre une situation où certaines lignes de ma sortie précédente sont supprimées - mais cela arrive si rarement que je l'ignore.
Paweł Gościcki
1
RPROMPT2doit également être défini pour que l'état s'affiche sur les lignes de continuation. De plus, lorsque vous utilisez ceci, vous pouvez vouloir faire en setopt transient_rpromptsorte que les modes pour les lignes précédemment acceptées ne soient pas affichés.
qqx
Une chose qui manque toujours: si je reviens en mode emacs ( bindkey -e), cela apparaît toujours [INS].
Daniel
1
@cheflo vous pouvez voir ma version actuelle de cette configuration ici: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - peut-être que cela vous aidera
Paweł Gościcki
5
zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

ces deux lignes s'assurent qu'il démarre en mode commande

Tranquillité
la source
Ne fonctionne pas, zsh démarre quand même en mode insertion
baldrs
0

Ce qui suit vous mettra en place avec un curseur modifié et une invite affichant le mode dans lequel vous vous trouvez. Vous pouvez changer DEFAULT_VI_MODEpour viinsou vicmd. Collez simplement ce qui suit dans un nouveau .zshrcpour commencer:

# 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)'

Remarque: je n'ai testé cela que dans Terminal.app (2.7.3) sur MacOS (10.12.6) avec zsh (5.3.1). De plus, si vous en ajoutez, edit-command-linele mode sera également correctement réglé.

casr
la source