1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-25 17:20:25 +02:00

unposted: more random calendar system fixes and improvements

This commit is contained in:
Peter Stephenson 2007-03-26 14:33:31 +00:00
parent 7072c10ae2
commit 4b7b7f56f1
7 changed files with 189 additions and 92 deletions

View file

@ -1,3 +1,15 @@
2007-03-26 Peter Stephenson <pws@csr.com>
* unposted (follow-on from 23228): Doc/Zsh/calsys.yo,
Functions/Calendar/calendar{,_edit,lockfiles,scandate,showdate}:
New calendar_edit (looks up file to edit and locks it);
calendar -a option; calendar_showdate -f fmt option;
make calendar_lockfiles use zsh/select to get higher resolution
timer to jitter delay; apply the summer time fix to
"<month>, <nth> <frob>day" as well; allow "2nd" as an
ordinal (also 1nd and 3nd, 4nd, ... since we aren't interested
in checking good English).
2007-03-25 Peter Stephenson <p.w.stephenson@ntlworld.com>
* usres/11333: Completion/Unix/Command/_ssh: users-hosts

View file

@ -309,8 +309,8 @@ subsect(Calendar system functions)
startitem()
findex(calendar)
xitem(tt(calendar) [ tt(-dDsv) ] [ tt(-C) var(calfile) ] [ -n var(num) ] [ tt(-S) var(showprog) ] [ [ var(start) ] var(end) ])(
item(tt(calendar -r) [ tt(-dDrsv) ] [ tt(-C) var(calfile) ] [ -n var(num) ] [ tt(-S) var(showprog) ] [ var(start) ])(
xitem(tt(calendar) [ tt(-adDsv) ] [ tt(-C) var(calfile) ] [ -n var(num) ] [ tt(-S) var(showprog) ] [ [ var(start) ] var(end) ])(
item(tt(calendar -r) [ tt(-adDrsv) ] [ tt(-C) var(calfile) ] [ -n var(num) ] [ tt(-S) var(showprog) ] [ var(start) ])(
Show events in the calendar.
With no arguments, show events from the start of today until the end of
@ -338,6 +338,10 @@ tt(~/.zshrc) file.
Options:
startitem()
item(tt(-a))(
Show all items in the calendar, regardless of the tt(start) and
tt(end).
)
item(tt(-C) var(calfile))(
Explicitly specify a calendar file instead of the value of
the tt(calendar-file) style or the the default tt(~/calendar).
@ -418,8 +422,19 @@ option tt(-L) indicates that tt(calendar_add) does not need to lock the
calendar file up the old one as it is already locked. These options will
not usually be needed by users.
)
findex(calendar_edit)
item(tt(calendar_edit))(
This calls the user's editor to edit the calendar file. The editor
is given by the variable tt(VISUAL), if set, else the variable tt(EDITOR).
If the calendar scheduler was running, then after editing the file
tt(calendar -s) is called to update it.
This function locks out the calendar system during the edit.
Hence it should be used to edit the calendar file if there is any
possibility of a calendar event occurring meanwhile.
)
findex(calendar_showdate)
item(tt(calendar_showdate) [ tt(-r) ] var(date-spec ...))(
item(tt(calendar_showdate) [ tt(-r) ] [ tt(-f) var(fmt) ] var(date-spec ...))(
The given var(date-spec) is interpreted and the corresponding date and
time printed. If the initial var(date-spec) begins with a tt(PLUS()) or
tt(-) it is treated as relative to the current time; var(date-spec)s after
@ -427,8 +442,16 @@ the first are treated as relative to the date calculated so far and
a leading tt(PLUS()) is optional in that case. This allows one to
use the system as a date calculator. For example, tt(calendar_showdate '+1
month, 1st Friday') shows the date of the first Friday of next month.
With the option tt(-r) nothing is printed but the value of the date and
timein seconds since the epoch is stored in the parameter tt(REPLY).
With the option tt(-f) var(fmt) the given date/time conversion format
is passed to tt(strftime); see notes on the tt(date-format) style below.
In order to avoid ambiguity with negative relative date specifications,
options must occur in separate words; in other words, tt(-r) and tt(-f)
should not be combined in the same word.
)
findex(calendar_sort)
item(tt(calendar_sort))(
@ -568,14 +591,24 @@ item(tt(calendar_lockfiles))(
Attempt to lock the files given in the argument. To prevent
problems with network file locking this is done in an ad hoc fashion
by attempting to create a symbolic link to the file with the name
var(file)tt(.lockfile). Otherwise, however, the function is not
specific to the calendar system. Three attempts are made to lock
the file before giving up.
var(file)tt(.lockfile). No other system level functions are used
for locking, i.e. the file can be accessed and modified by any
utility that does not use this mechanism. In particular, the user is not
prevented from editing the calendar file at the same time unless
tt(calendar_edit) is used.
Three attempts are made to lock the file before giving up. If the module
tt(zsh/zselect) is available, the times of the attempts are jittered so that
multiple instances of the calling function are unlikely to retry at the
same time.
The files locked are appended to the array tt(lockfiles), which should
be local to the caller.
If all files were successully, status zero is returned, else status one.
This function may be used as a general file locking function, although
this will only work if only this mechanism is used to lock files.
)
findex(calendar_read)
item(tt(calendar_read))(
@ -660,6 +693,11 @@ enditem()
texinode(Calendar Bugs)()(Calendar Utility Functions)(Calendar Function System)
sect(Bugs)
As the system is based entirely on shell functions (with a little support
from the tt(zsh/datetime) module) the mechanisms used are not as robust as
those provided by a dedicated calendar utility. Consequently the user
should not rely on the shell for vital alerts.
There is no tt(calendar_delete) function.
There is no localization support for dates and times, nor any support
@ -668,8 +706,6 @@ for the use of time zones.
Relative periods of months and years do not take into account the variable
number of days.
Recurrent events are not yet supported.
The tt(calendar_show) function is currently hardwired to use tt(xmessage)
for displaying alerts on X Window System displays. This should be
configurable and ideally integrate better with the desktop.

View file

@ -5,7 +5,7 @@ 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 tcalc tsched i rstat remaining
integer showcount icount repeating repeattime resched
integer showcount icount repeating repeattime resched showall
local -a calendar_entries calendar_addlines
local -a times calopts showprog lockfiles match mbegin mend
@ -96,6 +96,11 @@ while [[ ${argv[opti+1]} = -* ]]; do
###########################
# Options without arguments
###########################
(a)
# Show all entries
(( showall = 1 ))
;;
(d)
# Move out of date items to the done file.
(( done = 1 ))
@ -279,7 +284,7 @@ fi
fi
fi
(( shown = 0 ))
if (( t >= start && (remaining || t <= stop || icount < showcount) ))
if (( showall || (t >= start && (remaining || t <= stop || icount < showcount)) ))
then
$showprog $start $stop "$line"
(( icount++ ))

View file

@ -0,0 +1,21 @@
local editor=${VISUAL:-${EDITOR:-vi}}
local line calendar
local -a lockfiles
integer cal_running
sched | while read line; do
[[ $line = *" calendar -s "<->" "<-> ]] && (( cal_running = 1 ))
done
zstyle -s ':datetime:calendar:' calendar-file calendar || calendar=~/calendar
{
calendar_lockfiles $calendar || return 1
eval $editor \$calendar
} always {
(( ${#lockfiles} )) && rm -f $lockfiles
}
(( cal_running )) && calendar -s

View file

@ -3,7 +3,7 @@
local file lockfile msgdone
# Number of attempts to lock a file. Probably not worth stylising.
integer lockattempts=3
integer lockattempts=3 loadtried
# The lockfile name is not stylised: it has to be a fixed
# derivative of the main fail.
@ -18,7 +18,19 @@ for file; do
msgdone="${lockfile}: waiting to acquire lock"
zle -M $msgdone
fi
if (( ! loadtried )); then
zmodload -i zsh/zselect 2>/dev/null
(( loadtried = 1 ))
fi
if zmodload -e zsh/zselect; then
# This gives us finer grained timing (100th second).
# Randomize the sleep between .1 and 1 second so that
# we are much less likely to have multiple instances
# retrying at once.
zselect -t $(( 10 + RANDOM * 90 / 32768 ))
else
sleep 1
fi
done
if [[ -n $msgdone ]]; then
zle -M ${msgdone//?/ }

View file

@ -341,8 +341,8 @@ if (( relative == 0 )); then
date_found=1
;;
# Look for DAY[th/st/rd] MNAME[,] YEAR
((#bi)${~dspat}(<1-31>)(|th|st|rd)[[:space:]]##${~monthpat}(|,)[[:space:]]##((19|20)[0-9][0-9])*)
# Look for DAY[th/st/nd/rd] MNAME[,] YEAR
((#bi)${~dspat}(<1-31>)(|th|st|nd|rd)[[:space:]]##${~monthpat}(|,)[[:space:]]##((19|20)[0-9][0-9])*)
day=$match[2]
mname=$match[4]
year=$match[6]
@ -350,8 +350,8 @@ if (( relative == 0 )); then
date_found=1
;;
# Look for MNAME DAY[th/st/rd][,] YEAR
((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|rd)(|,)[[:space:]]##((19|20)[0-9][0-9])*)
# Look for MNAME DAY[th/st/nd/rd][,] YEAR
((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|nd|rd)(|,)[[:space:]]##((19|20)[0-9][0-9])*)
mname=$match[2]
day=$match[3]
year=$match[6]
@ -359,8 +359,8 @@ if (( relative == 0 )); then
date_found=1
;;
# Look for DAY[th/st/rd] MNAME; assume current year
((#bi)${~dspat}(<1-31>)(|th|st|rd)[[:space:]]##${~monthpat}(|,)([[:space:]]##*|))
# Look for DAY[th/st/nd/rd] MNAME; assume current year
((#bi)${~dspat}(<1-31>)(|th|st|nd|rd)[[:space:]]##${~monthpat}(|,)([[:space:]]##*|))
day=$match[2]
mname=$match[4]
strftime -s year "%Y" $EPOCHSECONDS
@ -368,8 +368,8 @@ if (( relative == 0 )); then
date_found=1
;;
# Look for MNAME DAY[th/st/rd]; assume current year
((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|rd)(|,)([[:space:]]##*|))
# Look for MNAME DAY[th/st/nd/rd]; assume current year
((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|nd|rd)(|,)([[:space:]]##*|))
mname=$match[2]
day=$match[3]
strftime -s year "%Y" $EPOCHSECONDS
@ -378,8 +378,8 @@ if (( relative == 0 )); then
;;
# Now it gets a bit ambiguous.
# Look for DAY[th/st/rd][/]MONTH[/ ,]YEAR
((#bi)${~dspat}(<1-31>)(|th|st|rd)/(<1-12>)((|,)[[:space:]]##|/)((19|20)[0-9][0-9])*)
# Look for DAY[th/st/nd/rd][/]MONTH[/ ,]YEAR
((#bi)${~dspat}(<1-31>)(|th|st|nd|rd)/(<1-12>)((|,)[[:space:]]##|/)((19|20)[0-9][0-9])*)
day=$match[2]
month=$match[4]
year=$match[7]
@ -387,8 +387,8 @@ if (( relative == 0 )); then
date_found=1
;;
# Look for MONTH[/]DAY[th/st/rd][/ ,]YEAR
((#bi)${~dspat}(<1-12>)/(<1-31>)(|th|st|rd)((|,)[[:space:]]##|/)((19|20)[0-9][0-9])*)
# Look for MONTH[/]DAY[th/st/nd/rd][/ ,]YEAR
((#bi)${~dspat}(<1-12>)/(<1-31>)(|th|st|nd|rd)((|,)[[:space:]]##|/)((19|20)[0-9][0-9])*)
month=$match[2]
day=$match[3]
year=$match[7]
@ -597,7 +597,9 @@ if (( relative )); then
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
time_found=1
fi
if [[ $relative = 2 && $line = (#bi)${~dspat_noday}(<->)(th|rd|st)(${~daypat})(|${~schars}*) ]]; then
# For the next three items we accumulate adjustments in "newadd".
# See note below for why they are special.
if [[ $relative = 2 && $line = (#bi)${~dspat_noday}(<->)(th|rd|nd|st)(${~daypat})(|${~schars}*) ]]; then
nth=$match[2]
test=${(L)${${match[4]##${~schars}#}%%${~schars}#}[1,3]}
wday=${dayarr[(I)$test]}
@ -618,42 +620,30 @@ if (( relative )); then
# whereas the day of the month calculated so far is...
strftime -s day2 "%d" $reldate
# so we need to compensate by...
(( reladd += (day - day2) * daysecs ))
(( newadd += (day - day2) * daysecs ))
fi
fi
if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(w|wk|week|weekly)${~repat} ]]; then
[[ -z $match[2] ]] && match[2]=1
(( newadd = relsign * 7 * daysecs * ${match[2]} ))
if (( relative == 2 )); then
# See explanation of this correction under days, below.
strftime -s h1 "%H" $(( relative_start + reladd ))
strftime -s h2 "%H" $(( relative_start + reladd + newadd ))
(( hd = h2 - h1 ))
# and of course we might go past midnight...
if (( hd > 12 )); then
(( hd -= 24 ))
elif (( hd < -12 )); then
(( hd += 24 ))
fi
(( newadd -= hd * 3600 ))
fi
(( reladd += newadd ))
(( newadd += relsign * 7 * daysecs * ${match[2]} ))
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
time_found=1
fi
if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(d|dy|day|daily)${~repat} ]]; then
[[ -z $match[2] ]] && match[2]=1
(( newadd = relsign * daysecs * ${match[2]} ))
if (( relative == 2 )); then
(( newadd += relsign * daysecs * ${match[2]} ))
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
time_found=1
fi
if (( relative == 2 && newadd )); then
# You thought a day was always the same time? Ho, ho, ho.
# If the clocks go forward or back, we can gain or lose
# an hour. Check this by seeing what the hour is before
# and after adding the number of days. If it changes,
# remove the difference.
#
# We need this correction for weeks, too, as above.
# (We could apply corrections for weeks and days together,
# in fact, but I've left it a little more modular).
# We need this correction for days (including days of a given
# month) and weeks.
# We don't need it for years and months because we calculated
# those by actually looking at the calendar for a given
# time of day, so the adjustment came out in the wash.
@ -690,9 +680,6 @@ if (( relative )); then
(( newadd -= hd * 3600 ))
fi
(( reladd += newadd ))
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
time_found=1
fi
if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(h|hr|hour|hourly)${~repat} ]]; then
[[ -z $match[2] ]] && match[2]=1
(( reladd += relsign * 60 * 60 * ${match[2]} ))

View file

@ -8,15 +8,39 @@ integer optr replyset
zstyle -s ':datetime:calendar_showdate:' date-format datefmt ||
datefmt="%a %b %d %H:%M:%S %Z %Y"
while [[ $argv[$OPTIND] != +* ]] && getopts "r" opt; do
case $opt in
(r)
# Memo to myself: both + and - are documented as giving relative
# times, so it's not a good idea to rewrite this to use getopts.
# We need to detect the small number of options this can actually
# handle.
while [[ $1 = -r || $1 = -- || $1 = -f* ]]; do
case $1 in
(-r)
shift
REPLY=0
optr=1
;;
(-f*)
if [[ $1 = -f?* ]]; then
datefmt=$1[3,-1]
shift
else
shift
if [[ -z $1 || $1 != *%* ]]; then
print "$0: -f requires a date/time specification" >&2
return 1
fi
datefmt=$1
shift
fi
;;
(--)
shift
break
;;
esac
done
shift $(( OPTIND - 1 ))
(( optr )) || local REPLY