Wie passe ich den vim-Modus von zsh an?

25

Ok, also habe ich endlich die große Veränderung vorgenommen. In meiner .zshenv habe ich meinen EDITOR geändert:

export EDITOR=vim

Es gibt ein paar Fragen, die so geringfügig sind, dass ich keine separaten Fragen für sie starten wollte. Hier sind sie:

  1. Wie kann ich zsh veranlassen, wie in vim zwischen Einfügemodus und Befehlsmodus zu unterscheiden? Dies würde den Cursor vorzugsweise von einer Unterstreichung in einen Block wie in vim ändern, aber das Anzeigen von Text am unteren Rand würde ebenfalls funktionieren.

  2. Wie kann ich dafür sorgen, dass es mehr wie ein Vim wirkt? Zum Beispiel wäre es mir lieber, wenn Sie sich standardmäßig im Befehlsmodus befinden und ihn nicht nach einem Befehl verlassen.

Jason Baker
quelle
//, Wurde bei Kommandozeilen-Änderungen ein merkwürdiges Verhalten festgestellt? Ich bin auf das ~Zeichen gestoßen, das eingefügt wurde, als ich die DeleteTaste drückte zsh. Ich fragte eine Frage über sie hier: superuser.com/questions/997593/...
Nathan Basanese

Antworten:

25

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

Funktion 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

Woher:

2. ) Ich vermute, dass Sie ein anderes zsh-Widget schreiben müssen, um dies zu tun. Lassen Sie sich vom ersten der beiden Links für das erste Problem inspirieren.

Akira
quelle
22

Die Lösung von akira hat bei der Verwendung von mehrzeiligen Eingabeaufforderungen das folgende Problem: Wenn Sie vom Ins-Modus in den Cmd-Modus wechseln, werden durch das erneute Zeichnen der Eingabeaufforderung nur wenige Zeilen aus der vorherigen Ausgabe gelöscht (und die neue Eingabeaufforderung wird nur wenige Zeilen darüber angezeigt). Wie viele Zeilen vorhanden sind, hängt davon ab, wie viele Zeilen sich in Ihrer Eingabeaufforderung befinden.

Die Art und Weise, damit umzugehen, ist zu benutzen zle-line-finish, ohne es zu benutzen zle reset-prompt. Ein Beispiel:

# 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

Und dann können Sie es zu Ihrer rechten Eingabeaufforderung hinzufügen, zum Beispiel:

RPROMPT='${vim_mode}'

Dies ist direkt aus meinem Blog-Post darüber:

Paweł Gościcki
quelle
Diese Antwort sollte eine Menge Stimmen bekommen. Dies ist das erste Mal, dass ich diese Lösung gesehen habe, und sie funktioniert dort, wo die anderen es nicht tun. Ich habe eine Stunde lang vergeblich mit dem zle-line-initWidget herumgespielt. Änderte es, um zu passen, was Pawel zur Verfügung stellte und Bingo!
Colin R
Vielen Dank! Es ist immer noch nicht 100% kugelsicher - von Zeit zu Zeit kommt es vor, dass einige Zeilen aus meiner vorherigen Ausgabe gelöscht werden -, aber es kommt so selten vor, dass ich es einfach ignoriere.
Paweł Gościcki
1
RPROMPT2sollte auch so eingestellt sein, dass der Status in Fortsetzungszeilen angezeigt wird. Wenn Sie dies verwenden, möchten Sie möglicherweise auch setopt transient_rprompt, dass die Modi für zuvor akzeptierte Zeilen nicht angezeigt werden.
QQX
Eine Sache, die noch fehlt: Wenn ich zurück in den Emacs-Modus ( bindkey -e) wechsle, wird dies immer noch angezeigt [INS].
Daniel
1
@cheflo du kannst meine aktuelle Version dieses Setups hier sehen: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - vielleicht hilft dir das
Paweł Gościcki
5
zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

Diese beiden Zeilen stellen sicher, dass es im Befehlsmodus gestartet wird

Ruhe
quelle
Funktioniert nicht, zsh startet trotzdem im Einfügemodus
baldrs
0

Das Folgende wird Sie mit einem geänderten Cursor und einer Eingabeaufforderung einrichten, die anzeigt, in welchem ​​Modus Sie sich befinden. Sie können DEFAULT_VI_MODEentweder zu viinsoder wechseln vicmd. Fügen Sie einfach das Folgende in ein frisches ein .zshrc, um zu beginnen:

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

Hinweis: Ich habe dies nur in Terminal.app (2.7.3) unter MacOS (10.12.6) mit zsh (5.3.1) getestet. Auch wenn Sie jemals hinzufügen, edit-command-linewird der Modus ebenfalls korrekt eingestellt.

casr
quelle