summaryrefslogtreecommitdiff
path: root/modules/calendar-sync.el
Commit message (Collapse)AuthorAgeFilesLines
* feat(music): add random-aware next/previous; refactor music + calendar-syncCraig Jennings2026-04-031-159/+69
| | | | | | | | | | Music: random mode now respected by next/previous keys. Previous navigates a 50-track play history ring buffer. Fixed playlist replacement bug. 24 new tests. Calendar-sync: consolidated duplicate parse functions, extracted timezone localization helper, unified expand-daily/monthly/yearly into parameterized function, removed dead code. 33 new characterization tests. -90 lines.
* fix(calendar-sync): handle variable-length date lists in RRULE UNTILCraig Jennings2026-03-091-3/+7
| | | | | | | date-to-time used (reverse date) which broke when RRULE UNTIL values were parsed as 5-element lists (year month day hour minute) from UTC timestamps. This caused recurring events with UTC UNTIL dates to expand to 0 occurrences, producing stale calendar entries.
* chore: rename chime.el references to ChimeCraig Jennings2026-02-231-1/+1
| | | | | Update load-path, GitHub URL, and all project/package name references to reflect the chime.el → Chime rename.
* perf(calendar-sync): replace shell-out timezone conversion with pure ElispCraig Jennings2026-02-141-32/+60
| | | | | | | | | convert-tz-to-local was spawning a `date` subprocess per timestamp, causing ~15s parse freezes on Proton (223 events) and ~10s on Google (1543 events). Replaced with encode-time/decode-time ZONE argument — same TZ database, no subprocess overhead. Parse times now 0.2-2.8s. Also adds phase timing instrumentation behind cj/debug-modules flag.
* fix(calendar-sync): increase fetch timeout for large calendarsCraig Jennings2026-02-061-1/+11
| | | | | | Google calendar (7k+ events, 4.5MB) was hitting the 30s hard-coded curl timeout. Use configurable calendar-sync-fetch-timeout (default 120s) with a separate 10s connect-timeout for fast failure on unreachable hosts.
* fix(calendar-sync): sanitize description text to prevent org heading corruptionCraig Jennings2026-02-061-2/+13
| | | | | | Event descriptions containing lines starting with * were being interpreted as org headings, breaking file structure. Replace leading asterisks with dashes before writing descriptions.
* fix(calendar-sync): fix heading order, continuation lines, and exception ↵Craig Jennings2026-02-051-6/+10
| | | | | | | | | | | | | | | | | | text cleaning Three bugs found during manual verification of calendar sync output: 1. Heading/timestamp order reversed in event-to-org — nreverse pattern put timestamp before the org heading. Swap initial list order. 2. get-property continuation line regex broken — the ^ anchor in "^\n[ \t]" prevented matching at the correct position, truncating long DESCRIPTION values at the first ICS line fold. Remove anchor, add explicit position check (matching get-all-property-lines pattern). 3. collect-recurrence-exceptions didn't clean text — exception instances got raw ICS text (literal \n, HTML tags) replacing the cleaned base event text. Wrap summary/description/location in clean-text.
* feat(calendar-sync): add event details — attendees, organizer, status, URLCraig Jennings2026-02-051-16/+208
| | | | | | | | Add ICS text unescaping (RFC 5545), HTML stripping, and new fields (attendees/status, organizer, meeting URL) to calendar-sync.el. event-to-org now outputs org property drawers. 88 new tests across 10 test files, 146/146 pass. Also fix pre-existing test require order and keymap guard issues.
* refactor(calendar): move calendar URLs into calendar-sync.elCraig Jennings2026-02-041-0/+12
| | | | | Consolidate calendar configuration within the module itself rather than requiring setup in init.el. Improves module encapsulation.
* feat(calendar-sync): add EXDATE support for excluded recurring event datesCraig Jennings2026-02-031-10/+135
| | | | | | | | | | | | | | | | | | | | | When someone deletes a single instance of a recurring meeting in Google Calendar, the calendar exports an EXDATE property marking that date as excluded. Previously, calendar-sync expanded the RRULE without filtering out these excluded dates, causing deleted instances to appear in org output. New functions: - calendar-sync--get-exdates: Extract all EXDATE values from event - calendar-sync--get-exdate-line: Get full EXDATE line with parameters - calendar-sync--parse-exdate: Parse EXDATE into datetime list - calendar-sync--collect-exdates: Collect excluded dates with TZ conversion - calendar-sync--exdate-matches-p: Check if occurrence matches an EXDATE - calendar-sync--filter-exdates: Filter out excluded dates from occurrences Modified calendar-sync--expand-recurring-event to collect and filter EXDATEs after RRULE expansion. Includes 47 new tests covering extraction, parsing, collection, filtering, and integration with RECURRENCE-ID exceptions.
* feat(calendar-sync): add RECURRENCE-ID exception handling for recurring eventsCraig Jennings2026-02-031-10/+178
| | | | | | | | | | | | | | | | | | | | | Handle rescheduled instances of recurring calendar events by processing RECURRENCE-ID properties from ICS files. When someone reschedules a single instance of a recurring meeting in Google Calendar, the calendar-sync module now shows the rescheduled time instead of the original RRULE time. New functions: - calendar-sync--get-recurrence-id: Extract RECURRENCE-ID from event - calendar-sync--get-recurrence-id-line: Get full line with TZID params - calendar-sync--parse-recurrence-id: Parse into (year month day hour minute) - calendar-sync--collect-recurrence-exceptions: Collect all exceptions by UID - calendar-sync--occurrence-matches-exception-p: Match occurrences to exceptions - calendar-sync--apply-single-exception: Apply exception data to occurrence - calendar-sync--apply-recurrence-exceptions: Apply all exceptions to occurrences Also adds DeepSat calendar configuration (dcal-file) to user-constants, init.el, and org-agenda-config. 48 unit and integration tests added covering normal, boundary, and error cases.
* feat(calendar-sync): add timezone conversion for TZID-qualified eventsCraig Jennings2026-02-011-12/+79
| | | | | | | | | | | | Events with TZID parameters (e.g., DTSTART;TZID=Europe/Lisbon) were displaying in the source timezone instead of local time. Added: - calendar-sync--extract-tzid: extracts TZID from property lines - calendar-sync--convert-tz-to-local: converts using date command - Modified parse-timestamp to accept optional TZID parameter - Modified parse-event to extract and pass TZID through pipeline Includes 40 new tests covering extraction, conversion, and integration.
* feat(calendar-sync): re-enable auto-sync on startupCraig Jennings2026-01-271-1/+1
| | | | Freeze bugs are fixed; safe to auto-sync again.
* fix(calendar-sync): resolve freeze on DST transitions and large ICS filesCraig Jennings2026-01-271-7/+13
| | | | | | | | | | | Two bugs caused Emacs to freeze during calendar sync: 1. split-events used catastrophic regex (\(.\|\n\)*?) on multi-MB ICS data. Replaced with buffer-based search-forward (0.011s for 4.5MB). 2. add-days used midnight for date arithmetic. On DST fall-back days, adding 86400s to midnight CDT yields 11pm CST (same date), creating an infinite loop. Fixed by using noon so ±1h DST shift stays correct.
* fix(calendar-sync): disable auto-start to prevent freezeCraig Jennings2026-01-141-1/+1
| | | | | | Proton calendar download causes Emacs to freeze. Disabled auto-sync by default until root cause is investigated. Manual sync still available via C-; g s keybinding.
* feat(calendar-sync): multi-calendar support with property testsCraig Jennings2025-12-021-73/+179
| | | | | | Added multi-URL calendar sync supporting Google and Proton calendars. Each calendar syncs to separate file with per-calendar state tracking. Added 13 property-based tests for RRULE expansion. Total: 150 tests passing.
* fix: add quick-sdcv quit binding and fix calendar-sync sentinelCraig Jennings2025-11-211-11/+13
| | | | | | | - Add 'q' keybinding in quick-sdcv-mode to quit-window for easier dictionary dismissal while reading epubs - Fix "Selecting deleted buffer" error in calendar-sync by checking buffer-live-p before accessing process buffer in sentinel
* feat(calendar-sync): Add RRULE support and refactor expansion functionsCraig Jennings2025-11-181-35/+385
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Implements complete recurring event (RRULE) expansion for Google Calendar with rolling window approach and comprehensive test coverage. Features: - RRULE expansion for DAILY, WEEKLY, MONTHLY, YEARLY frequencies - Support for INTERVAL, BYDAY, UNTIL, and COUNT parameters - Rolling window: -3 months to +12 months from current date - Fixed COUNT parameter bug (events no longer appear beyond their limit) - Fixed TZID parameter parsing (supports timezone-specific timestamps) - Replaced debug messages with cj/log-silently Refactoring: - Extracted helper functions to eliminate code duplication: - calendar-sync--date-to-time: Date to time conversion - calendar-sync--before-date-p: Date comparison - calendar-sync--create-occurrence: Event occurrence creation - Refactored all expansion functions to use helper functions - Reduced code duplication across daily/weekly/monthly/yearly expansion Testing: - 68 tests total across 5 test files - Unit tests for RRULE parsing, property extraction, weekly expansion - Integration tests for complete RRULE workflow - Tests for helper functions validating refactored code - All tests passing
* fix: increase calendar-sync curl timeout from 10 to 30 secondsCraig Jennings2025-11-171-1/+1
| | | | | | 10-second timeout was too aggressive for slower networks or delayed Google servers. Increased to 30 seconds to prevent timeout errors while still preventing indefinite hangs.
* feat(calendar-sync): Make ICS fetching asynchronousCraig Jennings2025-11-171-29/+42
| | | | | | | | | | | | | | Changed calendar-sync--fetch-ics from synchronous call-process to asynchronous make-process with callback pattern. This prevents Emacs from freezing during calendar syncs. Changes: - calendar-sync--fetch-ics now takes a callback parameter - Uses make-process with sentinel for async completion - calendar-sync-now updated to use callback pattern - Fetch completes in background without blocking Emacs All 56 tests pass. User confirmed improved responsiveness.
* chore(calendar-sync): Change default interval to 60 minutesCraig Jennings2025-11-171-3/+3
| | | | | | | | | | Changed default sync interval from 15 minutes to 60 minutes (1 hour). Rationale: - Calendar events typically don't change that frequently - Reduces network requests and potential blocking events - Users can still manually sync or adjust interval as needed - More conservative default that balances freshness with performance
* refactor(calendar-sync): Make interval configurable in minutesCraig Jennings2025-11-171-11/+12
| | | | | | | | | | | | | | | | | | | Changed calendar-sync-interval (seconds) to calendar-sync-interval-minutes for more user-friendly configuration. Changes: - Renamed: calendar-sync-interval → calendar-sync-interval-minutes - Units: seconds → minutes (default: 15) - Internal conversion to seconds happens in calendar-sync-start - Updated docstrings and messages to reference minutes Benefits: - More intuitive configuration (users think in minutes, not seconds) - Clearer variable name indicates units - No functional change, just better UX Example usage: (setq calendar-sync-interval-minutes 30) ; Sync every 30 minutes
* feat(calendar-sync): Add auto-start toggle and convert to defvarCraig Jennings2025-11-171-20/+17
| | | | | | | | | | | | | | | | | | | | | | | | Changes: 1. Converted defcustom → defvar (3 variables): - calendar-sync-ics-url - calendar-sync-interval - calendar-sync-file - Removed defgroup (not using customize system) 2. Added calendar-sync-auto-start variable (default: t) - Controls whether auto-sync starts when module loads - Set to nil to disable automatic startup 3. Updated initialization to check auto-start flag - Auto-sync only starts if both auto-start and URL are non-nil - Provides user control over automatic behavior Rationale: - Auto-sync is convenient but should be toggleable - defvar is simpler and more direct than defcustom - Consistent with project style (no customize interface) Default behavior: Auto-sync enabled (backwards compatible with user expectation)
* fix(calendar-sync): Remove carriage return characters from synced eventsCraig Jennings2025-11-171-2/+16
| | | | | | | | | | | | | | | | | | | | | | | Problem: Google Calendar .ics files use CRLF line endings (RFC 5545 spec), which resulted in 11,685 ^M (CR) characters appearing in gcal.org, particularly at the end of org header lines. Solution: - Created calendar-sync--normalize-line-endings function to strip all \r characters from .ics content - Integrated into calendar-sync--fetch-ics immediately after curl download - Ensures clean Unix LF-only line endings throughout parsing pipeline Testing: - Added comprehensive test suite: test-calendar-sync--normalize-line-endings.el - 16 tests covering Normal, Boundary, and Error cases - All 56 existing calendar-sync tests still pass (no regressions) - Verified: gcal.org now has 0 CR characters (was 11,685) Files modified: - modules/calendar-sync.el: Added normalize function, updated fetch function - tests/test-calendar-sync--normalize-line-endings.el: New comprehensive test suite
* feat(calendar-sync): Add automatic timezone detection and chronological sortingCraig Jennings2025-11-161-0/+438
Implemented calendar-sync.el as a complete replacement for org-gcal, featuring: **Core Functionality:** - One-way sync from Google Calendar to Org (via .ics URL) - UTC to local timezone conversion for all event timestamps - Chronological event sorting (past → present → future) - Non-blocking sync using curl (works reliably in daemon mode) **Automatic Timezone Detection:** - Detects timezone changes when traveling between timezones - Tracks timezone offset in seconds (-21600 for CST, -28800 for PST, etc.) - Triggers automatic re-sync when timezone changes detected - Shows informative messages: "Timezone change detected (UTC-6 → UTC-8)" **State Persistence:** - Saves sync state to ~/.emacs.d/data/calendar-sync-state.el - Persists timezone and last sync time across Emacs sessions - Enables detection even after closing Emacs before traveling **User Features:** - Interactive commands: calendar-sync-now, calendar-sync-start/stop - Keybindings: C-; g s (sync), C-; g a (start auto-sync), C-; g x (stop) - Optional auto-sync every 15 minutes (disabled by default) - Clear status messages for all operations **Code Quality:** - Comprehensive test coverage: 51 ERT tests (100% passing) - Refactored UTC conversion into separate function - Clean separation of concerns (parsing, conversion, formatting, sorting) - Well-documented with timezone behavior guide and changelog **Migration:** - Removed org-gcal-config.el (archived in modules/archived/) - Updated init.el to use calendar-sync - Moved gcal.org to .emacs.d/data/ for machine-independent syncing - Removed org-gcal appointment capture template Files modified: modules/calendar-sync.el:442, tests/test-calendar-sync.el:577 Files created: data/calendar-sync-state.el, tests/testutil-calendar-sync.el Documentation: docs/calendar-sync-timezones.md, docs/calendar-sync-changelog.md