Created
July 23, 2025 16:12
-
-
Save GeneralD/b920684a214d6bca59840f1afe16aa9a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # skim-tab: Replace zsh's default completion selection menu with skim! | |
| # Based on fzf-tab by Aloxaf | |
| # temporarily change options | |
| 'builtin' 'local' '-a' '_stb_opts' | |
| [[ ! -o 'aliases' ]] || _stb_opts+=('aliases') | |
| [[ ! -o 'sh_glob' ]] || _stb_opts+=('sh_glob') | |
| [[ ! -o 'no_brace_expand' ]] || _stb_opts+=('no_brace_expand') | |
| 'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand' | |
| # disable aliases | |
| typeset _stb_aliases="$(builtin alias -Lm '[^+]*')" | |
| builtin unalias -m '[^+]*' | |
| # Hook compadd to capture completions | |
| -stb-compadd() { | |
| # parse all options | |
| local -A apre hpre dscrs _oad _mesg | |
| local -a isfile _opts __ expl | |
| zparseopts -a _opts P:=apre p:=hpre d:=dscrs X+:=expl O:=_oad A:=_oad D:=_oad f=isfile \ | |
| i: S: s: I: x:=_mesg r: R: W: F: M+: E: q e Q n U C \ | |
| J:=__ V:=__ a=__ l=__ k=__ o::=__ 1=__ 2=__ | |
| # store $curcontext for further usage | |
| _stb_curcontext=${curcontext#:} | |
| # just delegate and leave if any of -O, -A or -D are given or skim-tab is not enabled | |
| if (( $#_oad != 0 || ! IN_SKIM_TAB )); then | |
| builtin compadd "$@" | |
| return | |
| fi | |
| # store matches in $__hits and descriptions in $__dscr | |
| local -a __hits __dscr | |
| if (( $#dscrs == 1 )); then | |
| __dscr=( "${(@P)${(v)dscrs}}" ) | |
| fi | |
| builtin compadd -A __hits -D __dscr "$@" | |
| local ret=$? | |
| if (( $#__hits == 0 )); then | |
| return $ret | |
| fi | |
| # only store the first `-X` | |
| expl=$expl[2] | |
| # keep order of group description | |
| [[ -n $expl ]] && _stb_groups+=$expl | |
| # store these values in _stb_compcap | |
| local -a keys=(apre hpre PREFIX SUFFIX IPREFIX ISUFFIX) | |
| local key expanded __tmp_value=$'<\0>' # placeholder | |
| for key in $keys; do | |
| expanded=${(P)key} | |
| if [[ -n $expanded ]]; then | |
| __tmp_value+=$'\0'$key$'\0'$expanded | |
| fi | |
| done | |
| if [[ -n $expl ]]; then | |
| # store group index | |
| __tmp_value+=$'\0group\0'$_stb_groups[(ie)$expl] | |
| fi | |
| if [[ -n $isfile ]]; then | |
| # NOTE: need a extra ${} here or ~ expansion won't work | |
| __tmp_value+=$'\0realdir\0'${${(Qe)~${:-$IPREFIX$hpre}}} | |
| fi | |
| _opts+=("${(@kv)apre}" "${(@kv)hpre}" $isfile) | |
| __tmp_value+=$'\0args\0'${(pj:\1:)_opts} | |
| # dscr - the string to show to users | |
| # word - the string to be inserted | |
| local dscr word i | |
| for i in {1..$#__hits}; do | |
| word=$__hits[i] dscr=$__dscr[i] | |
| if [[ -n $dscr ]]; then | |
| dscr=${dscr//$'\n'} | |
| elif [[ -n $word ]]; then | |
| dscr=$word | |
| fi | |
| _stb_compcap+=$dscr$'\2'$__tmp_value$'\0word\0'$word | |
| done | |
| # tell zsh that the match is successful | |
| builtin compadd "$@" | |
| } | |
| -stb-complete() { | |
| local -Ua _stb_groups | |
| local choice choices _stb_curcontext bs=$'\2' nul=$'\0' | |
| local ret=0 | |
| # must run with user options; don't move `emulate -L zsh` above this line | |
| COLUMNS=500 _stb__main_complete "$@" || ret=$? | |
| emulate -L zsh -o extended_glob | |
| local _stb_complist=() | |
| # Generate completion list from captured completions | |
| if (( $#_stb_compcap == 0 )); then | |
| return 1 | |
| fi | |
| local i | |
| local -A seen_words | |
| for i in {1..$#_stb_compcap}; do | |
| local display_text="${_stb_compcap[i]%$bs*}" | |
| # Extract the actual word from the stored data | |
| local -A v=("${(@0)${_stb_compcap[i]#*$bs}}") | |
| local word="$v[word]" | |
| # Only add if we haven't seen this word before | |
| if [[ -z ${seen_words[$word]} ]]; then | |
| _stb_complist+="$display_text" | |
| seen_words[$word]=1 | |
| fi | |
| done | |
| case $#_stb_complist in | |
| 0) return 1;; | |
| 1) | |
| choices=("${_stb_complist[1]}") | |
| ;; | |
| *) | |
| if [[ $compstate[insert] == *"unambiguous" ]] \ | |
| && [[ -n $compstate[unambiguous] ]] \ | |
| && [[ "$compstate[unambiguous]" != "$compstate[quote]$IPREFIX$PREFIX$compstate[quote]" ]]; then | |
| compstate[list]= | |
| compstate[insert]=unambiguous | |
| _stb_finish=1 | |
| return 0 | |
| fi | |
| # Use skim to select from completions with --no-hscroll | |
| local -a skim_args=( | |
| --no-hscroll | |
| --no-sort | |
| ) | |
| choices=("${(@f)"$(builtin print -rl -- $_stb_complist | sk "${skim_args[@]}")"}") | |
| ret=$? | |
| ;; | |
| esac | |
| # Store choices for application | |
| _stb_choices=("${(@)choices}") | |
| compstate[list]= | |
| compstate[insert]= | |
| return $ret | |
| } | |
| _stb-apply() { | |
| local choice bs=$'\2' | |
| for choice in "$_stb_choices[@]"; do | |
| [[ -n $choice ]] || continue | |
| local -A v=("${(@0)${_stb_compcap[(r)${(b)choice}$bs*]#*$bs}}") | |
| local -a args=("${(@ps:\1:)v[args]}") | |
| [[ -z $args[1] ]] && args=() # don't pass an empty string | |
| IPREFIX=${v[IPREFIX]-} PREFIX=${v[PREFIX]-} SUFFIX=${v[SUFFIX]-} ISUFFIX=${v[ISUFFIX]-} | |
| builtin compadd "${args[@]:--Q}" -Q -- "$v[word]" | |
| done | |
| compstate[list]= | |
| if (( $#_stb_choices == 1 )); then | |
| compstate[insert]='1' | |
| [[ $RBUFFER == ' '* ]] || compstate[insert]+=' ' | |
| elif (( $#_stb_choices > 1 )); then | |
| compstate[insert]='all' | |
| fi | |
| } | |
| skim-tab-complete() { | |
| local _stb_choices=() _stb_compcap=() _stb_finish=0 ret=0 | |
| local IN_SKIM_TAB=1 | |
| # Hide cursor during completion to prevent display issues | |
| echoti civis >/dev/tty 2>/dev/null | |
| { | |
| # Call original completion widget which will trigger our hooked _main_complete | |
| zle .stb-orig-$_stb_orig_widget || ret=$? | |
| # Apply the selected choices if completion didn't finish early | |
| if (( ! ret && ! _stb_finish )); then | |
| zle _stb-apply || ret=$? | |
| fi | |
| } always { | |
| # Always restore cursor and redisplay line | |
| echoti cnorm >/dev/tty 2>/dev/null | |
| zle .reset-prompt | |
| zle .redisplay | |
| } | |
| return $ret | |
| } | |
| disable-skim-tab() { | |
| emulate -L zsh -o extended_glob | |
| (( $+_stb_orig_widget )) || return 0 | |
| bindkey '^I' $_stb_orig_widget | |
| unset _stb_orig_widget | |
| # unhook compadd | |
| unfunction compadd 2>/dev/null | |
| functions[_main_complete]=$functions[_stb__main_complete] | |
| } | |
| enable-skim-tab() { | |
| emulate -L zsh -o extended_glob | |
| (( ! $+_stb_orig_widget )) || disable-skim-tab | |
| typeset -g _stb_orig_widget="${${$(builtin bindkey '^I')##* }:-expand-or-complete}" | |
| if (( ! $+widgets[.stb-orig-$_stb_orig_widget] )); then | |
| zle -A $_stb_orig_widget .stb-orig-$_stb_orig_widget | |
| fi | |
| bindkey -M emacs '^I' skim-tab-complete | |
| bindkey -M viins '^I' skim-tab-complete | |
| # make sure we can copy _main_complete | |
| autoload +X -Uz _main_complete | |
| # hook compadd | |
| functions[compadd]=$functions[-stb-compadd] | |
| # hook _main_complete to trigger skim-tab | |
| functions[_stb__main_complete]=$functions[_main_complete] | |
| function _main_complete() { -stb-complete "$@" } | |
| } | |
| toggle-skim-tab() { | |
| emulate -L zsh -o extended_glob | |
| if (( $+_stb_orig_widget )); then | |
| disable-skim-tab | |
| else | |
| enable-skim-tab | |
| fi | |
| } | |
| # Create ZLE widgets | |
| zle -N skim-tab-complete | |
| zle -N toggle-skim-tab | |
| # Register as a completion widget for proper completion state handling | |
| zle -C _stb-apply complete-word _stb-apply | |
| # Enable skim-tab by default | |
| enable-skim-tab | |
| # restore aliases | |
| eval "$_stb_aliases" | |
| builtin unset _stb_aliases | |
| # restore options | |
| (( ${#_stb_opts} )) && setopt ${_stb_opts[@]} | |
| 'builtin' 'unset' '_stb_opts' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment