aboutsummaryrefslogtreecommitdiff
path: root/dot_config/hypr/scripts/executable_tmux-smart-nav
diff options
context:
space:
mode:
authorpablu <me@pablu.de>2026-09-17 17:05:03 +0200
committerpablu <me@pablu.de>2026-09-17 17:05:03 +0200
commitf8312a59c775c740d9af173fafa65ab7e731e03e (patch)
treea54a9274376f20bbb35f07bccfeab8aef542fa0e /dot_config/hypr/scripts/executable_tmux-smart-nav
parent0716da5eef605977b804f34f265979cf39be844b (diff)
update codex config to not contain local project dirs, update .tmux.conf only for gentoo, make tmux work with hyprland
Diffstat (limited to 'dot_config/hypr/scripts/executable_tmux-smart-nav')
-rw-r--r--dot_config/hypr/scripts/executable_tmux-smart-nav105
1 files changed, 105 insertions, 0 deletions
diff --git a/dot_config/hypr/scripts/executable_tmux-smart-nav b/dot_config/hypr/scripts/executable_tmux-smart-nav
new file mode 100644
index 0000000..4275462
--- /dev/null
+++ b/dot_config/hypr/scripts/executable_tmux-smart-nav
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+
+set -u
+
+direction="${1:-}"
+terminal_pid="${2:-}"
+
+case "$direction" in
+ left)
+ tmux_key="C-h"
+ ;;
+ right)
+ tmux_key="C-l"
+ ;;
+ up)
+ tmux_key="C-k"
+ ;;
+ down)
+ tmux_key="C-j"
+ ;;
+ *)
+ printf 'usage: %s <left|right|up|down> <terminal-pid>\n' "$0" >&2
+ exit 2
+ ;;
+esac
+
+if [[ ! "$terminal_pid" =~ ^[0-9]+$ ]] || ! command -v tmux >/dev/null 2>&1; then
+ printf 'hyprland\n'
+ exit
+fi
+
+# A tmux client is a descendant of the terminal process that owns it. This
+# avoids acting on a client in another Ghostty window.
+is_descendant_of() {
+ local pid="$1"
+ local parent
+
+ while [[ "$pid" =~ ^[0-9]+$ && "$pid" -gt 1 ]]; do
+ if [[ "$pid" == "$terminal_pid" ]]; then
+ return 0
+ fi
+
+ parent="$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d '[:space:]')"
+ [[ -n "$parent" && "$parent" != "$pid" ]] || return 1
+ pid="$parent"
+ done
+
+ return 1
+}
+
+client_tty=""
+while read -r client_pid tty; do
+ if is_descendant_of "$client_pid"; then
+ client_tty="$tty"
+ break
+ fi
+done < <(tmux list-clients -F '#{client_pid} #{client_tty}' 2>/dev/null)
+
+if [[ -z "$client_tty" ]]; then
+ printf 'hyprland\n'
+ exit
+fi
+
+pane_id="$(tmux display-message -p -c "$client_tty" '#{pane_id}' 2>/dev/null)"
+pane_command="$(tmux display-message -p -c "$client_tty" '#{pane_current_command}' 2>/dev/null)"
+
+# Ghostty has one title for the whole tmux window, so it cannot identify the
+# focused pane's process. Ask Neovim through a pane-specific socket only when
+# tmux says this exact pane is running it.
+case "${pane_command,,}" in
+ nvim|vim)
+ safe_pane_id="${pane_id//[^a-zA-Z0-9_.-]/_}"
+ socket_path="${XDG_RUNTIME_DIR:-/tmp}/nvim-hypr-nav-pane-${safe_pane_id}.sock"
+ response="$(
+ printf 'nav:%s\n' "$direction" |
+ socat -T 0.25 -,ignoreeof "UNIX-CONNECT:$socket_path" 2>/dev/null || true
+ )"
+
+ if [[ "$response" == *success* ]]; then
+ printf 'handled\n'
+ exit
+ fi
+ ;;
+esac
+
+# Send the directional key through the matching client so tmux resolves it
+# against that client's own active pane. Its existing C-h/j/k/l bindings also
+# retain the configured Neovim handoff.
+at_edge="$(tmux display-message -p -c "$client_tty" "#{pane_at_${direction}}" 2>/dev/null)"
+
+if [[ -z "$pane_id" || "$at_edge" == "1" ]]; then
+ printf 'hyprland\n'
+ exit
+fi
+
+if tmux send-keys -c "$client_tty" -K "$tmux_key" >/dev/null 2>&1; then
+ selected_pane_id="$(tmux display-message -p -c "$client_tty" '#{pane_id}' 2>/dev/null)"
+
+ if [[ "$selected_pane_id" != "$pane_id" ]]; then
+ printf 'handled\n'
+ exit
+ fi
+fi
+
+printf 'hyprland\n'