From: sev Date: Mon, 30 Oct 2023 12:14:54 +0000 (-0500) Subject: make key handling and logout more robust X-Git-Url: https://git.sev.monster/~sev/dotfiles.git/commitdiff_plain/b484bab8b0951f1f1aa631b62fd486b685c6e0ff?ds=sidebyside make key handling and logout more robust key setup can know use either terminfo, termcap, or zkbd, and in all cases appends to the $key array topreserve existing keys that we do not reset. the increased knowledge in termcap/terminfo also resulted in .zlogout getting a facelift to no longer rely on system binaries for terminal reset. --- diff --git a/etc/zsh/.zlogout b/etc/zsh/.zlogout index c005421..1b2b266 100644 --- a/etc/zsh/.zlogout +++ b/etc/zsh/.zlogout @@ -10,9 +10,34 @@ _sev_zcleanup ## clean up any remaining sockets from gpg forwarding [[ -v _GNUPG_SOCK_DEST_BASE ]] && rm -f $_GNUPG_SOCK_DEST_BASE*(=N) +## manually reset terminal for interactive logout if [[ -o interactive ]] { + # send xterm scrollback clear extension just in case: + # - TERM may not be set correctly + # - terminfo/termcap database entry for reset may be buggy + echo -n '\e[3J' + # use terminfo/termcap directly instead of relying on system clear/reset: + # - often they are just wrappers for ncurses tput or other tools + # - they may not even exist on lightweight systems + # - provided scripts/binaries may be buggy or broken + y=0 + for x (rs1 rs2 rs3) { + [[ -v terminfo[$x] ]] || continue + echoti $x + y=1 + } + if (( y == 0 )) { + for x (rs r1 r2 r3) { + [[ -v termcap[$x] ]] || continue + echotc $x + y=1 + } + } + if (( y == 0 )) { + # fallback, send ECMA-48 clear + echo -n '\e[2J' + } echo logout - clear } ### load site-specific diff --git a/etc/zsh/.zshrc b/etc/zsh/.zshrc index 64c7c5e..bfe0d9f 100644 --- a/etc/zsh/.zshrc +++ b/etc/zsh/.zshrc @@ -62,11 +62,70 @@ compinit -d $cache/.zcompdump unset cache ### keys -bindkey -v -KEYTIMEOUT=10 -## populate key array -if (( $#terminfo == 0 )) { - # terminfo is not set or empty +## set up zkbd-style key array +if [[ ! -v _sev_force_zkbd && ( -v terminfo || -v termcap ) ]] { + # use application (keypad transmit) mode if the terminal supports it + # NOTE: we have to do this because termcap/terminfo keys are usually + # defined in application mode. terminals that do not define these + # capabilities are assumed to always be in application mode. + if [[ ( -v terminfo[smkx] && -v terminfo[rmkx] ) || + ( -v termcap[ks] && -v terminfo[ke] ) ]] { + autoload -Uz add-zle-hook-widget + function _enter-application-mode { + [[ -v terminfo[smkx] ]] && echoti smkx || echotc ks + } + add-zle-hook-widget line-init _enter-application-mode + function _exit-application-mode { + [[ -v terminfo[rmkx] ]] && echoti rmkx || echotc ke + } + add-zle-hook-widget line-finish _exit-application-mode + trap _exit-application-mode EXIT + } + # pull keys from terminfo/termcap + # TODO: Menu and more Shift- modifiers + typeset -gA key + typeset -lA newkey + if [[ -v terminfo ]] { + src=terminfo + newkey=(F1 kf1 F2 kf2 F3 kf3 F4 kf4 F5 kf5 F6 kf6 F7 kf7 F8 kf8 F9 kf9 + F10 kf10 F11 kf11 F12 kf12 + Backspace kbs + Shift-Tab kcbt + Insert kich1 + Home khome + PageUp kpp + Delete kdch1 + End kend + PageDown knp + Up kcuu1 + Down kcud1 + Left kcub1 + Right kcuf1 + ) + } elif [[ -v termcap ]] { + src=termcap + newkey=(F1 k1 F2 k2 F3 k3 F4 k4 F5 k5 F6 k6 F7 k7 F8 k8 F9 k9 + F10 k\; F11 F1 F12 F2 + Backspace kb + Shift-Tab kB + Insert kI + Home kh + PageUp kP + Delete kD + End @7 + PageDown kN + Up ku + Down kd + Left kl + Right kr + ) + } + for k v (${(kv)newkey}) { + key[$k]=${${(P)src}[$v]} + } + unset k v src newkey +} else { + # use zkbd if termcap/terminfo unavailable function find_keymap { for f in ${ZDOTDIR:-~}/.zkbd/$TERM{-${DISPLAY:-$VENDOR-$OSTYPE},} [[ -f $f ]] && keymap=$f && break @@ -87,39 +146,6 @@ if (( $#terminfo == 0 )) { echo "Failed to source keymap file $keymap" >&2 } unfunction find_keymap; unset keymap -} else { - # activate application mode for zle so terminfo keys work - # NOTE: don't do this for zkbd since application mode shouldn't have been - # enabled by zkbd when the keymap file was generated - if [[ -v terminfo[smkx] && -v terminfo[rmkx] ]] { - autoload -Uz add-zle-hook-widget - function _enter-application-mode { echoti smkx } - add-zle-hook-widget line-init _enter-application-mode - function _exit-application-mode { echoti rmkx } - add-zle-hook-widget line-finish _exit-application-mode - trap _exit-application-mode EXIT - } - # match zkbd hash as best we can to terminfo - typeset -gA key - key=(F1 kf1 F2 kf2 F3 kf3 F4 kf4 F5 kf5 F6 kf6 F7 kf7 F8 kf8 F9 kf9 - F10 kf10 F11 kf11 F12 kf12 - Backspace kbs - Backtab kcbt - Shift-Tab kcbt - Insert kich1 - Home khome - PageUp kpp - Delete kdch1 - End kend - PageDown knp - Up kcuu1 - Down kcud1 - Left kcub1 - Right kcuf1 - ) - for k v in ${(kv)key}; do - key[$k]=$terminfo[$v] - done; unset k v } ## load history search @@ -128,6 +154,9 @@ zle -N up-line-or-beginning-search zle -N down-line-or-beginning-search ## bind keys in both viins and vicmd modes +# NOTE: cursor keys are bound to normal/raw/nontransmit mode strings by +# default, and keys like Home and End are not bound at all, so we rebind +# everything to cover all scenarios typeset -A a a=( #key viins vicmd @@ -143,12 +172,12 @@ a=( Left 'backward-char' Right 'forward-char' ) -for k v in ${(kv)a}; do +for k v (${(kv)a}) { k=$key[$k] - if [[ -z "$k" ]] { continue } + if [[ -z $k ]] { continue } v=($=v) bindkey -- $k $v[1] - if [[ $v[2] == '-' ]] { + if [[ $v[2] == - ]] { # copy viins to vicmd verbatim bindkey -a -- $k $v[1] } elif (( $#v != 1 )) { @@ -158,7 +187,7 @@ for k v in ${(kv)a}; do # copy viins to vicmd and prepend vi- to it bindkey -a -- $k vi-$v[1] } -done +} unset a k v ### aliases