aboutsummaryrefslogtreecommitdiff
path: root/tmuxrdr/plugin/lib.sh
blob: c7146904a1d4ec02a8eb23407af12418a75b66b4 (plain)
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
# 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._-' '_'
}