| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
RFC 5545 3.3.10 bounds a recurrence inclusively: when UNTIL lines up with the
recurrence, that date is the last instance. The expansion loops guarded on
calendar-sync--before-date-p, a strict comparison, so the instance landing
exactly on UNTIL was dropped. Every bounded series silently lost its last
meeting from the agenda. A series whose UNTIL equals its start date lost the
only instance it had and vanished.
I added calendar-sync--date-on-or-before-p beside --before-date-p and swapped
the three UNTIL sites: the simple-recurrence loop feeding daily, monthly and
yearly, plus both weekly checks. --before-date-p is unchanged, since a date is
still not before itself.
The two UNTIL property tests asserted the wrong invariant. They required every
occurrence to fall strictly before UNTIL, the exclusive reading the RFC
contradicts, so they pinned the defect they should have caught. The property is
now on-or-before. An upper bound alone can't catch a dropped occurrence, so I
added one asserting the series reaches its UNTIL date.
Reverting the fix failed three daily tests and one property test, and no weekly
ones. The weekly loop was fixed but unguarded, so it has its own test now.
The comparison stays date-granular, matching --date-to-time. An UNTIL carrying a
time of day earlier than the event's start will include that final instance
where the RFC would exclude it. Making it datetime-precise means reworking
--date-to-time and the timezone conversions feeding it, a much larger change
than this bug warrants.
|
| |
|
|
| |
calendar-sync--get-exdates read (match-end 0) after split-string, whose internal matching clobbers the match data. The scan position jumped back to a comma offset inside the value and re-matched the same EXDATE line forever, growing the result list until the kernel OOM killer took the whole session down (twice, 2026-07-13). The fix captures the line's end position before the split. The comma-separated tests added with a9e61207 were the first code to hit this path. All 12 exdates tests and all 56 calendar-sync test files now pass in milliseconds.
|
| | |
|
| |
|
|
|
|
| |
Declining one occurrence of a recurring meeting left it on the agenda. Google emits that decline as a RECURRENCE-ID override carrying the user's PARTSTAT=DECLINED. But calendar-sync--parse-exception-event never read the override's attendee block, so the occurrence kept the series' inherited "accepted" status and the declined filter never dropped it. The apply side already re-derives status from an override's attendees. The parse side just wasn't supplying them.
The fix parses the override's ATTENDEE lines into :attendees, the same way parse-event does. A unit test covers the extraction. An integration test runs the full parse/apply/filter chain on a declined week.
|
|
|
Break the 1724-line calendar-sync.el into a thin public face plus four layered libraries, moving every function verbatim so behavior and public names are unchanged:
- calendar-sync-ics.el — base parsing: RFC 5545 text cleaning, VEVENT property extraction, attendee/organizer/URL parsing, timezone and timestamp conversion, date arithmetic, single-event parsing. Depends on neither of the other new modules.
- calendar-sync-recurrence.el — RRULE/EXDATE/RECURRENCE-ID expansion.
- calendar-sync-org.el — Org rendering and atomic file output.
- calendar-sync-source.el — sync state and persistence, async .ics fetch, the batch conversion worker, and the Google Calendar API path.
calendar-sync.el keeps configuration, the parse orchestrator, sync dispatch, the user commands, the timer, and the C-; g keymap, and requires the four layers. Each layer forward-declares the config defvars it reads, so no layer requires the top module back. The batch worker loads the whole graph, so source forward-declares the two functions it calls there.
Every public name is preserved, so all 574 existing calendar-sync tests pass unchanged through the require chain. The four new modules carry the load-graph and package headers and join the header-contract allowlist.
Claude-Session: https://claude.ai/code/session_014fyKMTTqLrZpL3rDF3dYc3
|