emulate -L zsh setopt extendedglob local line opt REPLY local calendar sched showprog integer time local -a times zmodload -i zsh/datetime || return 1 zmodload -i zsh/zutil || return 1 # Read the calendar file from the calendar-file style zstyle -s ':datetime:calendar:' calendar-file calendar || calendar=~/calendar # Read the programme to show the message from the show-prog style. # (Requires option -a or -s to be useful.) zstyle -s ':datetime:calendar:' show-prog showprog || showprog="print -r" [[ -f $calendar ]] || return 1 while getopts "aC:sS:x" opt; do case $opt in # Use the "asched" function to generate a message asynchronously. (a) sched=asched ;; (C) # Pick the calendar file, overriding style and default. calendar=$OPTARG ;; (s) # Use the "sched" builtin to generate a message before a prompt. sched=sched ;; (S) # Explicitly specify a show programme, overriding style and default. showprog=$OPTARG ;; (x) # Use xmessage as the show programme. Best used with -a. showprog=xmessage ;; (*) return 1 ;; esac done shift $(( OPTIND - 1 )) time=$EPOCHSECONDS # search today and tomorrow times=($time $(( time + 24*60*60 ))) autoload -Uz matchtime while read -r line; do if matchtime -t $line $times[1]; then print -r $line if [[ -n $sched && -n $REPLY ]]; then # eval needed in place of closures on REPLY and line. # i like perl. eval "function sched_$REPLY { unfunction sched_$REPLY $showprog \"Calendar entry is now due: \" ${(q)line} >&$TTY }" $sched $REPLY sched_$REPLY fi else for time in ${times[2,-1]}; do matchtime -t $line $time && print -r $line && break done fi done <$calendar return 0