vi-mode.plugin.zsh 5.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Control whether to force a redraw on each mode change.
#
# Resetting the prompt on every mode change can cause lag when switching modes.
# This is especially true if the prompt does things like checking git status.
#
# Set to "true" to force the prompt to reset on each mode change.
# Set to "false" to force the prompt *not* to reset on each mode change.
#
# (The default is not to reset, unless we're showing the mode in RPS1).
typeset -g VI_MODE_RESET_PROMPT_ON_MODE_CHANGE
typeset -g VI_KEYMAP=main

function _vi-mode-set-cursor-shape-for-keymap() {
  # https://vt100.net/docs/vt510-rm/DECSCUSR
  local _shape=0
  case "${1:-${VI_KEYMAP:-main}}" in
    main)    _shape=6 ;; # vi insert: line
    viins)   _shape=6 ;; # vi insert: line
    isearch) _shape=6 ;; # inc search: line
    command) _shape=6 ;; # read a command name
    vicmd)   _shape=2 ;; # vi cmd: block
    visual)  _shape=2 ;; # vi visual mode: block
    viopp)   _shape=0 ;; # vi operation pending: blinking block
    *)       _shape=0 ;;
  esac
  printf $'\e[%d q' "${_shape}"
}

29
30
# Updates editor information when the keymap changes.
function zle-keymap-select() {
31
  # update keymap variable for the prompt
32
  typeset -g VI_KEYMAP=$KEYMAP
33

34
35
36
37
38
  if [ "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE:-}" = true ]; then
    zle reset-prompt
    zle -R
  fi
  _vi-mode-set-cursor-shape-for-keymap "${VI_KEYMAP}"
39
40
}
zle -N zle-keymap-select
41

42
43
44
45
46
47
# These "echoti" statements were originally set in lib/key-bindings.zsh
# Not sure the best way to extend without overriding.
function zle-line-init() {
  typeset -g VI_KEYMAP=main
  (( ! ${+terminfo[smkx]} )) || echoti smkx
  _vi-mode-set-cursor-shape-for-keymap "${VI_KEYMAP}"
48
}
49
zle -N zle-line-init
50

51
52
53
54
55
function zle-line-finish() {
  (( ! ${+terminfo[rmkx]} )) || echoti rmkx
  _vi-mode-set-cursor-shape-for-keymap default
}
zle -N zle-line-finish
56
57
58

bindkey -v

59
60
61
62
# allow ctrl-p, ctrl-n for navigate history (standard behaviour)
bindkey '^P' up-history
bindkey '^N' down-history

63
64
65
66
67
# allow ctrl-h, ctrl-w, ctrl-? for char and word deletion (standard behaviour)
bindkey '^?' backward-delete-char
bindkey '^h' backward-delete-char
bindkey '^w' backward-kill-word

68
# allow ctrl-r and ctrl-s to search the history
69
bindkey '^r' history-incremental-search-backward
70
bindkey '^s' history-incremental-search-forward
71
72
73
74
75

# allow ctrl-a and ctrl-e to move to beginning/end of line
bindkey '^a' beginning-of-line
bindkey '^e' end-of-line

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
if [[ "${terminfo[kpp]}" != "" ]]; then
  bindkey "${terminfo[kpp]}" up-line-or-history       # [PageUp] - Up a line of history
fi
if [[ "${terminfo[knp]}" != "" ]]; then
  bindkey "${terminfo[knp]}" down-line-or-history     # [PageDown] - Down a line of history
fi

# start typing + [Up-Arrow] - fuzzy find history forward
if [[ "${terminfo[kcuu1]}" != "" ]]; then
  autoload -U up-line-or-beginning-search
  zle -N up-line-or-beginning-search
  bindkey "${terminfo[kcuu1]}" up-line-or-beginning-search
fi
# start typing + [Down-Arrow] - fuzzy find history backward
if [[ "${terminfo[kcud1]}" != "" ]]; then
  autoload -U down-line-or-beginning-search
  zle -N down-line-or-beginning-search
  bindkey "${terminfo[kcud1]}" down-line-or-beginning-search
fi

if [[ "${terminfo[khome]}" != "" ]]; then
  bindkey "${terminfo[khome]}" beginning-of-line      # [Home] - Go to beginning of line
fi
if [[ "${terminfo[kend]}" != "" ]]; then
  bindkey "${terminfo[kend]}"  end-of-line            # [End] - Go to end of line
fi

if [[ "${terminfo[kcbt]}" != "" ]]; then
  bindkey "${terminfo[kcbt]}" reverse-menu-complete   # [Shift-Tab] - move through the completion menu backwards
fi

bindkey '^?' backward-delete-char                     # [Backspace] - delete backward
if [[ "${terminfo[kdch1]}" != "" ]]; then
  bindkey "${terminfo[kdch1]}" delete-char            # [Delete] - delete forward
else
  bindkey "^[[3~" delete-char
  bindkey "^[3;5~" delete-char
  bindkey "\e[3~" delete-char
fi

() {
  local wrap_clipboard_widgets
  function wrap_clipboard_widgets() {
    # NB: Assume we are the first wrapper and that we only wrap native widgets
    # See zsh-autosuggestions.zsh for a more generic and more robust wrapper
    local verb="$1"
    shift

    local widget
    local wrapped_name
    for widget in "$@"; do
      wrapped_name="_zsh-vi-${verb}-${widget}"
      if [ "${verb}" = copy ]; then
        eval "
          function ${wrapped_name}() {
            zle .${widget}
            printf %s \"\${CUTBUFFER}\" | clipcopy
          }
        "
      else
        eval "
          function ${wrapped_name}() {
            CUTBUFFER=\"\$(clippaste)\"
            zle .${widget}
          }
        "
      fi
      zle -N "${widget}" "${wrapped_name}"
    done
  }

  wrap_clipboard_widgets copy vi-yank vi-yank-eol vi-backward-kill-word vi-change-whole-line vi-delete
  wrap_clipboard_widgets paste vi-put-{before,after}
  unfunction wrap_clipboard_widgets
}

152
153
# if mode indicator wasn't setup by theme, define default
if [[ "$MODE_INDICATOR" == "" ]]; then
154
  MODE_INDICATOR='%B%F{red}<%b<<%f'
155
156
157
fi

function vi_mode_prompt_info() {
158
159
160
161
162
163
164
  # If we're using the prompt to display mode info, and we haven't explicitly
  # disabled "reset prompt on mode change", then set it here.
  #
  # We do that here instead of the `if` statement below because the user may
  # set RPS1/RPROMPT to something else in their custom config.
  : "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE:=true}"

165
  echo "${${VI_KEYMAP/vicmd/$MODE_INDICATOR}/(main|viins)/}"
166
167
168
169
170
171
}

# define right prompt, if it wasn't defined by a theme
if [[ "$RPS1" == "" && "$RPROMPT" == "" ]]; then
  RPS1='$(vi_mode_prompt_info)'
fi