From 70b79b3ed8d04aa852837177636061dfc43e9b0b Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sun, 17 May 2026 12:54:24 +0200 Subject: [PATCH] Rename `icalendar-recur' type and related functions More context in Bug#80786 and: https://lists.gnu.org/archive/html/emacs-orgmode/2026-03/msg00286.html `icalendar-recur' as a type name for RRULE values was confusing and made the accessors for this type difficult to discover, because `icalendar-recur-' is also used as a prefix in icalendar-recur.el. This change renames the `icalendar-recur' type to `icalendar-rrule-value' and renames the accessor functions for these values appropriately. * lisp/calendar/icalendar-parser.el: Rename symbols as follows: (icalendar-recur): `icalendar-rrule-value' (icalendar-read-recur-rule-part): `icalendar-read-rrule-part' (icalendar-print-recur-rule-part): `icalendar-print-rrule-part' (icalendar-recur-rule-part): `icalendar-rrule-part' (icalendar-read-recur): `icalendar-read-rrule-value' (icalendar-print-recur): `icalendar-print-rrule-value' (icalendar--recur-value-types): `icalendar--rrule-value-types' (icalendar-recur-value-p): `icalendar-rrule-value-p' (icalendar-recur-freq): `icalendar-rrule-freq' (icalendar-recur-interval-size): `icalendar-rrule-interval-size' (icalendar-recur-until): `icalendar-rrule-until' (icalendar-recur-count): `icalendar-rrule-count' (icalendar-recur-weekstart): `icalendar-rrule-weekstart' (icalendar-recur-by*): `icalendar-rrule-by*'. (icalendar-rrule): (icalendar-index-insert): (icalendar-index-get): Update references. * lisp/calendar/icalendar-recur.el (icalendar-recur-find-interval): (icalendar-recur-nth-interval): (icalendar-recur-next-interval): (icalendar-recur-previous-interval): (icalendar-recur-refine-from-clauses): (icalendar-recur-recurrences-in-interval): (icalendar-recur-recurrences-in-window): (icalendar-recur-recurrences-to-count): (icalendar-recur-tz-observance-on): Update references. * lisp/calendar/diary-icalendar.el: Update references. * lisp/calendar/icalendar-shortdoc.el (icalendar): Update shortdoc examples. * lisp/gnus/gnus-icalendar.el: Update references. * test/lisp/calendar/diary-icalendar-tests.el: * test/lisp/calendar/icalendar-parser-tests.el: * test/lisp/calendar/icalendar-recur-tests.el: Update references in tests. --- lisp/calendar/diary-icalendar.el | 18 +-- lisp/calendar/icalendar-parser.el | 111 +++++++++-------- lisp/calendar/icalendar-recur.el | 124 +++++++++---------- lisp/calendar/icalendar-shortdoc.el | 28 ++--- lisp/gnus/gnus-icalendar.el | 6 +- test/lisp/calendar/diary-icalendar-tests.el | 46 +++---- test/lisp/calendar/icalendar-parser-tests.el | 6 +- test/lisp/calendar/icalendar-recur-tests.el | 8 +- 8 files changed, 176 insertions(+), 171 deletions(-) diff --git a/lisp/calendar/diary-icalendar.el b/lisp/calendar/diary-icalendar.el index bc58e7b5924..9604dce8e4e 100644 --- a/lisp/calendar/diary-icalendar.el +++ b/lisp/calendar/diary-icalendar.el @@ -2690,12 +2690,12 @@ recurrence rule values in these nodes are adjusted NDAYS forward." :duration (ical:period-dur-value value))) (t (ical:date/time-add value :day ndays))))))) (ical:rrule - (let ((mdays (ical:recur-by* 'BYMONTHDAY value)) - (ydays (ical:recur-by* 'BYYEARDAY value)) - (dows (ical:recur-by* 'BYDAY value)) + (let ((mdays (ical:rrule-by* 'BYMONTHDAY value)) + (ydays (ical:rrule-by* 'BYYEARDAY value)) + (dows (ical:rrule-by* 'BYDAY value)) (bad-clause - (cond ((ical:recur-by* 'BYSETPOS value) 'BYSETPOS) - ((ical:recur-by* 'BYWEEKNO value) 'BYWEEKNO)))) + (cond ((ical:rrule-by* 'BYSETPOS value) 'BYSETPOS) + ((ical:rrule-by* 'BYWEEKNO value) 'BYWEEKNO)))) ;; We can't reliably subtract days in the following cases, so bail: (when (< 28 ndays) (di:signal-export-error @@ -2970,12 +2970,12 @@ nil, if MONTHS, DAYS and YEARS are all integers)." rdates (seq-remove (apply-partially #'equal dtstart) rdates)))) ;; Return the pair of nodes (DTSTART RRULE) or (DTSTART RDATE): - (let* ((recur-value + (let* ((rrule-value (delq nil `((FREQ ,freq) ,(when bymonth (list 'BYMONTH bymonth)) ,(when bymonthday (list 'BYMONTHDAY bymonthday))))) - (rrule-node (when freq (ical:make-property ical:rrule recur-value))) + (rrule-node (when freq (ical:make-property ical:rrule rrule-value))) (rdate-node (when rdates (ical:make-property ical:rdate rdates (ical:valuetypeparam rdate-type)))) @@ -3548,7 +3548,7 @@ values (of the same type as START)." (interval (icr:find-interval date start rule))) (cl-typecase start (ical:date - (if (ical:recur-count rule) + (if (ical:rrule-count rule) (when (member date (icr:recurrences-to-count vevent)) entry) (when (member date (icr:recurrences-in-interval interval vevent)) @@ -3581,7 +3581,7 @@ values (of the same type as START)." (ical:date/time-add-duration start duration)) (di:format-time-as-local start))) (date-entry (concat entry-time " " entry))) - (when (memq (ical:recur-freq date-rule) '(HOURLY MINUTELY SECONDLY)) + (when (memq (ical:rrule-freq date-rule) '(HOURLY MINUTELY SECONDLY)) (setf (alist-get 'FREQ date-rule) 'DAILY) (setf (alist-get 'INTERVAL date-rule) 1) (setf (alist-get 'BYHOUR date-rule nil t) nil) diff --git a/lisp/calendar/icalendar-parser.el b/lisp/calendar/icalendar-parser.el index 93293f19cbf..c6100c828e4 100644 --- a/lisp/calendar/icalendar-parser.el +++ b/lisp/calendar/icalendar-parser.el @@ -1352,9 +1352,9 @@ See `icalendar-read-weekdaynum' for the format of VAL." ;; number alone just stands for a day: (car (rassq val ical:weekday-numbers)))) -(defun ical:read-recur-rule-part (s) - "Read an `icalendar-recur-rule-part' from string S. -S should have been matched against `icalendar-recur-rule-part'. +(defun ical:read-rrule-part (s) + "Read an `icalendar-rrule-part' from string S. +S should have been matched against `icalendar-rrule-part'. The return value is a list (KEYWORD VALUE), where VALUE may itself be a list, depending on the values allowed by KEYWORD." ;; TODO: this smells like a design flaw. Silence the byte compiler for now. @@ -1376,7 +1376,7 @@ itself be a list, depending on the values allowed by KEYWORD." (rx ical:weekdaynum) ",")) (WKST (cdr (assoc values ical:weekday-numbers))))))) -(defun ical:print-recur-rule-part (part) +(defun ical:print-rrule-part (part) "Serialize recur rule part PART to a string." (let ((keyword (car part)) (values (cadr part)) @@ -1398,7 +1398,7 @@ itself be a list, depending on the values allowed by KEYWORD." (concat (symbol-name keyword) "=" values-str))) -(rx-define ical:recur-rule-part +(rx-define ical:rrule-part ;; Group 11: keyword ;; Group 12: value(s) (or (seq (group-n 11 "FREQ") "=" (group-n 12 ical:freq)) @@ -1423,14 +1423,12 @@ itself be a list, depending on the values allowed by KEYWORD." (ical:comma-list ical:yeardaynum))) (seq (group-n 11 "WKST") "=" (group-n 12 ical:weekday)))) -(defun ical:read-recur (s) +(defun ical:read-rrule-value (s) "Read a recurrence rule value from string S. S should be a match against rx `icalendar-recur'." - ;; TODO: let's switch to keywords and a plist, so we can more easily - ;; write these clauses also in diary sexp entries without so many parens - (ical:read-list-with #'ical:read-recur-rule-part s (rx ical:recur-rule-part) ";")) + (ical:read-list-with #'ical:read-rrule-part s (rx ical:rrule-part) ";")) -(defun ical:print-recur (val) +(defun ical:print-rrule-value (val) "Serialize a recurrence rule value VAL to a string." ;; RFC5545 sec. 3.3.10: "to ensure backward compatibility with ;; applications that pre-date this revision of iCalendar the @@ -1438,15 +1436,15 @@ S should be a match against rx `icalendar-recur'." ;; RECUR value." (string-join (cons - (ical:print-recur-rule-part (assq 'FREQ val)) - (mapcar #'ical:print-recur-rule-part + (ical:print-rrule-part (assq 'FREQ val)) + (mapcar #'ical:print-rrule-part (seq-filter (lambda (part) (not (eq 'FREQ (car part)))) val))) ";")) -(defconst ical:-recur-value-types +(defconst ical:-rrule-value-types ;; `list-of' is not a cl-type specifier, just a symbol here; it is - ;; handled specially when checking types in `ical:recur-value-p': + ;; handled specially when checking types in `ical:rrule-value-p': '(FREQ (member YEARLY MONTHLY WEEKLY DAILY HOURLY MINUTELY SECONDLY) UNTIL (or ical:date-time ical:date) COUNT (integer 1 *) @@ -1470,7 +1468,7 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (cl-typep (car val) '(integer 0 6)) (cl-typep (cdr val) '(or (integer -53 -1) (integer 1 53))))) -(defun ical:recur-value-p (vals) +(defun ical:rrule-value-p (vals) "Return non-nil if VALS is an iCalendar recurrence rule value." (and (listp vals) ;; FREQ is always required: @@ -1487,11 +1485,11 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (assq 'BYHOUR vals) (assq 'BYMINUTE vals) (assq 'BYSECOND vals)) - (let ((freq (ical:recur-freq vals)) - (byday (ical:recur-by* 'BYDAY vals)) - (byweekno (ical:recur-by* 'BYWEEKNO vals)) - (bymonthday (ical:recur-by* 'BYMONTHDAY vals)) - (byyearday (ical:recur-by* 'BYYEARDAY vals))) + (let ((freq (ical:rrule-freq vals)) + (byday (ical:rrule-by* 'BYDAY vals)) + (byweekno (ical:rrule-by* 'BYWEEKNO vals)) + (bymonthday (ical:rrule-by* 'BYMONTHDAY vals)) + (byyearday (ical:rrule-by* 'BYYEARDAY vals))) (and ;; "The BYDAY rule part MUST NOT be specified with a numeric ;; value when the FREQ rule part is not set to MONTHLY or @@ -1518,7 +1516,7 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (when (consp kv) (let* ((keyword (car kv)) (val (cadr kv)) - (type (plist-get ical:-recur-value-types keyword))) + (type (plist-get ical:-rrule-value-types keyword))) (and keyword val type (if (and (consp type) (eq (car type) 'list-of)) @@ -1526,7 +1524,14 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (cl-typep val type)))))) vals))) -(ical:define-type ical:recur "RECUR" +(ical:define-type ical:rrule-value + ;; Renamed from "ical:recur", which turns out to + ;; produce confusing names downstream. Thus I've + ;; deviated from the standard here, and call + ;; `ical:rrule-value' what the standard calls a RECUR + ;; value. (`ical:rrule' is not available because that + ;; names the *property* containing such a value.) + "RECUR" "Type for Recurrence Rule values. When printed, a recurrence rule value looks like @@ -1587,39 +1592,39 @@ Some examples: Notice that singleton values are still wrapped in a list when the KEY accepts a list of values, but not when the KEY always has a single (e.g. integer) value." - '(satisfies ical:recur-value-p) - (ical:semicolon-list ical:recur-rule-part) - :reader ical:read-recur - :printer ical:print-recur + '(satisfies ical:rrule-value-p) + (ical:semicolon-list ical:rrule-part) + :reader ical:read-rrule-value + :printer ical:print-rrule-value :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.3.10") -(defun ical:recur-freq (recur-value) - "Return the frequency in RECUR-VALUE." - (car (alist-get 'FREQ recur-value))) +(defun ical:rrule-freq (rrule) + "Return the frequency in RRULE." + (car (alist-get 'FREQ rrule))) -(defun ical:recur-interval-size (recur-value) - "Return the interval size in RECUR-VALUE, or the default of 1." - (or (car (alist-get 'INTERVAL recur-value)) 1)) +(defun ical:rrule-interval-size (rrule) + "Return the interval size in RRULE, or the default of 1." + (or (car (alist-get 'INTERVAL rrule)) 1)) -(defun ical:recur-until (recur-value) - "Return the UNTIL date(-time) in RECUR-VALUE." - (car (alist-get 'UNTIL recur-value))) +(defun ical:rrule-until (rrule) + "Return the UNTIL date(-time) in RRULE." + (car (alist-get 'UNTIL rrule))) -(defun ical:recur-count (recur-value) - "Return the COUNT in RECUR-VALUE." - (car (alist-get 'COUNT recur-value))) +(defun ical:rrule-count (rrule) + "Return the COUNT in RRULE." + (car (alist-get 'COUNT rrule))) -(defun ical:recur-weekstart (recur-value) - "Return the weekday which starts the work week in RECUR-VALUE. -If no starting weekday is specified in RECUR-VALUE, returns the default, +(defun ical:rrule-weekstart (rrule) + "Return the weekday which starts the work week in RRULE. +If no starting weekday is specified in RRULE, returns the default, 1 (= Monday)." - (or (car (alist-get 'WKST recur-value)) 1)) + (or (car (alist-get 'WKST rrule)) 1)) -(defun ical:recur-by* (byunit recur-value) - "Return the values in the BYUNIT clause in RECUR-VALUE. +(defun ical:rrule-by* (byunit rrule) + "Return the values in the BYUNIT clause in RRULE. BYUNIT should be a symbol: \\='BYMONTH, \\='BYDAY, etc. -See `icalendar-recur' for all the possible BYUNIT values." - (car (alist-get byunit recur-value))) +See `icalendar-rrule-value' for all the possible BYUNIT values." + (car (alist-get byunit rrule))) ;;;; 3.3.11 Text (rx-define ical:escaped-char @@ -3272,7 +3277,7 @@ and times on which an `icalendar-vevent', `icalendar-todo', `icalendar-daylight' component recurs. Together with the `icalendar-dtstart', `icalendar-rdate', and `icalendar-exdate' properties, it defines the recurrence set of the component." - ical:recur + ical:rrule-value ;; TODO: faces for subexpressions? :child-spec (:zero-or-more (ical:otherparam)) :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.5.3") @@ -4567,7 +4572,7 @@ which see." (ical:dtend :first dtend-node :value dtend) (ical:due :value due) (ical:duration :value duration) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) (ical:exdate :all exdate-nodes) (ical:uid :value uid)) @@ -4592,7 +4597,7 @@ which see." ;; If the component has an RRULE that specifies a fixed number ;; of recurrences, compute them now and index them for each date ;; in each recurrence: - ((and recur-value (ical:recur-count recur-value)) + ((and rrule (ical:rrule-count rrule)) (let* ((tz (gethash (ical:with-param-of dtstart-node 'ical:tzidparam) tzid-index)) (recs (cons dtstart (icr:recurrences-to-count component tz)))) @@ -4605,7 +4610,7 @@ which see." (list (ical:date/time-to-date (ical:date/time-to-local rec)))))))))) ;; Same with RDATEs when there's no RRULE: - ((and rdates (not recur-value)) + ((and rdates (not rrule)) (dolist (rec (cons dtstart rdates)) (unless (or (cl-typep rec 'ical:period) (member rec exdates)) (let ((end-time @@ -4624,7 +4629,7 @@ which see." (setq dates (append dates (ical:dates-until start end t))))))) ;; A non-recurring event also gets an index entry for each date ;; until its end time: - ((not recur-value) + ((not rrule) (let ((end-time (or dtend due (when duration @@ -4703,13 +4708,13 @@ Only one keyword argument can be queried at a time." (dolist (component recurring) (ical:with-component component ((ical:dtstart :first dtstart-node :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) (ical:duration :value duration)) (unless (ical:date/time<= date dtstart) (let* ((tz (ical:with-param-of dtstart-node 'ical:tzidparam nil (gethash value (plist-get index :bytzid)))) - (int (icr:find-interval date dtstart recur-value tz)) + (int (icr:find-interval date dtstart rrule tz)) (recs (icr:recurrences-in-interval int component tz))) (catch 'found (dolist (rec recs) diff --git a/lisp/calendar/icalendar-recur.el b/lisp/calendar/icalendar-recur.el index fcebbc9c6f0..b6c766962c9 100644 --- a/lisp/calendar/icalendar-recur.el +++ b/lisp/calendar/icalendar-recur.el @@ -451,29 +451,29 @@ See `icalendar-recur-find-interval' for arguments' meanings." ;; Return the bounds: (icr:make-interval low high next-low))) -(defun icr:find-interval (target dtstart recur-value &optional vtimezone) +(defun icr:find-interval (target dtstart rrule &optional vtimezone) "Return the recurrence interval around TARGET. TARGET and DTSTART should be `icalendar-date' or `icalendar-date-time' -values. RECUR-VALUE should be an `icalendar-recur'. +values. RRULE should be an `icalendar-recur'. The returned value is an interval [LOW HIGH NEXT-LOW] which represents the lower and upper bounds of a recurrence interval around TARGET. For some N, LOW is equal to START + N*INTERVALSIZE units, HIGH is equal to START + (N+1)*INTERVALSIZE units, and LOW <= TARGET < HIGH. -START here is a time derived from DTSTART depending on RECUR-VALUE's +START here is a time derived from DTSTART depending on RRULE's FREQ part: the first day of the year for a \\='YEARLY rule, first day of the month for a \\='MONTHLY rule, etc. -RECUR-VALUE's interval determines INTERVALSIZE, and its frequency +RRULE's interval determines INTERVALSIZE, and its frequency determines the units: a month for \\='MONTHLY, etc. If VTIMEZONE is provided, it is used to set time zone information in the returned interval bounds. Otherwise, the bounds contain no time zone information and represent floating local times." - (let ((freq (ical:recur-freq recur-value)) - (intsize (ical:recur-interval-size recur-value)) - (weekstart (ical:recur-weekstart recur-value))) + (let ((freq (ical:rrule-freq rrule)) + (intsize (ical:rrule-interval-size rrule)) + (weekstart (ical:rrule-weekstart rrule))) (cl-case freq (SECONDLY (icr:find-secondly-interval target dtstart intsize vtimezone)) (MINUTELY (icr:find-minutely-interval target dtstart intsize vtimezone)) @@ -484,22 +484,22 @@ information and represent floating local times." (MONTHLY (icr:find-monthly-interval target dtstart intsize vtimezone)) (YEARLY (icr:find-yearly-interval target dtstart intsize vtimezone))))) -(defun icr:nth-interval (n dtstart recur-value &optional vtimezone) +(defun icr:nth-interval (n dtstart rrule &optional vtimezone) "Return the Nth recurrence interval after DTSTART. The returned value is an interval [LOW HIGH NEXT-LOW] which is the Nth recurrence interval after DTSTART. LOW is equal to START + N*INTERVALSIZE units, HIGH is equal to START + (N+1)*INTERVALSIZE units, and LOW <= TARGET < HIGH. START here is a time derived from DTSTART -depending on RECUR-VALUE's FREQ part: the first day of the year for a +depending on RRULE's FREQ part: the first day of the year for a \\='YEARLY rule, first day of the month for a \\='MONTHLY rule, etc. -RECUR-VALUE's interval determines INTERVALSIZE, and its frequency +RRULE's interval determines INTERVALSIZE, and its frequency determines the units: a month for \\='MONTHLY, etc. N should be a non-negative integer. Interval 0 is the interval containing DTSTART. DTSTART should be an `icalendar-date' or -`icalendar-date-time' value. RECUR-VALUE should be an +`icalendar-date-time' value. RRULE should be an `icalendar-recur'. If VTIMEZONE is provided, it is used to set time zone information in the @@ -509,8 +509,8 @@ information and represent floating local times." (let* ((start-dt (if (cl-typep dtstart 'ical:date) (ical:date-to-date-time dtstart :tz vtimezone) dtstart)) - (freq (ical:recur-freq recur-value)) - (intervalsize (ical:recur-interval-size recur-value)) + (freq (ical:rrule-freq rrule)) + (intervalsize (ical:rrule-interval-size rrule)) (unit (cl-case freq (YEARLY :year) (MONTHLY :month) @@ -520,16 +520,16 @@ information and represent floating local times." (MINUTELY :minute) (SECONDLY :second))) (target (ical:date/time-add start-dt unit (* n intervalsize) vtimezone))) - (icr:find-interval target dtstart recur-value vtimezone))) + (icr:find-interval target dtstart rrule vtimezone))) -(defun icr:next-interval (interval recur-value &optional vtimezone) +(defun icr:next-interval (interval rrule &optional vtimezone) "Return the next recurrence interval after INTERVAL. Given a recurrence interval [LOW HIGH NEXT], returns the next interval [NEXT HIGHER HIGHER-NEXT], where HIGHER and HIGHER-NEXT are determined -by the frequency and interval sizes of RECUR-VALUE." +by the frequency and interval sizes of RRULE." (let* ((new-low (icr:interval-next interval)) - (freq (ical:recur-freq recur-value)) + (freq (ical:rrule-freq rrule)) (unit (cl-case freq (YEARLY :year) (MONTHLY :month) @@ -538,7 +538,7 @@ by the frequency and interval sizes of RECUR-VALUE." (HOURLY :hour) (MINUTELY :minute) (SECONDLY :second))) - (intervalsize (ical:recur-interval-size recur-value)) + (intervalsize (ical:rrule-interval-size rrule)) (new-high (ical:date/time-add new-low unit 1 vtimezone)) (new-next (when (< 1 intervalsize) @@ -552,17 +552,17 @@ by the frequency and interval sizes of RECUR-VALUE." (icr:make-interval new-low new-high new-next))) -(defun icr:previous-interval (interval recur-value dtstart &optional vtimezone) +(defun icr:previous-interval (interval rrule dtstart &optional vtimezone) "Given a recurrence INTERVAL, return the previous interval. For an interval [LOW HIGH NEXT-LOW], the previous interval is [PREV-LOW PREV-HIGH LOW], where PREV-LOW and PREV-HIGH are determined by -the frequency and interval sizes of RECUR-VALUE (see +the frequency and interval sizes of RRULE (see `icalendar-recur-find-interval'). If the resulting period of time between PREV-LOW and PREV-HIGH occurs entirely before DTSTART, then the interval does not exist; in this case nil is returned." (let* ((upper (icr:interval-low interval)) - (freq (ical:recur-freq recur-value)) + (freq (ical:rrule-freq rrule)) (unit (cl-case freq (YEARLY :year) (MONTHLY :month) @@ -571,7 +571,7 @@ interval does not exist; in this case nil is returned." (HOURLY :hour) (MINUTELY :minute) (SECONDLY :second))) - (intervalsize (ical:recur-interval-size recur-value)) + (intervalsize (ical:rrule-interval-size rrule)) (new-low (ical:date/time-add upper unit (* -1 intervalsize) vtimezone)) (new-high (if (< 1 intervalsize) @@ -1032,12 +1032,12 @@ The returned value is RECURRENCES filtered by index." (pop dts)) (nreverse r))) -(defun icr:refine-from-clauses (interval recur-value dtstart +(defun icr:refine-from-clauses (interval rrule dtstart &optional vtimezone) - "Resolve INTERVAL into subintervals based on the clauses in RECUR-VALUE. + "Resolve INTERVAL into subintervals based on the clauses in RRULE. The resulting list of subintervals represents all times in INTERVAL -which match the BY* clauses of RECUR-VALUE except BYSETPOS, as well as +which match the BY* clauses of RRULE except BYSETPOS, as well as the constraints implicit in DTSTART. (For example, if there is no BYMINUTE clause, subintervals will have the same minute value as DTSTART.) @@ -1047,14 +1047,14 @@ components and TZID should be the `icalendar-tzid' property value of one of those timezones. In this case, TZID states the time zone of DTSTART, and the offsets effective in that time zone on the dates and times of recurrences will be local to that time zone." - (let ((freq (ical:recur-freq recur-value)) - (weekstart (ical:recur-weekstart recur-value)) + (let ((freq (ical:rrule-freq rrule)) + (weekstart (ical:rrule-weekstart rrule)) (subintervals (list interval))) (dolist (byunit (list 'BYMONTH 'BYWEEKNO 'BYYEARDAY 'BYMONTHDAY 'BYDAY 'BYHOUR 'BYMINUTE 'BYSECOND)) - (let ((values (ical:recur-by* byunit recur-value)) + (let ((values (ical:rrule-by* byunit rrule)) (in-month nil)) ;; When there is no explicit BY* clause, use the value implicit ;; in DTSTART. (These conditions are adapted from RFC8984: @@ -1086,26 +1086,26 @@ recurrences will be local to that time zone." (setq values (list (ical:date/time-weekday dtstart)))) (when (and (eq byunit 'BYMONTHDAY) (eq freq 'MONTHLY) - (not (ical:recur-by* 'BYDAY recur-value)) + (not (ical:rrule-by* 'BYDAY rrule)) (not values)) (setq values (list (ical:date/time-monthday dtstart)))) (when (and (eq freq 'YEARLY) - (not (ical:recur-by* 'BYYEARDAY recur-value))) + (not (ical:rrule-by* 'BYYEARDAY rrule))) (when (and (eq byunit 'BYMONTH) (not values) - (not (ical:recur-by* 'BYWEEKNO recur-value)) - (or (ical:recur-by* 'BYMONTHDAY recur-value) - (not (ical:recur-by* 'BYDAY recur-value)))) + (not (ical:rrule-by* 'BYWEEKNO rrule)) + (or (ical:rrule-by* 'BYMONTHDAY rrule) + (not (ical:rrule-by* 'BYDAY rrule)))) (setq values (list (ical:date/time-month dtstart)))) (when (and (eq byunit 'BYMONTHDAY) (not values) - (not (ical:recur-by* 'BYWEEKNO recur-value)) - (not (ical:recur-by* 'BYDAY recur-value))) + (not (ical:rrule-by* 'BYWEEKNO rrule)) + (not (ical:rrule-by* 'BYDAY rrule))) (setq values (list (ical:date/time-monthday dtstart)))) (when (and (eq byunit 'BYDAY) (not values) - (ical:recur-by* 'BYWEEKNO recur-value) - (not (ical:recur-by* 'BYMONTHDAY recur-value))) + (ical:rrule-by* 'BYWEEKNO rrule) + (not (ical:rrule-by* 'BYMONTHDAY rrule))) (setq values (list (ical:date/time-weekday dtstart))))) ;; Handle offsets in a BYDAY clause: @@ -1120,7 +1120,7 @@ recurrences will be local to that time zone." (when (and (eq byunit 'BYDAY) (or (eq freq 'MONTHLY) (and (eq freq 'YEARLY) - (ical:recur-by* 'BYMONTH recur-value)))) + (ical:rrule-by* 'BYMONTH rrule)))) (setq in-month t)) ;; On each iteration of the loop, we refine the subintervals @@ -1246,10 +1246,10 @@ retrieved on subsequent calls with the same arguments." (ical:with-component component ((ical:dtstart :value dtstart) (ical:tzoffsetfrom :value offset-from) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) ;; TODO: these can also be ical:period values (ical:exdate :all exdate-nodes)) - (if (not (or recur-value rdate-nodes)) + (if (not (or rrule rdate-nodes)) ;; No recurrences to calculate, so just return early: nil ;; Otherwise, calculate recurrences in the interval: @@ -1267,19 +1267,19 @@ retrieved on subsequent calls with the same arguments." (t (let* (;; Start by generating all the recurrences matching the ;; BY* clauses except for BYSETPOS: - (subs (icr:refine-from-clauses interval recur-value dtstart + (subs (icr:refine-from-clauses interval rrule dtstart vtimezone)) (sub-recs (icr:subintervals-to-recurrences subs dtstart vtimezone)) ;; Apply any BYSETPOS clause to this set: - (keep-indices (ical:recur-by* 'BYSETPOS recur-value)) + (keep-indices (ical:rrule-by* 'BYSETPOS rrule)) (pos-recs (if keep-indices (icr:bysetpos-filter keep-indices sub-recs) sub-recs)) ;; Remove any recurrences before DTSTART or after UNTIL ;; (both of which are inclusive bounds): - (until (ical:recur-until recur-value)) + (until (ical:rrule-until rrule)) (until-recs (seq-filter (lambda (rec) (and (ical:date/time<= dtstart rec) @@ -1345,9 +1345,9 @@ UTC offsets local to that time zone." (ical:with-component component ((ical:dtstart :value dtstart) (ical:tzoffsetfrom :value offset-from) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes)) - (if (not (or recur-value rdate-nodes)) + (if (not (or rrule rdate-nodes)) ;; No recurrences to calculate, so just return early: nil ;; Otherwise, calculate the recurrences in the window: @@ -1362,11 +1362,11 @@ UTC offsets local to that time zone." (let* (;; don't look for nonexistent intervals: (low-start (if (ical:date/time< lower dtstart) dtstart lower)) - (until (ical:recur-until recur-value)) + (until (ical:rrule-until rrule)) (high-end (if (and until (ical:date/time< until upper)) until upper)) - (curr-interval (icr:find-interval low-start dtstart recur-value + (curr-interval (icr:find-interval low-start dtstart rrule vtimezone)) - (high-interval (icr:find-interval high-end dtstart recur-value + (high-interval (icr:find-interval high-end dtstart rrule vtimezone)) (high-intbound (icr:interval-high high-interval)) (recurrences nil)) @@ -1376,7 +1376,7 @@ UTC offsets local to that time zone." (nconc (icr:recurrences-in-interval curr-interval component vtimezone) recurrences)) - (setq curr-interval (icr:next-interval curr-interval recur-value + (setq curr-interval (icr:next-interval curr-interval rrule vtimezone))) ;; exclude any recurrences inside the first and last intervals but @@ -1447,7 +1447,7 @@ UTC offsets local to that time zone." (ical:with-component component ((ical:dtstart :value dtstart) (ical:tzoffsetfrom :value offset-from) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes)) (when (memq (ical:ast-node-type component) '(ical:standard ical:daylight)) ;; in time zone observances, set the zone field in dtstart @@ -1457,18 +1457,18 @@ UTC offsets local to that time zone." :zone offset-from :dst (not (ical:daylight-component-p component))))) - (unless (or recur-value rdate-nodes) + (unless (or rrule rdate-nodes) (error "No recurrence data in component: %s" component)) - (unless (ical:recur-count recur-value) + (unless (ical:rrule-count rrule) (error "Recurrence rule has no COUNT clause")) - (let ((count (ical:recur-count recur-value)) - (int (icr:nth-interval 0 dtstart recur-value vtimezone)) + (let ((count (ical:rrule-count rrule)) + (int (icr:nth-interval 0 dtstart rrule vtimezone)) recs) (while (length< recs count) (setq recs (nconc recs (icr:recurrences-in-interval int component vtimezone (- count (length recs))))) - (setq int (icr:next-interval int recur-value vtimezone))) + (setq int (icr:next-interval int rrule vtimezone))) recs))) @@ -1771,7 +1771,7 @@ ignored." (dolist (obs (append stds dls)) (ical:with-component obs ((ical:dtstart :value start) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) (ical:tzoffsetfrom :value offset-from)) ;; DTSTART of the observance must be given as local time, and is @@ -1781,7 +1781,7 @@ ignored." (effective-start (ical:date-time-variant start :zone offset-from :dst (not is-daylight))) - (until (ical:recur-until recur-value)) + (until (ical:rrule-until rrule)) (bound ;; Optimization: compute a rough upper bound for when ;; an observance might apply, thus allowing us to skip @@ -1796,8 +1796,8 @@ ignored." (when until (ical:date-time-variant until :year (+ (decoded-time-year until) - (ical:recur-interval-size - recur-value))))) + (ical:rrule-interval-size + rrule))))) (observance-might-apply (if given-clock-time (icr:-w/in-locally-p given-clock-time effective-start bound) @@ -1859,11 +1859,11 @@ ignored." ;; start of each observance onset), which ;; `icr:tz-set-zone' knows to handle specially without ;; calling this function. - (when recur-value + (when rrule (let* ((target (or given-clock-time (decode-time given-abs-time offset-from))) (int (icr:find-interval - target effective-start recur-value offset-from)) + target effective-start rrule offset-from)) (<=given (if given-clock-time (lambda (rec) @@ -1883,7 +1883,7 @@ ignored." ;; actually be in the previous interval, e.g. ;; if `dt' is in January after an annual change to ;; Standard Time in November. So check that as well. - (setq int (icr:previous-interval int recur-value + (setq int (icr:previous-interval int rrule effective-start offset-from)) (setq int-recs diff --git a/lisp/calendar/icalendar-shortdoc.el b/lisp/calendar/icalendar-shortdoc.el index ef6f23cdfb9..cf706f54672 100644 --- a/lisp/calendar/icalendar-shortdoc.el +++ b/lisp/calendar/icalendar-shortdoc.el @@ -252,22 +252,22 @@ "(icalendar-recur-recurrences-to-count '(1 1 2026) '(12 31 2026) vevent)" :eg-result-string "((1 10 2026) (2 10 2026) (3 10 2026))") - (icalendar-recur-freq + (icalendar-rrule-freq :eval - (icalendar-recur-freq '((FREQ MONTHLY) (INTERVAL 3) (BYDAY ((5 . -1)))))) - (icalendar-recur-interval-size - :eval (icalendar-recur-interval-size '((FREQ MONTHLY) (BYDAY ((5 . -1))))) - :eval (icalendar-recur-interval-size '((FREQ MONTHLY) (INTERVAL 3)))) - (icalendar-recur-count - :eval (icalendar-recur-count '((FREQ MONTHLY) (INTERVAL 2) (COUNT 6)))) - (icalendar-recur-until - :eval (icalendar-recur-until '((FREQ WEEKLY) (UNTIL (12 31 2026))))) - (icalendar-recur-by* - :eval (icalendar-recur-by* 'BYDAY '((FREQ MONTHLY) (BYDAY ((5 . -1)))))) - (icalendar-recur-weekstart + (icalendar-rrule-freq '((FREQ MONTHLY) (INTERVAL 3) (BYDAY ((5 . -1)))))) + (icalendar-rrule-interval-size + :eval (icalendar-rrule-interval-size '((FREQ MONTHLY) (BYDAY ((5 . -1))))) + :eval (icalendar-rrule-interval-size '((FREQ MONTHLY) (INTERVAL 3)))) + (icalendar-rrule-count + :eval (icalendar-rrule-count '((FREQ MONTHLY) (INTERVAL 2) (COUNT 6)))) + (icalendar-rrule-until + :eval (icalendar-rrule-until '((FREQ WEEKLY) (UNTIL (12 31 2026))))) + (icalendar-rrule-by* + :eval (icalendar-rrule-by* 'BYDAY '((FREQ MONTHLY) (BYDAY ((5 . -1)))))) + (icalendar-rrule-weekstart :eval - (icalendar-recur-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)) (WKST 0))) + (icalendar-rrule-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)) (WKST 0))) :eval - (icalendar-recur-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)))))) + (icalendar-rrule-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)))))) (provide 'icalendar-shortdoc) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 0097f590b43..54f105f6fda 100644 --- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -131,18 +131,18 @@ (cl-defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event)) "Return recurring frequency of EVENT." - (ical:recur-freq (gnus-icalendar-event:recur event))) + (ical:rrule-freq (gnus-icalendar-event:recur event))) (cl-defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event)) "Return recurring interval of EVENT." - (ical:recur-interval-size (gnus-icalendar-event:recur event))) + (ical:rrule-interval-size (gnus-icalendar-event:recur event))) (cl-defmethod gnus-icalendar-event:recurring-days ((event gnus-icalendar-event)) "Return, when available, the week day numbers on which the EVENT recurs." (let ((rrule (gnus-icalendar-event:recur event))) (when rrule (mapcar (lambda (el) (if (consp el) (car el) el)) - (ical:recur-by* 'BYDAY rrule))))) + (ical:rrule-by* 'BYDAY rrule))))) (cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event)) (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event))) diff --git a/test/lisp/calendar/diary-icalendar-tests.el b/test/lisp/calendar/diary-icalendar-tests.el index 22faeb7aa23..06272a39cf4 100644 --- a/test/lisp/calendar/diary-icalendar-tests.el +++ b/test/lisp/calendar/diary-icalendar-tests.el @@ -817,8 +817,8 @@ SOURCE, if given, should be a symbol; it is used to name the test." (should (equal (ical:date-time-to-date dtstart) (calendar-nth-named-day 1 4 1 di:recurring-start-year))) (should (= 16 (decoded-time-hour dtstart))) - (should (eq (ical:recur-freq rrule) 'WEEKLY)) - (should (equal (ical:recur-by* 'BYDAY rrule) (list 4))))) + (should (eq (ical:rrule-freq rrule) 'WEEKLY)) + (should (equal (ical:rrule-by* 'BYDAY rrule) (list 4))))) (dit:parse-test ;; Multiline entry, parsed as one event: @@ -961,10 +961,10 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart '(5 28 1995))) - (should (eq (ical:recur-freq recur-value) 'YEARLY)) + (should (eq (ical:rrule-freq rrule) 'YEARLY)) (should (equal summary "H's birthday")))) (dit:parse-test @@ -977,11 +977,11 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart '(6 24 2012))) - (should (equal (ical:recur-freq recur-value) 'DAILY)) - (should (equal (ical:recur-until recur-value) '(7 10 2012))) + (should (equal (ical:rrule-freq rrule) 'DAILY)) + (should (equal (ical:rrule-until rrule) '(7 10 2012))) (should (equal summary "Vacation")))) (dit:parse-test @@ -994,11 +994,11 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart '(3 1 2012))) - (should (eq (ical:recur-freq recur-value) 'DAILY)) - (should (eq (ical:recur-interval-size recur-value) 50)) + (should (eq (ical:rrule-freq rrule) 'DAILY)) + (should (eq (ical:rrule-interval-size rrule) 50)) (should (equal summary "Renew medication")))) (dit:parse-test @@ -1011,13 +1011,13 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart (calendar-nth-named-day 4 4 11 di:recurring-start-year))) - (should (eq (ical:recur-freq recur-value) 'MONTHLY)) - (should (equal (ical:recur-by* 'BYMONTH recur-value) (list 11))) - (should (equal (ical:recur-by* 'BYDAY recur-value) (list '(4 . 4)))) + (should (eq (ical:rrule-freq rrule) 'MONTHLY)) + (should (equal (ical:rrule-by* 'BYMONTH rrule) (list 11))) + (should (equal (ical:rrule-by* 'BYDAY rrule) (list '(4 . 4)))) (should (equal summary "American Thanksgiving")))) (dit:parse-test @@ -1030,13 +1030,13 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart (calendar-nth-named-day 4 5 1 di:recurring-start-year))) - (should (eq (ical:recur-freq recur-value) 'MONTHLY)) + (should (eq (ical:rrule-freq rrule) 'MONTHLY)) ;; day 3 is Wednesday, so offset of 2 means Friday (=5): - (should (equal (ical:recur-by* 'BYDAY recur-value) (list '(5 . 4)))) + (should (equal (ical:rrule-by* 'BYDAY rrule) (list '(5 . 4)))) (should (equal summary "Monthly committee meeting")))) (dit:parse-test @@ -1052,11 +1052,11 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:exdate :values exdates) (ical:summary :value summary)) (should (equal dtstart '(11 11 2024))) - (should (eq (ical:recur-freq recur-value) 'WEEKLY)) + (should (eq (ical:rrule-freq rrule) 'WEEKLY)) (should (equal exdates '((12 23 2024) (12 30 2024)))) (should (equal summary "Reading group")))) @@ -1070,12 +1070,12 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart (list 10 22 di:recurring-start-year))) - (should (eq (ical:recur-freq recur-value) 'YEARLY)) - (should (equal (ical:recur-by* 'BYMONTH recur-value) (list 10 11 12))) - (should (equal (ical:recur-by* 'BYMONTHDAY recur-value) (list 22))) + (should (eq (ical:rrule-freq rrule) 'YEARLY)) + (should (equal (ical:rrule-by* 'BYMONTH rrule) (list 10 11 12))) + (should (equal (ical:rrule-by* 'BYMONTHDAY rrule) (list 22))) (should (equal summary "Rake leaves")))) (dit:parse-test diff --git a/test/lisp/calendar/icalendar-parser-tests.el b/test/lisp/calendar/icalendar-parser-tests.el index f3c5de35c87..8215f977e26 100644 --- a/test/lisp/calendar/icalendar-parser-tests.el +++ b/test/lisp/calendar/icalendar-parser-tests.el @@ -388,21 +388,21 @@ test." (ipt:parse/print-test "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1" -:type icalendar-recur +:type icalendar-rrule-value :parser icalendar-parse-value-node :printer icalendar-print-value-node :source rfc5545-sec3.3.10/1) (ipt:parse/print-test "FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30" -:type icalendar-recur +:type icalendar-rrule-value :parser icalendar-parse-value-node :printer icalendar-print-value-node :source rfc5545-sec3.3.10/2) (ipt:parse/print-test "FREQ=DAILY;COUNT=10;INTERVAL=2" -:type icalendar-recur +:type icalendar-rrule-value :parser icalendar-parse-value-node :printer icalendar-print-value-node :source rfc5545-sec3.3.10/3) diff --git a/test/lisp/calendar/icalendar-recur-tests.el b/test/lisp/calendar/icalendar-recur-tests.el index c1f7bb90974..199d6c4aa25 100644 --- a/test/lisp/calendar/icalendar-recur-tests.el +++ b/test/lisp/calendar/icalendar-recur-tests.el @@ -1383,7 +1383,7 @@ END:VTIMEZONE (ts-obs/onset (icr:tz-observance-on ts ict:tz-eastern))) (should (eq 'ical:daylight (ical:ast-node-type obs))) (should (equal dt onset)) - (should (equal end (ical:recur-until + (should (equal end (ical:rrule-until (ical:with-property-of obs 'ical:rrule nil value)))) (should (equal obs/onset ts-obs/onset))) @@ -1534,10 +1534,10 @@ SOURCE should be a symbol; it is used to name the test." ,(format "Parse and evaluate recur-value example from `%s':\n%s" source doc) :tags ,tags - (let* ((parsed (ical:parse-from-string 'ical:recur ,recur-string)) + (let* ((parsed (ical:parse-from-string 'ical:rrule-value ,recur-string)) (recvalue (ical:ast-node-value parsed)) - (until (ical:recur-until recvalue)) - (count (ical:recur-count recvalue)) + (until (ical:rrule-until recvalue)) + (count (ical:rrule-count recvalue)) (dtstart ,dtstart) (tzid (when (cl-typep dtstart 'ical:date-time)