summary refs log tree commit diff
path: root/Functions/Calendar/calendar
diff options
context:
space:
mode:
Diffstat (limited to 'Functions/Calendar/calendar')
-rw-r--r--Functions/Calendar/calendar88
1 files changed, 60 insertions, 28 deletions
diff --git a/Functions/Calendar/calendar b/Functions/Calendar/calendar
index 124fd9786..ea81c7ae7 100644
--- a/Functions/Calendar/calendar
+++ b/Functions/Calendar/calendar
@@ -1,21 +1,18 @@
 emulate -L zsh
 setopt extendedglob
 
-# standard ctime date/time format
-local ctime="%a %b %d %H:%M:%S %Z %Y"
-
-local line REPLY REPLY2 userange pruned
-local calendar donefile sched newfile warnstr mywarnstr
+local line restline REPLY REPLY2 userange pruned nobackup datefmt
+local calendar donefile sched newfile warnstr mywarnstr newdate
 integer time start stop today ndays y m d next=-1 shown done nodone
-integer verbose warntime mywarntime t tsched i rstat remaining
-integer showcount icount
-local -a calendar_entries
+integer verbose warntime mywarntime t tcalc tsched i rstat remaining
+integer showcount icount repeating repeattime resched
+local -a calendar_entries calendar_addlines
 local -a times calopts showprog lockfiles match mbegin mend
 
 zmodload -i zsh/datetime || return 1
 zmodload -i zsh/zutil || return 1
 
-autoload -U calendar_{read,scandate,show,lockfiles}
+autoload -U calendar_{add,read,scandate,show,lockfiles}
 
 # Read the calendar file from the calendar-file style
 zstyle -s ':datetime:calendar:' calendar-file calendar || calendar=~/calendar
@@ -27,6 +24,9 @@ zstyle -a ':datetime:calendar:' show-prog showprog ||
 # Amount of time before an event when it should be flagged.
 # May be overridden in individual entries
 zstyle -s ':datetime:calendar:' warn-time warnstr || warnstr="0:05"
+# default to standard ctime date/time format
+zstyle -s ':datetime:calendar:' date-format datefmt ||
+  datefmt="%a %b %d %H:%M:%S %Z %Y"
 
 if [[ -n $warnstr ]]; then
   if [[ $warnstr = <-> ]]; then
@@ -169,11 +169,11 @@ strftime -s wd "%u" $start
 
 if (( $# && !remaining )); then
   if [[ $1 = +* ]]; then
-    if ! calendar_scandate -ar ${1[2,-1]}; then
+    if ! calendar_scandate -a -R $start ${1[2,-1]}; then
       print "$0: failed to parse relative time: $1" >&2
       return 1
     fi
-    (( stop = start + REPLY ))
+    (( stop = REPLY ))
   elif [[ $1 = <-> ]]; then
     stop=$1
   else
@@ -184,8 +184,8 @@ if (( $# && !remaining )); then
     stop=$REPLY
   fi
   if (( stop < start )); then
-    strftime -s REPLY $ctime $start
-    strftime -s REPLY2 $ctime $stop
+    strftime -s REPLY $datefmt $start
+    strftime -s REPLY2 $datefmt $stop
     print "$0: requested end time is before start time:
   start: $REPLY
   end: $REPLY2" >&2
@@ -224,12 +224,12 @@ autoload -Uz matchdate
 
 if (( verbose )); then
   print -n "start: "
-  strftime $ctime $start
+  strftime $datefmt $start
   print -n "stop: "
   if (( remaining )); then
     print "none"
   else
-    strftime $ctime $stop
+    strftime $datefmt $stop
   fi
 fi
 
@@ -248,22 +248,32 @@ fi
     # REPLY2 to the line with the date and time removed.
     calendar_scandate -as $line || continue
     (( t = REPLY ))
+    restline=$REPLY2
 
     # Look for specific warn time.
-    pruned=${REPLY2#(|*[[:space:],])WARN[[:space:]]}
+    pruned=${restline#(|*[[:space:],])WARN[[:space:]]}
     (( mywarntime = warntime ))
     mywarnstr=$warnstr
-    if [[ $pruned != $REPLY2 ]]; then
-      if calendar_scandate -ars $pruned; then
-	(( mywarntime = REPLY ))
+    if [[ $pruned != $restline ]]; then
+      if calendar_scandate -asm -R $t $pruned; then
+	(( mywarntime = t - REPLY ))
 	mywarnstr=${pruned%%"$REPLY2"}
       fi
     fi
 
+    # Look for a repeat time.
+    (( repeating = 0 ))
+    pruned=${restline#(|*[[:space:],])RPT[[:space:]]}
+    if [[ $pruned != $restline ]]; then
+      if calendar_scandate -a -R $t $pruned; then
+	(( repeattime = REPLY, repeating = 1 ))
+      fi
+    fi
+
     if (( verbose )); then
       print "Examining: $line"
       print -n "  Date/time: "
-      strftime $ctime $t
+      strftime $datefmt $t
       if [[ -n $sched ]]; then
 	print "  Warning $mywarntime seconds ($mywarnstr) before"
       fi
@@ -272,7 +282,9 @@ fi
     if (( t >= start && (remaining || t <= stop || icount < showcount) ))
     then
       $showprog $start $stop "$line"
-      (( shown = 1, icount++ ))
+      (( icount++ ))
+      # Doesn't count as "shown" unless the event has now passed.
+      (( t <= EPOCHSECONDS )) && (( shown = 1 ))
     elif [[ -n $sched ]]; then
       (( tsched = t - mywarntime ))
       if (( tsched >= start && tsched <= stop)); then
@@ -280,22 +292,36 @@ fi
       fi
     fi
     if [[ -n $sched ]]; then
-      if (( t - mywarntime > EPOCHSECONDS )); then
+      if (( shown && repeating )); then
+	# Done and dusted, but a repeated event is due.
+	strftime -s newdate $datefmt $repeattime
+	calendar_addlines+=("$newdate$restline")
+
+	# We'll add this back in below, but we check in case the
+	# repeated event is the next one due.  It's not
+	# actually a disaster if there's an error and we fail
+	# to add the time.  Always try to reschedule this event.
+	(( tcalc = repeattime, resched = 1 ))
+      else
+	(( tcalc = t ))
+      fi
+
+      if (( tcalc - mywarntime > EPOCHSECONDS )); then
 	# schedule for a warning
-	(( tsched = t - mywarntime ))
+	(( tsched = tcalc - mywarntime, resched = 1 ))
       else
 	# schedule for event itself
-	(( tsched = t ))
+	(( tsched = tcalc ))
+	# but don't schedule unless the event has not yet been shown.
+	(( !shown )) && (( resched = 1 ))
       fi
-      if (( (tsched > EPOCHSECONDS || ! shown) &&
-	    (next < 0 || tsched < next) )); then
+      if (( resched && (next < 0 || tsched < next) )); then
 	(( next = tsched ))
       fi
     fi
     if [[ -n $donefile ]]; then
-      if (( t <= EPOCHSECONDS && shown )); then
+      if (( shown )); then
 	# Done and dusted.
-	# TODO: handle repeated times from REPLY2.
 	if ! print -r $line >>$donefile; then
 	  if (( done != 3 )); then
 	    (( done = 3 ))
@@ -346,9 +372,15 @@ New calendar left in $newfile." >&2
 Old calendar left in $calendar.old." >&2
       (( rstat = 1 ))
     fi
+    nobackup=-B
   elif [[ -n $donefile ]]; then
     rm -f $newfile
   fi
+
+  # Reschedule repeating events.
+  for line in $calendar_addlines; do
+    calendar_add -L $nobackup $line
+  done
 } always {
   (( ${#lockfiles} )) && rm -f $lockfiles
 }