example: Add IPC remote control example.
This commit is contained in:
178
examples/ipc-remote.sh
Executable file
178
examples/ipc-remote.sh
Executable file
@@ -0,0 +1,178 @@
|
||||
#!/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 <session-name | socket-path>" >&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 <text> 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
|
||||
Reference in New Issue
Block a user