Jak dostosować tryb vim zsh?

25

Ok, więc w końcu dokonałem świetnej zmiany. W moim .zshenv zmieniłem edytora:

export EDITOR=vim

Mam kilka pytań, które są tak drobne, że nie chciałem zaczynać od nich osobnych pytań. Tutaj są:

  1. Jak sprawić, aby zsh rozróżniał tryb wstawiania od trybu poleceń, tak jak w vimie? Najlepiej zmieniłoby to kursor z podkreślenia na blok jak w vimie, ale wyświetlanie tekstu na dole również by działało.

  2. Jak sprawić, by działał bardziej jak vim? Na przykład wolę, aby domyślnie był w trybie poleceń i nie wychodził z niego po jednym poleceniu.

Jason Baker
źródło
//, Czy zachowywałeś się dziwnie podczas edycji w wierszu poleceń? Natknąłem się na ~wstawianie postaci po wciśnięciu Deleteklawisza zsh. Zadałem pytanie na ten temat tutaj: superuser.com/questions/997593/...
Nathan Basanese

Odpowiedzi:

25

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

funkcja 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

Gdzie:

2. ) Podejrzewam, że musisz do tego napisać inny widget zsh, zainspiruj się pierwszym z dwóch łączy pierwszego problemu.

akira
źródło
22

Rozwiązanie akira ma następujący problem podczas korzystania z monitów wieloliniowych: przy przechodzeniu z trybu ins do trybu cmd przerysowanie monitu powoduje usunięcie kilku linii z poprzedniego wyniku (a nowy monit jest wyświetlany kilka linii powyżej). Ile wierszy zależy od liczby wierszy w wierszu polecenia.

Sposobem na poradzenie sobie z tym jest używanie zle-line-finish, bez korzystania z zle reset-promptniego. Przykład:

# 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

Następnie możesz dodać go do wiersza polecenia, na przykład:

RPROMPT='${vim_mode}'

To jest prosto z mojego postu na blogu na ten temat:

Paweł Gościcki
źródło
Ta odpowiedź powinna uzyskać dużo głosów. Po raz pierwszy widziałem to rozwiązanie i działa tam, gdzie inni tego nie robią. Godzinę spędziłem na grzebaniu w zle-line-initwidżecie bezskutecznie. Zmieniono tak, aby pasowało do tego, co zapewnił Paweł i bingo!
Colin R
Dzięki! Nadal nie jest w 100% kuloodporny - od czasu do czasu zdarza mi się, że niektóre wiersze z moich poprzednich wyników są usuwane - ale zdarza się to tak rzadko, że po prostu go ignoruję.
Paweł Gościcki
1
RPROMPT2należy również ustawić, aby status był wyświetlany w liniach kontynuacji. Podczas korzystania z tego możesz chcieć to zrobić setopt transient_rprompt, aby tryby dla wcześniej zaakceptowanych linii nie były wyświetlane.
qqx
Jednej rzeczy wciąż brakuje: jeśli przejdę z powrotem do trybu emacs ( bindkey -e), nadal będzie widoczny [INS].
Daniel
1
@cheflo możesz zobaczyć moją aktualną wersję tego ustawienia tutaj: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - może to ci pomoże
Paweł Gościcki
5
zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

te dwie linie upewniają się, że zaczyna się w trybie poleceń

Spokój
źródło
Nie działa, zsh i tak zaczyna się w trybie wstawiania
baldrs
0

Poniżej ustawisz zmodyfikowany kursor i monit wyświetlający, w jakim trybie jesteś. Możesz zmienić DEFAULT_VI_MODEna jeden viinslub vicmd. Po prostu wklej poniżej nowy, .zshrcaby rozpocząć:

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

Uwaga: testowałem to tylko w Terminal.app (2.7.3) na MacOS (10.12.6) z zsh (5.3.1). Ponadto, jeśli kiedykolwiek dodasz, edit-command-linetryb również zostanie poprawnie ustawiony.

casr
źródło