|
| 1 | +#!/bin/bash |
| 2 | +# completion.bash |
| 3 | +# |
| 4 | +# copied and modified from https://github.com/junegunn/fzf/blob/master/shell/completion.bash |
| 5 | +# |
| 6 | +# - $SKIM_TMUX (default: 0) |
| 7 | +# - $SKIM_TMUX_HEIGHT (default: '40%') |
| 8 | +# - $SKIM_COMPLETION_TRIGGER (default: '**') |
| 9 | +# - $SKIM_COMPLETION_OPTS (default: empty) |
| 10 | + |
| 11 | +# To use custom commands instead of find, override _skim_compgen_{path,dir} |
| 12 | +if ! declare -f _skim_compgen_path > /dev/null; then |
| 13 | + _skim_compgen_path() { |
| 14 | + echo "$1" |
| 15 | + command find -L "$1" \ |
| 16 | + -name .git -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \ |
| 17 | + -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@' |
| 18 | + } |
| 19 | +fi |
| 20 | + |
| 21 | +if ! declare -f _skim_compgen_dir > /dev/null; then |
| 22 | + _skim_compgen_dir() { |
| 23 | + command find -L "$1" \ |
| 24 | + -name .git -prune -o -name .svn -prune -o -type d \ |
| 25 | + -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@' |
| 26 | + } |
| 27 | +fi |
| 28 | + |
| 29 | +########################################################### |
| 30 | + |
| 31 | +# To redraw line after skim closes (printf '\e[5n') |
| 32 | +bind '"\e[0n": redraw-current-line' |
| 33 | + |
| 34 | +__skimcmd_complete() { |
| 35 | + [ -n "$TMUX_PANE" ] && [ "${SKIM_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] && |
| 36 | + echo "sk-tmux -d${SKIM_TMUX_HEIGHT:-40%}" || echo "sk" |
| 37 | +} |
| 38 | + |
| 39 | +_skim_orig_completion_filter() { |
| 40 | + sed 's/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _skim_orig_completion_\3="\1 %s \3 #\2";/' | |
| 41 | + awk -F= '{gsub(/[^A-Za-z0-9_= ;]/, "_", $1); print $1"="$2}' |
| 42 | +} |
| 43 | + |
| 44 | +_skim_opts_completion() { |
| 45 | + local cur prev opts |
| 46 | + COMPREPLY=() |
| 47 | + cur="${COMP_WORDS[COMP_CWORD]}" |
| 48 | + prev="${COMP_WORDS[COMP_CWORD-1]}" |
| 49 | + opts=" |
| 50 | + -x --extended |
| 51 | + -e --exact |
| 52 | + --algo |
| 53 | + -i +i |
| 54 | + -n --nth |
| 55 | + --with-nth |
| 56 | + -d --delimiter |
| 57 | + +s --no-sort |
| 58 | + --tac |
| 59 | + --tiebreak |
| 60 | + -m --multi |
| 61 | + --no-mouse |
| 62 | + --bind |
| 63 | + --cycle |
| 64 | + --no-hscroll |
| 65 | + --jump-labels |
| 66 | + --height |
| 67 | + --literal |
| 68 | + --reverse |
| 69 | + --margin |
| 70 | + --inline-info |
| 71 | + --prompt |
| 72 | + --header |
| 73 | + --header-lines |
| 74 | + --ansi |
| 75 | + --tabstop |
| 76 | + --color |
| 77 | + --no-bold |
| 78 | + --history |
| 79 | + --history-size |
| 80 | + --preview |
| 81 | + --preview-window |
| 82 | + -q --query |
| 83 | + -1 --select-1 |
| 84 | + -0 --exit-0 |
| 85 | + -f --filter |
| 86 | + --print-query |
| 87 | + --expect |
| 88 | + --sync" |
| 89 | + |
| 90 | + case "${prev}" in |
| 91 | + --tiebreak) |
| 92 | + COMPREPLY=( $(compgen -W "length begin end index" -- "$cur") ) |
| 93 | + return 0 |
| 94 | + ;; |
| 95 | + --color) |
| 96 | + COMPREPLY=( $(compgen -W "dark light 16 bw" -- "$cur") ) |
| 97 | + return 0 |
| 98 | + ;; |
| 99 | + --history) |
| 100 | + COMPREPLY=() |
| 101 | + return 0 |
| 102 | + ;; |
| 103 | + esac |
| 104 | + |
| 105 | + if [[ "$cur" =~ ^-|\+ ]]; then |
| 106 | + COMPREPLY=( $(compgen -W "${opts}" -- "$cur") ) |
| 107 | + return 0 |
| 108 | + fi |
| 109 | + |
| 110 | + return 0 |
| 111 | +} |
| 112 | + |
| 113 | +_skim_handle_dynamic_completion() { |
| 114 | + local cmd orig_var orig ret orig_cmd |
| 115 | + cmd="$1" |
| 116 | + shift |
| 117 | + orig_cmd="$1" |
| 118 | + orig_var="_skim_orig_completion_$cmd" |
| 119 | + orig="${!orig_var##*#}" |
| 120 | + if [ -n "$orig" ] && type "$orig" > /dev/null 2>&1; then |
| 121 | + $orig "$@" |
| 122 | + elif [ -n "$_skim_completion_loader" ]; then |
| 123 | + _completion_loader "$@" |
| 124 | + ret=$? |
| 125 | + eval "$(complete | command grep "\-F.* $orig_cmd$" | _skim_orig_completion_filter)" |
| 126 | + source "${BASH_SOURCE[0]}" |
| 127 | + return $ret |
| 128 | + fi |
| 129 | +} |
| 130 | + |
| 131 | +__skim_generic_path_completion() { |
| 132 | + local cur base dir leftover matches trigger cmd skim |
| 133 | + skim="$(__skimcmd_complete)" |
| 134 | + cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}" |
| 135 | + COMPREPLY=() |
| 136 | + trigger=${SKIM_COMPLETION_TRIGGER-'**'} |
| 137 | + cur="${COMP_WORDS[COMP_CWORD]}" |
| 138 | + if [[ "$cur" == *"$trigger" ]]; then |
| 139 | + base=${cur:0:${#cur}-${#trigger}} |
| 140 | + eval "base=$base" |
| 141 | + |
| 142 | + dir="$base" |
| 143 | + while true; do |
| 144 | + if [ -z "$dir" ] || [ -d "$dir" ]; then |
| 145 | + leftover=${base/#"$dir"} |
| 146 | + leftover=${leftover/#\/} |
| 147 | + [ -z "$dir" ] && dir='.' |
| 148 | + [ "$dir" != "/" ] && dir="${dir/%\//}" |
| 149 | + matches=$(eval "$1 $(printf %q "$dir")" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS" $skim $2 -q "$leftover" | while read -r item; do |
| 150 | + printf "%q$3 " "$item" |
| 151 | + done) |
| 152 | + matches=${matches% } |
| 153 | + if [ -n "$matches" ]; then |
| 154 | + COMPREPLY=( "$matches" ) |
| 155 | + else |
| 156 | + COMPREPLY=( "$cur" ) |
| 157 | + fi |
| 158 | + printf '\e[5n' |
| 159 | + return 0 |
| 160 | + fi |
| 161 | + dir=$(dirname "$dir") |
| 162 | + [[ "$dir" =~ /$ ]] || dir="$dir"/ |
| 163 | + done |
| 164 | + else |
| 165 | + shift |
| 166 | + shift |
| 167 | + shift |
| 168 | + _skim_handle_dynamic_completion "$cmd" "$@" |
| 169 | + fi |
| 170 | +} |
| 171 | +_skim_complete() { |
| 172 | + local cur selected trigger cmd skim post |
| 173 | + post="$(caller 0 | awk '{print $2}')_post" |
| 174 | + type -t "$post" > /dev/null 2>&1 || post=cat |
| 175 | + skim="$(__skimcmd_complete)" |
| 176 | + cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}" |
| 177 | + trigger=${SKIM_COMPLETION_TRIGGER-'**'} |
| 178 | + cur="${COMP_WORDS[COMP_CWORD]}" |
| 179 | + if [[ "$cur" == *"$trigger" ]]; then |
| 180 | + cur=${cur:0:${#cur}-${#trigger}} |
| 181 | + selected=$(cat | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS" $skim $1 -q "$cur" | $post | tr '\n' ' ') |
| 182 | + selected=${selected% } # Strip trailing space not to repeat "-o nospace" |
| 183 | + printf '\e[5n' |
| 184 | + if [ -n "$selected" ]; then |
| 185 | + COMPREPLY=("$selected") |
| 186 | + return 0 |
| 187 | + fi |
| 188 | + else |
| 189 | + shift |
| 190 | + _skim_handle_dynamic_completion "$cmd" "$@" |
| 191 | + fi |
| 192 | +} |
| 193 | +_skim_path_completion() { |
| 194 | + __skim_generic_path_completion _skim_compgen_path "-m" "" "$@" |
| 195 | +} |
| 196 | +# Deprecated. No file only completion. |
| 197 | +_skim_file_completion() { |
| 198 | + _skim_path_completion "$@" |
| 199 | +} |
| 200 | +_skim_dir_completion() { |
| 201 | + __skim_generic_path_completion _skim_compgen_dir "" "/" "$@" |
| 202 | +} |
| 203 | +_skim_complete_kill() { |
| 204 | + [ -n "${COMP_WORDS[COMP_CWORD]}" ] && return 1 |
| 205 | + local selected skim |
| 206 | + skim="$(__skimcmd_complete)" |
| 207 | + selected=$(ps -ef | sed 1d | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-50%} --min-height 15 --reverse $SKIM_DEFAULT_OPTIONS --preview 'echo {}' --preview-window down:3:wrap $SKIM_COMPLETION_OPTS" $skim -m | awk '{print $2}' | tr '\n' ' ') |
| 208 | + printf '\e[5n' |
| 209 | + if [ -n "$selected" ]; then |
| 210 | + COMPREPLY=( "$selected" ) |
| 211 | + return 0 |
| 212 | + fi |
| 213 | +} |
| 214 | +_skim_complete_telnet() { |
| 215 | + _skim_complete '-m' "$@" < <( |
| 216 | + command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' | |
| 217 | + awk '{if (length($2) > 0) {print $2}}' | sort -u |
| 218 | + ) |
| 219 | +} |
| 220 | +_skim_complete_ssh() { |
| 221 | + _skim_complete '-m' "$@" < <( |
| 222 | + cat <(cat ~/.ssh/config /etc/ssh/ssh_config 2> /dev/null | command grep -i '^host' | command grep -v '*') \ |
| 223 | + <(command grep -oE '^[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | awk '{ print $1 " " $1 }') \ |
| 224 | + <(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') | |
| 225 | + awk '{if (length($2) > 0) {print $2}}' | sort -u |
| 226 | + ) |
| 227 | +} |
| 228 | +_skim_complete_unset() { |
| 229 | + _skim_complete '-m' "$@" < <( |
| 230 | + declare -xp | sed 's/=.*//' | sed 's/.* //' |
| 231 | + ) |
| 232 | +} |
| 233 | +_skim_complete_export() { |
| 234 | + _skim_complete '-m' "$@" < <( |
| 235 | + declare -xp | sed 's/=.*//' | sed 's/.* //' |
| 236 | + ) |
| 237 | +} |
| 238 | +_skim_complete_unalias() { |
| 239 | + _skim_complete '-m' "$@" < <( |
| 240 | + alias | sed 's/=.*//' | sed 's/.* //' |
| 241 | + ) |
| 242 | +} |
| 243 | +# skim options |
| 244 | +complete -o default -F _skim_opts_completion skim |
| 245 | +d_cmds="${SKIM_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}" |
| 246 | +a_cmds=" |
| 247 | + awk cat diff diff3 |
| 248 | + emacs emacsclient ex file ftp g++ gcc gvim head hg java |
| 249 | + javac ld less more mvim nvim patch perl python ruby |
| 250 | + sed sftp sort source tail tee uniq vi view vim wc xdg-open |
| 251 | + basename bunzip2 bzip2 chmod chown curl cp dirname du |
| 252 | + find git grep gunzip gzip hg jar |
| 253 | + ln ls mv open rm rsync scp |
| 254 | + svn tar unzip zip" |
| 255 | +x_cmds="kill ssh telnet unset unalias export" |
| 256 | +# Preserve existing completion |
| 257 | +eval $(complete | |
| 258 | + sed -E '/-F/!d; / _skim/d; '"/ ($(echo $d_cmds $a_cmds $x_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' | |
| 259 | + _skim_orig_completion_filter) |
| 260 | +if type _completion_loader > /dev/null 2>&1; then |
| 261 | + _skim_completion_loader=1 |
| 262 | +fi |
| 263 | +_skim_defc() { |
| 264 | + local cmd func opts orig_var orig def |
| 265 | + cmd="$1" |
| 266 | + func="$2" |
| 267 | + opts="$3" |
| 268 | + orig_var="_skim_orig_completion_${cmd//[^A-Za-z0-9_]/_}" |
| 269 | + orig="${!orig_var}" |
| 270 | + if [ -n "$orig" ]; then |
| 271 | + printf -v def "$orig" "$func" |
| 272 | + eval "$def" |
| 273 | + else |
| 274 | + complete -F "$func" $opts "$cmd" |
| 275 | + fi |
| 276 | +} |
| 277 | +# Anything |
| 278 | +for cmd in $a_cmds; do |
| 279 | + _skim_defc "$cmd" _skim_path_completion "-o default -o bashdefault" |
| 280 | +done |
| 281 | +# Directory |
| 282 | +for cmd in $d_cmds; do |
| 283 | + _skim_defc "$cmd" _skim_dir_completion "-o nospace -o dirnames" |
| 284 | +done |
| 285 | +unset _skim_defc |
| 286 | +# Kill completion |
| 287 | +complete -F _skim_complete_kill -o nospace -o default -o bashdefault kill |
| 288 | +# Host completion |
| 289 | +complete -F _skim_complete_ssh -o default -o bashdefault ssh |
| 290 | +complete -F _skim_complete_telnet -o default -o bashdefault telnet |
| 291 | +# Environment variables / Aliases |
| 292 | +complete -F _skim_complete_unset -o default -o bashdefault unset |
| 293 | +complete -F _skim_complete_export -o default -o bashdefault export |
| 294 | +complete -F _skim_complete_unalias -o default -o bashdefault unalias |
| 295 | +unset cmd d_cmds a_cmds x_cmds |
0 commit comments