James Patrick
898500ffbb
I've reorganized some of the fzf dependency some. There are large number of resources I need from the fzf repo that I have been omitting because zplug does no work well with a repo that both has both bins and plugins. Instead I've been manually managing the fzf.zsh files and the fzf-tmux then using the binary from fzf-bin. This nominally worked for zsh it wasnone functioning for other things that used fzf as a dependency. Additionally this broke the rule of don't write what you don't have to mantra of this project.
202 lines
5.2 KiB
Bash
Executable File
202 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# fzf-tmux: starts fzf in a tmux pane
|
|
# usage: fzf-tmux [-u|-d [HEIGHT[%]]] [-l|-r [WIDTH[%]]] [--] [FZF OPTIONS]
|
|
|
|
fail() {
|
|
>&2 echo "$1"
|
|
exit 2
|
|
}
|
|
|
|
fzf="$(command -v fzf 2> /dev/null)" || fzf="$(dirname "$0")/fzf"
|
|
[[ -x "$fzf" ]] || fail 'fzf executable not found'
|
|
|
|
args=()
|
|
opt=""
|
|
skip=""
|
|
swap=""
|
|
close=""
|
|
term=""
|
|
[[ -n "$LINES" ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
|
|
[[ -n "$COLUMNS" ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
|
|
|
|
help() {
|
|
>&2 echo 'usage: fzf-tmux [-u|-d [HEIGHT[%]]] [-l|-r [WIDTH[%]]] [--] [FZF OPTIONS]
|
|
|
|
Layout
|
|
-u [HEIGHT[%]] Split above (up)
|
|
-d [HEIGHT[%]] Split below (down)
|
|
-l [WIDTH[%]] Split left
|
|
-r [WIDTH[%]] Split right
|
|
|
|
(default: -d 50%)
|
|
'
|
|
exit
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
arg="$1"
|
|
shift
|
|
[[ -z "$skip" ]] && case "$arg" in
|
|
-)
|
|
term=1
|
|
;;
|
|
--help)
|
|
help
|
|
;;
|
|
--version)
|
|
echo "fzf-tmux (with fzf $("$fzf" --version))"
|
|
exit
|
|
;;
|
|
-w*|-h*|-d*|-u*|-r*|-l*)
|
|
if [[ "$arg" =~ ^.[lrw] ]]; then
|
|
opt="-h"
|
|
if [[ "$arg" =~ ^.l ]]; then
|
|
opt="$opt -d"
|
|
swap="; swap-pane -D ; select-pane -L"
|
|
close="; tmux swap-pane -D"
|
|
fi
|
|
else
|
|
opt=""
|
|
if [[ "$arg" =~ ^.u ]]; then
|
|
opt="$opt -d"
|
|
swap="; swap-pane -D ; select-pane -U"
|
|
close="; tmux swap-pane -D"
|
|
fi
|
|
fi
|
|
if [[ ${#arg} -gt 2 ]]; then
|
|
size="${arg:2}"
|
|
else
|
|
if [[ "$1" =~ ^[0-9]+%?$ ]]; then
|
|
size="$1"
|
|
shift
|
|
else
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
if [[ "$size" =~ %$ ]]; then
|
|
size=${size:0:((${#size}-1))}
|
|
if [[ -n "$swap" ]]; then
|
|
opt="$opt -p $(( 100 - size ))"
|
|
else
|
|
opt="$opt -p $size"
|
|
fi
|
|
else
|
|
if [[ -n "$swap" ]]; then
|
|
if [[ "$arg" =~ ^.l ]]; then
|
|
max=$columns
|
|
else
|
|
max=$lines
|
|
fi
|
|
size=$(( max - size ))
|
|
[[ $size -lt 0 ]] && size=0
|
|
opt="$opt -l $size"
|
|
else
|
|
opt="$opt -l $size"
|
|
fi
|
|
fi
|
|
;;
|
|
--)
|
|
# "--" can be used to separate fzf-tmux options from fzf options to
|
|
# avoid conflicts
|
|
skip=1
|
|
continue
|
|
;;
|
|
*)
|
|
args+=("$arg")
|
|
;;
|
|
esac
|
|
[[ -n "$skip" ]] && args+=("$arg")
|
|
done
|
|
|
|
if [[ -z "$TMUX" || "$opt" =~ ^-h && "$columns" -le 40 || ! "$opt" =~ ^-h && "$lines" -le 15 ]]; then
|
|
"$fzf" "${args[@]}"
|
|
exit $?
|
|
fi
|
|
|
|
# --height option is not allowed
|
|
args+=("--no-height")
|
|
|
|
# Handle zoomed tmux pane by moving it to a temp window
|
|
if tmux list-panes -F '#F' | grep -q Z; then
|
|
zoomed=1
|
|
original_window=$(tmux display-message -p "#{window_id}")
|
|
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
|
|
tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
|
|
fi
|
|
|
|
set -e
|
|
|
|
# Clean up named pipes on exit
|
|
id=$RANDOM
|
|
argsf="${TMPDIR:-/tmp}/fzf-args-$id"
|
|
fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
|
|
fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
|
|
fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
|
|
cleanup() {
|
|
\rm -f $argsf $fifo1 $fifo2 $fifo3
|
|
|
|
# Restore tmux window options
|
|
if [[ "${#tmux_win_opts[@]}" -gt 0 ]]; then
|
|
eval "tmux ${tmux_win_opts[@]}"
|
|
fi
|
|
|
|
# Remove temp window if we were zoomed
|
|
if [[ -n "$zoomed" ]]; then
|
|
tmux display-message -p "#{window_id}" > /dev/null
|
|
tmux swap-pane -t $original_window \; \
|
|
select-window -t $original_window \; \
|
|
kill-window -t $tmp_window \; \
|
|
resize-pane -Z
|
|
fi
|
|
|
|
if [ $# -gt 0 ]; then
|
|
trap - EXIT
|
|
exit 130
|
|
fi
|
|
}
|
|
trap 'cleanup 1' SIGUSR1
|
|
trap 'cleanup' EXIT
|
|
|
|
envs="env TERM=$TERM "
|
|
[[ -n "$FZF_DEFAULT_OPTS" ]] && envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
|
|
[[ -n "$FZF_DEFAULT_COMMAND" ]] && envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
|
|
|
|
mkfifo -m o+w $fifo2
|
|
mkfifo -m o+w $fifo3
|
|
|
|
# Build arguments to fzf
|
|
opts=""
|
|
for arg in "${args[@]}"; do
|
|
arg="${arg//\\/\\\\}"
|
|
arg="${arg//\"/\\\"}"
|
|
arg="${arg//\`/\\\`}"
|
|
arg="${arg//$/\\$}"
|
|
opts="$opts \"$arg\""
|
|
done
|
|
|
|
pppid=$$
|
|
echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" > $argsf
|
|
close="; trap - EXIT SIGINT SIGTERM $close"
|
|
|
|
tmux_win_opts=( $(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/') )
|
|
|
|
if [[ -n "$term" ]] || [[ -t 0 ]]; then
|
|
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
|
|
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux set-window-option synchronize-panes off \;\
|
|
set-window-option remain-on-exit off \;\
|
|
split-window $opt "$envs bash -c 'cd $(printf %q "$PWD"); exec -a fzf bash $argsf'" $swap \
|
|
> /dev/null 2>&1
|
|
else
|
|
mkfifo $fifo1
|
|
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; echo \$? > $fifo3 $close" >> $argsf
|
|
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux set-window-option synchronize-panes off \;\
|
|
set-window-option remain-on-exit off \;\
|
|
split-window $opt "$envs bash -c 'exec -a fzf bash $argsf'" $swap \
|
|
> /dev/null 2>&1
|
|
cat <&0 > $fifo1 &
|
|
fi
|
|
cat $fifo2
|
|
exit "$(cat $fifo3)"
|
|
|