Created
January 23, 2026 01:06
-
-
Save 343N/e9f49d6fef4bdad51897274c683428c4 to your computer and use it in GitHub Desktop.
menu WIP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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