201 lines
6.6 KiB
Bash
201 lines
6.6 KiB
Bash
# http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html
|
|
# http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Builtins
|
|
# http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Standard-Widgets
|
|
|
|
zmodload -i zsh/zutil
|
|
|
|
# OMZ takes over zle-line-init/finish, to:
|
|
# a) provide hooks for multiple init/finish functions, like $precmd_functions does
|
|
# b) disable [sr]mkx on the few systems whose system zsh configuration enables it
|
|
typeset -g -a zle_line_init_functions zle_line_finish_functions
|
|
function zle-line-init() {
|
|
local fcn
|
|
for fcn in "${zle_line_init_functions[@]}"; do
|
|
$fcn
|
|
done
|
|
}
|
|
function zle-line-finish() {
|
|
local fcn
|
|
for fcn in "${zle_line_finish_functions[@]}"; do
|
|
$fcn
|
|
done
|
|
}
|
|
zle -N zle-line-init
|
|
zle -N zle-line-finish
|
|
|
|
# DEBUG: This is the old stuff we used to do to put the keypads in application mode
|
|
# during command line editing. It's included here to make it easy to test the
|
|
# new key binding logic under both normal and application modes. This should
|
|
# go away once the modeless key binding stuff is tested.
|
|
# Note: This breaks the zle-line-init/finish hooks from above.
|
|
if (( $_OMZ_DEBUG_SMKX )); then
|
|
if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
|
|
function zle-line-init() {
|
|
echoti smkx
|
|
}
|
|
function zle-line-finish() {
|
|
echoti rmkx
|
|
}
|
|
zle -N zle-line-init
|
|
zle -N zle-line-finish
|
|
fi
|
|
fi
|
|
# end old keypad-mode stuff
|
|
|
|
|
|
# Extra portability cursor key mappings for local-mode keypad and terminals
|
|
# which deviate from typical terminfo entries. Supplements $terminfo.
|
|
# Maps capability names to |-delimited lists of character sequences.
|
|
# Reflects the capabilities of the $TERM defined at startup.
|
|
typeset -AHg _omz_terminfo_extra
|
|
_omz_terminfo_extra=(
|
|
# Start with the basic Xterm local-mode sequences. (Some people call
|
|
# these "ANSI" key sequences.)
|
|
kcuu1 "\e[A" # up
|
|
kcud1 "\e[B" # down
|
|
kcuf1 "\e[C" # right ("forward")
|
|
kcub1 "\e[D" # left ("backward")
|
|
khome "\e[H" # home
|
|
kend "\e[F" # end
|
|
)
|
|
# Portability entries for terminals we can't recognize from $TERM
|
|
# Putty and others may send the VT220 editing keypad sequences for
|
|
# Home/End. Bind those too, since there's no collision risk AFAIK.
|
|
# TODO: Should we alias the whole 6-key VT220 editing keypad?
|
|
_omz_terminfo_extra[khome]="$_omz_terminfo_extra[khome]|\e[1~"
|
|
_omz_terminfo_extra[kend]="$_omz_terminfo_extra[kend]|\e[4~"
|
|
# Do *not* bind '\e[Ow' here, which Putty may also send for End, because
|
|
# it collides with application-mode numeric keypad sequences.
|
|
|
|
# Terminal-specific portability entries for the current terminal, for
|
|
# terminals whose local-mode sequences are known to differ from Xterm's
|
|
case "$TERM" in
|
|
rxvt-unicode*)
|
|
# rxvt-unicde local-cursor sequences that differ from xterm
|
|
_omz_terminfo_extra[khome]="$_omz_terminfo_extra[khome]|\e[7~"
|
|
_omz_terminfo_extra[kend]="$_omz_terminfo_extra[kend]|\e[8~"
|
|
esac
|
|
|
|
# omz_bindkey - an extension to bindkey
|
|
#
|
|
# omz_bindkey [options] -t <capability> <command>
|
|
# omz_bindkey -c <modifier> <cursor-key> <command>
|
|
# omz_bindkey [...normal bindkey arguments...]
|
|
#
|
|
# Adds the following features on top of bindkey:
|
|
# 1) Logging
|
|
# 2) -t: binds a key, using terminfo and OMZ portability mappings
|
|
# 3) -c: binds an Xterm-style modified cursor key sequence
|
|
#
|
|
# Returns:
|
|
# 0 if a binding was made
|
|
# 1 if no binding was made
|
|
# 2 if an error occurred
|
|
function omz_bindkey() {
|
|
emulate -L zsh
|
|
# Note: "seq" is short for "sequence" in these functions
|
|
# We must capture all of bindkey's options to get ordering right when calling it
|
|
local -a omz_opts bindkey_opts
|
|
omz_opts=()
|
|
bindkey_opts=()
|
|
local -A optvals
|
|
zparseopts -a bindkey_opts -A optvals -D -E t:=omz_opts c=omz_opts M:
|
|
if [[ -n ${omz_opts[(r)-t]} ]]; then
|
|
# OMZ terminfo-based binding
|
|
local cap=${optvals[-t]}
|
|
local retval=1 seq seqs
|
|
seqs=()
|
|
if [[ -n "${terminfo[$cap]}" ]]; then
|
|
seqs=("$seqs[@]" "${terminfo[$cap]}")
|
|
fi
|
|
if [[ -n "${_omz_terminfo_extra[$cap]}" ]]; then
|
|
seqs=("$seqs[@]" "${(s:|:)_omz_terminfo_extra[$cap]}")
|
|
fi
|
|
# Done with a while loop because for seems to break here
|
|
local ix=0
|
|
while (( ++ix <= $#seqs )); do
|
|
seq="${seqs[$ix]}"
|
|
_omz_dbg_print -r "omz_bindkey: terminfo: $cap '${(q)seq}' $@"
|
|
bindkey "${bindkey_opts[@]}" $seq "$@"
|
|
retval=0
|
|
done
|
|
return $retval
|
|
elif [[ -n ${omz_opts[(r)-c]} ]]; then
|
|
# "-c" for "composed modified-cursor" keys
|
|
_omz_dbg_print -r "omz_bindkey: modified-cursor: '$1' '$2' '$3'"
|
|
_omz_bindkey_modified_cursor_key_xterm "$1" "$2" "$3"
|
|
else
|
|
_omz_dbg_print -r "omz_bindkey: passthrough: ${(q)@}"
|
|
bindkey "${bindkey_opts[@]}" "$@"
|
|
fi
|
|
}
|
|
|
|
# Xterm style function key modifier codes
|
|
typeset -Ag _omz_ti_modifiers
|
|
_omz_ti_modifiers=(
|
|
'shift' 2
|
|
'alt' 3
|
|
'alt-shift' 4
|
|
'ctrl' 5
|
|
'ctrl-shift' 6
|
|
'ctrl-alt' 7
|
|
'ctrl-alt-shift' 8
|
|
'meta' 9
|
|
'meta-shift' 10
|
|
'meta-alt' 11
|
|
'meta-alt-shift' 12
|
|
'meta-ctrl' 13
|
|
'meta-ctrl-shift' 14
|
|
'meta-ctrl-alt' 15
|
|
'meta-ctrl-alt-shift' 16
|
|
)
|
|
|
|
# Binds a modified cursor key sequence
|
|
# Uses xterm modifier mask codes,
|
|
# per http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
|
|
# When used in combination, modifier keys must be supplied in the following canonical order:
|
|
# meta ctrl alt shift
|
|
function _omz_bindkey_modified_cursor_key_xterm() {
|
|
emulate -L zsh
|
|
local opts
|
|
opts=()
|
|
zparseopts -a opts -D -E M:
|
|
local modifier=$1 key=$2 widget=$3
|
|
local CSI='\e[' # Control Sequence Introducer
|
|
local seq modified_seq
|
|
local -A modifiers keys
|
|
set -A modifiers ${(kv)_omz_ti_modifiers}
|
|
keys=(
|
|
up A
|
|
down B
|
|
right C
|
|
left D
|
|
home H
|
|
end F
|
|
)
|
|
if [[ -z "$modifiers[$modifier]" ]] || [[ -z "$keys[$key]" ]]; then
|
|
_omz_dbg_print -r "Invalid modified-cursor-key: modifier=$modifier key=$key"
|
|
return 1
|
|
fi
|
|
seq="${CSI}${keys[$key]}"
|
|
_omz_bindkey_modified_cursor_seq_xterm_step "$seq" "$modifier"
|
|
# Wokaround for iTerm2: it reports alt as meta, so bind alt-modified sequences
|
|
# to the meta-modified variant, too.
|
|
# See https://gitlab.com/gnachman/iterm2/issues/3753
|
|
if [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
|
|
if [[ "$modifier" == "alt" ]]; then
|
|
_omz_bindkey_modified_cursor_seq_xterm_step "$seq" "meta"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function _omz_bindkey_modified_cursor_seq_xterm_step() {
|
|
local seq="$1" modifier="$2"
|
|
local modified_seq
|
|
local -A modifiers keys
|
|
set -A modifiers ${(kv)_omz_ti_modifiers}
|
|
modified_seq="${seq[1,-2]}1;$modifiers[$modifier]${seq[-1,-1]}"
|
|
omz_bindkey "${opts[@]}" "$modified_seq" "$widget"
|
|
}
|
|
|