mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-12-29 16:25:35 +01:00
c.f. 23023: new calendar function system.
This commit is contained in:
parent
ab8b8026dc
commit
6b1b34d1da
23 changed files with 1787 additions and 8 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
2006-12-01 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* c.f. 23023: Completion/Unix/Type/_list_files, Doc/.distfiles,
|
||||
Doc/Makefile.in, Doc/zsh.yo, Doc/zshcalsys.yo, Doc/Zsh/.distfiles,
|
||||
Doc/Zsh/calsys.yo, Doc/Zsh/compsys.yo, Doc/Zsh/intro.yo,
|
||||
Doc/Zsh/manual.yo, Doc/Zsh/modules.yo, Doc/Zsh/tcpsys.yo,
|
||||
Functions/Calendar/.distfiles, Functions/Calendar/age,
|
||||
Functions/Calendar/calendar, Functions/Calendar/calendar_add,
|
||||
Functions/Calendar/calendar_lockfiles,
|
||||
Functions/Calendar/calendar_read,
|
||||
Functions/Calendar/calendar_scandate,
|
||||
Functions/Calendar/calendar_show,
|
||||
Functions/Calendar/calendar_sort, Src/Modules/datetime.mdd: new
|
||||
calendar system with age glob qualifier function; files
|
||||
_list_files to be able not to trample over external stat.
|
||||
|
||||
2006-11-28 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 23022: Test/ztst.zsh: don't allow WORDCHARS to be exported
|
||||
|
|
|
@ -48,6 +48,13 @@ done
|
|||
|
||||
zmodload -i zsh/stat 2>/dev/null || return 1
|
||||
|
||||
# Enable stat temporarily if disabled to avoid clashes.
|
||||
integer disable_stat
|
||||
if [[ ${builtins[stat]} != defined ]]; then
|
||||
(( disable_stat = 1 ))
|
||||
enable stat
|
||||
fi
|
||||
|
||||
dir=${2:+$2/}
|
||||
dir=${(Q)dir}
|
||||
|
||||
|
@ -66,4 +73,5 @@ done
|
|||
|
||||
(( ${#listfiles} )) && listopts=(-d listfiles -l -o)
|
||||
|
||||
(( disable_stat )) && disable stat
|
||||
return 0
|
||||
|
|
|
@ -2,7 +2,8 @@ DISTFILES_SRC='
|
|||
.cvsignore .distfiles Makefile.in
|
||||
META-FAQ.yo intro.ms
|
||||
version.yo zmacros.yo zman.yo ztexi.yo
|
||||
zsh.yo zshbuiltins.yo zshcompctl.yo zshcompsys.yo zshcompwid.yo
|
||||
zsh.yo zshbuiltins.yo zshcalsys.yo
|
||||
zshcompctl.yo zshcompsys.yo zshcompwid.yo
|
||||
zshexpn.yo zshmisc.yo zshmodules.yo zshoptions.yo zshparam.yo
|
||||
zshroadmap.yo zshzftpsys.yo zshzle.yo zshcontrib.yo zshtcpsys.yo
|
||||
zsh.texi
|
||||
|
|
|
@ -45,7 +45,7 @@ TEXI2HTML = texi2html --output . --ifinfo --split=chapter
|
|||
.SUFFIXES: .yo .1
|
||||
|
||||
# man pages to install
|
||||
MAN = zsh.1 zshbuiltins.1 zshcompctl.1 zshcompwid.1 zshcompsys.1 \
|
||||
MAN = zsh.1 zshbuiltins.1 zshcalsys.1 zshcompctl.1 zshcompwid.1 zshcompsys.1 \
|
||||
zshcontrib.1 zshexpn.1 zshmisc.1 zshmodules.1 \
|
||||
zshoptions.1 zshparam.1 zshroadmap.1 zshtcpsys.1 zshzftpsys.1 zshzle.1 \
|
||||
zshall.1
|
||||
|
@ -70,6 +70,7 @@ Zsh/mod_zprof.yo Zsh/mod_zpty.yo Zsh/mod_zselect.yo \
|
|||
Zsh/mod_zutil.yo
|
||||
|
||||
YODLSRC = zmacros.yo zman.yo ztexi.yo Zsh/arith.yo Zsh/builtins.yo \
|
||||
Zsh/calsys.yo \
|
||||
Zsh/compat.yo Zsh/compctl.yo Zsh/compsys.yo Zsh/compwid.yo Zsh/cond.yo \
|
||||
Zsh/contrib.yo Zsh/exec.yo Zsh/expn.yo \
|
||||
Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/manual.yo \
|
||||
|
@ -175,6 +176,8 @@ zsh.1 zshall.1: Zsh/intro.yo Zsh/metafaq.yo Zsh/invoke.yo Zsh/files.yo \
|
|||
|
||||
zshbuiltins.1: Zsh/builtins.yo
|
||||
|
||||
zshcalsys.1: Zsh/calsys.yo
|
||||
|
||||
zshcompctl.1: Zsh/compctl.yo
|
||||
|
||||
zshcompwid.1: Zsh/compwid.yo
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
DISTFILES_SRC='
|
||||
.cvsignore .distfiles
|
||||
arith.yo builtins.yo compat.yo compctl.yo compsys.yo compwid.yo
|
||||
arith.yo builtins.yo calsys.yo compat.yo compctl.yo compsys.yo compwid.yo
|
||||
cond.yo exec.yo expn.yo filelist.yo files.yo func.yo grammar.yo
|
||||
index.yo intro.yo invoke.yo jobs.yo manual.yo metafaq.yo mod_cap.yo
|
||||
mod_clone.yo mod_compctl.yo mod_complete.yo mod_complist.yo
|
||||
|
|
547
Doc/Zsh/calsys.yo
Normal file
547
Doc/Zsh/calsys.yo
Normal file
|
@ -0,0 +1,547 @@
|
|||
texinode(Calendar Function System)(TCP Function System)(Zsh Modules)(Top)
|
||||
chapter(Calendar Function System)
|
||||
cindex(calendar function system)
|
||||
cindex(zsh/datetime, function system based on)
|
||||
sect(Description)
|
||||
|
||||
The shell is supplied with a series of functions to replace and enhance the
|
||||
traditional Unix tt(calendar) programme, which warns the user of imminent
|
||||
or future events, details of which are stored in a text file (typically
|
||||
tt(calendar) in the user's home directory). The version provided here
|
||||
includes a mechanism for alerting the user when an event is due.
|
||||
|
||||
In addition a function tt(age) is provided that can be used in a glob
|
||||
qualifier; it allows files to be selected based on their modification
|
||||
times.
|
||||
|
||||
The format of the tt(calendar) file and the dates used there in and in
|
||||
the tt(age) function are described first, then the functions that can
|
||||
be called to examine and modify the tt(calendar) file.
|
||||
|
||||
The functions here depend on the availability of the tt(zsh/datetime)
|
||||
module which is usually installed with the shell. The library function
|
||||
tt(strptime+LPAR()RPAR()) must be available; it is present on most recent
|
||||
operating systems.
|
||||
|
||||
startmenu()
|
||||
menu(Calendar File and Date Formats)
|
||||
menu(Calendar System User Functions)
|
||||
menu(Calendar Styles)
|
||||
menu(Calendar Utility Functions)
|
||||
menu(Calendar Bugs)
|
||||
endmenu()
|
||||
|
||||
|
||||
texinode(Calendar File and Date Formats)(Calendar System User Functions)()(Calendar Function System)
|
||||
sect(File and Date Formats)
|
||||
|
||||
subsect(Calendar File Format)
|
||||
|
||||
The calendar file is by default tt(~/calendar). This can be configured
|
||||
by the tt(calendar-file) style, see
|
||||
ifzman(the section STYLES below)\
|
||||
ifnzman(noderef(Calendar Styles)). The basic format consists
|
||||
of a series of separate lines, with no indentation, each including
|
||||
a date and time specification followed by a description of the event.
|
||||
|
||||
Various enhancements to this format are supported, based on the syntax
|
||||
of Emacs calendar mode. An indented line indicates a continuation line
|
||||
that continues the description of the event from the preceeding line
|
||||
(note the date may not be continued in this way). An initial ampersand
|
||||
(tt(&)) is ignored for compatibility.
|
||||
|
||||
The Emacs extension that a date with no description may refer to a number
|
||||
of succeeding events at different times is not supported.
|
||||
|
||||
Unless the tt(done-file) style has been altered, any events which
|
||||
have been processed are appended to the file with the same name as the
|
||||
calendar file with the suffix tt(.done), hence tt(~/calendar.done) by
|
||||
default.
|
||||
|
||||
An example is shown below.
|
||||
|
||||
subsect(Date Format)
|
||||
|
||||
The format of the date and time is designed to allow flexibility without
|
||||
admitting ambiguity. Note that there is no localization support; month and
|
||||
day names must be in English (though only the first three letters are
|
||||
significant) and separator characters are fixed. Furthermore, time zones
|
||||
are not handled; all times are assumed to be local.
|
||||
|
||||
It is recommended that, rather than exploring the intricacies of the
|
||||
system, users find a date format that is natural to them and stick to it.
|
||||
This will avoid unexpected effects. Various key facts should be noted.
|
||||
|
||||
startitemize()
|
||||
itemiz(In particular, note the confusion between
|
||||
var(month)tt(/)var(day)tt(/)var(year) and
|
||||
var(day)tt(/)var(month)tt(/)var(year) when the month is numeric; these
|
||||
formats should be avoided if at all possible. Many alternatives are
|
||||
available.)
|
||||
itemiz(The year must be given in full to avoid confusion, and only years
|
||||
from 1900 to 2099 inclusive are matched.)
|
||||
enditemize()
|
||||
|
||||
The following give some obvious examples; users finding here
|
||||
a format they like and not subject to vagaries of style may skip
|
||||
the full description. As dates and times are matched separately
|
||||
(even though the time may be embedded in the date), any date format
|
||||
may be mixed with any format for the time of day provide the
|
||||
separators are clear (whitespace, colons, commas).
|
||||
|
||||
example(2007/04/03 13:13
|
||||
2007/04/03:13:13
|
||||
2007/04/03 1:13 pm
|
||||
3rd April 2007, 13:13
|
||||
April 3rd 2007 1:13 p.m.
|
||||
Apr 3, 2007 13:13
|
||||
Tue Apr 03 13:13:00 2007
|
||||
13:13 2007/apr/3)
|
||||
|
||||
More detailed rules follow.
|
||||
|
||||
Times are parsed and extracted before dates. They must use colons
|
||||
to separate hours and minutes, though a dot is allowed before seconds
|
||||
if they are present. This limits time formats to the following:
|
||||
|
||||
startitemize()
|
||||
itemiz(var(HH)tt(:)var(MM)[tt(:)var(SS)[tt(.)var(FFFFF)]] [tt(am)|tt(pm)|tt(a.m.)|tt(p.m.)])
|
||||
itemiz(var(HH)tt(:)var(MM)tt(.)var(SS)[tt(.)var(FFFFF)] [tt(am)|tt(pm)|tt(a.m.)|tt(p.m.)])
|
||||
enditemize()
|
||||
|
||||
Here, square brackets indicate optional elements, possibly with
|
||||
alternatives. Fractions of a second are recognised but ignored. For
|
||||
absolute times (the normal format require by the tt(calendar) file and the
|
||||
tt(age) function) a date is mandatory but a time of day is not; the time
|
||||
returned is at the start of the date. One variation is allowed: if
|
||||
tt(a.m.) or tt(p.m.) or one of their variants is present, an hour without a
|
||||
minute is allowed, e.g. tt(3 p.m.).
|
||||
|
||||
Time zones are not handled, though if one is matched following a time
|
||||
specification it will be removed to allow a surrounding date to be
|
||||
parsed. This only happens if the format of the timezone is not too
|
||||
unusual. The following are examples of forms that are understood:
|
||||
|
||||
example(+0100
|
||||
GMT
|
||||
GMT-7
|
||||
CET+1CDT)
|
||||
|
||||
Any part of the timezone that is not numeric must have exactly three
|
||||
capital letters in the name.
|
||||
|
||||
Dates suffer from the ambiguity between var(DD)tt(/)var(MM)tt(/)var(YYYY)
|
||||
and var(MM)tt(/)var(DD)tt(/)var(YYYY). It is recommended this form is
|
||||
avoided with purely numeric dates, but use of ordinals,
|
||||
eg. tt(3rd/04/2007), will resolve the ambiguity as the ordinal is always
|
||||
parsed as the day of the month. Years must be four digits (and the first
|
||||
two must be tt(19) or tt(20)); tt(03/04/08) is not recognised. Other
|
||||
numbers may have leading zeroes, but they are not required. The following
|
||||
are handled:
|
||||
|
||||
startitemize()
|
||||
itemiz(var(YYYY)tt(/)var(MM)tt(/)var(DD))
|
||||
itemiz(var(YYYY)tt(-)var(MM)tt(-)var(DD))
|
||||
itemiz(var(YYYY)tt(/)var(MNM)tt(/)var(DD))
|
||||
itemiz(var(YYYY)tt(-)var(MNM)tt(-)var(DD))
|
||||
itemiz(var(DD)[tt(th)|tt(st)|tt(rd)] var(MNM)[tt(,)] [ var(YYYY) ])
|
||||
itemiz(var(MNM) var(DD)[tt(th)|tt(st)|tt(rd)][tt(,)] [ var(YYYY) ])
|
||||
itemiz(var(DD)[tt(th)|tt(st)|tt(rd)]tt(/)var(MM)[tt(,)] var(YYYY))
|
||||
itemiz(var(DD)[tt(th)|tt(st)|tt(rd)]tt(/)var(MM)tt(/)var(YYYY))
|
||||
itemiz(var(MM)tt(/)var(DD)[tt(th)|tt(st)|tt(rd)][tt(,)] var(YYYY))
|
||||
itemiz(var(MM)tt(/)var(DD)[tt(th)|tt(st)|tt(rd)]tt(/)var(YYYY))
|
||||
enditemize()
|
||||
|
||||
Here, var(MNM) is at least the first three letters of a month name,
|
||||
matched case-insensitively. The remainder of the month name may appear but
|
||||
its contents are irrelevant, so janissary, febrile, martial, apricot,
|
||||
maybe, junta, etc. are happily handled.
|
||||
|
||||
Where the year is shown as optional, the current year is assumed. There
|
||||
are only two such cases, the form tt(Jun 20) or tt(14 September) (the only
|
||||
two commonly occurring forms, apart from a "the" in some forms of English,
|
||||
which isn't currently supported). Such dates will of course become
|
||||
ambiguous in the future, so should ideally be avoided.
|
||||
|
||||
Times may follow dates with a colon, e.g. tt(1965/07/12:09:45); this is in
|
||||
order to provide a format with no whitespace. A comma and whitespace are
|
||||
allowed, e.g. tt(1965/07/12, 09:45). Currently the order of these
|
||||
separators is not checked, so illogical formats such as tt(1965/07/12, :
|
||||
,09:45) will also be matched. For simplicity such variations are not shown
|
||||
in the list above. Otherwise, a time is only recognised as being
|
||||
associated with a date if there is only whitespace in between, or if the
|
||||
time was embedded in the date.
|
||||
|
||||
Days of the week are not scanned, but will be ignored if they occur
|
||||
at the start of the date pattern only.
|
||||
|
||||
For example, the standard date format:
|
||||
|
||||
example(Fri Aug 18 17:00:48 BST 2006)
|
||||
|
||||
is handled by matching var(HH)tt(:)var(MM)tt(:)var(SS) and removing it
|
||||
together with the matched (but unused) time zone. This leaves the following:
|
||||
|
||||
example(Fri Aug 18 2006)
|
||||
|
||||
tt(Fri) is ignored and the rest is matched according to the standard rules.
|
||||
|
||||
subsect(Relative Time Format)
|
||||
|
||||
In certain places relative times are handled. Here, a date is not allowed;
|
||||
instead a combination of various supported periods are allowed, together
|
||||
with an optional time. The periods must be in order from most to
|
||||
least significant.
|
||||
|
||||
The periods handled, with possible abbreviations are:
|
||||
|
||||
startitem()
|
||||
item(Years)(
|
||||
tt(years), tt(yrs), tt(ys), tt(year), tt(yr), tt(y).
|
||||
Currently a year is 365.25 days, not a calendar year.
|
||||
)
|
||||
item(Months)(
|
||||
tt(months), tt(mons), tt(mnths), tt(mths), tt(month), tt(mon),
|
||||
tt(mnth), tt(mth). Note that tt(m), tt(ms), tt(mn), tt(mns)
|
||||
are ambiguous and are em(not) handled. Currently a month is a period
|
||||
of 30 days rather than a calendar month.
|
||||
)
|
||||
item(Weeks)(
|
||||
tt(weeks), tt(wks), tt(ws), tt(week), tt(wk), tt(w)
|
||||
)
|
||||
item(Days)(
|
||||
tt(days), tt(dys), tt(ds), tt(day), tt(dy), tt(d)
|
||||
)
|
||||
item(Minutes)(
|
||||
tt(minutes), tt(mins), tt(minute), tt(min), but em(not) tt(m),
|
||||
tt(ms), tt(mn) or tt(mns)
|
||||
)
|
||||
item(Seconds)(
|
||||
tt(seconds), tt(secs), tt(ss), tt(second), tt(sec), tt(s)
|
||||
)
|
||||
enditem()
|
||||
|
||||
Spaces between the numbers are optional, but are required between items,
|
||||
although a comma may be used (with or without spaces).
|
||||
|
||||
Here are some examples:
|
||||
|
||||
example(30 years 3 months 4 days 3:42:41
|
||||
14 days 5 hours
|
||||
4d,10hr)
|
||||
|
||||
subsect(Example)
|
||||
|
||||
Here is an example calendar file. It uses a consistent date format,
|
||||
as recommended above. The second entry has a continuation line.
|
||||
|
||||
example(Feb 1, 2006 14:30 Pointless bureaucratic meeting
|
||||
Mar 27, 2006 11:00 Mutual recrimination and finger pointing
|
||||
Bring water pistol and waterproofs
|
||||
Apr 10, 2006 13:30 Even more pointless blame assignment exercise)
|
||||
|
||||
|
||||
texinode(Calendar System User Functions)(Calendar Styles)(Calendar File and Date Formats)(Calendar Function System)
|
||||
sect(User Functions)
|
||||
|
||||
This section describes functions that are designed to be called
|
||||
directly by the user. The first part describes those functions
|
||||
associated with the user's calendar; the second part describes
|
||||
the use in glob qualifiers.
|
||||
|
||||
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) ])(
|
||||
Show events in the calendar.
|
||||
|
||||
With no arguments, show events from the start of today until the end of
|
||||
the next working day after today. In other words, if today is Friday,
|
||||
Saturday, or Sunday, show up to the end of the following Monday, otherwise
|
||||
show today and tomorrow.
|
||||
|
||||
If var(end) is given, show events from the start of today up to the time
|
||||
and date given, which is in the format described in the previous section.
|
||||
Note that if this is a date the time is assumed to be midnight at the
|
||||
start of the date, so that effectively this shows all events before
|
||||
the given date.
|
||||
|
||||
var(end) may start with a tt(+), in which case the remainder of the
|
||||
specification is a relative time format as described in the previous
|
||||
section indicating the range of time from the start time that is to
|
||||
be included.
|
||||
|
||||
If var(start) is also given, show events starting from that time and date.
|
||||
The word tt(now) can be used to indicate the current time.
|
||||
|
||||
To implement an alert when events are due, include tt(calendar -s) in your
|
||||
tt(~/.zshrc) file.
|
||||
|
||||
Options:
|
||||
|
||||
startitem()
|
||||
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).
|
||||
)
|
||||
item(tt(-d))(
|
||||
Move any events that have passed from the calendar file to the
|
||||
"done" file, as given by the tt(done-file) style or the default
|
||||
which is the calendar file with tt(.done) appended. This option
|
||||
is implied by the tt(-s) option.
|
||||
)
|
||||
item(tt(-D))(
|
||||
Turns off the option tt(-d), even if the tt(-s) option is also present.
|
||||
)
|
||||
item(tt(-n) var(num), tt(-)var(num))(
|
||||
Show at least var(num) events, if present in the calendar file, regardless
|
||||
of the tt(start) and tt(end).
|
||||
)
|
||||
item(tt(-r))(
|
||||
Show all the remaining options in the calendar, ignoring the given tt(end)
|
||||
time. The tt(start) time is respected; any argument given is treated
|
||||
as a tt(start) time.
|
||||
)
|
||||
item(tt(-s))(
|
||||
Use the shell's tt(sched) command to schedule a timed event that
|
||||
will warn the user when an event is due. Note that the tt(sched) command
|
||||
only runs if the shell is at an interactive prompt; a foreground taks
|
||||
blocks the scheduled task from running until it is finished.
|
||||
|
||||
The timed event usually runs the programme tt(calendar_show) to show
|
||||
the event, as described in
|
||||
ifzman(the section UTILITY FUNCTIONS below)\
|
||||
ifnzman(noderef(Calendar Utility Functions)).
|
||||
|
||||
By default, a warning of the event is shown five minutes before it is due.
|
||||
The warning period can be configured by the style tt(warn-time) or
|
||||
for a single calendar entry by including tt(WARN) var(reltime) in the first
|
||||
line of the entry, where var(reltime) is one of the usual relative time
|
||||
formats.
|
||||
|
||||
It is safe to run tt(calendar -s) to reschedule an existing event
|
||||
(if the calendar file has changed, for example), and also to have it
|
||||
running in multiples instances of the shell since the calendar file
|
||||
is locked when in use.
|
||||
|
||||
By default, expired events are moved to the "done" file; see the tt(-d)
|
||||
option. Use tt(-D) to prevent this.
|
||||
)
|
||||
item(tt(-S) var(showprog))(
|
||||
Explicitly specify a programme to be used for showing events instead
|
||||
of the value of the tt(show-prog) style or the default tt(calendar_show).
|
||||
)
|
||||
item(tt(-v))(
|
||||
Verbose: show more information about stages of processing.
|
||||
)
|
||||
enditem()
|
||||
)
|
||||
findex(calendar_add)
|
||||
item(tt(calendar_add) var(event ...))(
|
||||
Adds a single event to the calendar in the appropriate location.
|
||||
Using this function ensures that the calendar file is sorted in date
|
||||
and time order. It also makes special arrangments for locking
|
||||
the file will it is altered. The old calendar is left in a file
|
||||
with the suffix tt(.old).
|
||||
)
|
||||
findex(calendar_sort)
|
||||
item(tt(calendar_sort))(
|
||||
Sorts the calendar file into date and time order. The old calendar is
|
||||
left in a file with the suffix tt(.old).
|
||||
)
|
||||
enditem()
|
||||
|
||||
subsect(Glob qualifiers)
|
||||
findex(age)
|
||||
|
||||
The function tt(age) can be autoloaded and use separately from
|
||||
the calendar system, although it uses the function tt(calendar_scandate)
|
||||
for date formatting. It requires the tt(zsh/stat) builtin, which
|
||||
makes available the builtin tt(stat). This may conflict with an
|
||||
external programme of the same name; if it does, the builtin may be
|
||||
disabled for normal operation by including the following code in
|
||||
an initialization file:
|
||||
|
||||
example(zmodload -i zsh/stat
|
||||
disable stat)
|
||||
|
||||
tt(age) selects files having a given modification time for use
|
||||
as a glob qualifer. The format of the date is the same as that
|
||||
understood by the calendar system, described in
|
||||
ifzman(the section FILE AND DATE FORMATS above)\
|
||||
ifnzman(noderef(Calendar File and Date Formats)).
|
||||
|
||||
The function can take one or two arguments, which can be supplied either
|
||||
directly as command or arguments, or separately as shell parameters.
|
||||
|
||||
example(print *+LPAR()e:age 2006/10/04 2006/10/09:+RPAR())
|
||||
|
||||
The example above matches all files modified between the start of those
|
||||
dates.
|
||||
|
||||
example(print *+LPAR()e:age 2006/10/04+RPAR())
|
||||
|
||||
The example above matches all files modified on that date. If the second
|
||||
argument is omitted it is taken to be exactly 24 hours after the first
|
||||
argument (even if the first argument contains a time).
|
||||
|
||||
example(print *+LPAR()e-age 2006/10/04:10:15 2006/10/04:10:45-RPAR())
|
||||
|
||||
The example above supplies times. Note that whitespace within the time and
|
||||
date specification must be quoted to ensure tt(age) receives the correct
|
||||
arguments, hence the use of the additional colon to separate the date and
|
||||
time.
|
||||
|
||||
example(AGEREF1=2006/10/04:10:15
|
||||
AGEREF2=2006/10/04:10:45
|
||||
print *+LPAR()PLUS()age+RPAR())
|
||||
|
||||
This shows the same example before using another form of argument
|
||||
passing. The dates and times in the parameters tt(AGEREF1) and tt(AGEREF2)
|
||||
stay in effect until unset, but will be overridden if any argument is
|
||||
passed as an explicit argument to age. Any explicit argument
|
||||
causes both parameters to be ignored.
|
||||
|
||||
|
||||
texinode(Calendar Styles)(Calendar Utility Functions)(Calendar System User Functions)(Calendar Function System)
|
||||
sect(Styles)
|
||||
|
||||
The zsh style mechanism using the tt(zstyle) command is describe in
|
||||
ifzman(zmanref(zshmodules))\
|
||||
ifnzman(noderef(The zsh/zutil Module)). This is the same mechanism
|
||||
used in the completion system.
|
||||
|
||||
The styles below are all examined in the context
|
||||
tt(:datetime:)var(function)tt(:), for example tt(:datetime:calendar:).
|
||||
|
||||
startitem()
|
||||
kindex(calendar-file)
|
||||
item(tt(calendar-file))(
|
||||
The location of the main calendar. The default is tt(~/calendar).
|
||||
)
|
||||
kindex(done-file)
|
||||
item(tt(done-file))(
|
||||
The location of the file to which events which have passed are appended.
|
||||
The default is the calendar file location with the suffix tt(.done).
|
||||
The style may be set to an empty string in which case a "done" file
|
||||
will not be maintained.
|
||||
)
|
||||
kindex(show-prog)
|
||||
item(tt(show-prog))(
|
||||
The programme run by tt(calendar) for showing events. It will
|
||||
be passed the start time and stop time of the events requested in seconds
|
||||
since the epoch followed by the event text. Note that tt(calendar -s) uses
|
||||
a start time and stop time equal to one another to indicate alerts
|
||||
for specific events.
|
||||
|
||||
The default is the function tt(calendar_show).
|
||||
)
|
||||
kindex(warn-time)
|
||||
item(tt(warn-time))(
|
||||
The time before an event at which a warning will be displayed, if the
|
||||
first line of the event does not include the text tt(EVENT) var(reltime).
|
||||
The default is 5 minutes.
|
||||
)
|
||||
enditem()
|
||||
|
||||
|
||||
texinode(Calendar Utility Functions)(Calendar Bugs)(Calendar Styles)(Calendar Function System)
|
||||
sect(Utility functions)
|
||||
|
||||
startitem()
|
||||
findex(calendar_lockfiles)
|
||||
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.
|
||||
|
||||
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.
|
||||
)
|
||||
findex(calendar_read)
|
||||
item(tt(calendar_read))(
|
||||
This is a backend used by various other functions to parse the
|
||||
calendar file, which is passed as the only argument. The array
|
||||
tt(calendar_entries) is set to the list of events in the file; no
|
||||
pruning is done except that ampersands are removed from the start of
|
||||
the line. Each entry may contain multiple lines.
|
||||
)
|
||||
findex(calendar_scandate)
|
||||
item(tt(calendar_scandate))(
|
||||
This is a generic function to parse dates and times that may be
|
||||
used separately from the calendar system. The argument is a date
|
||||
or time specification as described in
|
||||
ifzman(the section FILE AND DATE FORMATS above)\
|
||||
ifnzman(noderef(Calendar File and Date Formats). The parameter tt(REPLY)
|
||||
is set to the number of seconds since the epoch corresponding to that date
|
||||
or time. By default, the date and time may occur anywhere within the given
|
||||
argument.
|
||||
|
||||
Returns status zero if the date and time were successfully parsed,
|
||||
else one.
|
||||
|
||||
Options:
|
||||
startitem()
|
||||
item(tt(-a))(
|
||||
The date and time are anchored to the start of the argument; they
|
||||
will not be matched if there is preceeding text.
|
||||
)
|
||||
item(tt(-A))(
|
||||
The date and time are anchored to both the start and end of the argument;
|
||||
they will not be matched if the is any other text in the argument.
|
||||
)
|
||||
item(tt(-d))(
|
||||
Enable additional debugging output.
|
||||
)
|
||||
item(tt(-r))(
|
||||
The arguments passed is to be parsed as a relative time.
|
||||
)
|
||||
item(tt(-s))(
|
||||
In addition to setting tt(REPLY), set tt(REPLY2) to the remainder of
|
||||
the argument after the date and time have been stripped. This is
|
||||
empty if the option tt(-A) was given.
|
||||
)
|
||||
enditem()
|
||||
)
|
||||
findex(calendar_show)
|
||||
item(tt(calendar_show))(
|
||||
The function used by default to display events. It accepts a start time
|
||||
and end time for events, both in epoch seconds, and an event description.
|
||||
|
||||
The event is always printed to standard output. If the command line editor
|
||||
is active (which will usually be the case) the command line will be
|
||||
redisplayed after the output.
|
||||
|
||||
If the parameter tt(DISPLAY) is set and the start and end times are
|
||||
the same (indicating a scheduled event), the function uses the
|
||||
command tt(xmessage) to display a window with the event details.
|
||||
)
|
||||
enditem()
|
||||
|
||||
texinode(Calendar Bugs)(Calendar Utility Functions)()(Calendar Function System)
|
||||
sect(Bugs)
|
||||
|
||||
There is no tt(calendar_delete) function.
|
||||
|
||||
There is no localization support for dates and times, nor any support
|
||||
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.
|
||||
|
||||
tt(calendar_lockfiles) hangs the shell while waiting for a lock on a file.
|
||||
If called from a scheduled task, it should instead reschedule the event
|
||||
that caused it.
|
|
@ -1361,10 +1361,14 @@ specified will always be completed.
|
|||
kindex(file-list, completion style)
|
||||
item(tt(file-list))(
|
||||
This style controls whether files completed using the standard builtin
|
||||
mechanism are to be listed with a long list similar to tt(ls -l)
|
||||
(although note that this feature actually uses the shell module
|
||||
mechanism are to be listed with a long list similar to tt(ls -l).
|
||||
Note that this feature uses the shell module
|
||||
tt(zsh/stat) for file information; this loads the builtin tt(stat)
|
||||
which will replace any external tt(stat) executable).
|
||||
which will replace any external tt(stat) executable. To avoid
|
||||
this the following code can be included in an initialization file:
|
||||
|
||||
example(zmodload -i zsh/stat
|
||||
disable stat)
|
||||
|
||||
The style may either be set to a true value (or `tt(all)'), or
|
||||
one of the values `tt(insert)' or `tt(list)', indicating that files
|
||||
|
|
|
@ -26,6 +26,7 @@ list(em(zshcompwid) Zsh completion widgets)
|
|||
list(em(zshcompsys) Zsh completion system)
|
||||
list(em(zshcompctl) Zsh completion control)
|
||||
list(em(zshmodules) Zsh loadable modules)
|
||||
list(em(zshcalsys) Zsh built-in calendar functions)
|
||||
list(em(zshtcpsys) Zsh built-in TCP functions)
|
||||
list(em(zshzftpsys) Zsh built-in FTP client)
|
||||
list(em(zshcontrib) Additional zsh functions and utilities)
|
||||
|
|
|
@ -34,6 +34,7 @@ menu(Completion Widgets)
|
|||
menu(Completion System)
|
||||
menu(Completion Using compctl)
|
||||
menu(Zsh Modules)
|
||||
menu(Calendar Function System)
|
||||
menu(TCP Function System)
|
||||
menu(Zftp Function System)
|
||||
menu(User Contributions)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
texinode(Zsh Modules)(TCP Function System)(Completion Using compctl)(Top)
|
||||
texinode(Zsh Modules)(Calendar Function System)(Completion Using compctl)(Top)
|
||||
chapter(Zsh Modules)
|
||||
cindex(modules)
|
||||
sect(Description)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
texinode(TCP Function System)(Zftp Function System)(Zsh Modules)(Top)
|
||||
texinode(TCP Function System)(Zftp Function System)(Calendar Function System)(Top)
|
||||
chapter(TCP Function System)
|
||||
cindex(TCP function system)
|
||||
cindex(ztcp, function system based on)
|
||||
|
|
|
@ -64,6 +64,7 @@ ifnzman(includefile(Zsh/compwid.yo))
|
|||
ifnzman(includefile(Zsh/compsys.yo))
|
||||
ifnzman(includefile(Zsh/compctl.yo))
|
||||
ifnzman(includefile(Zsh/modules.yo))
|
||||
ifnzman(includefile(Zsh/calsys.yo))
|
||||
ifnzman(includefile(Zsh/tcpsys.yo))
|
||||
ifnzman(includefile(Zsh/zftpsys.yo))
|
||||
ifnzman(includefile(Zsh/contrib.yo))
|
||||
|
@ -81,6 +82,7 @@ source(zshcompwid)
|
|||
source(zshcompsys)
|
||||
source(zshcompctl)
|
||||
source(zshmodules)
|
||||
source(zshcalsys)
|
||||
source(zshtcpsys)
|
||||
source(zshzftpsys)
|
||||
source(zshcontrib)
|
||||
|
|
3
Doc/zshcalsys.yo
Normal file
3
Doc/zshcalsys.yo
Normal file
|
@ -0,0 +1,3 @@
|
|||
manpage(ZSHCALSYS)(1)(date())(zsh version())
|
||||
manpagename(zshcalsys)(zsh calendar system)
|
||||
includefile(Zsh/calsys.yo)
|
6
Functions/Calendar/.distfiles
Normal file
6
Functions/Calendar/.distfiles
Normal file
|
@ -0,0 +1,6 @@
|
|||
DISTFILES_SRC='
|
||||
.distfiles
|
||||
age
|
||||
calendar calendar_add calendar_lockfiles calendar_read
|
||||
calendar_scandate calendar_show calendar_sort
|
||||
'
|
73
Functions/Calendar/age
Normal file
73
Functions/Calendar/age
Normal file
|
@ -0,0 +1,73 @@
|
|||
# Match the age of a file, for use as a glob qualifer. Can
|
||||
# take one or two arguments, which can be supplied by one of two
|
||||
# ways (always the same for both arguments):
|
||||
#
|
||||
# print *(e:age 2006/10/04 2006/10/09:)
|
||||
#
|
||||
# Match all files modified between the start of those dates.
|
||||
#
|
||||
# print *(e:age 2006/10/04)
|
||||
#
|
||||
# Match all files modified on that date. If the second argument is
|
||||
# omitted it is taken to be exactly 24 hours after the first argument
|
||||
# (even if the first argument contains a time).
|
||||
#
|
||||
# print *(e:age 2006/10/04:10:15 2006/10/04:10:45)
|
||||
#
|
||||
# Supply times. All the time and formats handled by calendar_scandate
|
||||
# are allowed, but whitespace must be quoted to ensure age receives
|
||||
# the correct arguments.
|
||||
#
|
||||
# AGEREF1=2006/10/04:10:15
|
||||
# AGEREF2=2006/10/04:10:45
|
||||
# print *(+age)
|
||||
#
|
||||
# The same example using the other form of argument passing. The
|
||||
# dates stay in effect until unset, but will be overridden if
|
||||
# any argument is passed in the first format.
|
||||
|
||||
emulate -L zsh
|
||||
integer mystat disable_stat
|
||||
|
||||
zmodload -i zsh/stat
|
||||
# Allow the builtin stat to be hidden.
|
||||
zmodload -i zsh/parameter
|
||||
if [[ $builtins[stat] != defined ]]; then
|
||||
(( disable_stat = 1 ))
|
||||
enable stat
|
||||
fi
|
||||
|
||||
autoload -U calendar_scandate
|
||||
|
||||
local -a vals
|
||||
|
||||
[[ -e $REPLY ]] || return 1
|
||||
stat -A vals +mtime $REPLY || return 1
|
||||
|
||||
if (( $# >= 1 )); then
|
||||
local AGEREF=$1
|
||||
# if 1 argument given, never use globally defined AGEREF2
|
||||
local AGEREF2=$2
|
||||
fi
|
||||
|
||||
integer mtime=$vals[1] date1 date2
|
||||
local REPLY
|
||||
|
||||
if calendar_scandate $AGEREF; then
|
||||
date1=$REPLY
|
||||
|
||||
if [[ -n $AGEREF2 ]] && calendar_scandate $AGEREF2; then
|
||||
date2=$REPLY
|
||||
else
|
||||
(( date2 = date1 + 24 * 60 * 60 ))
|
||||
fi
|
||||
|
||||
(( date1 <= mtime && mtime <= date2 ))
|
||||
else
|
||||
mystat=1
|
||||
fi
|
||||
|
||||
# If the builtin stat was previously disabled, disable it again.
|
||||
(( disable_stat )) && disable stat
|
||||
|
||||
return $mystat
|
356
Functions/Calendar/calendar
Normal file
356
Functions/Calendar/calendar
Normal file
|
@ -0,0 +1,356 @@
|
|||
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
|
||||
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
|
||||
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}
|
||||
|
||||
# Read the calendar file from the calendar-file style
|
||||
zstyle -s ':datetime:calendar:' calendar-file calendar || calendar=~/calendar
|
||||
newfile=$calendar.new.$HOST.$$
|
||||
zstyle -s ':datetime:calendar:' done-file donefile || donefile="$calendar.done"
|
||||
# Read the programme to show the message from the show-prog style.
|
||||
zstyle -a ':datetime:calendar:' show-prog showprog ||
|
||||
showprog=(calendar_show)
|
||||
# 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"
|
||||
|
||||
if [[ -n $warnstr ]]; then
|
||||
if [[ $warnstr = <-> ]]; then
|
||||
(( warntime = warnstr ))
|
||||
elif ! calendar_scandate -ar $warnstr; then
|
||||
print >&2 \
|
||||
"warn-time value '$warnstr' not understood; using default 5 minutes"
|
||||
warnstr="5 mins"
|
||||
(( warntime = 5 * 60 ))
|
||||
else
|
||||
(( warntime = REPLY ))
|
||||
fi
|
||||
fi
|
||||
|
||||
[[ -f $calendar ]] || return 1
|
||||
|
||||
# We're not using getopts because we want +... to refer to a
|
||||
# relative time, not an option, and allow some other additions
|
||||
# like handling -<->.
|
||||
integer opti=0
|
||||
local opt optrest optarg
|
||||
|
||||
while [[ ${argv[opti+1]} = -* ]]; do
|
||||
(( opti++ ))
|
||||
opt=${argv[opti][2]}
|
||||
optrest=${argv[opti][3,-1]}
|
||||
[[ -z $opt || $opt = - ]] && break
|
||||
while [[ -n $opt ]]; do
|
||||
case $opt in
|
||||
########################
|
||||
# Options with arguments
|
||||
########################
|
||||
([CnS])
|
||||
if [[ -n $optrest ]]; then
|
||||
optarg=$optrest
|
||||
optrest=
|
||||
elif (( opti < $# )); then
|
||||
optarg=$argv[++opti]
|
||||
optrest=
|
||||
else
|
||||
print -r "$0: option -$opt requires an argument." >&2
|
||||
return 1
|
||||
fi
|
||||
case $opt in
|
||||
(C)
|
||||
# Pick the calendar file, overriding style and default.
|
||||
calendar=$optarg
|
||||
;;
|
||||
|
||||
(n)
|
||||
# Show this many remaining events regardless of date.
|
||||
showcount=$optarg
|
||||
if (( showcount <= 0 )); then
|
||||
print -r "$0: option -$opt requires a positive integer." >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
|
||||
(S)
|
||||
# Explicitly specify a show programme, overriding style and default.
|
||||
# Colons in the argument are turned into space.
|
||||
showprog=(${(s.:.)optarg})
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
###########################
|
||||
# Options without arguments
|
||||
###########################
|
||||
(d)
|
||||
# Move out of date items to the done file.
|
||||
(( done = 1 ))
|
||||
;;
|
||||
|
||||
(D)
|
||||
# Don't use done; needed with sched
|
||||
(( nodone = 1 ))
|
||||
;;
|
||||
|
||||
(r)
|
||||
# Show all remaining options in the calendar, i.e.
|
||||
# respect start time but ignore end time.
|
||||
# Any argument is treated as a start time.
|
||||
(( remaining = 1 ))
|
||||
;;
|
||||
|
||||
(s)
|
||||
# Use the "sched" builtin to scan at the appropriate time.
|
||||
sched=sched
|
||||
(( done = 1 ))
|
||||
;;
|
||||
|
||||
(v)
|
||||
# Verbose
|
||||
verbose=1
|
||||
;;
|
||||
|
||||
(<->)
|
||||
# Shorthand for -n <->
|
||||
showcount=$opt
|
||||
;;
|
||||
|
||||
(*)
|
||||
print "$0: unrecognised option: -$opt" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
opt=$optrest[1]
|
||||
optrest=$optrest[2,-1]
|
||||
done
|
||||
done
|
||||
calopts=($argv[1,opti])
|
||||
shift $(( opti ))
|
||||
|
||||
# Use of donefile requires explicit or implicit option request, plus
|
||||
# no explicit -D. It may already be empty because of the style.
|
||||
(( done && !nodone )) || donefile=
|
||||
|
||||
if (( $# > 1 || ($# == 1 && remaining) )); then
|
||||
if [[ $1 = now ]]; then
|
||||
start=$EPOCHSECONDS
|
||||
elif [[ $1 = <-> ]]; then
|
||||
start=$1
|
||||
else
|
||||
if ! calendar_scandate -a $1; then
|
||||
print "$0: failed to parse date/time: $1" >&2
|
||||
return 1
|
||||
fi
|
||||
start=$REPLY
|
||||
fi
|
||||
shift
|
||||
else
|
||||
# Get the time at which today started.
|
||||
y=${(%):-"%D{%Y}"} m=${(%):-"%D{%m}"} d=${(%):-"%D{%d}"}
|
||||
strftime -s today -r "%Y/%m/%d" "$y/$m/$d"
|
||||
start=$today
|
||||
fi
|
||||
# day of week of start time
|
||||
strftime -s wd "%u" $start
|
||||
|
||||
if (( $# && !remaining )); then
|
||||
if [[ $1 = +* ]]; then
|
||||
if ! calendar_scandate -ar ${1[2,-1]}; then
|
||||
print "$0: failed to parse relative time: $1" >&2
|
||||
return 1
|
||||
fi
|
||||
(( stop = start + REPLY ))
|
||||
elif [[ $1 = <-> ]]; then
|
||||
stop=$1
|
||||
else
|
||||
if ! calendar_scandate -a $1; then
|
||||
print "$0: failed to parse date/time: $1" >&2
|
||||
return 1
|
||||
fi
|
||||
stop=$REPLY
|
||||
fi
|
||||
if (( stop < start )); then
|
||||
strftime -s REPLY $ctime $start
|
||||
strftime -s REPLY2 $ctime $stop
|
||||
print "$0: requested end time is before start time:
|
||||
start: $REPLY
|
||||
end: $REPLY2" >&2
|
||||
return 1
|
||||
fi
|
||||
shift
|
||||
else
|
||||
# By default, show 2 days. If it's Friday (5) show up to end
|
||||
# of Monday (4) days; likewise on Saturday show 3 days.
|
||||
# If -r, this is calculated but not used. This is paranoia,
|
||||
# to avoid an unusable value of stop; but it shouldn't get used.
|
||||
case $wd in
|
||||
(5)
|
||||
ndays=4
|
||||
;;
|
||||
|
||||
(6)
|
||||
ndays=3
|
||||
;;
|
||||
|
||||
(*)
|
||||
ndays=2
|
||||
;;
|
||||
esac
|
||||
stop=$(( start + ndays * 24 * 60 * 60 ))
|
||||
fi
|
||||
|
||||
if (( $# )); then
|
||||
print "Usage: $0 [ start-date-time stop-date-time ]" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
autoload -Uz matchdate
|
||||
|
||||
[[ -n $donefile ]] && rm -f $newfile
|
||||
|
||||
if (( verbose )); then
|
||||
print -n "start: "
|
||||
strftime $ctime $start
|
||||
print -n "stop: "
|
||||
if (( remaining )); then
|
||||
print "none"
|
||||
else
|
||||
strftime $ctime $stop
|
||||
fi
|
||||
fi
|
||||
|
||||
# start of block for following always to clear up lockfiles.
|
||||
{
|
||||
if [[ -n $donefile ]]; then
|
||||
# Attempt to lock both $donefile and $calendar.
|
||||
# Don't lock $newfile; we've tried our best to make
|
||||
# the name unique.
|
||||
calendar_lockfiles $calendar $donefile || return 1
|
||||
fi
|
||||
|
||||
calendar_read $calendar
|
||||
for line in $calendar_entries; do
|
||||
# This call sets REPLY to the date and time in seconds since the epoch,
|
||||
# REPLY2 to the line with the date and time removed.
|
||||
calendar_scandate -as $line || continue
|
||||
(( t = REPLY ))
|
||||
|
||||
# Look for specific warn time.
|
||||
pruned=${REPLY2#(|*[[:space:],])WARN[[:space:]]}
|
||||
(( mywarntime = warntime ))
|
||||
mywarnstr=$warnstr
|
||||
if [[ $pruned != $REPLY2 ]]; then
|
||||
if calendar_scandate -ars $pruned; then
|
||||
(( mywarntime = REPLY ))
|
||||
mywarnstr=${pruned%%"$REPLY2"}
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( verbose )); then
|
||||
print "Examining: $line"
|
||||
print -n " Date/time: "
|
||||
strftime $ctime $t
|
||||
if [[ -n $sched ]]; then
|
||||
print " Warning $mywarntime seconds ($mywarnstr) before"
|
||||
fi
|
||||
fi
|
||||
(( shown = 0 ))
|
||||
if (( t >= start && (remaining || t <= stop || icount < showcount) ))
|
||||
then
|
||||
$showprog $start $stop "$line"
|
||||
(( shown = 1, icount++ ))
|
||||
elif [[ -n $sched ]]; then
|
||||
(( tsched = t - mywarntime ))
|
||||
if (( tsched >= start && tsched <= stop)); then
|
||||
$showprog $start $stop "due in ${mywarnstr}: $line"
|
||||
fi
|
||||
fi
|
||||
if [[ -n $sched ]]; then
|
||||
if (( t - mywarntime > EPOCHSECONDS )); then
|
||||
# schedule for a warning
|
||||
(( tsched = t - mywarntime ))
|
||||
else
|
||||
# schedule for event itself
|
||||
(( tsched = t ))
|
||||
fi
|
||||
if (( (tsched > EPOCHSECONDS || ! shown) &&
|
||||
(next < 0 || tsched < next) )); then
|
||||
(( next = tsched ))
|
||||
fi
|
||||
fi
|
||||
if [[ -n $donefile ]]; then
|
||||
if (( t <= EPOCHSECONDS && shown )); then
|
||||
# Done and dusted.
|
||||
# TODO: handle repeated times from REPLY2.
|
||||
if ! print -r $line >>$donefile; then
|
||||
if (( done != 3 )); then
|
||||
(( done = 3 ))
|
||||
print "Failed to append to $donefile" >&2
|
||||
fi
|
||||
elif (( done != 3 )); then
|
||||
(( done = 2 ))
|
||||
fi
|
||||
else
|
||||
# Still not over.
|
||||
if ! print -r $line >>$newfile; then
|
||||
if (( done != 3 )); then
|
||||
(( done = 3 ))
|
||||
print "Failed to append to $newfile" >&2
|
||||
fi
|
||||
elif (( done != 3 )); then
|
||||
(( done = 2 ))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n $sched ]]; then
|
||||
if [[ $next -ge 0 ]]; then
|
||||
# Remove any existing calendar scheduling.
|
||||
# Luckily sched doesn't delete its schedule in a subshell.
|
||||
sched | while read line; do
|
||||
if [[ $line = (#b)[[:space:]]#(<->)[[:space:]]##*[[:space:]]'calendar -s'* ]]; then
|
||||
# End of pipeline run in current shell, so delete directly.
|
||||
sched -1 $match[1]
|
||||
fi
|
||||
done
|
||||
$sched $next calendar "${calopts[@]}" $next $next
|
||||
else
|
||||
$showprog $start $stop \
|
||||
"No more calendar events: calendar not rescheduled.
|
||||
Run \"calendar -s\" again if you add to it."
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( done == 2 )); then
|
||||
if ! mv $calendar $calendar.old; then
|
||||
print "Couldn't back up $calendar to $calendar.old.
|
||||
New calendar left in $newfile." >&2
|
||||
(( rstat = 1 ))
|
||||
elif ! mv $newfile $calendar; then
|
||||
print "Failed to rename $newfile to $calendar.
|
||||
Old calendar left in $calendar.old." >&2
|
||||
(( rstat = 1 ))
|
||||
fi
|
||||
elif [[ -n $donefile ]]; then
|
||||
rm -f $newfile
|
||||
fi
|
||||
} always {
|
||||
(( ${#lockfiles} )) && rm -f $lockfiles
|
||||
}
|
||||
|
||||
return $rstat
|
69
Functions/Calendar/calendar_add
Normal file
69
Functions/Calendar/calendar_add
Normal file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/env zsh
|
||||
|
||||
# All arguments are joined with spaces and inserted into the calendar
|
||||
# file at the appropriate point.
|
||||
#
|
||||
# While the function compares the date of the new entry with dates in the
|
||||
# existing calendar file, it does not do any sorting; it inserts the new
|
||||
# entry before the first existing entry with a later date and time.
|
||||
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
|
||||
local calendar newfile REPLY lastline
|
||||
local -a calendar_entries lockfiles
|
||||
integer newdate done rstat
|
||||
|
||||
autoload -U calendar_{read,lockfiles}
|
||||
|
||||
# Read the calendar file from the calendar-file style
|
||||
zstyle -s ':datetime:calendar_add:' calendar-file calendar ||
|
||||
calendar=~/calendar
|
||||
newfile=$calendar.new.$HOST.$$
|
||||
|
||||
if ! calendar_scandate -a "$*"; then
|
||||
print "$0: failed to parse date/time" >&2
|
||||
return 1
|
||||
fi
|
||||
(( newdate = $REPLY ))
|
||||
|
||||
# $calendar doesn't necessarily exist yet.
|
||||
|
||||
# start of block for following always to clear up lockfiles.
|
||||
{
|
||||
calendar_lockfiles $calendar || return 1
|
||||
|
||||
if [[ -f $calendar ]]; then
|
||||
calendar_read $calendar
|
||||
|
||||
{
|
||||
for line in $calendar_entries; do
|
||||
if (( ! done )) && calendar_scandate -a $line && (( REPLY > newdate )); then
|
||||
print -r -- "$*"
|
||||
(( done = 1 ))
|
||||
elif [[ $REPLY -eq $newdate && $line = "$*" ]]; then
|
||||
(( done = 1 ))
|
||||
fi
|
||||
print -r -- $line
|
||||
done
|
||||
(( done )) || print -r -- "$*"
|
||||
} >$newfile
|
||||
if ! mv $calendar $calendar.old; then
|
||||
print "Couldn't back up $calendar to $calendar.old.
|
||||
New calendar left in $newfile." >&2
|
||||
(( rstat = 1 ))
|
||||
fi
|
||||
else
|
||||
print -r -- $line >$newfile
|
||||
fi
|
||||
|
||||
if (( !rstat )) && ! mv $newfile $calendar; then
|
||||
print "Failed to rename $newfile to $calendar.
|
||||
Old calendar left in $calendar.old." >&2
|
||||
(( rstat = 1 ))
|
||||
fi
|
||||
} always {
|
||||
(( ${#lockfiles} )) && rm -f $lockfiles
|
||||
}
|
||||
|
||||
return $rstat
|
43
Functions/Calendar/calendar_lockfiles
Normal file
43
Functions/Calendar/calendar_lockfiles
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Lock the given files.
|
||||
# Append the names of lockfiles to the array lockfiles.
|
||||
|
||||
local file lockfile msgdone
|
||||
# Number of attempts to lock a file. Probably not worth stylising.
|
||||
integer lockattempts=3
|
||||
|
||||
# The lockfile name is not stylised: it has to be a fixed
|
||||
# derivative of the main fail.
|
||||
for file; do
|
||||
lockfile=$file.lockfile
|
||||
for (( i = 0; i < lockattempts; i++ )); do
|
||||
if ln -s $file $lockfile >/dev/null 2>&1; then
|
||||
lockfiles+=($lockfile)
|
||||
break
|
||||
fi
|
||||
if zle && [[ -z $msgdone ]]; then
|
||||
msgdone="${lockfile}: waiting to acquire lock"
|
||||
zle -M $msgdone
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [[ -n $msgdone ]]; then
|
||||
zle -M ${msgdone//?/ }
|
||||
msgdone=
|
||||
fi
|
||||
if [[ ${lockfiles[-1]} != $lockfile ]]; then
|
||||
msgdone="Failed to lock $file; giving up after $lockattempts attempts.
|
||||
Another instance of calendar may be using it.
|
||||
Delete $lockfiles if you believe this to be an error."
|
||||
if zle; then
|
||||
zle -M $msgdone
|
||||
else
|
||||
print $msgdone >&2
|
||||
fi
|
||||
# The parent should take action to delete any lockfiles
|
||||
# already locked. Typically this won't be necessary, since
|
||||
# we will always lock the main calendar file first.
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
35
Functions/Calendar/calendar_read
Normal file
35
Functions/Calendar/calendar_read
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Utility for "calendar" to read entries into the array calendar_entries.
|
||||
# This should be local to the caller.
|
||||
# The only argument is the file to read. We expect options etc. to
|
||||
# be correct.
|
||||
#
|
||||
# This is based on Emacs calendar syntax, which has two implications:
|
||||
# - Lines beginning with whitespace are continuation lines.
|
||||
# Hence we have to read the entire file first to determine entries.
|
||||
# - Lines beginning with "&" are inhibited from producing marks in
|
||||
# Emacs calendar window. This is irrelevant to us, so we
|
||||
# we simply remove leading ampersands. This is necessary since
|
||||
# we expect the date to start at the beginning of the line.
|
||||
#
|
||||
# TODO: Emacs has some special handling for entries where the first line
|
||||
# has only the date and continuation lines indicate times. Actually,
|
||||
# it doesn't parse the times as far as I can see, but if we want to
|
||||
# handle that format sensibly we would need to here. It could
|
||||
# be tricky to get right.
|
||||
|
||||
local calendar=$1 line
|
||||
local -a lines
|
||||
|
||||
lines=(${(f)"$(<$calendar)"})
|
||||
|
||||
calendar_entries=()
|
||||
# ignore blank lines
|
||||
for line in $lines; do
|
||||
if [[ $line = [[:space:]]* ]]; then
|
||||
if (( ${#calendar_entries} )); then
|
||||
calendar_entries[-1]+=$'\n'$line
|
||||
fi
|
||||
else
|
||||
calendar_entries+=(${line##\&})
|
||||
fi
|
||||
done
|
519
Functions/Calendar/calendar_scandate
Normal file
519
Functions/Calendar/calendar_scandate
Normal file
|
@ -0,0 +1,519 @@
|
|||
# Scan a line for various common date and time formats.
|
||||
# Set REPLY to the number of seconds since the epoch at which that
|
||||
# time occurs. The time does not need to be matched; this will
|
||||
# produce midnight at the start of the date.
|
||||
#
|
||||
# Absolute times
|
||||
#
|
||||
# The rules below are fairly complicated, to allow any natural (and
|
||||
# some highly unnatural but nonetheless common) combination of
|
||||
# time and date used by English speakers. It is recommended that,
|
||||
# rather than exploring the intricacies of the system, users find
|
||||
# a date format that is natural to them and stick to it. This
|
||||
# will avoid unexpected effects. Various key facts should be noted,
|
||||
# explained in more detail below:
|
||||
#
|
||||
# - In particular, note the confusion between month/day/year and
|
||||
# day/month/year when the month is numeric; this format should be
|
||||
# avoided if at all possible. Many alternatives are available.
|
||||
# - However, there is currently no localization support, so month
|
||||
# names must be English (though only the first three letters are required).
|
||||
# The same applies to days of the week if they occur (they are not useful).
|
||||
# - The year must be given in full to avoid confusion, and only years
|
||||
# from 1900 to 2099 inclusive are matched.
|
||||
# - Although timezones are parsed (complicated formats may not be recognized),
|
||||
# they are then ignored; no time adjustment is made.
|
||||
#
|
||||
# The following give some obvious examples; users finding here
|
||||
# a format they like and not subject to vagaries of style may skip
|
||||
# the full description. As dates and times are matched separately
|
||||
# (even though the time may be embedded in the date), any date format
|
||||
# may be mixed with any format for the time of day provide the
|
||||
# separators are clear (whitespace, colons, commas).
|
||||
# 2007/04/03 13:13
|
||||
# 2007/04/03:13:13
|
||||
# 2007/04/03 1:13 pm
|
||||
# 3rd April 2007, 13:13
|
||||
# April 3rd 2007 1:13 p.m.
|
||||
# Apr 3, 2007 13:13
|
||||
# Tue Apr 03 13:13:00 2007
|
||||
# 13:13 2007/apr/3
|
||||
#
|
||||
# Times are parsed and extracted before dates. They must use colons
|
||||
# to separate hours and minutes, though a dot is allowed before seconds
|
||||
# if they are present. This limits time formats to
|
||||
# HH:MM[:SS[.FFFFF]] [am|pm|a.m.|p.m.]
|
||||
# HH:MM.SS[.FFFFF] [am|pm|a.m.|p.m.]
|
||||
# in which square brackets indicate optional elements, possibly with
|
||||
# alternatives. Fractions of a second are recognised but ignored.
|
||||
# Unless -r is given (see below), a date is mandatory but a time of day is
|
||||
# not; the time returned is at the start of the date.
|
||||
#
|
||||
# Time zones are not handled, though if one is matched following a time
|
||||
# specification it will be removed to allow a surrounding date to be
|
||||
# parsed. This only happens if the format of the timezone is not too
|
||||
# wacky:
|
||||
# +0100
|
||||
# GMT
|
||||
# GMT-7
|
||||
# CET+1CDT
|
||||
# etc. are all understood, but any part of the timezone that is not numeric
|
||||
# must have exactly three capital letters in the name.
|
||||
#
|
||||
# Dates suffer from the ambiguity between DD/MM/YYYY and MM/DD/YYYY. It is
|
||||
# recommended this form is avoided with purely numeric dates, but use of
|
||||
# ordinals, eg. 3rd/04/2007, will resolve the ambiguity as the ordinal is
|
||||
# always parsed as the day of the month. Years must be four digits (and
|
||||
# the first two must be 19 or 20); 03/04/08 is not recognised. Other
|
||||
# numbers may have leading zeroes, but they are not required. The
|
||||
# following are handled:
|
||||
# YYYY/MM/DD
|
||||
# YYYY-MM-DD
|
||||
# YYYY/MNM/DD
|
||||
# YYYY-MNM-DD
|
||||
# DD[th|st|rd] MNM[,] YYYY
|
||||
# DD[th|st|rd] MNM[,] current year assumed
|
||||
# MNM DD[th|st|rd][,] YYYY
|
||||
# MNM DD[th|st|rd][,] current year assumed
|
||||
# DD[th|st|rd]/MM[,] YYYY
|
||||
# DD[th|st|rd]/MM/YYYY
|
||||
# MM/DD[th|st|rd][,] YYYY
|
||||
# MM/DD[th|st|rd]/YYYY
|
||||
# Here, MNM is at least the first three letters of a month name,
|
||||
# matched case-insensitively. The remainder of the month name may appear but
|
||||
# its contents are irrelevant, so janissary, febrile, martial, apricot,
|
||||
# etc. are happily handled.
|
||||
#
|
||||
# Note there are only two cases that assume the current year, the
|
||||
# form "Jun 20" or "14 September" (the only two commonly occurring
|
||||
# forms, apart from a "the" in some forms of English, which isn't
|
||||
# currently supported). Such dates will of course become ambiguous
|
||||
# in the future, so should ideally be avoided.
|
||||
#
|
||||
# Times may follow dates with a colon, e.g. 1965/07/12:09:45; this
|
||||
# is in order to provide a format with no whitespace. A comma
|
||||
# and whitespace are allowed, e.g. "1965/07/12, 09:45".
|
||||
# Currently the order of these separators is not checked, so
|
||||
# illogical formats such as "1965/07/12, : ,09:45" will also
|
||||
# be matched. Otherwise, a time is only recognised as being associated
|
||||
# with a date if there is only whitespace in between, or if the time
|
||||
# was embedded in the date.
|
||||
#
|
||||
# Days of the week are not scanned, but will be ignored if they occur
|
||||
# at the start of the date pattern only.
|
||||
#
|
||||
# For example, the standard date format:
|
||||
# Fri Aug 18 17:00:48 BST 2006
|
||||
# is handled by matching HH:MM:SS and removing it together with the
|
||||
# matched (but unused) time zone. This leaves the following:
|
||||
# Fri Aug 18 2006
|
||||
# "Fri" is ignored and the rest is matched according to the sixth of
|
||||
# the standard rules.
|
||||
#
|
||||
# Relative times
|
||||
# ==============
|
||||
#
|
||||
# The option -r allows a relative time. Years (or ys, yrs, or without s),
|
||||
# months (or mths, mons, mnths, months, or without s --- "m", "ms" and
|
||||
# "mns" are ambiguous and are not handled), weeks (or ws, wks, or without
|
||||
# s) and days (or ds, dys, days, or without s), hours (or hs, hrs, with or
|
||||
# without s), minutes (or mins, with or without s) and seconds (or ss,
|
||||
# secs, with or without s) are understood. Spaces between the numbers
|
||||
# are optional, but are required between items, although a comma
|
||||
# may be used (with or without spaces).
|
||||
#
|
||||
# Note that a year here is 365.25 days and a month is 30 days. TODO:
|
||||
# improve this by passing down base time and adjusting. (This will
|
||||
# be crucial for events repeating monthly.) TODO: it then makes
|
||||
# sense to make PERIODly = 1 PERIOD (also for PERIOD = dai!)
|
||||
#
|
||||
# This allows forms like:
|
||||
# 30 years 3 months 4 days 3:42:41
|
||||
# 14 days 5 hours
|
||||
# 4d,10hr
|
||||
# In this case absolute dates are ignored.
|
||||
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
|
||||
zmodload -i zsh/datetime || return 1
|
||||
|
||||
# separator characters before time or between time and date
|
||||
# allow , - or : before the time: this allows spaceless but still
|
||||
# relatively logical dates like 2006/09/19:14:27
|
||||
# don't allow / before time ! the above
|
||||
# is not 19 hours 14 mins and 27 seconds after anything.
|
||||
local tschars="[-,:[:space:]]"
|
||||
# start pattern for time when anchored
|
||||
local tspat_anchor="(${tschars}#)"
|
||||
# ... when not anchored
|
||||
local tspat_noanchor="(|*${tschars})"
|
||||
# separator characters between elements. comma is fairly
|
||||
# natural punctuation; otherwise only allow whitespace.
|
||||
local schars="[.,[:space:]]"
|
||||
local daypat="${schars}#(sun|mon|tue|wed|thu|fri|sat)[a-z]#${schars}#"
|
||||
# Start pattern for date: treat , as space for simplicity. This
|
||||
# is illogical at the start but saves lots of minor fiddling later.
|
||||
# Date start pattern when anchored at the start.
|
||||
# We need to be able to ignore the day here, although (for consistency
|
||||
# with the unanchored case) we don't remove it until later.
|
||||
# (The problem in the other case is that matching anything before
|
||||
# the day of the week is greedy, so the day of the week gets ignored
|
||||
# if it's optional.)
|
||||
local dspat_anchor="(|(#B)${daypat}(#b)${schars}#)"
|
||||
# Date start pattern when not anchored at the start.
|
||||
local dspat_noanchor="(|*${schars})"
|
||||
# end pattern for relative times: similar remark about use of $schars.
|
||||
local repat="(|s)(|${schars}*)"
|
||||
# not locale-dependent! I don't know how to get the months out
|
||||
# of the system for the purpose of finding out where they occur.
|
||||
# We may need some completely different heuristic.
|
||||
local monthpat="(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]#"
|
||||
# days, not handled but we need to ignore them. also not localized.
|
||||
|
||||
integer year month day hour minute second
|
||||
local opt line orig_line mname MATCH MBEGIN MEND tz
|
||||
local -a match mbegin mend
|
||||
# Flags that we found a date or a time (maybe a relative time)
|
||||
integer date_found time_found
|
||||
# Indices of positions of start and end of time and dates found.
|
||||
# These are actual character indices as zsh would normally use, i.e.
|
||||
# line[time_start,time_end] is the string for the time.
|
||||
integer time_start time_end date_start date_end
|
||||
integer anchor anchor_end debug relative reladd setvar
|
||||
|
||||
while getopts "aAdrs" opt; do
|
||||
case $opt in
|
||||
(a)
|
||||
# anchor
|
||||
(( anchor = 1 ))
|
||||
;;
|
||||
|
||||
(A)
|
||||
# anchor at end, too
|
||||
(( anchor = 1, anchor_end = 1 ))
|
||||
;;
|
||||
|
||||
(d)
|
||||
# enable debug output
|
||||
(( debug = 1 ))
|
||||
;;
|
||||
|
||||
(r)
|
||||
(( relative = 1 ))
|
||||
;;
|
||||
|
||||
(s)
|
||||
(( setvar = 1 ))
|
||||
;;
|
||||
|
||||
(*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $(( OPTIND - 1 ))
|
||||
|
||||
line=$1 orig_line=$1
|
||||
|
||||
local dspat tspat
|
||||
if (( anchor )); then
|
||||
# Anchored at the start.
|
||||
dspat=$dspat_anchor
|
||||
if (( relative )); then
|
||||
tspat=$tspat_anchor
|
||||
else
|
||||
# We'll test later if the time is associated with the date.
|
||||
tspat=$tspat_noanchor
|
||||
fi
|
||||
else
|
||||
dspat=$dspat_noanchor
|
||||
tspat=$tspat_noanchor
|
||||
fi
|
||||
|
||||
# Look for a time separately; we need colons for this.
|
||||
case $line in
|
||||
# with seconds, am/pm: don't match / in front.
|
||||
((#ibm)${~tspat}(<0-12>):(<0-59>)[.:]((<0-59>)(.<->|))[[:space:]]#([ap])(|.)[[:space:]]#m(.|[[:space:]]|(#e))(*))
|
||||
hour=$match[2]
|
||||
minute=$match[3]
|
||||
second=$match[5]
|
||||
[[ $match[7] = (#i)p ]] && (( hour <= 12 )) && (( hour += 12 ))
|
||||
time_found=1
|
||||
;;
|
||||
|
||||
# no seconds, am/pm
|
||||
((#ibm)${~tspat}(<0-12>):(<0-59>)[[:space:]]#([ap])(|.)[[:space:]]#m(.|[[:space:]]|(#e))(*))
|
||||
hour=$match[2]
|
||||
minute=$match[3]
|
||||
[[ $match[4] = (#i)p ]] && (( hour <= 12 )) && (( hour += 12 ))
|
||||
time_found=1
|
||||
;;
|
||||
|
||||
# no colon, even, but a.m./p.m. indicator
|
||||
((#ibm)${~tspat}(<0-12>)[[:space:]]#([ap])(|.)[[:space:]]#m(.|[[:space:]]|(#e))(*))
|
||||
hour=$match[2]
|
||||
minute=0
|
||||
[[ $match[3] = (#i)p ]] && (( hour <= 12 )) && (( hour += 12 ))
|
||||
time_found=1
|
||||
;;
|
||||
|
||||
# 24 hour clock, with seconds
|
||||
((#ibm)${~tspat}(<0-24>):(<0-59>)[.:]((<0-59>)(.<->|))(*))
|
||||
hour=$match[2]
|
||||
minute=$match[3]
|
||||
second=$match[5]
|
||||
time_found=1
|
||||
;;
|
||||
|
||||
# 24 hour clock, no seconds
|
||||
((#ibm)${~tspat}(<0-24>):(<0-59>)(*))
|
||||
hour=$match[2]
|
||||
minute=$match[3]
|
||||
time_found=1
|
||||
;;
|
||||
esac
|
||||
|
||||
(( hour == 24 )) && hour=0
|
||||
|
||||
if (( time_found )); then
|
||||
# time was found
|
||||
time_start=$mbegin[2]
|
||||
time_end=$mend[-2]
|
||||
# Remove the timespec because it may be in the middle of
|
||||
# the date (as in the output of "date".
|
||||
# There may be a time zone, too, which we don't yet handle.
|
||||
# (It's not in POSIX strptime() and libraries don't support it well.)
|
||||
# This attempts to remove some of the weirder forms.
|
||||
if [[ $line[$time_end+1,-1] = (#b)[[:space:]]#([A-Z][A-Z][A-Z]|[-+][0-9][0-9][0-9][0-9])([[:space:]]|(#e))* || \
|
||||
$line[$time_end+1,-1] = (#b)[[:space:]]#([A-Z][A-Z][A-Z](|[-+])<0-12>)([[:space:]]|(#e))* || \
|
||||
$line[$time_end+1,-1] = (#b)[[:space:]]#([A-Z][A-Z][A-Z](|[-+])<0-12>[A-Z][A-Z][A-Z])([[:space:]]|(#e))* ]]; then
|
||||
(( time_end += ${mend[-1]} ))
|
||||
tz=$match[1]
|
||||
fi
|
||||
line=$line[1,time_start-1]$line[time_end+1,-1]
|
||||
(( debug )) && print "line after time: $line"
|
||||
fi
|
||||
|
||||
if (( relative == 0 )); then
|
||||
# Date.
|
||||
case $line in
|
||||
# Look for YEAR[-/.]MONTH[-/.]DAY
|
||||
((#bi)${~dspat}((19|20)[0-9][0-9])[-/](<1-12>)[-/](<1-31>)*)
|
||||
year=$match[2]
|
||||
month=$match[4]
|
||||
day=$match[5]
|
||||
date_start=$mbegin[2] date_end=$mend[5]
|
||||
date_found=1
|
||||
;;
|
||||
|
||||
# Same with month name
|
||||
((#bi)${~dspat}((19|20)[0-9][0-9])[-/]${~monthpat}[-/](<1-31>)*)
|
||||
year=$match[2]
|
||||
mname=$match[4]
|
||||
day=$match[5]
|
||||
date_start=$mbegin[2] date_end=$mend[5]
|
||||
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])*)
|
||||
day=$match[2]
|
||||
mname=$match[4]
|
||||
year=$match[6]
|
||||
date_start=$mbegin[2] date_end=$mend[6]
|
||||
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])*)
|
||||
mname=$match[2]
|
||||
day=$match[3]
|
||||
year=$match[6]
|
||||
date_start=$mbegin[2] date_end=$mend[6]
|
||||
date_found=1
|
||||
;;
|
||||
|
||||
# Look for DAY[th/st/rd] MNAME; assume current year
|
||||
((#bi)${~dspat}(<1-31>)(|th|st|rd)[[:space:]]##${~monthpat}(|,)([[:space:]]##*|))
|
||||
day=$match[2]
|
||||
mname=$match[4]
|
||||
strftime -s year "%Y" $EPOCHSECONDS
|
||||
date_start=$mbegin[2] date_end=$mend[5]
|
||||
date_found=1
|
||||
;;
|
||||
|
||||
# Look for MNAME DAY[th/st/rd]; assume current year
|
||||
((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|rd)(|,)([[:space:]]##*|))
|
||||
mname=$match[2]
|
||||
day=$match[3]
|
||||
strftime -s year "%Y" $EPOCHSECONDS
|
||||
date_start=$mbegin[2] date_end=$mend[5]
|
||||
date_found=1
|
||||
;;
|
||||
|
||||
# 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])*)
|
||||
day=$match[2]
|
||||
month=$match[4]
|
||||
year=$match[7]
|
||||
date_start=$mbegin[2] date_end=$mend[7]
|
||||
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])*)
|
||||
month=$match[2]
|
||||
day=$match[3]
|
||||
year=$match[7]
|
||||
date_start=$mbegin[2] date_end=$mend[7]
|
||||
date_found=1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if (( date_found )); then
|
||||
# date found
|
||||
# see if there's a day at the start
|
||||
if [[ ${line[1,$date_start-1]} = (#bi)${~daypat} ]]; then
|
||||
date_start=$mbegin[1]
|
||||
fi
|
||||
line=${line[1,$date_start-1]}${line[$date_end+1,-1]}
|
||||
if (( time_found )); then
|
||||
# If we found a time, it must be associated with the date,
|
||||
# or we can't use it. Since we removed the time from the
|
||||
# string to find the date, however, it's complicated to
|
||||
# know where both were found. Reconstruct the date indices of
|
||||
# the original string.
|
||||
if (( time_start <= date_start )); then
|
||||
# Time came before start of date; add length in.
|
||||
(( date_start += time_end - time_start + 1 ))
|
||||
fi
|
||||
if (( time_start <= date_end )); then
|
||||
(( date_end += time_end - time_start + 1 ))
|
||||
fi
|
||||
|
||||
if (( time_end + 1 < date_start )); then
|
||||
# If time wholly before date, OK if only separator characters
|
||||
# in between. (This allows some illogical stuff with commas
|
||||
# but that's probably not important.)
|
||||
if [[ ${orig_line[time_end+1,date_start-1]} != ${~schars}# ]]; then
|
||||
# Clearly this can't work if anchor is set. In principle,
|
||||
# we could match the date and ignore the time if it wasn't.
|
||||
# However, that seems dodgy.
|
||||
return 1
|
||||
else
|
||||
# Form massaged line by removing the entire date/time chunk.
|
||||
line="${orig_line[1,time_start-1]}${orig_line[date_end+1,-1]}"
|
||||
fi
|
||||
elif (( date_end + 1 < time_start )); then
|
||||
# If date wholly before time, OK if only time separator characters
|
||||
# in between. This allows 2006/10/12:13:43 etc.
|
||||
if [[ ${orig_line[date_end+1,time_start-1]} != ${~tschars}# ]]; then
|
||||
# Here, we assume the time is associated with something later
|
||||
# in the line. This is pretty much inevitable for the sort
|
||||
# of use we are expecting. For example,
|
||||
# 2006/10/24 Meeting from early, may go on till 12:00.
|
||||
# or with some uses of the calendar system,
|
||||
# 2006/10/24 MR 1 Another pointless meeting WARN 01:00
|
||||
# The 01:00 says warn an hour before, not that the meeting starts
|
||||
# at 1 am. About the only safe way round would be to force
|
||||
# a time to be present, but that's not how the traditional
|
||||
# calendar programme works.
|
||||
#
|
||||
# Hence we need to reconstruct.
|
||||
(( time_found = 0, hour = 0, minute = 0, second = 0 ))
|
||||
line="${orig_line[1,date_start-1]}${orig_line[date_end+1,-1]}"
|
||||
else
|
||||
# As above.
|
||||
line="${orig_line[1,date_start-1]}${orig_line[time_end+1,-1]}"
|
||||
fi
|
||||
fi
|
||||
if (( debug )); then
|
||||
print "Time string: $time_start,$time_end:" \
|
||||
"'$orig_line[time_start,time_end]'"
|
||||
print "Date string: $date_start,$date_end:" \
|
||||
"'$orig_line[date_start,date_end]'"
|
||||
print "Remaining line: '$line'"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( relative )); then
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(y|yr|year)${~repat} ]]; then
|
||||
(( reladd += ((365*4+1) * 24 * 60 * 60 * ${match[2]} + 1) / 4 ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(mth|mon|mnth|month)${~repat} ]]; then
|
||||
(( reladd += 30 * 24 * 60 * 60 * ${match[2]} ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(w|wk|week)${~repat} ]]; then
|
||||
(( reladd += 7 * 24 * 60 * 60 * ${match[2]} ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(d|dy|day)${~repat} ]]; then
|
||||
(( reladd += 24 * 60 * 60 * ${match[2]} ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(h|hr|hour)${~repat} ]]; then
|
||||
(( reladd += 60 * 60 * ${match[2]} ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(min|minute)${~repat} ]]; then
|
||||
(( reladd += 60 * ${match[2]} ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
if [[ $line = (#bi)${~dspat}(<->)[[:blank:]]#(s|sec|second)${~repat} ]]; then
|
||||
(( reladd += ${match[2]} ))
|
||||
line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
|
||||
time_found=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( relative )); then
|
||||
# If no date was found, we're in trouble unless we found a time.
|
||||
if (( time_found )); then
|
||||
if (( anchor_end )); then
|
||||
# must be left with only separator characters
|
||||
if [[ $line != ${~schars}# ]]; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
(( REPLY = reladd + (hour * 60 + minute) * 60 + second ))
|
||||
[[ -n $setvar ]] && REPLY2=$line
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
elif (( ! date_found )); then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if (( anchor_end )); then
|
||||
# must be left with only separator characters
|
||||
if [[ $line != ${~schars}# ]]; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local fmt nums
|
||||
if [[ -n $mname ]]; then
|
||||
fmt="%Y %b %d %H %M %S"
|
||||
nums="$year $mname $day $hour $minute $second"
|
||||
else
|
||||
fmt="%Y %m %d %H %M %S"
|
||||
nums="$year $month $day $hour $minute $second"
|
||||
fi
|
||||
|
||||
strftime -s REPLY -r $fmt $nums
|
||||
|
||||
[[ -n $setvar ]] && REPLY2=$line
|
||||
|
||||
return 0
|
24
Functions/Calendar/calendar_show
Normal file
24
Functions/Calendar/calendar_show
Normal file
|
@ -0,0 +1,24 @@
|
|||
integer start=$1 stop=$2
|
||||
shift 2
|
||||
|
||||
[[ -o zle ]] && zle -I
|
||||
print -r "$*"
|
||||
|
||||
local -a cmd
|
||||
zmodload -i zsh/parameter || return
|
||||
|
||||
# Use xmessage to display the message if the start and stop time
|
||||
# are the same, indicating we have been scheduled to display it.
|
||||
# Don't do this if there's already an xmessage for the same user.
|
||||
# HERE: this should be configurable and we should be able to do
|
||||
# better if xmessage isn't available, e.g. wish.
|
||||
if [[ -n $DISPLAY && $start -eq $stop ]]; then
|
||||
if [[ -n ${commands[xmessage]} ]]; then
|
||||
cmd=(xmessage -center)
|
||||
fi
|
||||
if [[ -n $cmd[0] ]] &&
|
||||
! ps -u$UID | grep $cmd[0] >/dev/null 2>&1; then
|
||||
# turn off job control for this
|
||||
($cmd "$*" &)
|
||||
fi
|
||||
fi
|
67
Functions/Calendar/calendar_sort
Normal file
67
Functions/Calendar/calendar_sort
Normal file
|
@ -0,0 +1,67 @@
|
|||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
|
||||
autoload -U calendar_{read,scandate,lockfiles}
|
||||
|
||||
local calendar line REPLY new lockfile
|
||||
local -a calendar_entries
|
||||
local -a times lines_sorted lines_unsorted lines_failed lockfiles
|
||||
integer i
|
||||
|
||||
# Read the calendar file from the calendar-file style
|
||||
zstyle -s ':datetime:calendar:' calendar-file calendar || calendar=~/calendar
|
||||
|
||||
# Start block for "always" to handle lockfile
|
||||
{
|
||||
calendar_lockfiles $calendar || return 1
|
||||
|
||||
new=$calendar.new.$$
|
||||
calendar_read $calendar
|
||||
if [[ ${#calendar_entries} -eq 0 || \
|
||||
( ${#calendar_entries} -eq 1 && -z $calendar_entries[1] ) ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
for line in $calendar_entries; do
|
||||
if calendar_scandate -a $line; then
|
||||
lines_unsorted+=("${(l.16..0.)REPLY}:$line")
|
||||
else
|
||||
lines_failed+=($line)
|
||||
fi
|
||||
done
|
||||
|
||||
if (( ${#lines_unsorted} )); then
|
||||
lines_sorted=(${${(o)lines_unsorted}##[0-9]##:})
|
||||
fi
|
||||
|
||||
{
|
||||
for line in "${lines_failed[@]}"; do
|
||||
print "$line # BAD DATE"
|
||||
done
|
||||
(( ${#lines_sorted} )) && print -l "${lines_sorted[@]}"
|
||||
} > $new
|
||||
|
||||
if [[ ! -s $new ]]; then
|
||||
print "Writing to $new failed."
|
||||
return 1
|
||||
elif (( ${#lines_failed} )); then
|
||||
print "Warning: lines with date that couldn't be parsed.
|
||||
Output (with unparseable dates marked) left in $new"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! mv $calendar $calendar.old; then
|
||||
print "Couldn't back-up $calendar to $calendar.old.
|
||||
New calendar left in $new"
|
||||
return 1
|
||||
fi
|
||||
if ! mv $new $calendar; then
|
||||
print "Failed to rename $new to $calendar.
|
||||
Old calendar left in $calendar.old"
|
||||
return 1
|
||||
fi
|
||||
|
||||
print "Old calendar left in $calendar.old"
|
||||
} always {
|
||||
(( ${#lockfiles} )) && rm -rf $lockfiles
|
||||
}
|
|
@ -3,6 +3,7 @@ name=zsh/datetime
|
|||
link=either
|
||||
load=no
|
||||
|
||||
functions='Functions/Calendar/*'
|
||||
autobins="strftime"
|
||||
|
||||
objects="datetime.o"
|
||||
|
|
Loading…
Reference in a new issue