#!/bin/bash
#Display calendar with arrow key navigation for month and year.
# By The Free Thinker, 2020. gopher://aussies.space/1/~freet/
#
#Usage:
# browsecal.sh [cal args] [-m month] [-y year]
#
#See "man cal" for "cal args".
#
# UP = next year, DOWN = last year, RIGHT = next month,
# LEFT = last month, SPACE = current month/year, q = quit.
#
#Example usage:
# browsecal.sh -3 -y 2013 -m 1
# urxvt -geometry 22x9 -title "Calendar" -e browsecal.sh

clear

#Process command-line arguments:
calargs=
until [ -z "$1" ]
do
case "$1" in
       "-m") shift; [ ! -z "${1##*[!0-9]*}" ] && month=$1 || month=`date -d "$1 1" +%-m` ;; #https://stackoverflow.com/a/2704760
       "-y") shift; year=$1 ;;
       *) calargs="$calargs $1" ;;
esac
shift
done

[ -z $month ] && month=`date +%-m`
[ -z $year ] && year=`date +%-Y`

cal $calargs $month $year || exit

oldIFS="$IFS"
IFS=
#Arrow key reading from:
# https://stackoverflow.com/a/46481173
escape_char=$(printf "\u1b")
while true
do
read -rsn1 mode # get 1 character
if [[ $mode == $escape_char ]]; then
   read -rsn2 mode # read 2 more chars
fi
case $mode in
#key q
   'q') exit ;;

#key SPACE
   ' ') IFS=" "
        month=`date +%-m`
        year=`date +%-Y`
        clear
        cal $calargs $month $year
        IFS=
       ;;

#key UP
   '[A') IFS=" "
         (( year++ ))
         clear
         cal $calargs $month $year
         IFS=
        ;;

#key DOWN
   '[B') IFS=" "
         [ $year -gt 1 ] && (( year-- ))
         clear
         cal $calargs $month $year
         IFS=
        ;;

#key LEFT
   '[D') IFS=" "
         if [ $month -gt 1 ]; then
           (( month-- ))
         else
           (( year-- ))
           month=12
         fi
         clear
         cal $calargs $month $year
         IFS=
        ;;

#key RIGHT
   '[C') IFS=" "
         if [ $month -lt 12 ]; then
           (( month++ ))
         else
           (( year++ ))
           month=1
         fi
         clear; cal $calargs $month $year
         IFS=
        ;;
esac
done

IFS="$oldIFS"