mirror of
https://github.com/hydroxycarbamide/dotfiles.git
synced 2025-05-04 20:09:08 -04:00
112 lines
3.2 KiB
Bash
112 lines
3.2 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Intelligently navigate tmux panes and Vim splits using the same keys.
|
|
# This also supports SSH tunnels where Vim is running on a remote host.
|
|
#
|
|
# +-------------+------------+-----------------------------+
|
|
# | inside Vim? | is Zoomed? | Action taken by key binding |
|
|
# +-------------+------------+-----------------------------+
|
|
# | No | No | Focus directional tmux pane |
|
|
# | No | Yes | Nothing: ignore key binding |
|
|
# | Yes | No | Seamlessly focus Vim / tmux |
|
|
# | Yes | Yes | Focus directional Vim split |
|
|
# +-------------+------------+-----------------------------+
|
|
#
|
|
# See https://sunaku.github.io/tmux-select-pane.html for documentation.
|
|
|
|
get_tmux_option() { tmux show-option -gqv "$@" | grep . ;}
|
|
|
|
navigate=$(sed '1,/^exit #.*$/d; s/^ *#.*//; /^$/d' "$0")
|
|
navigate_left=" $navigate L 'tmux select-pane -L' 'tmux send-keys C-w h'"
|
|
navigate_down=" $navigate D 'tmux select-pane -D' 'tmux send-keys C-w j'"
|
|
navigate_up=" $navigate U 'tmux select-pane -U' 'tmux send-keys C-w k'"
|
|
navigate_right="$navigate R 'tmux select-pane -R' 'tmux send-keys C-w l'"
|
|
navigate_back=" $navigate l 'tmux select-pane -l || tmux select-pane -t1'\
|
|
'tmux send-keys C-w p' \
|
|
'pane_is_zoomed' "
|
|
|
|
for direction in left down up right back; do
|
|
option="@navigate-$direction"
|
|
handler="navigate_$direction"
|
|
if key=$(get_tmux_option "$option"); then
|
|
eval "action=\$$handler" # resolve handler variable
|
|
tmux bind-key $key run-shell -b ": $option; $action"
|
|
fi
|
|
done
|
|
|
|
exit #------------------------------------------------------------------------
|
|
|
|
# interpolate tmux values ONCE at "compile time"
|
|
# (this is the reason for the double ## escapes)
|
|
pane_title="#{q:pane_title}"
|
|
pane_current_command="#{q:pane_current_command}"
|
|
window_zoomed_flag=#{window_zoomed_flag}
|
|
|
|
pane_is_zoomed() {
|
|
test $window_zoomed_flag -eq 1
|
|
}
|
|
|
|
command_is_vim() {
|
|
case "${1%% *}" in
|
|
(vi|?vi|vim*|?vim*|view|?view|vi??*)
|
|
true
|
|
;;
|
|
(*)
|
|
false
|
|
;;
|
|
esac
|
|
}
|
|
|
|
pane_contains_vim() {
|
|
command_is_vim "$pane_current_command" ||
|
|
command_is_vim "$pane_title"
|
|
}
|
|
|
|
pane_contains_neovim_terminal() {
|
|
case "$pane_title" in
|
|
(nvim?term://*)
|
|
true
|
|
;;
|
|
(*)
|
|
false
|
|
;;
|
|
esac
|
|
}
|
|
|
|
navigate() {
|
|
tmux_navigation_direction=$1
|
|
tmux_navigation_command=$2
|
|
vim_navigation_command=$3
|
|
vim_navigation_only_if=${4:-true}
|
|
|
|
# try navigating Vim
|
|
if pane_contains_vim && eval "$vim_navigation_only_if"; then
|
|
|
|
# parse navigable directions from Vim's title
|
|
vim_navigable_directions=${pane_title####* }
|
|
|
|
# if desired direction is navigable in Vim...
|
|
case "l$vim_navigable_directions" in (*$tmux_navigation_direction*)
|
|
|
|
# leave insert mode in NeoVim terminal
|
|
if pane_contains_neovim_terminal; then
|
|
tmux send-keys C-\\ C-n
|
|
fi
|
|
|
|
# navigate Vim and don't fall through
|
|
eval "$vim_navigation_command"
|
|
return
|
|
|
|
;;
|
|
esac
|
|
|
|
# otherwise fall through into tmux navigation
|
|
fi
|
|
|
|
# try navigating tmux
|
|
if ! pane_is_zoomed; then
|
|
eval "$tmux_navigation_command"
|
|
fi
|
|
}
|
|
|
|
navigate
|