sync shell scripts with fzf(6c9adea)

This commit is contained in:
Jinzhou Zhang 2020-10-18 11:41:50 +08:00
parent 0ad8553755
commit 6fdbe38f7a
5 changed files with 325 additions and 137 deletions

View file

@ -2,10 +2,10 @@
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/-completion.bash
# /_/ /___/_/ completion.bash
#
# - $SKIM_TMUX (default: 0)
# - $SKIM_TMUX_HEIGHT (default: '40%')
# - $SKIM_TMUX_OPTS (default: empty)
# - $SKIM_COMPLETION_TRIGGER (default: '**')
# - $SKIM_COMPLETION_OPTS (default: empty)
# copied and modified from https://github.com/junegunn/fzf/blob/master/shell/completion.bash
@ -38,9 +38,9 @@ bind '"\e[0n": redraw-current-line'
__skim_comprun() {
if [ "$(type -t _skim_comprun 2>&1)" = function ]; then
_skim_comprun "$@"
elif [ -n "$TMUX_PANE" ] && [ "${SKIM_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ]; then
elif [ -n "$TMUX_PANE" ] && { [ "${SKIM_TMUX:-0}" != 0 ] || [ -n "$SKIM_TMUX_OPTS" ]; }; then
shift
sk-tmux -d "${SKIM_TMUX_HEIGHT:-40%}" "$@"
sk-tmux ${SKIM_TMUX_OPTS:--d${SKIM_TMUX_HEIGHT:-40%}} -- "$@"
else
shift
sk "$@"
@ -191,6 +191,27 @@ __skim_generic_path_completion() {
}
_skim_complete() {
# Split arguments around --
local args rest str_arg i sep
args=("$@")
sep=
for i in "${!args[@]}"; do
if [[ "${args[$i]}" = -- ]]; then
sep=$i
break
fi
done
if [[ -n "$sep" ]]; then
str_arg=
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
args=("${args[@]:0:$sep}")
else
str_arg=$1
args=()
shift
rest=("$@")
fi
local cur selected trigger cmd post
post="$(caller 0 | awk '{print $2}')_post"
type -t "$post" > /dev/null 2>&1 || post=cat
@ -201,7 +222,7 @@ _skim_complete() {
if [[ "$cur" == *"$trigger" ]]; then
cur=${cur:0:${#cur}-${#trigger}}
selected=$(cat | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS $1" __skim_comprun "$2" -q "$cur" | $post | tr '\n' ' ')
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' ' ')
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
if [ -n "$selected" ]; then
COMPREPLY=("$selected")
@ -211,8 +232,7 @@ _skim_complete() {
printf '\e[5n'
return 0
else
shift
_skim_handle_dynamic_completion "$cmd" "$@"
_skim_handle_dynamic_completion "$cmd" "${rest[@]}"
fi
}
@ -230,22 +250,30 @@ _skim_dir_completion() {
}
_skim_complete_kill() {
[ -n "${COMP_WORDS[COMP_CWORD]}" ] && return 1
local selected
selected=$(command ps -ef | sed 1d | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-50%} --min-height 15 --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS --preview 'echo {}' --preview-window down:3:wrap" __skim_comprun "kill" -m | awk '{print $2}' | tr '\n' ' ')
selected=${selected% }
printf '\e[5n'
if [ -n "$selected" ]; then
COMPREPLY=( "$selected" )
return 0
local trigger=${SKIM_COMPLETION_TRIGGER-'**'}
local cur="${COMP_WORDS[COMP_CWORD]}"
if [[ -z "$cur" ]]; then
COMP_WORDS[$COMP_CWORD]=$trigger
elif [[ "$cur" != *"$trigger" ]]; then
return 1
fi
_skim_proc_completion "$@"
}
_skim_proc_completion() {
_skim_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
command ps -ef | sed 1d
)
}
_skim_proc_completion_post() {
awk '{print $2}'
}
_skim_host_completion() {
_skim_complete '--no-multi' "$@" < <(
cat <(cat ~/.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 '[*?]') \
_skim_complete --no-multi -- "$@" < <(
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 '[*?]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
awk '{if (length($2) > 0) {print $2}}' | sort -u
@ -253,13 +281,13 @@ _skim_host_completion() {
}
_skim_var_completion() {
_skim_complete '-m' "$@" < <(
_skim_complete -m -- "$@" < <(
declare -xp | sed 's/=.*//' | sed 's/.* //'
)
}
_skim_alias_completion() {
_skim_complete '-m' "$@" < <(
_skim_complete -m -- "$@" < <(
alias | sed 's/=.*//' | sed 's/.* //'
)
}
@ -277,11 +305,10 @@ a_cmds="
find git grep gunzip gzip hg jar
ln ls mv open rm rsync scp
svn tar unzip zip"
x_cmds="kill"
# Preserve existing completion
eval "$(complete |
sed -E '/-F/!d; / _skim/d; '"/ ($(echo $d_cmds $a_cmds $x_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' |
sed -E '/-F/!d; / _skim/d; '"/ ($(echo $d_cmds $a_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' |
__skim_orig_completion_filter)"
if type _completion_loader > /dev/null 2>&1; then
@ -313,17 +340,17 @@ for cmd in $d_cmds; do
__skim_defc "$cmd" _skim_dir_completion "-o nospace -o dirnames"
done
# Kill completion
# Kill completion (supports empty completion trigger)
complete -F _skim_complete_kill -o default -o bashdefault kill
unset cmd d_cmds a_cmds x_cmds
unset cmd d_cmds a_cmds
_skim_setup_completion() {
local kind fn cmd
kind=$1
fn=_skim_${1}_completion
if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then
echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host COMMANDS..."
echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..."
return 1
fi
shift

View file

@ -2,14 +2,79 @@
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/-completion.zsh
# /_/ /___/_/ completion.zsh
#
# - $SKIM_TMUX (default: 0)
# - $SKIM_TMUX_HEIGHT (default: '40%')
# - $SKIM_TMUX_OPTS (default: '-d 40%')
# - $SKIM_COMPLETION_TRIGGER (default: '**')
# - $SKIM_COMPLETION_OPTS (default: empty)
if [[ $- =~ i ]]; then
# Both branches of the following `if` do the same thing -- define
# __skim_completion_options such that `eval $__skim_completion_options` sets
# all options to the same values they currently have. We'll do just that at
# the bottom of the file after changing options to what we prefer.
#
# IMPORTANT: Until we get to the `emulate` line, all words that *can* be quoted
# *must* be quoted in order to prevent alias expansion. In addition, code must
# be written in a way works with any set of zsh options. This is very tricky, so
# careful when you change it.
#
# Start by loading the builtin zsh/parameter module. It provides `options`
# associative array that stores current shell options.
if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
# This is the fast branch and it gets taken on virtually all Zsh installations.
#
# ${(kv)options[@]} expands to array of keys (option names) and values ("on"
# or "off"). The subsequent expansion# with (j: :) flag joins all elements
# together separated by spaces. __skim_completion_options ends up with a value
# like this: "options=(shwordsplit off aliases on ...)".
__skim_completion_options="options=(${(j: :)${(kv)options[@]}})"
else
# This branch is much slower because it forks to get the names of all
# zsh options. It's possible to eliminate this fork but it's not worth the
# trouble because this branch gets taken only on very ancient or broken
# zsh installations.
() {
# That `()` above defines an anonymous function. This is essentially a scope
# for local parameters. We use it to avoid polluting global scope.
'local' '__skim_opt'
__skim_completion_options="setopt"
# `set -o` prints one line for every zsh option. Each line contains option
# name, some spaces, and then either "on" or "off". We just want option names.
# Expansion with (@f) flag splits a string into lines. The outer expansion
# removes spaces and everything that follow them on every line. __skim_opt
# ends up iterating over option names: shwordsplit, aliases, etc.
for __skim_opt in "${(@)${(@f)$(set -o)}%% *}"; do
if [[ -o "$__skim_opt" ]]; then
# Option $__skim_opt is currently on, so remember to set it back on.
__skim_completion_options+=" -o $__skim_opt"
else
# Option $__skim_opt is currently off, so remember to set it back off.
__skim_completion_options+=" +o $__skim_opt"
fi
done
# The value of __skim_completion_options here looks like this:
# "setopt +o shwordsplit -o aliases ..."
}
fi
# Enable the default zsh options (those marked with <Z> in `man zshoptions`)
# but without `aliases`. Aliases in functions are expanded when functions are
# defined, so if we disable aliases here, we'll be sure to have no pesky
# aliases in any of our functions. This way we won't need prefix every
# command with `command` or to quote every word to defend against global
# aliases. Note that `aliases` is not the only option that's important to
# control. There are several others that could wreck havoc if they are set
# to values we don't expect. With the following `emulate` command we
# sidestep this issue entirely.
'emulate' 'zsh' '-o' 'no_aliases'
# This brace is the start of try-always block. The `always` part is like
# `finally` in lesser languages. We use it to *always* restore user options.
{
# Bail out if not interactive shell.
[[ -o interactive ]] || return 0
# To use custom commands instead of find, override _skim_compgen_{path,dir}
if ! declare -f _skim_compgen_path > /dev/null; then
@ -34,9 +99,13 @@ fi
__skim_comprun() {
if [[ "$(type _skim_comprun 2>&1)" =~ function ]]; then
_skim_comprun "$@"
elif [ -n "$TMUX_PANE" ] && [ "${SKIM_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ]; then
elif [ -n "$TMUX_PANE" ] && { [ "${SKIM_TMUX:-0}" != 0 ] || [ -n "$SKIM_TMUX_OPTS" ]; }; then
shift
sk-tmux -d "${SKIM_TMUX_HEIGHT:-40%}" "$@"
if [ -n "$SKIM_TMUX_OPTS" ]; then
sk-tmux ${(Q)${(Z+n+)SKIM_TMUX_OPTS}} -- "$@"
else
sk-tmux -d ${SKIM_TMUX_HEIGHT:-40%} -- "$@"
fi
else
shift
sk "$@"
@ -48,6 +117,7 @@ __skim_extract_command() {
local token tokens
tokens=(${(z)1})
for token in $tokens; do
token=${(Q)token}
if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
echo "$token"
return
@ -107,16 +177,37 @@ _skim_feed_fifo() (
)
_skim_complete() {
local fifo skim_opts lbuf cmd matches post
setopt localoptions ksh_arrays
# Split arguments around --
local args rest str_arg i sep
args=("$@")
sep=
for i in {0..${#args[@]}}; do
if [[ "${args[$i]}" = -- ]]; then
sep=$i
break
fi
done
if [[ -n "$sep" ]]; then
str_arg=
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
args=("${args[@]:0:$sep}")
else
str_arg=$1
args=()
shift
rest=("$@")
fi
local fifo lbuf cmd matches post
fifo="${TMPDIR:-/tmp}/skim-complete-fifo-$$"
skim_opts=$1
lbuf=$2
lbuf=${rest[0]}
cmd=$(__skim_extract_command "$lbuf")
post="${funcstack[2]}_post"
post="${funcstack[1]}_post"
type $post > /dev/null 2>&1 || post=cat
_skim_feed_fifo "$fifo"
matches=$(cat "$fifo" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS" __skim_comprun "$cmd" ${(Q)${(Z+n+)skim_opts}} -q "${(Q)prefix}" | $post | tr '\n' ' ')
matches=$(SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS $str_arg" __skim_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ')
if [ -n "$matches" ]; then
LBUFFER="$lbuf$matches"
fi
@ -125,16 +216,16 @@ _skim_complete() {
}
_skim_complete_telnet() {
_skim_complete '-m' "$@" < <(
_skim_complete --no-multi -- "$@" < <(
command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' |
awk '{if (length($2) > 0) {print $2}}' | sort -u
)
}
_skim_complete_ssh() {
_skim_complete '-m' "$@" < <(
_skim_complete --no-multi -- "$@" < <(
setopt localoptions nonomatch
command cat <(cat ~/.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 '[*?]') \
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 '[*?]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
awk '{if (length($2) > 0) {print $2}}' | sort -u
@ -142,23 +233,33 @@ _skim_complete_ssh() {
}
_skim_complete_export() {
_skim_complete '-m' "$@" < <(
_skim_complete -m -- "$@" < <(
declare -xp | sed 's/=.*//' | sed 's/.* //'
)
}
_skim_complete_unset() {
_skim_complete '-m' "$@" < <(
_skim_complete -m -- "$@" < <(
declare -xp | sed 's/=.*//' | sed 's/.* //'
)
}
_skim_complete_unalias() {
_skim_complete '-m' "$@" < <(
_skim_complete --no-multi -- "$@" < <(
alias | sed 's/=.*//'
)
}
_skim_complete_kill() {
_skim_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
command ps -ef | sed 1d
)
}
_skim_complete_kill_post() {
awk '{print $2}'
}
skim-completion() {
local tokens cmd prefix trigger tail matches lbuf d_cmds
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
@ -183,20 +284,21 @@ skim-completion() {
tokens=(${tokens[0,-2]})
fi
lbuf=$LBUFFER
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
# Kill completion (do not require trigger sequence)
if [ $cmd = kill -a ${LBUFFER[-1]} = ' ' ]; then
matches=$(command ps -ef | sed 1d | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-50%} --min-height 15 --reverse $SKIM_DEFAULT_OPTIONS $SKIM_COMPLETION_OPTS --preview 'echo {}' --preview-window down:3:wrap" __skim_comprun "$cmd" -m | awk '{print $2}' | tr '\n' ' ')
if [ -n "$matches" ]; then
LBUFFER="$LBUFFER$matches"
fi
zle reset-prompt
if [ "$cmd" = kill -a ${LBUFFER[-1]} = ' ' ]; then
tail=$trigger
tokens+=$trigger
lbuf="$lbuf$trigger"
fi
# Trigger sequence given
elif [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
d_cmds=(${=SKIM_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
[ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
[ -z "${tokens[-1]}" ] && lbuf=$LBUFFER || lbuf=${LBUFFER:0:-${#tokens[-1]}}
[ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}}
if eval "type _skim_complete_${cmd} > /dev/null"; then
prefix="$prefix" eval _skim_complete_${cmd} ${(q)lbuf}
@ -220,4 +322,8 @@ skim-completion() {
zle -N skim-completion
bindkey '^I' skim-completion
fi
} always {
# Restore the original options.
eval $__skim_completion_options
'unset' '__skim_completion_options'
}

View file

@ -1,3 +1,16 @@
# ____ ____
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/ key-bindings.bash
#
# - $SKIM_TMUX_OPTS
# - $SKIM_CTRL_T_COMMAND
# - $SKIM_CTRL_T_OPTS
# - $SKIM_CTRL_R_OPTS
# - $SKIM_ALT_C_COMMAND
# - $SKIM_ALT_C_OPTS
# Key bindings
# ------------
# copied and modified from https://github.com/junegunn/fzf/blob/master/shell/key-bindings.bash
@ -6,7 +19,7 @@ __skim_select__() {
-o -type f -print \
-o -type d -print \
-o -type l -print 2> /dev/null | cut -b3-"}"
eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_CTRL_T_OPTS" sk -m "$@" | while read -r item; do
eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_CTRL_T_OPTS" $(__skimcmd) -m "$@" | while read -r item; do
printf '%q ' "$item"
done
echo
@ -14,85 +27,70 @@ __skim_select__() {
if [[ $- =~ i ]]; then
__skim_use_tmux__() {
[ -n "$TMUX_PANE" ] && [ "${SKIM_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ]
}
__skimcmd() {
__skim_use_tmux__ &&
echo "sk-tmux -d${SKIM_TMUX_HEIGHT:-40%}" || echo "sk"
}
__skim_select_tmux__() {
local height
height=${SKIM_TMUX_HEIGHT:-40%}
if [[ $height =~ %$ ]]; then
height="-p ${height%\%}"
else
height="-l $height"
fi
tmux split-window $height "cd $(printf %q "$PWD"); SKIM_DEFAULT_OPTIONS=$(printf %q "$SKIM_DEFAULT_OPTIONS") PATH=$(printf %q "$PATH") SKIM_CTRL_T_COMMAND=$(printf %q "$SKIM_CTRL_T_COMMAND") SKIM_CTRL_T_OPTS=$(printf %q "$SKIM_CTRL_T_OPTS") bash -c 'source \"${BASH_SOURCE[0]}\"; RESULT=\"\$(__skim_select__ --no-height)\"; tmux setb -b skim \"\$RESULT\" \\; pasteb -b skim -t $TMUX_PANE \\; deleteb -b skim || tmux send-keys -t $TMUX_PANE \"\$RESULT\"'"
[ -n "$TMUX_PANE" ] && { [ "${SKIM_TMUX:-0}" != 0 ] || [ -n "$SKIM_TMUX_OPTS" ]; } &&
echo "sk-tmux ${SKIM_TMUX_OPTS:--d${SKIM_TMUX_HEIGHT:-40%}} -- " || echo "sk"
}
skim-file-widget() {
if __skim_use_tmux__; then
__skim_select_tmux__
else
local selected="$(__skim_select__)"
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
fi
local selected="$(__skim_select__)"
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
}
__skim_cd__() {
local cmd dir
cmd="${SKIM_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
-o -type d -print 2> /dev/null | cut -b3-"}"
dir=$(eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS" $(__skimcmd) -m) && printf 'cd %q' "$dir"
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"
}
__skim_history__() (
local line
line=$(
__skim_history__() {
local output
output=$(
builtin fc -lnr -2147483648 |
perl -p -l0 -e 'BEGIN { getc; $/ = "\n\t" } s/^[ *]//; $_ = '"$1"' - $. . "\t$_"' |
SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS --tiebreak=score,index $SKIM_CTRL_R_OPTS -m --read0" $(__skimcmd)
)
echo "${line#*$'\t'}"
)
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{$_}++' |
SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS --no-multi --read0" $(__skimcmd) --query "$READLINE_LINE"
) || return
READLINE_LINE=${output#*$'\t'}
if [ -z "$READLINE_POINT" ]; then
echo "$READLINE_LINE"
else
READLINE_POINT=0x7fffffff
fi
}
# Required to refresh the prompt after skim
bind -m emacs-standard '"\er": redraw-current-line'
# CTRL-T - Paste the selected file path into the command line
if [ $BASH_VERSINFO -gt 3 ]; then
bind -m emacs-standard -x '"\C-t": "skim-file-widget"'
elif __skim_use_tmux__; then
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__skim_select_tmux__`\e\C-e\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
else
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__skim_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
fi
# CTRL-R - Paste the selected command from history into the command line
bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u__skim_history__ $HISTCMD\e\C-e`"\C-a"`\C-e\e\C-e\er"'
# ALT-C - cd into the selected directory
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__skim_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
bind -m vi-command '"\C-z": emacs-editing-mode'
bind -m vi-insert '"\C-z": emacs-editing-mode'
bind -m emacs-standard '"\C-z": vi-editing-mode'
# CTRL-T - Paste the selected file path into the command line
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
# CTRL-T - Paste the selected file path into the command line
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__skim_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
# CTRL-R - Paste the selected command from history into the command line
bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
# CTRL-R - Paste the selected command from history into the command line
bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u"$(__skim_history__)"\e\C-e\er"'
bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
else
# CTRL-T - Paste the selected file path into the command line
bind -m emacs-standard -x '"\C-t": skim-file-widget'
bind -m vi-command -x '"\C-t": skim-file-widget'
bind -m vi-insert -x '"\C-t": skim-file-widget'
# CTRL-R - Paste the selected command from history into the command line
bind -m emacs-standard -x '"\C-r": __skim_history__'
bind -m vi-command -x '"\C-r": __skim_history__'
bind -m vi-insert -x '"\C-r": __skim_history__'
fi
# ALT-C - cd into the selected directory
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__skim_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'

View file

@ -1,6 +1,21 @@
#!/bin/fish
# completion.fish
# copied and modified from https://github.com/junegunn/fzf/blob/master/shell/completion.fish
# ____ ____
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/ key-bindings.fish
#
# - $SKIM_TMUX_OPTS
# - $SKIM_CTRL_T_COMMAND
# - $SKIM_CTRL_T_OPTS
# - $SKIM_CTRL_R_OPTS
# - $SKIM_ALT_C_COMMAND
# - $SKIM_ALT_C_OPTS
# Key bindings
# ------------
function skim_key_bindings
# Store current token in $dir as root for the 'find' command
@ -11,13 +26,13 @@ function skim_key_bindings
# "-path \$dir'*/\\.*'" matches hidden files/folders inside $dir but not
# $dir itself, even if hidden.
set -q SKIM_CTRL_T_COMMAND; or set -l SKIM_CTRL_T_COMMAND "
test -n "$SKIM_CTRL_T_COMMAND"; or set -l SKIM_CTRL_T_COMMAND "
command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
-o -type f -print \
-o -type d -print \
-o -type l -print 2> /dev/null | sed 's@^\./@@'"
set -q SKIM_TMUX_HEIGHT; or set SKIM_TMUX_HEIGHT 40%
test -n "$SKIM_TMUX_HEIGHT"; or set SKIM_TMUX_HEIGHT 40%
begin
set -lx SKIM_DEFAULT_OPTIONS "--height $SKIM_TMUX_HEIGHT --reverse $SKIM_DEFAULT_OPTIONS $SKIM_CTRL_T_OPTS"
eval "$SKIM_CTRL_T_COMMAND | "(__skimcmd)' -m --query "'$skim_query'"' | while read -l r; set result $result $r; end
@ -37,9 +52,9 @@ function skim_key_bindings
end
function skim-history-widget -d "Show command history"
set -q SKIM_TMUX_HEIGHT; or set SKIM_TMUX_HEIGHT 40%
test -n "$SKIM_TMUX_HEIGHT"; or set SKIM_TMUX_HEIGHT 40%
begin
set -lx SKIM_DEFAULT_OPTIONS "--height $SKIM_TMUX_HEIGHT $SKIM_DEFAULT_OPTIONS --tiebreak=score,index --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS -m"
set -lx SKIM_DEFAULT_OPTIONS "--height $SKIM_TMUX_HEIGHT $SKIM_DEFAULT_OPTIONS --tiebreak=index --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS --no-multi"
set -l FISH_MAJOR (echo $version | cut -f1 -d.)
set -l FISH_MINOR (echo $version | cut -f2 -d.)
@ -63,13 +78,13 @@ function skim_key_bindings
set -l dir $commandline[1]
set -l skim_query $commandline[2]
set -q SKIM_ALT_C_COMMAND; or set -l SKIM_ALT_C_COMMAND "
test -n "$SKIM_ALT_C_COMMAND"; or set -l SKIM_ALT_C_COMMAND "
command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
-o -type d -print 2> /dev/null | sed 's@^\./@@'"
set -q SKIM_TMUX_HEIGHT; or set SKIM_TMUX_HEIGHT 40%
test -n "$SKIM_TMUX_HEIGHT"; or set SKIM_TMUX_HEIGHT 40%
begin
set -lx SKIM_DEFAULT_OPTIONS "--height $SKIM_TMUX_HEIGHT --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS"
eval "$SKIM_ALT_C_COMMAND | "(__skimcmd)' -m --query "'$skim_query'"' | read -l result
eval "$SKIM_ALT_C_COMMAND | "(__skimcmd)' --no-multi --query "'$skim_query'"' | read -l result
if [ -n "$result" ]
cd $result
@ -83,10 +98,12 @@ function skim_key_bindings
end
function __skimcmd
set -q SKIM_TMUX; or set SKIM_TMUX 0
set -q SKIM_TMUX_HEIGHT; or set SKIM_TMUX_HEIGHT 40%
if [ $SKIM_TMUX -eq 1 ]
echo "sk-tmux -d$SKIM_TMUX_HEIGHT"
test -n "$SKIM_TMUX"; or set SKIM_TMUX 0
test -n "$SKIM_TMUX_HEIGHT"; or set SKIM_TMUX_HEIGHT 40%
if [ -n "$SKIM_TMUX_OPTS" ]
echo "sk-tmux $SKIM_TMUX_OPTS -- "
else if [ $SKIM_TMUX -eq 1 ]
echo "sk-tmux -d$SKIM_TMUX_HEIGHT -- "
else
echo "sk"
end
@ -113,12 +130,12 @@ function skim_key_bindings
else
set dir (__skim_get_dir $commandline)
if [ "$dir" = "." -a (string sub -l 1 $commandline) != '.' ]
if [ "$dir" = "." -a (string sub -l 1 -- $commandline) != '.' ]
# if $dir is "." but commandline is not a relative path, this means no file path found
set skim_query $commandline
else
# Also remove trailing slash after dir, to "split" input properly
set skim_query (string replace -r "^$dir/?" '' "$commandline")
set skim_query (string replace -r "^$dir/?" -- '' "$commandline")
end
end
@ -130,15 +147,15 @@ function skim_key_bindings
set dir $argv
# Strip all trailing slashes. Ignore if $dir is root dir (/)
if [ (string length $dir) -gt 1 ]
set dir (string replace -r '/*$' '' $dir)
if [ (string length -- $dir) -gt 1 ]
set dir (string replace -r '/*$' -- '' $dir)
end
# Iteratively check if dir exists and strip tail end of path
while [ ! -d "$dir" ]
# If path is absolute, this can keep going until ends up at /
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
set dir (dirname "$dir")
set dir (dirname -- "$dir")
end
echo $dir

View file

@ -1,7 +1,42 @@
# ____ ____
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/ key-bindings.zsh
#
# - $SKIM_TMUX_OPTS
# - $SKIM_CTRL_T_COMMAND
# - $SKIM_CTRL_T_OPTS
# - $SKIM_CTRL_R_OPTS
# - $SKIM_ALT_C_COMMAND
# - $SKIM_ALT_C_OPTS
# Key bindings
# ------------
# copied and modified from https://github.com/junegunn/fzf/blob/master/shell/key-bindings.zsh
if [[ $- == *i* ]]; then
# The code at the top and the bottom of this file is the same as in completion.zsh.
# Refer to that file for explanation.
if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
__skim_key_bindings_options="options=(${(j: :)${(kv)options[@]}})"
else
() {
__skim_key_bindings_options="setopt"
'local' '__skim_opt'
for __skim_opt in "${(@)${(@f)$(set -o)}%% *}"; do
if [[ -o "$__skim_opt" ]]; then
__skim_key_bindings_options+=" -o $__skim_opt"
else
__skim_key_bindings_options+=" +o $__skim_opt"
fi
done
}
fi
'emulate' 'zsh' '-o' 'no_aliases'
{
[[ -o interactive ]] || return 0
# CTRL-T - Paste the selected file path(s) into the command line
__fsel() {
@ -22,13 +57,9 @@ __fsel() {
return $ret
}
__skim_use_tmux__() {
[ -n "$TMUX_PANE" ] && [ "${SKIM_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ]
}
__skimcmd() {
__skim_use_tmux__ &&
echo "sk-tmux -d${SKIM_TMUX_HEIGHT:-40%}" || echo "sk"
[ -n "$TMUX_PANE" ] && { [ "${SKIM_TMUX:-0}" != 0 ] || [ -n "$SKIM_TMUX_OPTS" ]; } &&
echo "sk-tmux ${SKIM_TMUX_OPTS:--d${SKIM_TMUX_HEIGHT:-40%}} -- " || echo "sk"
}
skim-file-widget() {
@ -57,16 +88,22 @@ skim-cd-widget() {
setopt localoptions pipefail no_aliases 2> /dev/null
REPORTTIME_=$REPORTTIME
unset REPORTTIME
local dir="$(eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS" $(__skimcmd) -m)"
local dir="$(eval "$cmd" | SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} --reverse $SKIM_DEFAULT_OPTIONS $SKIM_ALT_C_OPTS" $(__skimcmd) --no-multi)"
REPORTTIME=$REPORTTIME_
unset REPORTTIME_
if [[ -z "$dir" ]]; then
zle redisplay
return 0
fi
cd "$dir"
unset dir # ensure this doesn't end up appearing in prompt expansion
if [ -z "$BUFFER" ]; then
BUFFER="cd ${(q)dir}"
zle accept-line
else
print -sr "cd ${(q)dir}"
cd "$dir"
fi
local ret=$?
unset dir # ensure this doesn't end up appearing in prompt expansion
zle skim-redraw-prompt
return $ret
}
@ -77,8 +114,8 @@ bindkey '\ec' skim-cd-widget
skim-history-widget() {
local selected num
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
selected=( $(fc -rl 1 |
SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS -n2..,.. --tiebreak=score,index $SKIM_CTRL_R_OPTS --query=${(qqq)LBUFFER} -m" $(__skimcmd)) )
selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\**\s+(.*)/, $1)}++' |
SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS --query=${(qqq)LBUFFER} --no-multi" $(__skimcmd)) )
local ret=$?
if [ -n "$selected" ]; then
num=$selected[1]
@ -92,4 +129,7 @@ skim-history-widget() {
zle -N skim-history-widget
bindkey '^R' skim-history-widget
fi
} always {
eval $__skim_key_bindings_options
'unset' '__skim_key_bindings_options'
}