blob: 36d27aae6b0e7ff5789c6aa6290bc95a0b9a717e (
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
#!/usr/bin/env bash
set -u
direction="${1:-}"
terminal_pid="${2:-}"
case "$direction" in
left|right|up|down)
;;
*)
printf 'usage: %s <left|right|up|down> <terminal-pid>\n' "$0" >&2
exit 2
;;
esac
# Window titles can change with the workspace. Find a foreground Herdr
# process belonging to this terminal instead of relying on its title.
is_in_terminal() {
local pid="$1"
local parent
while [[ "$pid" =~ ^[0-9]+$ && "$pid" -gt 1 ]]; do
[[ "$pid" == "$terminal_pid" ]] && return 0
parent="$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d '[:space:]')"
[[ -n "$parent" && "$parent" != "$pid" ]] || return 1
pid="$parent"
done
return 1
}
herdr_found=false
if [[ "$terminal_pid" =~ ^[0-9]+$ ]]; then
while read -r pid process_group foreground_group; do
# The server has no foreground terminal; a suspended client is not active.
if [[ "$foreground_group" -gt 0 && "$process_group" == "$foreground_group" ]] &&
is_in_terminal "$pid"; then
herdr_found=true
break
fi
done < <(ps -C herdr -o pid=,pgid=,tpgid= 2>/dev/null)
fi
if [[ "$herdr_found" != true ]]; then
printf 'not-herdr\n'
exit
fi
herdr_bin="${HERDR_BIN_PATH:-$HOME/.local/share/mise/installs/herdr/latest/herdr}"
if [[ ! -x "$herdr_bin" ]]; then
printf 'hyprland\n'
exit
fi
handled() {
printf 'handled\n'
exit
}
fall_through() {
printf 'hyprland\n'
exit
}
current="$("$herdr_bin" pane current --current 2>/dev/null)" || {
fall_through
}
pane_id="$(jq -r '.result.pane.pane_id // empty' <<<"$current")"
if [[ -z "$pane_id" ]]; then
fall_through
fi
process_info="$(
"$herdr_bin" pane process-info --pane "$pane_id" 2>/dev/null || true
)"
nvim_pid="$(
jq -r '
[
(.result.process_info.foreground_processes // [])[]
| select(
((.name // "") | ascii_downcase) == "nvim"
or ((.name // "") | ascii_downcase) == "vim"
)
| .pid
][0] // empty
' <<<"$process_info" 2>/dev/null
)"
if [[ -n "$nvim_pid" ]]; then
safe_pane_id="${pane_id//[^a-zA-Z0-9_.-]/_}"
runtime_dir="${XDG_RUNTIME_DIR:-/tmp}"
socket_path="$runtime_dir/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
handled
fi
fi
neighbor="$(
"$herdr_bin" pane neighbor \
--pane "$pane_id" \
--direction "$direction" \
2>/dev/null
)" || {
fall_through
}
# A zoomed pane deliberately falls through to Hyprland. Do not expose or
# navigate to another Herdr pane.
if jq -e '.result.neighbor.layout.zoomed == true' \
>/dev/null 2>&1 <<<"$neighbor"; then
fall_through
fi
neighbor_id="$(
jq -r '.result.neighbor.neighbor_pane_id // empty' <<<"$neighbor"
)"
# Herdr 0.7.5 returns the current pane itself when there is no neighbour.
if [[ -z "$neighbor_id" || "$neighbor_id" == "$pane_id" ]]; then
fall_through
fi
if "$herdr_bin" pane focus \
--pane "$pane_id" \
--direction "$direction" \
>/dev/null 2>&1; then
handled
else
fall_through
fi
|