сделать мой режим показа приглашения zsh в режиме vi

44

Я использую bindkey -v(для башкеров set -o viя думаю, что работает и в zsh) или в режиме vi (m). но меня беспокоит то, что у меня нет визуальной подсказки, чтобы сказать мне, находится ли я в режиме вставки или командном режиме. Кто-нибудь знает, как я могу заставить мою подсказку отображать режим?

xenoterracide
источник

Ответы:

25

Я нашел это через SU . Вот основной пример, хотя я все еще настраиваю его для себя:

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

Я бы объяснил, но я пока не очень понимаю

xenoterracide
источник
1
Я попробовал этот подход, но нашел одну проблему. Если вы сделаете что-то подобное CTRL+Cв режиме vi-command, запрос будет сброшен, но при этом вы увидите, что вы находитесь в командном режиме, когда вы действительно находитесь в режиме вставки. zle-line-initвсегда следует менять индикатор на режим вставки. По какой-то причине $KEYMAPне обновляется должным образом при вызове zle-line-init.
Патрик
2
zle reset-promptудалит 1 (или больше) строк над приглашением (если ваше приглашение является многострочным) при перерисовке :( Для меня это
showtopper
@ PawełGościcki, кажется, проблема, когда у вас есть две или более линий PS1.
Метафокс
@ Metaphox Я знаю, поэтому я сказал «(если ваш запрос многострочный)». Любое исправление для этого?
Павел Гольчицкий
@ PawełGościcki Ой, прости, я как-то пропустил слова в скобках, плохая привычка. Нет, я не нашел решения для этого. На какой ты платформе? Было интересно, если это специфично для OS X.
Метафокс
18

Вы уже нашли, zle-keymap-selectчто выполняется при изменении режима. Вы можете использовать его для установки какого-либо другого визуального индикатора, отличного от приглашения, в зависимости от того, что ваш терминал поддерживает (и, конечно, ваш вкус в отображении индикатора режима).

Существует стандартная возможность terminfo для изменения формы курсора. Однако некоторые терминалы отображают один и тот же курсор в обоих режимах. Идея Xterm о менее видимом курсоре состоит в том, чтобы заставить его мигать (и это должно быть включено с помощью -bcаргумента командной строки или cursorBlinkресурса).

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

С некоторыми терминалами вы также можете изменить цвет курсора с помощью print -n '\e]12;pink\a'(по названию цвета) или print -n '\e]12;#abcdef\a'(по спецификации RGB). Эти последовательности описаны в документации xterm, в ctlseqsфайле; современные эмуляторы терминала обычно эмулируют xterm, хотя они могут не поддерживать все его функции.

Жиль "ТАК - перестань быть злым"
источник
По какой - то причине , я получаю mainза KEYMAPвместо viins, не знаю , почему.
Грэм
1
@Graeme main- это псевдоним для viinsили в emacsзависимости от того, думал ли zsh, что ваш любимый редактор был vi или нет, когда он запускался. Я думал, что он будет использовать viinsпри переключении режима обратно vicmd, но кажется, что он использует mainвместо этого. Обновлено.
Жиль "ТАК - перестань быть злым"
1
Вам все еще нужно удвоить zle-line-init(или любую другую альтернативу), так zle-keymap-selectкак не вызывается, если нажатие клавиши enter меняет раскладку клавиатуры.
Грэм
9

Для людей, имеющих проблемы с использованием reset-prompt с многострочными приглашениями, это сработало для меня: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html В сочетании с https: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-line Я закончил тем, что сделал:

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

Вы можете попробовать VimMode

Hemant
источник
4
Я надеялся на что-то немного менее связное и немного более объяснительное. Мне нравится знать, как все работает.
ксенотеррацид
1
На самом деле это все там. Посмотрите на комментарии функций и как они связаны с событиями смены режима.
Мартин
5

Это то, что я использую, чтобы изменить курсор между «Блоком» и «Лучом» в zsh:

(Протестировано с термитом , гном-терминалом и мат-терминалом )

# 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
источник
Это будет работать только на терминалах и эмуляторах терминалов, которые понимают DECSCUSR.
JdeBP
1
Мне это нравится. Я беспокоюсь , что письмо к preexec могут взаимодействовать с другими использований, поэтому я изменил его немного , чтобы использовать add-zsh-hookследующим образом: gist.github.com/MatrixManAtYrService/...
MatrixManAtYrService
4

Другое решение для изменения формы курсора между двутавровой балкой и блоком (для подчеркивания используйте \033[4 q). Добавьте это к вашему ~/.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

Изменено с https://bbs.archlinux.org/viewtopic.php?id=95078 . Протестировано в гном-терминале 3.22.


Обновить

Еще одно решение для изменения формы курсора можно найти здесь . Этот, очевидно, работает для iTerm2, который я не имею возможности протестировать, но добавляю его сюда на случай, если он пригодится кому-то еще. Окончательное дополнение к вашему ~/.zshrcбудет

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
источник
1
Я подтвердил, что обновленный скрипт для iTerm2 действительно работает.
Джейсон Денни
Первый скрипт будет работать только на терминалах и эмуляторах терминалов, которые понимают DECSCUSR.
JdeBP
Это действительно элегантное решение, которое не загромождает мою оболочку
tsturzl
3

В настоящее время я использую Zsh с темой Bullet Train . Следуя примеру, приведенному в ответе Себастьяна Бласка , я получил следующий код

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

Это только изменит значение по умолчанию $ на буквы N в обычном режиме, а I - в режиме вставки.

Это изображение является примером, когда в обычном режиме я нажимаю Ctrl+ C:

введите описание изображения здесь

Лучано Алмейда
источник
2

Вот еще одна версия, основанная на посте Себастьяна Бласка . Предполагалось, что это будет как можно более незаметно, так как во всех других решениях, которые я мог найти, использовались дополнительные строки, статус справа или добавленные символы.

Это просто меняет цвет $с белого на красный, когда включен нормальный режим. Отредактируйте подсказку по своему вкусу

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
источник
2

Версия для oh-my-zshпользователей

Есть плагин для oh-my-zshзвонков, vi-modeкоторый можно найти здесь:

robbyrussell / о-мой-ЗШ / плагины / VI-режим

Я использую Antigen для управления своими плагинами, поэтому включить его было так же просто, как добавить это в мой .zshrc:

antigen bundle vi-mode
Джонатан Ландрум
источник
1

ЗШ-ВИМ-режим плагин способен показывать индикатор для вставки, команды поиска, замены и визуальных режимов. Он использует базовую технику других ответов для подключения к различным хукам ZLE (zle-keymap-select, zle-isearch-update и т. Д.). Проверяет [[ $ZLE_STATE = *overwrite* ]]режим замены. Он проверяет, $REGION_ACTIVEчтобы определить визуальный режим.

Логика усложняется некоторыми причудами того, как ZSH запускает события при выходе из режима поиска.

Еще одна приятная особенность модуля - возможность менять форму и цвет курсора в зависимости от режима. Например, вы можете использовать вертикальную черту в режиме INSERT и мигающую подчеркивание в режиме SEARCH.

Тим Смит
источник
Этот плагин отличный.
jdhao