···11+#!/usr/bin/env bash
22+set -e
33+44+# Usage:
55+# sw
66+# - start a stopwatch from 0, save start time
77+# sw [-r|--resume]
88+# - start a stopwatch from the last saved start time (or current time if no last saved start time exists)
99+# - "-r" stands for --resume
1010+1111+function finish {
1212+ tput cnorm # Restore cursor
1313+ exit 0
1414+}
1515+1616+trap finish EXIT
1717+1818+# Use GNU date if possible as it's most likely to have nanoseconds available.
1919+if hash gdate 2>/dev/null; then
2020+ GNU_DATE=gdate
2121+elif date --version | grep 'GNU coreutils' >/dev/null; then
2222+ GNU_DATE=date
2323+fi
2424+2525+function datef {
2626+ if [[ -z "$GNU_DATE" ]]; then
2727+ date "$@"
2828+ else
2929+ $GNU_DATE "$@"
3030+ fi
3131+}
3232+3333+# Display nanoseconsd only if supported
3434+if datef +%N | grep -q N 2>/dev/null; then
3535+ DATE_FORMAT="+%H:%M:%S"
3636+else
3737+ DATE_FORMAT="+%H:%M:%S.%N"
3838+ NANOS_SUPPORTED=true
3939+fi
4040+4141+tput civis # hide cursor
4242+4343+# If -r is passed, use saved start time from ~/.sw
4444+if [[ "$1" == "-r" || "$1" == "--resume" ]]; then
4545+ if [[ ! -f $HOME/.sw ]]; then
4646+ datef +%s > $HOME/.sw
4747+ fi
4848+ START_TIME=$(cat $HOME/.sw)
4949+else
5050+ START_TIME=$(datef +%s)
5151+ echo -n $START_TIME > $HOME/.sw
5252+fi
5353+5454+# GNU date accepts the input date differently than BSD
5555+if [[ -z "$GNU_DATE" ]]; then
5656+ DATE_INPUT="-v-${START_TIME}S"
5757+else
5858+ DATE_INPUT="--date now-${START_TIME}sec"
5959+fi
6060+6161+while [ true ]; do
6262+ STOPWATCH=$(TZ=UTC datef $DATE_INPUT $DATE_FORMAT | ( [[ "$NANOS_SUPPORTED" ]] && sed 's/.\{7\}$//' || cat ) )
6363+ printf "\r\e%s" $STOPWATCH
6464+ sleep 0.03
6565+done