!/usr/bin/env bash

############################################################################### # # demo-magic.sh # # Copyright © 2015 Paxton Hare # # This script lets you script demos in bash. It runs through your demo script when you press # ENTER. It simulates typing and runs commands. # ###############################################################################

# the speed to “type” the text TYPE_SPEED=20

# no wait after “p” or “pe” NO_WAIT=false

# if > 0, will pause for this amount of seconds before automatically proceeding with any p or pe PROMPT_TIMEOUT=0

# don’t show command number unless user specifies it SHOW_CMD_NUMS=false

# handy color vars for pretty prompts BLACK=“033[0;30m” BLUE=“033[0;34m” GREEN=“033[0;32m” GREY=“033[0;90m” CYAN=“033[0;36m” RED=“033[0;31m” PURPLE=“033[0;35m” BROWN=“033[0;33m” WHITE=“033[1;37m” COLOR_RESET=“033[0m”

C_NUM=0

# prompt and command color which can be overriden DEMO_PROMPT=“$ ” DEMO_CMD_COLOR=$BLACK DEMO_COMMENT_COLOR=$GREY

## # prints the script usage ## function usage() {

echo -e ""
echo -e "Usage: $0 [options]"
echo -e ""
echo -e "\tWhere options is one or more of:"
echo -e "\t-h\tPrints Help text"
echo -e "\t-d\tDebug mode. Disables simulated typing"
echo -e "\t-n\tNo wait"
echo -e "\t-w\tWaits max the given amount of seconds before proceeding with demo (e.g. '-w5')"
echo -e ""

}

## # wait for user to press ENTER # if $PROMPT_TIMEOUT > 0 this will be used as the max time for proceeding automatically ## function wait() {

if [[ "$PROMPT_TIMEOUT" == "0" ]]; then
  read -rs
else
  read -rst "$PROMPT_TIMEOUT"
fi

}

## # print command only. Useful for when you want to pretend to run a command # # takes 1 param - the string command to print # # usage: p “ls -l” # ## function p() {

if [[ ${1:0:1} == "#" ]]; then
  cmd=$DEMO_COMMENT_COLOR$1$COLOR_RESET
else
  cmd=$DEMO_CMD_COLOR$1$COLOR_RESET
fi

# render the prompt
x=$(PS1="$DEMO_PROMPT" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}')

# show command number is selected
if $SHOW_CMD_NUMS; then
 printf "[$((++C_NUM))] $x"
else
 printf "$x"
fi

# wait for the user to press a key before typing the command
if [ $NO_WAIT = false ]; then
  wait
fi

if [[ -z $TYPE_SPEED ]]; then
  echo -en "$cmd"
else
  echo -en "$cmd" | pv -qL $[$TYPE_SPEED+(-2 + RANDOM%5)];
fi

# wait for the user to press a key before moving on
if [ $NO_WAIT = false ]; then
  wait
fi
echo ""

}

## # Prints and executes a command # # takes 1 parameter - the string command to run # # usage: pe “ls -l” # ## function pe() {

# print the command
p "$@"
run_cmd "$@"

}

## # print and executes a command immediately # # takes 1 parameter - the string command to run # # usage: pei “ls -l” # ## function pei {

NO_WAIT=true pe "$@"

}

## # Enters script into interactive mode # # and allows newly typed commands to be executed within the script # # usage : cmd # ## function cmd() {

# render the prompt
x=$(PS1="$DEMO_PROMPT" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}')
printf "$x\033[0m"
read command
run_cmd "${command}"

}

function run_cmd() {

function handle_cancel() {
  printf ""
}

trap handle_cancel SIGINT
stty -echoctl
eval "$@"
stty echoctl
trap - SIGINT

}

function check_pv() {

command -v pv >/dev/null 2>&1 || {

  echo ""
  echo -e "${RED}##############################################################"
  echo "# HOLD IT!! I require pv but it's not installed.  Aborting." >&2;
  echo -e "${RED}##############################################################"
  echo ""
  echo -e "${COLOR_RESET}Installing pv:"
  echo ""
  echo -e "${BLUE}Mac:${COLOR_RESET} $ brew install pv"
  echo ""
  echo -e "${BLUE}Other:${COLOR_RESET} http://www.ivarch.com/programs/pv.shtml"
  echo -e "${COLOR_RESET}"
  exit 1;
}

}

check_pv # # handle some default params # -h for help # -d for disabling simulated typing # while getopts “:dhncw:” opt; do

case $opt in
  h)
    usage
    exit 1
    ;;
  d)
    unset TYPE_SPEED
    ;;
  n)
    NO_WAIT=true
    ;;
  c)
    SHOW_CMD_NUMS=true
    ;;
  w)
    PROMPT_TIMEOUT=$OPTARG
    ;;
esac

done