ustaw mój tryb wyświetlania zsh w trybie vi

44

Używam bindkey -v(dla bash-erów set -o vimyślę, że to działa również w zsh) lub vi (m). ale denerwuje mnie to, że nie mam żadnej wizualnej wskazówki, która powiedziałaby mi, czy jestem w trybie wstawiania, czy w trybie poleceń. Czy ktoś wie, jak mogę sprawić, by mój monit wyświetlał ten tryb?

ksenoterracid
źródło

Odpowiedzi:

25

Znalazłem to za pośrednictwem SU . Oto podstawowy przykład, ale wciąż dostosowuję go do siebie:

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

Wyjaśniłbym to, ale tak naprawdę tego jeszcze nie rozumiem

ksenoterracid
źródło
1
Próbowałem tego podejścia, ale znalazłem jeden problem. Jeśli zrobisz coś takiego, CTRL+Cgdy jesteś w trybie polecenia vi, monit zostanie zresetowany, ale zasygnalizuje, że jesteś w trybie poleceń, gdy naprawdę jesteś w trybie wstawiania. zle-line-initpowinien zawsze zmieniać wskaźnik na tryb wstawiania. Z jakiegoś powodu $KEYMAPnie jest poprawnie aktualizowany po wywołaniu zle-line-init.
Patrick
2
zle reset-promptpodczas przerysowywania usunie 1 (lub więcej) linii nad wierszem (jeśli twój wiersz jest wielowierszowy) :( Jest to dla mnie showstopper.
Paweł Gościcki
@ PawełGościcki wydaje się, że to problem, gdy masz dwie lub więcej linii PS1.
Metaphox
@ Metaphox Wiem, dlatego powiedziałem „(jeśli twój monit jest wieloliniowy)”. Jakaś poprawka na to?
Paweł Gościcki,
@ PawełGościcki aww przepraszam, ale jakoś pominąłem słowa w nawiasach, zły nawyk. Nie, nie znalazłem rozwiązania tego problemu. Na jakiej platformie jesteś? Zastanawiałem się, czy jest to specyficzne dla OS X.
Metaphox
18

Znalazłeś już, zle-keymap-selectktóry jest wykonywany przy każdej zmianie trybu. Możesz go użyć, aby ustawić inny wskaźnik wizualny niż monit, w zależności od tego, co obsługuje terminal (i oczywiście od gustu w wyświetlaniu wskaźnika trybu).

Istnieje standardowa możliwość zmiany kształtu kursora przez terminfo . Jednak niektóre terminale wyświetlają ten sam kursor w obu trybach. Pojęcie mniej widocznego kursora przez Xterm polega na tym, że miga (i należy to włączyć za pomocą -bcargumentu lub cursorBlinkzasobu wiersza poleceń ).

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

W przypadku niektórych terminali można również zmienić kolor kursora za pomocą print -n '\e]12;pink\a'(według nazwy koloru) lub print -n '\e]12;#abcdef\a'(według specyfikacji RGB). Sekwencje te są opisane w dokumentacji xterm, w ctlseqspliku; nowoczesne emulatory terminali zazwyczaj emulują xterm, chociaż mogą nie obsługiwać wszystkich jego funkcji.

Gilles „SO- przestań być zły”
źródło
Z jakiegoś powodu mam maindla KEYMAPzamiast viins, nie wiem dlaczego.
Graeme
1
@Graeme mainto pseudonim dla viinslub w emacszależności od tego, czy zsh myślał, że twój ulubiony edytor to vi, czy nie, kiedy się zaczął. Myślałem, że przydałby się viinsprzy przełączaniu trybu z powrotem vicmd, ale wydaje się, że mainzamiast tego używa . Zaktualizowano
Gilles 'SO - przestań być zły'
1
Nadal musisz podwoić liczbę zle-line-init(lub dowolną alternatywę), ponieważ zle-keymap-selectnie zostanie wywołany, jeśli naciśnięcie klawisza Enter zmieni mapę klawiszy.
Graeme
9

Dla osób, które mają problemy z używaniem resetowania z monitami wielowierszowymi, działało to dla mnie: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html W połączeniu z https: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-line Skończyło się na tym, że:

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
źródło
5

możesz wypróbować VimMode

Hemant
źródło
4
Miałem nadzieję na coś nieco mniej powiązanego i bardziej wyjaśniającego. Lubię wiedzieć, jak to działa.
ksenoterrakid,
1
Właściwie to wszystko tam jest. Spójrz na komentarze funkcji i ich powiązania ze zdarzeniami zmiany trybu.
Martin
5

To jest to, czego używam do zmiany kursora między kształtem „Block” i „Beam” w zsh:

(Testowane z termitem , gnome-terminal i 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
źródło
Działa to tylko na terminalach i emulatorach terminali, które rozumieją DECSCUSR.
JdeBP
1
Lubię to. Obawiam się, że pisanie do preexec może wchodzić w interakcje z innymi zastosowaniami, więc zmodyfikowałem go nieco add-zsh-hooktak, aby używał
MatrixManAtYrService
4

Inne rozwiązanie do zmiany kształtu kursora między dwuteownikiem a blokiem (w celu podkreślenia, użyj \033[4 q). Dodaj to do swojego ~/.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

Zmodyfikowano z https://bbs.archlinux.org/viewtopic.php?id=95078 . Testowany w gnome-terminalu 3.22.


Aktualizacja

Jeszcze inne rozwiązanie zmiany kształtów kursora można znaleźć tutaj . Ten najwyraźniej działa dla iTerm2, którego nie mam środków do przetestowania, ale dodając go tutaj na wypadek, gdyby był użyteczny dla kogoś innego. Ostatnim dodatkiem do twojego ~/.zshrcbyłoby

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
źródło
1
Potwierdziłem, że zaktualizowany skrypt dla iTerm2 rzeczywiście działa.
Jason Denney
Pierwszy skrypt będzie działał tylko na terminalach i emulatorach terminali, które rozumieją DECSCUSR.
JdeBP
To naprawdę eleganckie rozwiązanie, które nie zaśmieca mojej skorupy
tsturzl,
3

Obecnie używam Zsh z motywem Bullet Train . Idąc za przykładem podanym przez odpowiedź Sebastiana Blaska , skończyłem z kodem poniżej

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

Spowoduje to jedynie zmianę domyślnej $ na litery N na tryb normalny i I na tryb wstawiania.

Ten obraz jest przykładem, gdy w trybie normalnym naciskam Ctrl+ C:

wprowadź opis zdjęcia tutaj

Luciano Almeida
źródło
2

Oto kolejna wersja oparta na postie Sebastiana Blaska . To miało być jak najbardziej nieinwazyjne, ponieważ wszystkie inne rozwiązania, które mogłem znaleźć, wykorzystywały dodatkowe linie, status po prawej stronie lub dodane znaki.

To po prostu zmienia kolor $z białego na czerwony, gdy włączony jest tryb normalny. Edytuj monit zgodnie ze swoimi upodobaniami

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
źródło
2

Wersja dla oh-my-zshużytkowników

Istnieje wtyczka dla oh-my-zshwywoływanych, vi-modektórą można znaleźć tutaj:

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

Używam Antigen do zarządzania moimi wtyczkami, więc włączenie tego było tak proste, jak dodanie tego do mojego .zshrc:

antigen bundle vi-mode
Jonathan Landrum
źródło
1

Zsh-vim-mode wtyczka jest w stanie pokazać wskaźnik dla wkładki, dowodzenia, wyszukiwanie, zamienianie i trybów wizualnych. Wykorzystuje podstawową technikę innych odpowiedzi, aby podłączyć się do różnych zaczepów ZLE (zle-keymap-select, zle-isearch-update itp.). Sprawdza [[ $ZLE_STATE = *overwrite* ]]tryb zamiany. Sprawdza, $REGION_ACTIVEaby zidentyfikować tryb wizualny.

Logikę komplikują niektóre dziwactwa, w jaki sposób ZSH uruchamia zdarzenia podczas opuszczania trybu isearch.

Kolejną miłą cechą modułu jest możliwość zmiany kształtu i koloru kursora w zależności od trybu. Na przykład możesz użyć pionowego paska w trybie WSTAWIANIA i migającego podkreślenia w trybie WYSZUKIWANIA.

Tim Smith
źródło
Ta wtyczka jest świetna.
jdhao