#!/bin/bash

sanitize_name () {
    tr -cs 'a-zA-Z0-9.-' '[-*]' \
        | sed -e 's|^[.-]*||' \
              -e 's|[.-]*$||' \
        | cut -c 1-63
}

if [[ $1 = -h* || $1 = --h* ]]; then
	echo "Usage: ${0##*/} [-Z]"
	echo
	echo "-Z	Suspend dtach itself when ^Z is pressed"
	exit 0
fi

command -v dtach >&/dev/null || { echo >&2 "dtach not found"; exit 127; }

z=-z
if [[ $1 == "-Z" ]]; then
	z=
	shift
fi

if [[ -n $XDG_RUNTIME_DIR ]]; then
	socketdir=${XDG_RUNTIME_DIR%/}/dtach
else
	socketdir=${TMPDIR:-/tmp}/dtach-$(id -un)
fi

(umask 077; mkdir -p "$socketdir")

[[ -d $socketdir ]] || { echo >&2 "Couldn't find or create $socketdir"; exit 1; }

shopt -s nullglob
sockets=("$socketdir"/*)


true <<-'=cut'
=pod
new_socket

Prompts user for a command and starts a new dtach socket calling that command.
The command may start with dtach options (starting with -). The socket will be
named after the executable, with a trailing number if necessary to avoid
duplicate names.

If the command is empty, uses $SHELL as the command.

The path to the socket will be put into the environment as $DTACH.

=cut

function new_socket {
	local -a command
	local name socketbasename

	echo -n "[Options]? "
	read -ra options

	echo -n "[Command]? "
	read -ra command
	if [[ ${#command} -eq 0 ]]; then
		command=("$SHELL")
	fi
	local executable="${command[0]}"

	echo -n "[Name]? "
	read -r name

	socketbasename=${name:-${executable##*/}}
	socketbasename=$(sanitize_name <<<"$socketbasename")
	local socketpath=$socketdir/$socketbasename
	local count=0
	while [[ -e $socketpath ]]; do
		socketbasename=${executable##*/}${count}
		socketpath=$socketdir/$socketbasename
		(( count++ ))
	done
	export DTACH=$socketpath
	exec dtach -c "$DTACH" -E $z "${options[@]}" "${command[@]}"
}


true <<-'=cut'
=pod
reattach_socket

Reattaches to an existing socket.  The path to the socket will be put into the
environment as $DTACH.

=cut

function reattach_socket {
	DTACH=$1
	export DTACH
	exec dtach -a "$DTACH" $z -E
}


[[ -z ${DTACH:-} ]] || { echo >&2 "Already in dtach; exiting"; exit 3; }


if [[ ${#sockets} -gt 0 ]]; then
	select sock in NEW CANCEL "${sockets[@]}"; do
		if [[ $sock == NEW ]]; then
			new_socket
		elif [[ $sock == CANCEL ]]; then
			exit 0
		else
			reattach_socket "$sock"
		fi
	done
else
	new_socket
fi

# vim:noet:sw=8:sts=8:ts=8
