Skip to content

Instantly share code, notes, and snippets.

@343N
Created January 23, 2026 01:06
Show Gist options
  • Select an option

  • Save 343N/e9f49d6fef4bdad51897274c683428c4 to your computer and use it in GitHub Desktop.

Select an option

Save 343N/e9f49d6fef4bdad51897274c683428c4 to your computer and use it in GitHub Desktop.
menu WIP
#!/bin/bash
set -euo pipefail
# Simple interactive menu:
# - Navigate with Up/Down arrows
# - Press 1..9 to select instantly (if present)
# - For 10+ items, type digits (e.g. 12) then Enter
# - Press Enter to confirm current selection
# - Press q or Esc to quit
OPTIONS=("$@")
if [[ "${#OPTIONS[@]}" -eq 0 ]]; then
# Default options if none were provided on the command line
OPTIONS=("Create New Session" "Enter Existing Session")
fi
selected=0
typed_number=""
cleanup() {
# restore cursor + clear styling
tput cnorm 2>/dev/null || true
printf '\033[0m' || true
}
# Arrange to call trapERR when an error is raised
trap cleanup ERR EXIT INT TERM
draw_main_menu() {
# clear screen + move cursor home
printf '\033[2J\033[H'
printf 'Use \033[1m↑/↓\033[0m or \033[1mnumber keys\033[0m. Enter=confirm, q/Esc=quit\n'
if [[ -n "$typed_number" ]]; then
printf 'Typed: \033[1m%s\033[0m (Enter to select)\n' "$typed_number"
fi
printf '\n'
for i in "${!OPTIONS[@]}"; do
if [[ "$i" -eq "$selected" ]]; then
# reverse video highlight
printf ' \033[7m%d) %s\033[0m\n' "$((i+1))" "${OPTIONS[$i]}"
else
printf ' %d) %s\n' "$((i+1))" "${OPTIONS[$i]}"
fi
done
}
draw_session_menu() {
# clear screen + move cursor home
printf '\033[2J\033[H'
printf 'Use \033[1m↑/↓\033[0m or \033[1mnumber keys\033[0m. Enter=confirm, q/Esc=quit\n'
if [[ -n "$typed_number" ]]; then
printf 'Typed: \033[1m%s\033[0m (Enter to select)\n' "$typed_number"
fi
printf '\n'
for i in "${!OPTIONS[@]}"; do
if [[ "$i" -eq "$selected" ]]; then
# reverse video highlight
printf ' \033[7m%d) %s\033[0m\n' "$((i+1))" "${OPTIONS[$i]}"
else
printf ' %d) %s\n' "$((i+1))" "${OPTIONS[$i]}"
fi
done
}
confirm() {
local idx="$1"
printf '\nYou picked: %d) %s\n' "$((idx+1))" "${OPTIONS[$idx]}"
echo "TODO: implement action for selection $((idx+1))"
}
main() {
tput civis 2>/dev/null || true # hide cursor
while true; do
draw_main_menu
# read a single key (silent, no echo)
IFS= read -rsn1 key || true
case "$key" in
"")
# Enter: if the user typed a number, use it; otherwise confirm highlight
if [[ -n "$typed_number" ]]; then
if [[ "$typed_number" =~ ^[0-9]+$ ]]; then
# interpret as 1-based menu number
num=$typed_number
typed_number=""
if (( num >= 1 && num <= ${#OPTIONS[@]} )); then
selected=$((num - 1))
draw_menu
confirm "$selected"
break
fi
fi
typed_number=""
fi
draw_menu
confirm "$selected"
break
;; # Enter
q|Q) echo; echo "Bye!"; break ;;
$'\x7f'|$'\b')
# Backspace
if [[ -n "$typed_number" ]]; then
typed_number="${typed_number::-1}"
fi
;;
[0-9])
# Digit: if 1..9 and within range, select instantly.
# Otherwise accumulate digits (e.g. for 10+).
if [[ -z "$typed_number" ]]; then
num=$key
if (( num >= 1 && num <= 9 && num <= ${#OPTIONS[@]} )); then
selected=$((num - 1))
draw_menu
confirm "$selected"
break
fi
fi
typed_number+="$key"
;;
$'\e')
# Could be Esc alone OR an arrow key sequence.
# Arrow keys typically arrive as: ESC [ A/B
IFS= read -rsn2 -t 0.025 rest || rest=""
if [[ "$rest" == "[A" ]]; then
# Up
selected=$((((selected - 1) + ${#OPTIONS[@]}) % ${#OPTIONS[@]}))
# ((selected = (selected - 1)))
typed_number=""
elif [[ "$rest" == "[B" ]]; then
# Down
# ((selected = (selected + 1)))
selected=$((((selected + 1)) % ${#OPTIONS[@]}))
typed_number=""
else
# Esc by itself -> quit
echo; echo "Bye!"
break
fi
;;
esac
done
}
main
#!/usr/bin/env bash
set -euo pipefail
# Prints: "<screen_id> attached" or "<screen_id> detached" for each session.
out="$(screen -ls 2>/dev/null || true)"
if [[ -z "${out//[[:space:]]/}" ]] || grep -qiE 'no sockets found' <<<"$out"; then
echo "No screen sessions."
exit 0
fi
printf '%s\n' "$out" | awk '
match($0, /^[ \t]*([0-9]+)\.[^ \t]+[ \t]*\(([^)]*)\)+[ \t]*\(([^)]*)\)/, m) {
num=m[1]
state=tolower(m[3])
print num " " state
}
'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment