Commit abd31241 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Add a terminal startup script

parent 81565a3f
Loading
Loading
Loading
Loading
+145 −0
Original line number Diff line number Diff line
#!/bin/bash
set -eu
shopt -s extglob lastpipe

. ~/.shell/lib/shared.sh

declare -r CODE_HIGHLIGHT=$(tput setab 15; tput setaf 16)
declare -r CODE_RESET=$(tput sgr0)
declare -a OPTIONS=(
	ssh="SSH: connect to a remote host"
	tmux="Tmux: connect to local terminal multiplexer"
	shell="Shell: start a local shell ($SHELL)"
	manual="Enter command manually"
)
declare -i FOCUS=0

if [[ -v TMUX ]] || ! has tmux; then
	unset OPTIONS[1]
	OPTIONS=( "${OPTIONS[@]}" )
fi

_clear() { clear; echo; }

interact() {
	local STATE=ssh
	trap 'read -N1 -p "Press any key to exit"' EXIT
	while _clear && do_$STATE; do
		has do_$STATE || die "Unknown state: $STATE"
	done
	die "Command for the $STATE state failed: $_"
}

do_ssh() {
	local host
	while read -p 'Connect to SSH host [empty for other options]: ' host args; do
		[[ -z $host ]] && STATE=options && return
		exec ssh $host $args
	done
}

do_tmux() {
	exec tmux attach
}

do_shell() {
	exec -l $SHELL
}

do_manual() {
	read -e -p '> '
	eval $REPLY
	exit
}

do_options() {
	local SELECTION
	while [[ ! -v SELECTION ]]; do
		display_options
		process_keys
	done
	local opt=${OPTIONS[$SELECTION]}
	STATE=${opt%%=*}
}

display_options() {
	_clear
	echo "Options:${1+ $1}"
	for i in "${!OPTIONS[@]}"; do
		local prefix=" " suffix=
		local opt=${OPTIONS[$i]}
		local name=${opt%%=*} desc=${opt#*=}
		[[ $i -eq ${1-$FOCUS} ]] && prefix="$CODE_HIGHLIGHT>" suffix=$CODE_RESET
		local rhs=$(tput hpa $((COLUMNS-${#name}-2)))"[$name]"
		printf "$prefix %2d: %s%s$suffix\n" $i "$desc" "$rhs"
	done
	echo
}

select_from() {
	local choice=$1
	if [[ $choice =~ ^[0-9]+$ && -v OPTIONS[choice] ]]; then
		SELECTION=$choice
		return 0
	fi

	local i=0
	declare -gA named_options
	if [[ ! -v named_options ]]; then
		named_options=()
		for opt in "${OPTIONS[@]}"; do
			named_options[${opt%%=*}]=$((i++))
		done
	fi

	if [[ ! -v named_options[$choice] ]]; then
		echo >&2 "Unknown choice: $choice"
		return 1
	fi

	SELECTION=${named_options[$choice]}
}

process_keys() {
	local key choice
	while read -s -N1 key; do
		case $key in
			$'\n') SELECTION=$FOCUS; break ;;
			$'\e') process_esc_seq ;;
			*) read -ei "$key" choice; select_from "$choice" && break ;;
		esac
	done
}

process_esc_seq() {
	local buff=
	local opt_min=0
	local opt_max=$((${#OPTIONS[*]}-1))
	while read -rs -N1 key; do
		buff+=$key
		case $buff in
			# arrow keys
			[[O]A) let 'FOCUS=(--FOCUS>=opt_min)?FOCUS:opt_min'; break ;;
			[[O]B) let 'FOCUS=(++FOCUS<=opt_max)?FOCUS:opt_max'; break ;;

			# any other ESC input sequences
			\[*([0-;])[A-Z~]) return ;;
		esac
	done
	display_options
}

has_client() {
	tmux list-clients -F '#{client_termname}' | while read termname; do
		echo "$termname $TERM"
		if [[ $termname == $TERM ]]; then
			return 0
		fi
	done
	return 1
}

has_client && interact

# No other terms of this one's kind attached to Tmux, lets be the first
exec tmux attach