如何自定义zsh的vim模式?


23

好的,所以我终于做出了很大的改变。在我的.zshenv中,我改变了我的编辑:

export EDITOR=vim

我有几个问题非常小,我不想为他们提出单独的问题。他们来了:

  1. 如何让zsh区分插入模式和命令模式,就像在vim中一样?优选地,这将像在vim中那样将光标从下划线改变为块,但是在底部显示文本也将起作用。

  2. 我如何让它更像vim?例如,我宁愿它在默认情况下处于命令模式,并且在一个命令之后不会离开它。


//,您是否通过命令行编辑获得了任何奇怪的行为?我一直在跑步 ~ 当我按下时插入字符 Delete 键入 zsh。我在这里问了一个问题: superuser.com/questions/997593/...
Nathan Basanese

Answers:


24

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

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

哪里:

2。 )我怀疑你必须编写另一个zsh-widget来做到这一点,从第一个问题的两个链接中的第一个获得灵感。


19

当使用多行提示时,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 小部件无济于事。改变它以匹配Pawel提供的和宾果游戏!
Colin R

谢谢!它仍然不是100%防弹 - 我经常遇到一种情况,即我之前的输出中的某些行被删除 - 但它很少发生我只是忽略它。
Paweł Gościcki

1
RPROMPT2 也应该设置,以便状态显示在延续行中。此外,使用此功能时您可能想要这样做 setopt transient_rprompt 这样就不会显示以前接受的线条的模式。
qqx

还有一件事仍然缺失:如果我切换回emacs模式( bindkey -e )它仍然显示 [INS]
Daniel

1
@cheflo你可以在这里看到我这个设置的当前版本: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - 也许这会对你有所帮助
Paweł Gościcki

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

注意:我只使用zsh(5.3.1)在MacOS(10.12.6)上的Terminal.app(2.7.3)中测试了这个。此外,如果您添加 edit-command-line 那么模式也会正确设置。

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.