aboutsummaryrefslogtreecommitdiff
path: root/tmuxrdr/plugin/lib.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tmuxrdr/plugin/lib.sh')
-rw-r--r--tmuxrdr/plugin/lib.sh95
1 files changed, 95 insertions, 0 deletions
diff --git a/tmuxrdr/plugin/lib.sh b/tmuxrdr/plugin/lib.sh
new file mode 100644
index 00000000..c7146904
--- /dev/null
+++ b/tmuxrdr/plugin/lib.sh
@@ -0,0 +1,95 @@
+# Shared by the commands in bin/. POSIX sh -- macOS /bin/sh is bash 3.2.
+# Sourced, never run. Every command acts through the herdr CLI, or the raw
+# socket for the one method the CLI does not wrap (pane.focus by id).
+
+set -u
+
+H="${HERDR_BIN_PATH:-herdr}"
+BIN="$(cd "$(dirname "$0")" && pwd)"
+
+# tmux shows messages and errors ("can't find window: 0") on its status line;
+# here they are herdr toasts.
+say() {
+ "$H" notification show "$1" --sound none >/dev/null 2>&1 \
+ || printf '%s\n' "$1" >&2
+}
+
+fail() {
+ say "$1"
+ exit 1
+}
+
+# One newline-delimited JSON request on the session's socket.
+api() {
+ printf '%s\n' "$1" | nc -U -w 2 "${HERDR_SOCKET_PATH:?not run by herdr}"
+}
+
+# The pane the key was pressed in. Keybinding commands and popups get
+# HERDR_ACTIVE_PANE_ID; plugin actions get it in their context JSON; anything
+# else asks the server which pane is focused.
+active_pane() {
+ _p="${HERDR_ACTIVE_PANE_ID:-}"
+ if [ -z "$_p" ] && [ -n "${HERDR_PLUGIN_CONTEXT_JSON:-}" ]; then
+ _p="$(printf '%s' "$HERDR_PLUGIN_CONTEXT_JSON" \
+ | jq -r '.focused_pane_id // empty')"
+ fi
+ if [ -z "$_p" ]; then
+ _p="$("$H" pane current | jq -r '.result.pane.pane_id // empty')"
+ fi
+ [ -n "$_p" ] || fail "no current pane"
+ printf '%s' "$_p"
+}
+
+# pane_info PANE FIELD -- e.g. workspace_id, tab_id.
+pane_info() {
+ "$H" pane get "$1" | jq -r --arg k "$2" '.result.pane[$k] // empty'
+}
+
+# Panes of the tab holding PANE, in layout order: tmux's pane index order.
+tab_panes() {
+ "$H" pane layout --pane "$1" | jq -r '.result.layout.panes[].pane_id'
+}
+
+# 0-based position of PANE in its tab: tmux's #P (pane-base-index 0).
+pane_index() {
+ _i="$(tab_panes "$1" | grep -n -x -F "$1" | cut -d: -f1)"
+ printf '%s' "$((${_i:-1} - 1))"
+}
+
+# Tabs of WORKSPACE in tab-bar order, one "tab_id<TAB>label" per line.
+workspace_tabs() {
+ "$H" tab list --workspace "$1" | jq -r '.result.tabs[] | [.tab_id, .label] | @tsv'
+}
+
+focus_pane() {
+ api "{\"id\":\"tmux-mode\",\"method\":\"pane.focus\",\"params\":{\"pane_id\":\"$1\"}}" >/dev/null
+}
+
+swap() {
+ "$H" pane swap --source-pane "$1" --target-pane "$2" >/dev/null
+}
+
+# One keypress, unbuffered, for (y/n) prompts.
+read_key() {
+ _tty="$(stty -g)"
+ stty -icanon -echo min 1 time 0
+ _k="$(dd bs=1 count=1 2>/dev/null)"
+ stty "$_tty"
+ printf '%s' "$_k"
+}
+
+# Plugin state (marks, focus history) lives where herdr puts this plugin's,
+# one directory per session: herdr shares that directory across sessions,
+# and ids repeat between them -- every named session has its own w1. The
+# session is the directory holding its socket (herdr for the default one).
+state_dir() {
+ _d="${HERDR_PLUGIN_STATE_DIR:?run as a herdr plugin action}"
+ _d="$_d/$(basename "$(dirname "${HERDR_SOCKET_PATH:?not run by herdr}")")"
+ mkdir -p "$_d"
+ printf '%s' "$_d"
+}
+
+# Tab and workspace ids hold colons; keep file names plain.
+key_of() {
+ printf '%s' "$1" | tr -c 'A-Za-z0-9._-' '_'
+}