在vi模式下使我的zsh提示显示模式


44

我使用bindkey -v(对于bash-ers,set -o vi我认为也可以在zsh中使用)或vi(m)模式。但令我感到困惑的是,我没有任何视觉提示可以告诉我是处于插入模式还是命令模式。有谁知道我如何使我的提示显示模式?

Answers:


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

我会解释,除非我还不太了解


1
我尝试了这种方法,但是发现了一个问题。如果您CTRL+C在vi命令模式下执行类似操作,则提示会重置,但是当您真正处于插入模式时,请在命令模式下指示您。zle-line-init应始终将指示器更改为插入模式。由于某些原因,$KEYMAP调用zle-line-init时未正确更新。
Patrick

2
zle reset-prompt将在重绘时删除提示上方的1(或更多)行(如果您的提示是多行):(这对我来说是个好
习惯

@PawełGościcki当您有两行或更多行PS1时,这似乎是一个问题。
Metaphox

@Metaphox我知道,这就是为什么我说“(如果您的提示是多行)”的原因。有什么解决办法吗?
帕维尔Gościcki

@PawełGościcki抱歉,我以某种方式跳过了括号中的单词,这是坏习惯。不,我没有找到解决办法。您在什么平台上?想知道这是否是OS X特定的。
Metaphox

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,尽管它们可能不支持其所有功能。


出于某种原因,我得到mainKEYMAP不是viins,不知道为什么。
Graeme 2014年

1
@Graeme mainzsh的别名,viins或者emacs取决于zsh在启动时是否以为您最喜欢的编辑器是vi。我以为viins从模式切换回模式时会用到它vicmd,但似乎使用了它main。更新。
吉尔斯(Gillles)“所以-别再作恶了”

1
您仍然需要加倍zle-line-init(或其他选择),因为zle-keymap-select如果按回车键更改键盘映射不会被调用。
Graeme 2014年

9

对于使用多行提示使用重置提示时遇到问题的人,这对我有用:http: //zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.htmlhttps://结合使用我最终做了以下操作: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

这就是我用来在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'
}

这仅适用于了解DECSCUSR的终端和终端仿真器。
JdeBP

1
我喜欢这个。我担心写给preexec可能会与其他用法交互,因此我对其进行了少许修改以使其使用,add-zsh-hook例如:gist.github.com/MatrixManAtYrService/…–
MatrixManAtYrService

4

更改I型光束和块之间的光标形状的另一种解决方案(对于下划线,请使用\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修改。在gnome终端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

1
我确认iTerm2的更新脚本确实有效。
杰森·丹尼

第一个脚本仅适用于了解DECSCUSR的终端和终端仿真器。
JdeBP

这是一个非常优雅的解决方案,不会弄乱我的外壳
tsturzl

3

我目前正在将Zsh与Bullet Train主题一起使用。按照塞巴斯蒂安·布拉斯克Sebastian Blask)答案给出的示例,我最终得到了下面的代码

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

这是来自塞巴斯蒂安·布拉斯克(Sebastian Blask)的帖子的另一个版本。这样做的目的是尽可能避免干扰,因为我可以找到的所有其他解决方案都使用额外的行,右侧的状态或添加的字符。

$当启用正常模式时,这只是将颜色从白色更改为红色。根据您的喜好编辑提示

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

所述的zsh-VIM-模式插件能够显示为插入,命令,搜索,替换,和视觉模式的指示符。它使用其他答案的基本技术来挂钩各种ZLE挂钩(zle-keymap-select,zle-isearch-update等)。它检查[[ $ZLE_STATE = *overwrite* ]]替换模式。它检查$REGION_ACTIVE以识别视觉模式。

离开isearch模式时ZSH如何触发事件的一些怪癖使逻辑变得复杂。

该模块的另一个不错的功能是能够根据模式更改光标形状和颜色。例如,您可以在INSERT模式下使用竖线,而在SEARCH模式下使用闪烁的下划线。


这个插件很棒。
jdhao
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.