Como personalizo o modo vim do zsh?

25

Ok, então finalmente fiz a grande mudança. No meu .zshenv, mudei meu EDITOR:

export EDITOR=vim

Há algumas perguntas que são tão pequenas que não quero iniciar perguntas separadas para elas. Aqui estão eles:

  1. Como faço para o zsh distinguir entre o modo de inserção e o modo de comando, como no vim? De preferência, isso mudaria o cursor de um sublinhado para um bloco como no vim, mas a exibição de texto na parte inferior também funcionaria.

  2. Como faço para agir mais como o vim? Por exemplo, eu prefiro que esteja no modo de comando por padrão e não saia depois de um comando.

Jason Baker
fonte
//, Você está tendo algum comportamento estranho com as edições da linha de comando? Fui correndo para o ~personagem ficar inserido quando eu pressionar a Deletechave no zsh. Eu fiz uma pergunta sobre isso aqui: superuser.com/questions/997593/...
Nathan Basanese

Respostas:

25

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

função zle-line-init zle-keymap-select {
    RPS1 = "$ {$ {KEYMAP / vicmd / - NORMAL -} / (principal | viins) / - INSERIR -}"
    RPS2 = $ RPS1
    zle reset-prompt
}
zle -N zle-line-init
zle -N zle-keymap-select

Onde:

2. ) suspeito que você precise escrever outro widget zsh para fazer isso, inspire-se no primeiro dos dois links para o primeiro problema.

akira
fonte
22

A solução da akira apresenta o seguinte problema ao usar prompts de várias linhas: ao passar do modo ins para o cmd, o prompt redesenhado faz com que poucas linhas sejam excluídas da saída anterior (e o novo prompt é exibido poucas linhas acima). Quantas linhas depende de quantas linhas você tem em seu prompt.

A maneira de lidar com isso é usar zle-line-finish, sem usar zle reset-promptlá. Um exemplo:

# 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

E então você pode adicioná-lo ao seu prompt direito, por exemplo:

RPROMPT='${vim_mode}'

Isso é direto do meu post sobre isso:

Paweł Gościcki
fonte
Esta resposta deve receber muitos votos. É a primeira vez que vejo essa solução e funciona onde os outros não. Passei uma hora brincando com o zle-line-initwidget sem sucesso. Mudou para combinar com o que Pawel forneceu e bingo!
Colin R
Obrigado! Ainda não é 100% à prova de balas - de tempos em tempos, experimento uma situação em que algumas linhas da minha saída anterior são excluídas - mas isso acontece tão raramente que eu simplesmente a ignoro.
Paweł Gościcki 28/11
1
RPROMPT2também deve ser definido para que o status seja exibido nas linhas de continuação. Além disso, ao usar isso, convém fazer setopt transient_rpromptcom que os modos das linhas aceitas anteriormente não sejam exibidos.
Qqx
Uma coisa ainda está faltando: se eu voltar ao modo emacs ( bindkey -e), ele ainda será exibido [INS].
Daniel
1
@cheflo você pode ver a minha versão atual dessa configuração aqui: github.com/pjg/dotfiles/blob/master/.zshrc#L518-L584 - talvez isso irá ajudá-lo
Paweł Gościcki
5
zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

essas duas linhas garantem que ele inicie no modo de comando

Tranquilidade
fonte
Não funciona, começa zsh no modo de inserção de qualquer maneira
Baldrs
0

O abaixo irá configurá-lo com um cursor modificado e um prompt exibindo em qual modo você está. Você pode alterar DEFAULT_VI_MODEpara viinsou vicmd. Basta colar o abaixo em um novo .zshrcpara começar:

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

Nota: Eu testei isso apenas no Terminal.app (2.7.3) no MacOS (10.12.6) com zsh (5.3.1). Além disso, se você adicionar edit-command-line, o modo também será definido corretamente.

casr
fonte