Как настроить режим vim в zsh?

25

Итак, я наконец-то внес большое изменение. В моем .zshenv я изменил мой редактор:

export EDITOR=vim

У меня есть пара вопросов, которые настолько незначительны, что я не хотел задавать для них отдельные вопросы. Вот они:

  1. Как заставить zsh различать режим вставки и командный режим, как в vim? Предпочтительно, это изменит курсор с подчеркивания на блок, как в vim, но отображение текста внизу также будет работать.

  2. Как мне заставить его вести себя как vim? Например, я бы предпочел, чтобы он был в командном режиме по умолчанию и не выходил из него после одной команды.

Джейсон Бейкер
источник
//, Вы получали какое-то странное поведение с правками командной строки? Я сталкиваюсь с тем, что ~персонажа вставляют, когда я нажимаю Deleteклавишу zsh. Я задал вопрос об этом здесь: superuser.com/questions/997593/…
Натан Басанезе

Ответы:

25

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

функция 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

Где:

  • «RPS» обозначает «правую строку приглашения» и определяет приглашение, появляющееся в правой части терминала, а синтаксис $ {variable / pattern / replace} является синтаксисом «раскрытия параметра», см. Http: // mywiki .wooledge.org / BashSheet # Parameter_Operations .

  • «zle -N» вызывает привязку определяемых пользователем виджетов «zle-line-init» и «zle-keymap-select» (к функциям оболочки с одинаковыми именами), так что они будут вызываться при инициализации редактора строк и раскладка клавиш изменяется соответственно, см .: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#SEC125 .

2. ) Я подозреваю, что для этого вам нужно написать еще один zsh-виджет, вдохновившись первой из двух ссылок на первую проблему.

Акира
источник
22

Решение akira имеет следующую проблему при использовании многострочных приглашений: при переходе из режима ins в режим cmd перерисовка подсказки приводит к удалению нескольких строк из предыдущего вывода (а новое приглашение отображается несколькими строками выше). Сколько строк зависит от того, сколько строк у вас в приглашении.

Способ справиться с этим - использовать zle-line-finish, не используя zle reset-promptтам. Пример:

# 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

И тогда вы можете добавить его в правую строку, например:

RPROMPT='${vim_mode}'

Это прямо из моего блога об этом:

Павел Гольчицкий
источник
Этот ответ должен получить много голосов. Я впервые вижу это решение, и оно работает там, где другие не видят. Я потратил час, возился с zle-line-initвиджетом безрезультатно. Изменил это, чтобы соответствовать тому, что предоставил Павел и бинго!
Колин Р
Благодарность! Это все еще не на 100% пуленепробиваемый - время от времени я сталкиваюсь с ситуацией, когда некоторые строки из моего предыдущего вывода удаляются - но это случается так редко, что я просто игнорирую это.
Павел Гольчицкий
1
RPROMPT2следует установить так, чтобы статус отображался в продолжениях строк. Кроме того, при использовании этого вы можете сделать setopt transient_rpromptтак, чтобы режимы для ранее принятых линий не отображались.
qqx
Одна вещь, которая все еще отсутствует: если я переключаюсь обратно в режим emacs ( bindkey -e), он все еще показывает [INS].
Даниил
1
@cheflo, вы можете увидеть мою текущую версию этой установки здесь: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - возможно, это поможет вам
Павел Гольчицкий
5
zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

эти две строки убедитесь, что он начинается в командном режиме

спокойствие
источник
Не работает, zsh все равно запускается в режиме вставки
baldrs
0

Ниже приведены настройки с измененным курсором и подсказкой, показывающей, в каком режиме вы находитесь. Вы можете изменить DEFAULT_VI_MODEлибо на, viinsлибо на vicmd. Просто вставьте ниже, .zshrcчтобы начать:

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

Примечание: я проверял это только в Terminal.app (2.7.3) на MacOS (10.12.6) с помощью zsh (5.3.1). Кроме того, если вы когда-либо добавите, edit-command-lineрежим будет установлен правильно.

CASR
источник