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
|
#!/bin/sh
# tmux prefix+: (command-prompt). Herdr has no command language of its own, so
# this takes the tmux commands that have a herdr counterpart, with their usual
# aliases and flags, and passes anything else to the herdr CLI -- `:pane list`
# runs `herdr pane list` and shows the result. Run as a popup.
. "$(dirname "$0")/../lib.sh"
action() { "$H" plugin action invoke "tmuxrdr.tmux-mode.$1" >/dev/null; }
pause() { printf '\n[press any key]'; read_key >/dev/null; }
printf ':'
IFS= read -r line || exit 0
[ -n "$line" ] || exit 0
eval "set -- $line" || { pause; exit 1; }
cmd="$1"
shift
p="$(active_pane)"
has() { case " $* " in *" $flag "*) return 0 ;; esac; return 1; }
opt() { # opt -t ARGS...: the value after -t, if any
_f="$1"; shift
while [ $# -gt 0 ]; do
[ "$1" = "$_f" ] && { printf '%s' "${2:-}"; return; }
shift
done
}
# tmux's sessions are herdr's workspaces. A target (-t) is a workspace's name
# or id, as tmux takes "name", "name:" or "=name"; prints the id.
session_id() {
_t="${1#=}"; _t="${_t%%:*}"
"$H" workspace list | jq -r --arg t "$_t" \
'[.result.workspaces[] | select(.label == $t or .workspace_id == $t)][0].workspace_id // empty'
}
current_session() { pane_info "$p" workspace_id; }
# The case lives in a function: bash 3.2, which is macOS /bin/sh, misparses a
# case statement written inside $(...) -- its pattern parentheses end the
# substitution early.
run() {
case "$cmd" in
kill-pane | killp) "$H" pane close "$p" ;;
kill-window | killw) "$H" tab close "$(pane_info "$p" tab_id)" ;;
kill-session)
t="$(opt -t "$@")"
if [ -n "$t" ]; then w="$(session_id "$t")"; [ -n "$w" ] || { echo "can't find session: $t"; exit 1; }
else w="$(current_session)"; fi
"$H" workspace close "$w" ;;
new-session | new)
# new-session [-A] [-d] [-s name] [-c dir]: a workspace, switched to
# unless -d; -A switches to an existing one of that name instead.
name="$(opt -s "$@")"; dir="$(opt -c "$@")"
flag=-A; attach=""; has "$@" && attach=1
flag=-d; focus=--focus; has "$@" && focus=--no-focus
if [ -n "$name" ]; then
w="$(session_id "$name")"
if [ -n "$w" ]; then
[ -n "$attach" ] || { echo "duplicate session: $name"; exit 1; }
"$H" workspace focus "$w"; exit
fi
fi
set -- workspace create "$focus"
[ -n "$name" ] && set -- "$@" --label "$name"
[ -n "$dir" ] && set -- "$@" --cwd "$dir"
"$H" "$@" ;;
attach-session | attach | a)
t="$(opt -t "$@")"; w="$(session_id "${t:-}")"
[ -n "$w" ] || { echo "can't find session: ${t:-}"; exit 1; }
"$H" workspace focus "$w" ;;
list-sessions | ls)
# tmux: "name: N windows (attached)"; herdr keeps no creation time.
"$H" workspace list | jq -r '.result.workspaces[]
| "\(.label): \(.tab_count) windows\(if .focused then " (attached)" else "" end)"'
exit 2 ;;
kill-server) "$H" server stop ;;
new-window | neww) "$H" tab create --workspace "$(pane_info "$p" workspace_id)" --focus ;;
split-window | splitw | new-pane | newp)
flag=-h; dir=down; has "$@" && dir=right
"$H" pane split "$p" --direction "$dir" --focus ;;
rename-window | renamew) "$H" tab rename "$(pane_info "$p" tab_id)" "$*" ;;
rename-session | rename) "$H" workspace rename "$(pane_info "$p" workspace_id)" "$*" ;;
select-window | selectw) t="$(opt -t "$@")"; t="${t#:}"; sh "$BIN/select-window" "${t#=}" ;;
break-pane | breakp) sh "$BIN/break-pane" ;;
move-window | movew) t="$(opt -t "$@")"; sh "$BIN/move-window" "${t#:}" ;;
swap-pane | swapp)
flag=-U; if has "$@"; then sh "$BIN/swap-pane" prev
else flag=-D; if has "$@"; then sh "$BIN/swap-pane" next; else action swap-marked; fi; fi ;;
rotate-window | rotatew) flag=-D; if has "$@"; then sh "$BIN/rotate-window" down; else sh "$BIN/rotate-window" up; fi ;;
last-window | last) action last-window ;;
switch-client | switchc)
flag=-l; if has "$@"; then action last-session; exit; fi
t="$(opt -t "$@")"
if [ -n "$t" ]; then
w="$(session_id "$t")"; [ -n "$w" ] || { echo "can't find session: $t"; exit 1; }
"$H" workspace focus "$w"; exit
fi
# -n / -p: the next / previous workspace in the sidebar's order, wrapping.
flag=-n; step=0; has "$@" && step=1
flag=-p; has "$@" && step=-1
[ "$step" != 0 ] || { echo "switch-client: -t, -n, -p or -l"; exit 1; }
w="$("$H" workspace list | jq -r --argjson s "$step" '.result.workspaces as $w
| ($w | map(.focused) | index(true)) as $i
| $w[(($i + $s) % ($w | length) + ($w | length)) % ($w | length)].workspace_id')"
"$H" workspace focus "$w" ;;
select-pane | selectp)
flag=-m; if has "$@"; then action mark; exit; fi
flag=-M; if has "$@"; then action clear-mark; exit; fi
for d in L:left R:right U:up D:down; do
flag="-${d%%:*}"; has "$@" && { "$H" pane focus --direction "${d#*:}" --pane "$p"; exit; }
done
echo "select-pane: only -L -R -U -D -m -M are supported"; exit 1 ;;
resize-pane | resizep)
flag=-Z; has "$@" && { "$H" pane zoom "$p" --toggle; exit; }
n="$(printf '%s\n' "$@" | grep -x '[0-9][0-9]*' | head -n 1)"
for d in L:left R:right U:up D:down; do
flag="-${d%%:*}"; has "$@" && { "$H" pane resize --direction "${d#*:}" --amount "$(awk "BEGIN { print ${n:-1} / 100 }")" --pane "$p"; exit; }
done
echo "resize-pane: only -L -R -U -D [N] and -Z are supported"; exit 1 ;;
select-layout | selectl) flag=-E; if has "$@"; then action spread-layout; else echo "select-layout: only -E is supported"; exit 1; fi ;;
display-message | display) if [ $# -gt 0 ]; then say "$*"; else sh "$BIN/display-message"; fi ;;
paste-buffer | pasteb) sh "$BIN/paste-buffer" ;;
source-file | source) "$H" server reload-config ;;
detach-client | detach) echo "detach-client: not scriptable in herdr; use prefix+d"; exit 1 ;;
*) "$H" "$cmd" "$@"; echo; exit 2 ;;
esac
}
out="$(run "$@" 2>&1)"
status=$?
# tmux's own commands close the prompt quietly on success; errors, and
# anything handed to the herdr CLI, stay on screen until a key.
case "$status" in
0) ;;
*) printf '%s\n' "$out"; pause ;;
esac
|