From 63dfac3ec3912daf6d7efd72130ade4fd73f231d Mon Sep 17 00:00:00 2001 From: Hugues Hiegel Date: Tue, 19 Jun 2012 17:52:18 +0200 Subject: [Keys] Vim-mode. --- user:hugues/KeyBindings.zsh | 16 ++- user:hugues/Vim.zsh | 313 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+), 6 deletions(-) create mode 100644 user:hugues/Vim.zsh (limited to 'user:hugues') diff --git a/user:hugues/KeyBindings.zsh b/user:hugues/KeyBindings.zsh index c8df315..a79047f 100644 --- a/user:hugues/KeyBindings.zsh +++ b/user:hugues/KeyBindings.zsh @@ -13,13 +13,13 @@ # Lancez un chtit bindkey dans votre zsh pour voir... # -set_keymap() -{ - main=$1 - bindkey -A main $main -} +#set_keymap() +#{ +# main=$1 +# bindkey -A main $main +#} # Vi-mode -set_keymap viins +#set_keymap viins bindkey '^[[3~' delete-char # delete bindkey '^[[2~' overwrite-mode # insert @@ -279,3 +279,7 @@ zle-keymap-select() } zle -N zle-keymap-select #zle -N zle-line-init zle-keymap-select ## CRASHES UPON MULTILINE COMMAND... + + +source $ZDOTDIR/user:hugues/Vim.zsh + diff --git a/user:hugues/Vim.zsh b/user:hugues/Vim.zsh new file mode 100644 index 0000000..c197656 --- /dev/null +++ b/user:hugues/Vim.zsh @@ -0,0 +1,313 @@ +zstyle ':zle:replace-pattern' edit-previous false +autoload -Uz replace-string +autoload -Uz replace-string-again +zle -N replace-pattern replace-string +zle -N replace-string-again + +### vi-mode.zsh - example vi mode setup for zsh. +### +### Zsh's line editor has two built-in editing models. One is modeled +### after the `emacs' editor's input system, the other is modeled after +### the `vi' editor's modal input mode. +### +### To use the latter, it is helpful to track the current input mode +### and update the prompt dynamically to reflect the current mode at +### all times. +### +### This setup tracks the current mode in `$psvar[x]', which is +### available in prompts in the `%xv' expansion. It'll be one of the +### following strings: +### +### "i" - insert mode +### "c" - command mode +### "im" - insert mode, with a minibuffer being active +### "cm" - ditto, but for command mode +### "r" - replace mode: insert mode with the overwrite bit set. +### +### The `x' is configurable via the `psvmodeidx' variable below. +### +### The code in this file requires zsh version 4.3.1 or newer. +### +### Copyright (c) 2010, Frank Terbeck +### The same licensing terms as with zsh apply. + +############################################################################ +### CONFIGURATION ########################################################## + +# Use either `ins' or `cmd' as the default input mode. +zle_default_mode='cmd' + +# This defines in which index of `$psvar[]' the information is tracked. +# The default is `1'. Set this to whatever fits you best. +psvmodeidx='8' + +# If this is set to `yes', use `C-d' instead of `ESC' to switch from insert +# mode to command mode. `ESC' may require a timeout to actually take effect. +# Using `C-d' will work immediately. Therefore that is the default. +zle_use_ctrl_d='no' + +# If set to `yes', make viins mode behave more like `emacs' mode. Bindings +# such as `^r' and `^s' will work. Backspace and `^w' will work more like +# emacs would, too. +zle_ins_more_like_emacs='no' + +# This is an example prompt to show how this can be used. Yours may +# obviously be a lot more colourful and whatnot. As ugly as you like. +#PS1='%(?..[%?]-)%1v-(%!) %3~ %% ' + +############################################################################ +### MODE SETUP - Do not change anything below! ############################# + +# Create _functions[] arrays for `zle-line-init', `zle-line-finish' +# and `zle-keymap-select', too. Analogous to precmd_functions[] +# etc. The actual functions only cycle through these arrays and +# execute all existing functions in order. +typeset -ga zle_init_functions +typeset -ga zle_finish_functions +typeset -ga zle_keymap_functions + +# This is an associative array, that tracks the current zle +# state. This may contain the following key-value pairs: +# minibuffer - values: yes/no; yes if a minibuffer is active. +# overwrite - values: yes/no; yes if zle is in overwrite mode. +typeset -gA ft_zle_state + + +# We're not in overwrite mode, when zsh starts. +ft_zle_state[overwrite]=no + +# When this is hooked into `zle-keymap-select', keymap changes are +# correctly tracked in `psvar[x]', which may be used in PS1 as `%xv'. +function ft-psvx() { + if [[ ${ft_zle_state[minibuffer]} == yes ]]; then + if [[ ${psvar[$psvmodeidx]} != *m ]]; then + psvar[$psvmodeidx]="${psvar[$psvmodeidx]}m" + fi + else + case ${KEYMAP} in + vicmd) psvar[$psvmodeidx]='';; + *) + if [[ ${ft_zle_state[overwrite]} == yes ]]; then + psvar[$psvmodeidx]='R' + else + psvar[$psvmodeidx]='i' + fi + ;; + esac + fi + zle 'reset-prompt' +} + +# This needs to be hooked into `zle-line-finish' to make sure the next +# newly drawn prompt has the correct mode display. +function ft-psvx-default() { + if [[ ${zle_default_mode} == 'cmd' ]]; then + psvar[$psvmodeidx]='' + else + psvar[$psvmodeidx]='i' + fi +} +# This makes sure the first prompt is drawn correctly. +ft-psvx-default + +# Need to handle SIGINT, too (which is sent by ^C). +# If we don't do this, being in a minibuffer and pressing ^C confuses +# the zle state variable; the `minibuffer' state won't be turned off. +function TRAPINT() { + ft_zle_state[minibuffer]=no + ft-psvx-default + zle reset-prompt 2>/dev/null + return 127 +} + +# If a keymap change is done, we do need a status update, obviously. +zle_keymap_functions=( "${zle_keymap_functions[@]}" ft-psvx ) +# When a command line finishes, the next keyboard mode needs to be set +# up, so that `psvar[x]' is correct when the next prompt is drawn. +zle_finish_functions=( "${zle_finish_functions[@]}" ft-psvx-default ) +if [[ ${zle_default_mode} == 'cmd' ]]; then + # We cannot simply link `vicmd' to `main'. If we'd do that the + # whole input system could not be set into insert mode. See the + # zshzle(1) manual for details. To make vicmd the default mode + # for new command lines, we simply turn it on in `zle-line-init()'. + zle_init_functions=( "${zle_init_functions[@]}" ft-vi-cmd ) +fi + +function zle-line-init() { + local w + for w in "${zle_init_functions[@]}"; do + (( ${+functions[$w]} )) && "$w" + done +} +zle -N zle-line-init +function zle-line-finish() { + local w + for w in "${zle_finish_functions[@]}"; do + (( ${+functions[$w]} )) && "$w" + done +} +zle -N zle-line-finish +function zle-keymap-select() { + local w + for w in "${zle_keymap_functions[@]}"; do + (( ${+functions[$w]} )) && "$w" + done +} +zle -N zle-keymap-select + +# Link `viins' to `main'. +bindkey -v + +############################################################################ +### VI WIDGETS ############################################################# + +# This setup may change the `ESC' keybinding to `C-d'. That defeats the +# possibility to exit zsh by pressing `C-d' (which usually sends EOF). +# With this widget, you can type `:q' to exit the shell from vicmd. +function ft-zshexit { + [[ -o hist_ignore_space ]] && BUFFER=' ' + BUFFER="${BUFFER}exit" + zle .accept-line +} +zle -N q ft-zshexit + +# First the ones that change the input method directly; namely cmd mode, +# insert mode and replace mode. +function ft-vi-replace() { + ft_zle_state[overwrite]=yes + zle vi-replace + ft-psvx +} + +function ft-vi-insert() { + ft_zle_state[overwrite]=no + zle vi-insert +} + +# Since I want to bind `vi-cmd-mode' to Ctrl-D (which is what I'm doing in +# vim and emacs-viper, too) I need to wrap this widget into a user-widget, +# because only those have an effect with empty command buffers and bindings +# to the key, which sends `EOF'. This also needs the ignore_eof option set. +function ft-vi-cmd() { + ft_zle_state[overwrite]=no + zle vi-cmd-mode +} + +function ft-vi-cmd-cmd() { + zle -M 'Use `:q'\'' to exit the shell.' +} + +# ...and now the widgets that open minibuffers... +# Oh, yeah. You cannot wrap `execute-named-cmd', so no minibuffer-signaling +# for that. See . +function ft-markminibuf() { + ft_zle_state[minibuffer]=yes + ft-psvx + zle "$1" + ft_zle_state[minibuffer]=no + ft-psvx +} + +if (( ${+widgets[.history-incremental-pattern-search-backward]} )); then + function history-incremental-pattern-search-backward() { + ft-markminibuf .history-incremental-pattern-search-backward + } +else + function history-incremental-search-backward() { + ft-markminibuf .history-incremental-search-backward + } +fi + +if (( ${+widgets[.history-incremental-pattern-search-forward]} )); then + function history-incremental-pattern-search-forward() { + ft-markminibuf .history-incremental-pattern-search-forward + } +else + function history-incremental-search-forward() { + ft-markminibuf .history-incremental-search-forward + } +fi + +function ft-vi-search-back() { + ft-markminibuf vi-history-search-backward +} + +function ft-vi-search-fwd() { + ft-markminibuf vi-history-search-forward +} + +function ft-replace-pattern() { + ft-markminibuf replace-pattern +} + +# register the created widgets +for w in \ + ft-replace-pattern \ + ft-vi-{cmd,cmd-cmd,replace,insert,search-back,search-fwd} +do + zle -N "$w" +done; unset w + +############################################################################ +### ALTERED KEYBINDINGS #################################################### + +if [[ ${zle_use_ctrl_d} == 'yes' ]]; then + # Remove the escape key binding. + bindkey -r '^[' +fi +bindkey -M viins '^d' ft-vi-cmd +bindkey -M vicmd '^d' ft-vi-cmd-cmd +setopt ignore_eof + +bindkey -M vicmd '/' ft-vi-search-fwd +bindkey -M vicmd '?' ft-vi-search-back +bindkey -M vicmd 'i' ft-vi-insert +bindkey -M vicmd 'R' ft-vi-replace + +# The following four widgets require something like the following, to +# load and initialise the `replace-pattern' and `replace-string-again' +# widgets: +# +# zstyle ':zle:replace-pattern' edit-previous false +# autoload -Uz replace-string +# autoload -Uz replace-string-again +# zle -N replace-pattern replace-string +# zle -N replace-string-again +# +# ...and that *before* this file is sourced. + +if (( ${+widgets[replace-pattern]} )); then + bindkey -M vicmd '^x,' ft-replace-pattern + bindkey -M viins '^x,' ft-replace-pattern +fi + +if (( ${+widgets[replace-string-again]} )); then + bindkey -M vicmd '^x.' replace-string-again + bindkey -M viins '^x.' replace-string-again +fi + +if [[ ${zle_ins_more_like_emacs} == 'yes' ]]; then + if (( ${+widgets[.history-incremental-pattern-search-backward]} )); then + bindkey -M viins '^r' history-incremental-pattern-search-backward + bindkey -M vicmd '^r' history-incremental-pattern-search-backward + else + bindkey -M viins '^r' history-incremental-search-backward + bindkey -M vicmd '^r' history-incremental-search-backward + fi + if (( ${+widgets[.history-incremental-pattern-search-forward]} )); then + bindkey -M viins '^s' history-incremental-pattern-search-forward + bindkey -M vicmd '^s' history-incremental-pattern-search-forward + else + bindkey -M viins '^s' history-incremental-search-forward + bindkey -M vicmd '^s' history-incremental-search-forward + fi + bindkey -M vicmd '^[h' run-help + bindkey -M viins '^[h' run-help + bindkey -M viins '^p' up-line-or-history + bindkey -M viins '^n' down-line-or-history + bindkey -M viins '^w' backward-kill-word + bindkey -M viins '^h' backward-delete-char + bindkey -M viins '^?' backward-delete-char +fi + +true -- cgit v1.2.3