#!/bin/sh
#/
#/ spl - Screen PreLoad
#/
#/ Use this tool to spin up a slow-loading program in a screen session before
#/ you need it. Then the program will appear instantly when you call for it.
#/
#/ "spl matlab" will bring up Matlab inside a screen session and cd to the
#/ directory you were in. It will also spin up Matlab in a second background
#/ screen session. The next time (and all subsequent times) you run "spl matlab"
#/ it should come up near instantaneously.
#/
#/ Optionally, "spl spinup matlab" just loads Matlab in a background screen
#/ session, which can be used to make "spl matlab" load faster the very first
#/ time it's run.
#/
#/ You can replace "matlab" with "octave", "pylab", and any commands you tell spl
#/ about. Running spl creates example configuration files in $HOME/.spl
#/ Use these as a template to tell spl about other commands you want to spin up
#/ in screen. The command run inside screen is $HOME/.spl/PROGRAM.cmd. Just
#/ before you use it, screen will send $HOME/.spl/PROGRAM.keys to the program.
#/ The .cmd and .keys files can refer to environment variables, including
#/ ($1, $2, ... "$@"), which are set to any arguments passed to spl after the
#/ PROGRAM name.
#/
#/ $HOME/.spl/PROGRAM.id is an integer id that increments to keep track of the
#/ screen sessions.
#/
#/ Screen will use $HOME/.spl/screenrc rather than your default ~/.screenrc
#/ Replace it with a symlink if you do want to use your standard screen setup.
#/
#/ Use "screen -ls" as usual to diagnose what screen sessions are available, and
#/ the usual screen commands to sort things out if anything goes wrong.
#/
# Iain Murray, 2016. MIT license.

set -e

CONFDIR="$HOME"/.spl

if [ \! -d "$CONFDIR" ] ; then
    # Create default spl configuration
    mkdir -p "$CONFDIR"
    echo 'matlab -nodesktop -nosplash' > "$CONFDIR"/matlab.cmd
    echo 'cd "$PWD"' > "$CONFDIR"/matlab.keys
    echo 'octave --no-gui' > "$CONFDIR"/octave.cmd
    echo 'cd "$PWD"' > "$CONFDIR"/octave.keys
    echo 'ipython --pylab' > "$CONFDIR"/pylab.cmd
    echo 'cd "$PWD"' > "$CONFDIR"/pylab.keys
fi

# Default screen configuration for spl
if [ \! -e "$CONFDIR"/screenrc ] ; then
cat > "$CONFDIR"/screenrc <<EOF
# I use ctrl-a a lot. Map main command key to ctrl-u
escape ^Uu
# Make the fact I'm inside screen less obvious
vbell off
startup_message off
hardstatus string "%h"
termcapinfo xterm ti@:te@
msgminwait 0
msgwait 0
EOF
fi

# Usage message:
if [ "$#" -eq 0 ] || [ "${1#-}" \!= "$1" ] ; then
    grep '^#/' <"$0" | cut -c4-
    exit 1
fi

spinup()
{
    if [ \! -e "$CONFDIR/$NAME".cmd ] ; then
        echo "You need to configure $NAME before asking spl to run it."
        exit 1
    fi
    # Race conditions seem unlikely as this tool is intended for single-user
    # interactive use. Simple locking based on symlinks. If program hangs here,
    # simply delete the lock file.
    until ln -s /dev/null "$CONFDIR/$NAME".id.lock 2> /dev/null ; do sleep 0.1 ; done
    ID=$(cat "$CONFDIR/$NAME".id 2> /dev/null) || ID=0
    NEWID=$(($ID+1))
    echo "$NEWID" > "$CONFDIR/$NAME".id
    rm "$CONFDIR/$NAME".id.lock
    screen \
        -c "$CONFDIR"/screenrc \
        -d -m \
        -S spl_"$NAME"_"$NEWID" \
        $(eval echo $(cat "$CONFDIR/$NAME".cmd))
}

if [ "$1" = spinup ] ; then
    NAME="$2"
    shift 2
    spinup
    exit 0
fi

NAME="$1"
shift
spinup

KEYS=$(eval echo $(cat "$CONFDIR/$NAME".keys))
if screen -q -c "$CONFDIR"/screenrc -S spl_"$NAME"_"$ID" -p 0 -X stuff "$KEYS" ; then
    # Attach to previously session that we've just stuffed KEYS into
    screen -c "$CONFDIR"/screenrc -S spl_"$NAME"_"$ID" -r
else
    # It seems there wasn't a running session, so we'll spin up yet another
    # session, and attach to the one we span up first.
    spinup
    screen -c "CONFDIR"/screenrc -S spl_"$NAME"_"$ID" -p 0 -X stuff "$KEYS"
    screen -c "CONFDIR"/screenrc -S spl_"$NAME"_"$ID" -r
fi

