blob: 4275462268d15491bcc7da18736661c0d29062cf (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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'
|