#!/usr/bin/env bash # IPC remote control for pikl-menu. # # Connects to a running pikl instance over its Unix socket and # lets you send commands interactively. You see the effects in # the pikl terminal in real time. # # Usage: # Terminal 1: echo -e "alpha\nbeta\ngamma\ndelta" | pikl --ipc --session demo # Terminal 2: ./examples/ipc-remote.sh demo # # Requires: socat (for socket I/O) # # The session name is optional. Without it, you'll need to pass # the full socket path as the first argument. set -euo pipefail # ── Socket path ────────────────────────────────────────── resolve_socket() { local arg="${1:-}" if [[ -z "$arg" ]]; then echo "usage: ipc-remote.sh " >&2 exit 2 fi # If it looks like a path, use it directly if [[ "$arg" == */* || "$arg" == *.sock ]]; then echo "$arg" return fi # Otherwise treat it as a session name local uid uid=$(id -u) echo "/run/user/${uid}/pikl-${arg}.sock" } SOCK=$(resolve_socket "${1:-}") if [[ ! -S "$SOCK" ]]; then echo "socket not found: $SOCK" >&2 echo "" >&2 echo "make sure pikl is running with --ipc:" >&2 echo " echo -e 'alpha\nbeta\ngamma' | pikl --ipc --session demo" >&2 exit 1 fi if ! command -v socat >/dev/null 2>&1; then echo "socat is required but not installed." >&2 echo "install it with your package manager (pacman -S socat, brew install socat, etc.)" >&2 exit 1 fi # ── IPC helpers ────────────────────────────────────────── ipc_send() { echo "$1" | socat - "UNIX-CONNECT:${SOCK}" 2>/dev/null } ipc_fire() { # Fire-and-forget: send command, don't wait for response echo "$1" | socat -t 0.1 - "UNIX-CONNECT:${SOCK}" 2>/dev/null || true } # ── Commands ───────────────────────────────────────────── cmd_state() { local resp resp=$(ipc_send '{"action":"get_state","id":"q"}') echo "$resp" | python3 -m json.tool 2>/dev/null || echo "$resp" } cmd_selection() { local resp resp=$(ipc_send '{"action":"get_selection","id":"q"}') echo "$resp" | python3 -m json.tool 2>/dev/null || echo "$resp" } cmd_move_down() { ipc_fire '{"action":"move_down"}'; } cmd_move_up() { ipc_fire '{"action":"move_up"}'; } cmd_top() { ipc_fire '{"action":"move_to_top"}'; } cmd_bottom() { ipc_fire '{"action":"move_to_bottom"}'; } cmd_page_down() { ipc_fire '{"action":"page_down"}'; } cmd_page_up() { ipc_fire '{"action":"page_up"}'; } cmd_toggle() { ipc_fire '{"action":"toggle_select"}'; } cmd_select_all() { ipc_fire '{"action":"select_all"}'; } cmd_clear() { ipc_fire '{"action":"clear_selections"}'; } cmd_confirm() { ipc_fire '{"action":"confirm"}'; } cmd_cancel() { ipc_fire '{"action":"cancel"}'; } cmd_filter() { local text="${1:-}" if [[ -z "$text" ]]; then read -rp "filter text: " text fi ipc_fire "{\"action\":\"set_filter\",\"text\":\"${text}\"}" } cmd_add() { local items="${1:-}" if [[ -z "$items" ]]; then echo "enter items to add (one per line, empty line to finish):" local lines=() while IFS= read -rp "> " line; do [[ -z "$line" ]] && break lines+=("\"${line}\"") done items=$(IFS=,; echo "${lines[*]}") fi ipc_fire "{\"action\":\"add_items\",\"items\":[${items}]}" } cmd_replace() { echo "enter new items (one per line, empty line to finish):" local lines=() while IFS= read -rp "> " line; do [[ -z "$line" ]] && break lines+=("\"${line}\"") done local items items=$(IFS=,; echo "${lines[*]}") ipc_fire "{\"action\":\"replace_items\",\"items\":[${items}]}" } # ── Interactive loop ───────────────────────────────────── show_help() { cat <<'HELP' pikl IPC remote control ─────────────────────── j / down move cursor down k / up move cursor up g jump to top G jump to bottom f set filter F clear filter space toggle select a select all c clear selections s get state S get selection + add items r replace all items enter confirm selection q cancel menu ? show this help x exit remote HELP } main() { echo "connected to: $SOCK" show_help while true; do read -rp "ipc> " -n1 key || break echo "" case "$key" in j) cmd_move_down ;; k) cmd_move_up ;; g) cmd_top ;; G) cmd_bottom ;; f) read -rp "filter: " text; cmd_filter "$text" ;; F) cmd_filter "" ;; " ") cmd_toggle ;; a) cmd_select_all ;; c) cmd_clear ;; s) cmd_state ;; S) cmd_selection ;; +) cmd_add ;; r) cmd_replace ;; "") cmd_confirm; echo "confirmed."; break ;; q) cmd_cancel; echo "cancelled."; break ;; x) echo "bye."; break ;; "?") show_help ;; *) echo "unknown key '$key'. press ? for help." ;; esac done } main