1- # ____ ____
2- # / __/___ / __/
3- # / /_/_ / / /_
4- # / __/ / /_/ __/
5- # /_/ /___/_/ key-bindings.bash
6- #
71# - $SKIM_TMUX_OPTS
82# - $SKIM_CTRL_T_COMMAND
93# - $SKIM_CTRL_T_OPTS
104# - $SKIM_CTRL_R_OPTS
115# - $SKIM_ALT_C_COMMAND
126# - $SKIM_ALT_C_OPTS
7+ # - $SKIM_COMPLETION_TRIGGER (default: '**')
8+ # - $SKIM_COMPLETION_OPTS (default: empty)
139
1410# Key bindings
1511# ------------
@@ -27,9 +23,10 @@ __skim_select__() {
2723
2824if [[ $- =~ i ]]; then
2925
26+
3027__skimcmd () {
3128 [ -n " $TMUX_PANE " ] && { [ " ${SKIM_TMUX:- 0} " != 0 ] || [ -n " $SKIM_TMUX_OPTS " ]; } &&
32- echo " sk- tmux ${SKIM_TMUX_OPTS:- -d ${SKIM_TMUX_HEIGHT:- 40% } } -- " || echo " sk"
29+ echo " sk -- tmux= ${SKIM_TMUX_OPTS:- center, ${SKIM_TMUX_HEIGHT:- 40% } } -- " || echo " sk"
3330}
3431
3532skim-file-widget () {
@@ -42,7 +39,8 @@ __skim_cd__() {
4239 local cmd dir
4340 cmd=" ${SKIM_ALT_C_COMMAND:- " command find -L . -mindepth 1 \\ ( -path '*/\\ .*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\ ) -prune \
4441 -o -type d -print 2> /dev/null | cut -b3-" }"
45- dir=$( eval " $cmd " | SKIM_DEFAULT_OPTIONS=" --height ${SKIM_TMUX_HEIGHT:- 40% } --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS " $( __skimcmd) --no-multi) && printf ' cd %q' " $dir "
42+ dir=$( eval " $cmd " | SKIM_DEFAULT_OPTIONS=" --height ${SKIM_TMUX_HEIGHT:- 40% } --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS " $( __skimcmd) --no-multi)
43+ printf ' cd %q' " $dir "
4644}
4745
4846__skim_history__ () {
@@ -52,6 +50,7 @@ __skim_history__() {
5250 last_hist=$( HISTTIMEFORMAT=' ' builtin history 1) perl -n -l0 -e ' BEGIN { getc; $/ = "\n\t"; $HISTCMD = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCMD - $. . "\t$_" if !$seen{$_}++' |
5351 SKIM_DEFAULT_OPTIONS=" --height ${SKIM_TMUX_HEIGHT:- 40% } $SKIM_DEFAULT_OPTIONS -n2..,.. --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS --no-multi --read0" $( __skimcmd) --query " $READLINE_LINE "
5452 ) || return
53+ echo -e " \033[0m"
5554 READLINE_LINE=${output#* $' \t ' }
5655 if [ -z " $READLINE_POINT " ]; then
5756 echo " $READLINE_LINE "
@@ -94,4 +93,290 @@ bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__skim_cd__`\e\C-e\er\C-m\C-y\C-h
9493bind -m vi-command ' "\ec": "\C-z\ec\C-z"'
9594bind -m vi-insert ' "\ec": "\C-z\ec\C-z"'
9695
96+ # Completion
97+
98+ if ! declare -f _skim_compgen_path > /dev/null; then
99+ _skim_compgen_path () {
100+ echo " $1 "
101+ command find -L " $1 " \
102+ -name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
103+ -a -not -path " $1 " -print 2> /dev/null | sed ' s@^\./@@'
104+ }
105+ fi
106+
107+ if ! declare -f _skim_compgen_dir > /dev/null; then
108+ _skim_compgen_dir () {
109+ command find -L " $1 " \
110+ -name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
111+ -a -not -path " $1 " -print 2> /dev/null | sed ' s@^\./@@'
112+ }
113+ fi
114+
115+ # ##########################################################
116+
117+ # To redraw line after skim closes (printf '\e[5n')
118+ bind ' "\e[0n": redraw-current-line'
119+
120+ __skim_comprun () {
121+ if [ " $( type -t _skim_comprun 2>&1 ) " = function ]; then
122+ _skim_comprun " $@ "
123+ elif [ -n " $TMUX_PANE " ] && { [ " ${SKIM_TMUX:- 0} " != 0 ] || [ -n " $SKIM_TMUX_OPTS " ]; }; then
124+ shift
125+ sk --tmux= ${SKIM_TMUX_OPTS:- center,${SKIM_TMUX_HEIGHT:- 40% } } -- " $@ "
126+ else
127+ shift
128+ sk " $@ "
129+ fi
130+ }
131+
132+ __skim_orig_completion_filter () {
133+ sed ' s/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _skim_orig_completion_\3="\1 %s \3 #\2"; [[ "\1" = *" -o nospace "* ]] \&\& [[ ! "$__skim_nospace_commands" = *" \3 "* ]] \&\& __skim_nospace_commands="$__skim_nospace_commands \3 ";/' |
134+ awk -F= ' {OFS = FS} {gsub(/[^A-Za-z0-9_= ;]/, "_", $1);}1'
135+ }
136+
137+ _skim_handle_dynamic_completion () {
138+ local cmd orig_var orig ret orig_cmd orig_complete
139+ cmd=" $1 "
140+ shift
141+ orig_cmd=" $1 "
142+ orig_var=" _skim_orig_completion_$cmd "
143+ orig=" ${! orig_var##*# } "
144+ if [ -n " $orig " ] && type " $orig " > /dev/null 2>&1 ; then
145+ $orig " $@ "
146+ elif [ -n " $_skim_completion_loader " ]; then
147+ orig_complete=$( complete -p " $orig_cmd " 2> /dev/null)
148+ _completion_loader " $@ "
149+ ret=$?
150+ # _completion_loader may not have updated completion for the command
151+ if [ " $( complete -p " $orig_cmd " 2> /dev/null) " != " $orig_complete " ]; then
152+ eval " $( complete | command grep " -F.* $orig_cmd $" | __skim_orig_completion_filter) "
153+ if [[ " $__skim_nospace_commands " = * " $orig_cmd " * ]]; then
154+ eval " ${orig_complete/ -F / -o nospace -F } "
155+ else
156+ eval " $orig_complete "
157+ fi
158+ fi
159+ return $ret
160+ fi
161+ }
162+
163+ __skim_generic_path_completion () {
164+ local cur base dir leftover matches trigger cmd
165+ cmd=" ${COMP_WORDS[0]// [^A-Za-z0-9_=]/ _} "
166+ COMPREPLY=()
167+ trigger=${SKIM_COMPLETION_TRIGGER-' **' }
168+ cur=" ${COMP_WORDS[COMP_CWORD]} "
169+ if [[ " $cur " == * " $trigger " ]]; then
170+ base=${cur: 0: ${# cur} -${# trigger} }
171+ eval " base=$base "
172+
173+ [[ $base = * " /" * ]] && dir=" $base "
174+ while true ; do
175+ if [ -z " $dir " ] || [ -d " $dir " ]; then
176+ leftover=${base/# " $dir " }
177+ leftover=${leftover/# \/ }
178+ [ -z " $dir " ] && dir=' .'
179+ [ " $dir " != " /" ] && dir=" ${dir/% \/ / } "
180+ matches=$( eval " $1 $( printf %q " $dir " ) " | SKIM_DEFAULT_OPTIONS=" --height ${SKIM_TMUX_HEIGHT:- 40% } --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS $2 " __skim_comprun " $4 " -q " $leftover " | while read -r item; do
181+ printf " %q$3 " " $item "
182+ done)
183+ matches=${matches% }
184+ [[ -z " $3 " ]] && [[ " $__skim_nospace_commands " = * " ${COMP_WORDS[0]} " * ]] && matches=" $matches "
185+ if [ -n " $matches " ]; then
186+ COMPREPLY=( " $matches " )
187+ else
188+ COMPREPLY=( " $cur " )
189+ fi
190+ printf ' \e[5n'
191+ return 0
192+ fi
193+ dir=$( dirname " $dir " )
194+ [[ " $dir " =~ /$ ]] || dir=" $dir " /
195+ done
196+ else
197+ shift
198+ shift
199+ shift
200+ _skim_handle_dynamic_completion " $cmd " " $@ "
201+ fi
202+ }
203+
204+ _skim_complete () {
205+ # Split arguments around --
206+ local args rest str_arg i sep
207+ args=(" $@ " )
208+ sep=
209+ for i in " ${! args[@]} " ; do
210+ if [[ " ${args[$i]} " = -- ]]; then
211+ sep=$i
212+ break
213+ fi
214+ done
215+ if [[ -n " $sep " ]]; then
216+ str_arg=
217+ rest=(" ${args[@]: $((sep + 1)): ${# args[@]} } " )
218+ args=(" ${args[@]: 0: $sep } " )
219+ else
220+ str_arg=$1
221+ args=()
222+ shift
223+ rest=(" $@ " )
224+ fi
225+
226+ local cur selected trigger cmd post
227+ post=" $( caller 0 | awk ' {print $2}' ) _post"
228+ type -t " $post " > /dev/null 2>&1 || post=cat
229+
230+ cmd=" ${COMP_WORDS[0]// [^A-Za-z0-9_=]/ _} "
231+ trigger=${SKIM_COMPLETION_TRIGGER-' **' }
232+ cur=" ${COMP_WORDS[COMP_CWORD]} "
233+ if [[ " $cur " == * " $trigger " ]]; then
234+ cur=${cur: 0: ${# cur} -${# trigger} }
235+
236+ selected=$( SKIM_DEFAULT_OPTIONS=" --height ${SKIM_TMUX_HEIGHT:- 40% } --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS $str_arg " __skim_comprun " ${rest[0]} " " ${args[@]} " -q " $cur " | $post | tr ' \n' ' ' )
237+ selected=${selected% } # Strip trailing space not to repeat "-o nospace"
238+ if [ -n " $selected " ]; then
239+ COMPREPLY=(" $selected " )
240+ else
241+ COMPREPLY=(" $cur " )
242+ fi
243+ printf ' \e[5n'
244+ echo -e " \033[0m"
245+ return 0
246+ else
247+ _skim_handle_dynamic_completion " $cmd " " ${rest[@]} "
248+ fi
249+ }
250+
251+ _skim_path_completion () {
252+ __skim_generic_path_completion _skim_compgen_path " -m" " " " $@ "
253+ }
254+
255+ # Deprecated. No file only completion.
256+ _skim_file_completion () {
257+ _skim_path_completion " $@ "
258+ }
259+
260+ _skim_dir_completion () {
261+ __skim_generic_path_completion _skim_compgen_dir " " " /" " $@ "
262+ }
263+
264+ _skim_complete_kill () {
265+ local trigger=${SKIM_COMPLETION_TRIGGER-' **' }
266+ local cur=" ${COMP_WORDS[COMP_CWORD]} "
267+ if [[ -z " $cur " ]]; then
268+ COMP_WORDS[$COMP_CWORD ]=$trigger
269+ elif [[ " $cur " != * " $trigger " ]]; then
270+ return 1
271+ fi
272+
273+ _skim_proc_completion " $@ "
274+ }
275+
276+ _skim_proc_completion () {
277+ _skim_complete -m --preview ' echo {}' --preview-window down:3:wrap --min-height 15 -- " $@ " < <(
278+ command ps -ef | sed 1d
279+ )
280+ }
281+
282+ _skim_proc_completion_post () {
283+ awk ' {print $2}'
284+ }
285+
286+ _skim_host_completion () {
287+ _skim_complete --no-multi -- " $@ " < <(
288+ command cat <( command tail -n +1 ~ /.ssh/config ~ /.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i ' ^\s*host\(name\)\? ' | awk ' {for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v ' [*?]' ) \
289+ <( command grep -oE ' ^[[a-z0-9.,:-]+' ~ /.ssh/known_hosts | tr ' ,' ' \n' | tr -d ' [' | awk ' { print $1 " " $1 }' ) \
290+ <( command grep -v ' ^\s*\(#\|$\)' /etc/hosts | command grep -Fv ' 0.0.0.0' ) |
291+ awk ' {if (length($2) > 0) {print $2}}' | sort -u
292+ )
293+ }
294+
295+ _skim_var_completion () {
296+ _skim_complete -m -- " $@ " < <(
297+ declare -xp | sed ' s/=.*//' | sed ' s/.* //'
298+ )
299+ }
300+
301+ _skim_alias_completion () {
302+ _skim_complete -m -- " $@ " < <(
303+ alias | sed ' s/=.*//' | sed ' s/.* //'
304+ )
305+ }
306+
307+ d_cmds=" ${SKIM_COMPLETION_DIR_COMMANDS:- cd pushd rmdir} "
308+ a_cmds="
309+ awk cat diff diff3
310+ emacs emacsclient ex file ftp g++ gcc gvim head hg java
311+ javac ld less more mvim nvim patch perl python ruby
312+ sed sftp sort source tail tee uniq vi view vim wc xdg-open
313+ basename bunzip2 bzip2 chmod chown curl cp dirname du
314+ find git grep gunzip gzip hg jar
315+ ln ls mv open rm rsync scp
316+ svn tar unzip zip"
317+
318+ # Preserve existing completion
319+ eval " $( complete |
320+ sed -E ' /-F/!d; / _skim/d; ' " / ($( echo $d_cmds $a_cmds | sed ' s/ /|/g; s/+/\\+/g' ) )$/" ' !d' |
321+ __skim_orig_completion_filter) "
322+
323+ if type _completion_loader > /dev/null 2>&1 ; then
324+ _skim_completion_loader=1
325+ fi
326+
327+ __skim_defc () {
328+ local cmd func opts orig_var orig def
329+ cmd=" $1 "
330+ func=" $2 "
331+ opts=" $3 "
332+ orig_var=" _skim_orig_completion_${cmd// [^A-Za-z0-9_]/ _} "
333+ orig=" ${! orig_var} "
334+ if [ -n " $orig " ]; then
335+ printf -v def " $orig " " $func "
336+ eval " $def "
337+ else
338+ complete -F " $func " $opts " $cmd "
339+ fi
340+ }
341+
342+ # Anything
343+ for cmd in $a_cmds ; do
344+ __skim_defc " $cmd " _skim_path_completion " -o default -o bashdefault"
345+ done
346+
347+ # Directory
348+ for cmd in $d_cmds ; do
349+ __skim_defc " $cmd " _skim_dir_completion " -o nospace -o dirnames"
350+ done
351+
352+ # Kill completion (supports empty completion trigger)
353+ complete -F _skim_complete_kill -o default -o bashdefault kill
354+
355+ unset cmd d_cmds a_cmds
356+
357+ _skim_setup_completion () {
358+ local kind fn cmd
359+ kind=$1
360+ fn=_skim_${1} _completion
361+ if [[ $# -lt 2 ]] || ! type -t " $fn " > /dev/null; then
362+ echo " usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..."
363+ return 1
364+ fi
365+ shift
366+ eval " $( complete -p " $@ " 2> /dev/null | grep -v " $fn " | __skim_orig_completion_filter) "
367+ for cmd in " $@ " ; do
368+ case " $kind " in
369+ dir) __skim_defc " $cmd " " $fn " " -o nospace -o dirnames" ;;
370+ var) __skim_defc " $cmd " " $fn " " -o default -o nospace -v" ;;
371+ alias) __skim_defc " $cmd " " $fn " " -a" ;;
372+ * ) __skim_defc " $cmd " " $fn " " -o default -o bashdefault" ;;
373+ esac
374+ done
375+ }
376+
377+ # Environment variables / Aliases / Hosts
378+ _skim_setup_completion ' var' export unset
379+ _skim_setup_completion ' alias' unalias
380+ _skim_setup_completion ' host' ssh telnet
381+
97382fi
0 commit comments