#!/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 \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'