#!/bin/sh
# TMUXIE - TMUX(1) session manager (wrapper)
#
# 2026/09/13 - Restored POSIX-compatibility by using whole seconds for sleep.
# 2026/09/12 - Waits, when applicable, for tmux-resurrect to finish restoring
#              prior sessions.
# 2025/10/26 - Now reads the user's tmux prefix out of .tmux.conf for display
#              in the menu, instead of assuming the default prefix is in use.
#              Now uses a POSIX compatible natural sort for sessions.
#              Also added a -h (and --help) help command.
# 2024/01/08 - adapted to change in "tmux ls" output ron@vnetworx.net
# 2012/01/28 - Ported to tmux by Ron Guerin <ron@vnetworx.net>
# 1996/03/28 - Written for GNU screen by Marc O. Gloor <mgloor@fhzh.ch>
#
# Dual-licensed: GPL 2 and later, BSD.  You may choose which license
# your use of tmuxie will comply with.
#
# BSD:
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# GPL:
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA

set -e

#global settings
VERSION='2.1.2'
TMPF=$(mktemp -t .tmuxie.XXXXXX || exit 1)
ACTIVE_TMUXES="tmux \ls 2>/dev/null | awk '{ print \$1, \$10}' | sed 's/://' | awk '{
	line = \$0;
	name = \$1;
	if (match(name, /[0-9]+/)) {
		prefix = substr(name, 1, RSTART-1);
		num = substr(name, RSTART, RLENGTH);
		suffix = substr(name, RSTART+RLENGTH);
		printf \"%s\\t%03d\\t%s\\t%s\\n\", prefix, num, suffix, line;
	} else {
		printf \"zzz\\t000\\t%s\\t%s\\n\", name, line;
	}
}' | sort -k1,1 -k2,2n -k3,3 | cut -f4"

i=0
e=0

get_tmux_prefix() { # Get tmux prefix from ~/.tmux.conf
	prefix="C-b"
	if [ -f "$HOME/.tmux.conf" ]; then
		found=$(grep -E 'set(-option)?[[:space:]]+-g[[:space:]]+prefix' "$HOME/.tmux.conf" | tail -n 1 | awk '{print $NF}')
		[ -n "$found" ] && prefix="$found"
	fi
	echo "$prefix" | sed 's/^C-/CTRL-/'
}

help() {
cat <<EOF

tmuxie - tmux terminal session manager (ported from screenie)

Usage:
  $(basename "$0") [options]

Options:
  -v, --version           Show version
  -h, --help              Show this help message and exit
  -j, --job <name> <cmd>  Start a new tmux session with given name and command

Description:
  This script lists running tmux sessions and allows you to attach or start new ones.

Once you're inside a tmux session, press '$(get_tmux_prefix) d' to detach
and return to the session selection menu.

Further information may be available on the man page.
EOF
}

menu() {
	(
		echo
		echo -n " Use 'a' to add jobs"
		if [ $e = 0 ]; then
			echo "."
		else
			if [ $e = 1 ]; then
				echo " or '1' to choose the"
			else
				echo " or '1'-'$e' to choose a currently"
			fi
			echo " running (tmux) session."
		fi
		echo
		echo " Once you're inside the (tmux) session press "
		echo " '$(get_tmux_prefix) d' to return to the session selection menu."
	) | fmt
}

# Where tmux-resurrect keeps its save files (mirrors resurrect's own default
# lookup: @resurrect-dir tmux option, else $XDG_DATA_HOME, else ~/.tmux).
resurrect_dir() {
	dir=$(tmux show-options -gqv @resurrect-dir 2>/dev/null) || true
	if [ -z "$dir" ]; then
		if [ -n "$XDG_DATA_HOME" ]; then
			dir="$XDG_DATA_HOME/tmux/resurrect"
		else
			dir="$HOME/.tmux/resurrect"
		fi
	fi
	case "$dir" in
		"~"*) dir="$HOME${dir#\~}" ;;
	esac
	echo "$dir"
}

# If the tmux server isn't up yet, starting it (which sources .tmux.conf)
# is what kicks off tmux-resurrect/continuum's automatic session restore in
# the background. Give that restore a moment to finish before we go on, so
# we don't race it: see a stale/empty session list, or collide trying to
# create a session it's about to (re)create itself.
wait_for_resurrect() {
	if tmux list-sessions >/dev/null 2>&1; then
		return 0	# server already running, no restore race possible
	fi

	tmux start-server 2>/dev/null || true

	rdir=$(resurrect_dir)
	[ -e "$rdir/last" ] || return 0	# nothing saved for resurrect to restore

	prev=
	stable=0
	tries=0
	while [ $tries -lt 10 ]; do
		cur=$(tmux list-sessions 2>/dev/null) || true
		if [ -n "$cur" ] && [ "$cur" = "$prev" ]; then
			stable=`expr \( $stable + 1 \)`
			[ $stable -ge 2 ] && break
		else
			stable=0
		fi
		prev=$cur
		tries=`expr \( $tries + 1 \)`
		sleep 1
	done
}

# starting jobs from commandline
fork_jobs() {
	wait_for_resurrect
	# start tmux job (skip if a session by this name is already running,
	# e.g. resurrect's restore raced us to create it)
	if tmux has-session -t "$sname" 2>/dev/null; then
		echo "session '$sname' already exists, skipping" >&2
		return 0
	fi
	tmux new-session -s $sname -d $pjob
}

# Cleanup
clean_exit() {
	rm $TMPF
	if [ -f $TMPF.status ]; then
		rm $TMPF.status
	fi
	exit 0
}

# Command-line options
case "$1" in
	-h|--help)
		help
		clean_exit
		;;
	-v|--version)
		echo $VERSION
		clean_exit
		;;
	-j|--job)
		sname=$(echo $2) ;
		sname=$(echo $sname | tr " " "_") ;
		pjob=$(echo $3) ;
		pjob=$(echo $pjob) ;
		fork_jobs
		clean_exit
		;;
esac

wait_for_resurrect

while :; do
	clear
	echo "" && echo " TMUXIE - tmux terminal session manager ported from screenie" && echo ""
	eval $ACTIVE_TMUXES | (
		while read sessions; do
			e=`expr \( $e + 1 \)`
			if [ $e -lt 10 ]; then
				echo -n "  $e) "
			else
				echo -n " $e) "
			fi
			echo $sessions
		done
		echo ""
		echo " a) add job"
		echo " q) quit"
		menu e
	)
	echo "" ; echo -n " Select: "
	read ANSW
		case $ANSW in
			A|a)
				echo -n " session name: " && read sname
				echo -n " job: " && read pjob
				sname=$(echo $sname | tr " " "_")
				if tmux has-session -t "$sname" 2>/dev/null; then
					echo "" ; echo " session '$sname' already exists, not creating it again."
				else
					tmux new-session -s $sname -d $pjob || {
						echo "" ; echo " failed to create session '$sname'."
					}
				fi ;;
			0|Q|q)
				echo ""; clean_exit ;;
		esac

		eval $ACTIVE_TMUXES | (
			while read pat; do
				# display tmux session menu no. (int)
				i=`expr \( $i + 1 \)` && echo -n " $i) " >/dev/null 2>&1
				# set internal session 'no sessionid' var (string)
				sess_id=$(echo $pat|awk 'split($0, token, ".") {print token[1]}')
				k=$(echo -n  $i" "$sess_id)
				m=$(echo $k | awk '{print $1}')
				n=$(echo $k | awk '{print $2}')
				s=$(echo $k | awk '{print $3}')
				case $ANSW in
					$m) echo $n > $TMPF ; echo $s > $TMPF.status ; break;
				esac
			done
		)

	if [ -f $TMPF.status ]; then
		ATTACH=TRUE
		if [ "$(cat $TMPF.status)" = "(attached)" ]; then
			echo "" ; echo -n " Session is attached, continue (Y/N)? "
			read ATTACHED

			case $ATTACHED in
				Y|y)
					ATTACH=TRUE
					;;
				*)
					ATTACH=FALSE
					;;
			esac
		fi
		if [ $ATTACH = TRUE ]; then
			tmux attach -t $(cat $TMPF) >/dev/null 2>&1
		fi
		rm $TMPF.status
	fi
	cat /dev/null > $TMPF
done

clean_exit
#eof
