mach meine zsh prompt show mode im vi mode


44

Ich benutze bindkey -v(für bash-er set -o videnke ich, dass das auch in zsh funktioniert) oder vi (m) Modus. aber es stört mich, dass ich keinen visuellen Anhaltspunkt habe, um mir zu sagen, ob ich mich im Einfüge- oder im Befehlsmodus befinde. Weiß jemand, wie ich meine Eingabeaufforderung veranlassen kann, den Modus anzuzeigen?

Antworten:


25

Ich habe das über SU gefunden . Hier ist das grundlegende Beispiel, obwohl ich es immer noch für mich selbst anpasse:

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

Ich würde es erklären, außer ich verstehe es noch nicht wirklich


1
Ich habe diesen Ansatz ausprobiert, aber ein Problem gefunden. Wenn Sie CTRL+Cim vi-Befehlsmodus etwas tun , wird die Eingabeaufforderung zurückgesetzt, Sie werden jedoch im Befehlsmodus angezeigt, wenn Sie sich wirklich im Einfügemodus befinden. zle-line-initsollte immer die Anzeige in den Einfügemodus ändern. Aus irgendeinem Grund $KEYMAPwird es nicht richtig aktualisiert, wenn zle-line-init aufgerufen wird.
Patrick

2
zle reset-promptlöscht 1 (oder mehr) Zeilen oberhalb der Eingabeaufforderung (wenn Ihre Eingabeaufforderung mehrzeilig ist) beim Neuzeichnen :( Dies ist ein Showstopper für mich.
Paweł Gościcki

@ PawełGościcki es scheint ein Problem zu sein, wenn Sie zwei oder mehr Zeilen von PS1 haben.
Metaphox

@ Metaphox Ich weiß, warum ich "(wenn Ihre Eingabeaufforderung mehrzeilig ist)" gesagt habe. Irgendeine Lösung dafür?
Paweł Gościcki

@ PawełGościcki aww sorry, ich habe die Wörter in Klammern übersprungen, schlechte Angewohnheit. Nein, dafür habe ich keine Lösung gefunden. Auf welcher Plattform bist du? Ich habe mich gefragt, ob dies OS X-spezifisch ist.
Metaphox

18

Sie haben bereits gefunden, zle-keymap-selectwas ausgeführt wird, wenn sich der Modus ändert. Sie können es verwenden, um eine andere visuelle Anzeige als die Eingabeaufforderung festzulegen, je nachdem, was Ihr Terminal unterstützt (und natürlich, wie Sie die Anzeige für den Modus bevorzugen).

Es gibt eine Standard- Terminfo-Funktion , um die Form des Cursors zu ändern. Einige Terminals zeigen jedoch in beiden Modi denselben Cursor an. Xterms Vorstellung von einem weniger sichtbaren Cursor besteht darin, dass er blinkt (und dies muss mit dem -bcBefehlszeilenargument oder der cursorBlinkRessource aktiviert werden ).

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

Bei einigen Terminals können Sie die Cursorfarbe auch mit print -n '\e]12;pink\a'(nach Farbname) oder print -n '\e]12;#abcdef\a'(nach RGB-Spezifikation) ändern . Diese Sequenzen werden in der xterm-Dokumentation in der ctlseqsDatei beschrieben. Moderne Terminalemulatoren emulieren normalerweise xterm, obwohl sie möglicherweise nicht alle Funktionen unterstützen.


Aus irgendeinem Grund bekomme ich mainfür KEYMAPstatt viins, nicht sicher , warum.
Graeme

1
@Graeme mainist ein Alias ​​für viinsoder emacsabhängig davon, ob zsh dachte, Ihr Lieblingseditor wäre vi oder nicht, als er gestartet wurde. Ich dachte, es würde verwendet, viinswenn der Modus zurückgeschaltet wird vicmd, aber es scheint, dass es mainstattdessen verwendet wird. Aktualisiert.
Gilles 'SO- hör auf böse zu sein'

1
Sie müssen sich immer noch mit zle-line-init(oder einer anderen Alternative) verdoppeln, da zle-keymap-selectsie nicht aufgerufen werden, wenn Sie die Eingabetaste drücken, um die Tastaturbelegung zu ändern.
Graeme

9

Für die Leute, die Probleme mit der Verwendung von reset-prompt bei mehrzeiligen Eingabeaufforderungen haben, funktionierte dies für mich: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html In Kombination mit https: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-line Am Ende machte ich Folgendes :

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

5

Sie können VimMode versuchen


4
Ich hatte auf etwas gehofft, das ein bisschen weniger verknüpfend und ein bisschen erklärender war. Ich mag es zu wissen, wie die Dinge funktionieren.
Xenoterracide

1
Eigentlich ist alles da. Sehen Sie sich die Kommentare zu den Funktionen an und wie sie an die Modusänderungsereignisse gebunden sind.
Martin

5

Dies ist, was ich benutze, um den Cursor zwischen 'Block' und 'Beam' Form in zsh zu ändern:

(Getestet mit Termite , Gnome-Terminal und 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'
}

Dies funktioniert nur auf Terminals und Terminalemulatoren, die DECSCUSR verstehen.
JdeBP

1
Ich mag das. Ich mache mir Sorgen, dass das Schreiben in preexec mit anderen Verwendungen in Wechselwirkung treten könnte, daher habe ich es leicht geändert, um es add-zsh-hookwie folgt
MatrixManAtYrService

4

Eine andere Lösung zum Ändern der Cursorform zwischen I-Beam und Block (für Unterstreichung verwenden \033[4 q). Fügen Sie dieses Ihrem hinzu ~/.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

Geändert von https://bbs.archlinux.org/viewtopic.php?id=95078 . Getestet in gnome-terminal 3.22.


Aktualisieren

Eine weitere Lösung zum Ändern der Cursorformen finden Sie hier . Dieser funktioniert anscheinend für iTerm2, das ich nicht testen kann, sondern hier hinzufüge, falls es für jemand anderen nützlich ist. Die letzte Ergänzung zu Ihrem ~/.zshrcwäre

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

1
Ich habe bestätigt, dass das aktualisierte Skript für iTerm2 tatsächlich funktioniert hat.
Jason Denney

Das erste Skript funktioniert nur auf Terminals und Terminalemulatoren, die DECSCUSR verstehen.
JdeBP

Dies ist eine wirklich elegante Lösung, die meine Muschel nicht
verstopft

3

Ich benutze derzeit Zsh mit Bullet Train Theme. Dem Beispiel von Sebastian Blask folgend , landete ich mit dem folgenden Code

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

Dies ändert nur die Standardeinstellung $ in die Buchstaben N für den normalen Modus und I für den Einfügemodus.

Dieses Bild ist ein Beispiel, wenn ich im normalen Modus Ctrl+ drücke C:

Bildbeschreibung hier eingeben


2

Hier ist noch eine andere Version, basierend auf Sebastian Blask's Post . Dies sollte so unauffällig wie möglich sein, da alle anderen Lösungen, die ich finden konnte, zusätzliche Zeilen, den Status auf der rechten Seite oder hinzugefügte Zeichen enthielten.

Dies ändert einfach die Farbe $von Weiß nach Rot, wenn der normale Modus aktiviert ist. Bearbeiten Sie die Eingabeaufforderung nach Ihren Wünschen

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


1

Das Plugin zsh-vim-mode kann einen Indikator für die Modi Einfügen, Befehlen, Suchen, Ersetzen und Visuelles anzeigen. Es verwendet die grundlegende Technik anderer Antworten, um sich in die verschiedenen ZLE-Hooks einzuklinken (zle-keymap-select, zle-isearch-update usw.). Es prüft den [[ $ZLE_STATE = *overwrite* ]]Ersetzungsmodus. Es prüft $REGION_ACTIVEden visuellen Modus.

Die Logik wird durch einige Macken kompliziert, wie ZSH Ereignisse auslöst, wenn der Suchmodus verlassen wird.

Ein weiteres nettes Merkmal des Moduls ist die Möglichkeit, die Cursorform und -farbe je nach Modus zu ändern. Beispielsweise können Sie im INSERT-Modus einen vertikalen Balken und im SEARCH-Modus eine blinkende Unterstreichung verwenden.


Dieses Plugin ist großartig.
JDHAO
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.