From 0afa3fba94157d5e18f9a086e0b67b7cfd2aedf0 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 17 Nov 2025 02:54:02 -0600 Subject: fix(calendar-sync): Remove carriage return characters from synced events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- modules/calendar-sync.el | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'modules/calendar-sync.el') diff --git a/modules/calendar-sync.el b/modules/calendar-sync.el index 8450b282..feb7188d 100644 --- a/modules/calendar-sync.el +++ b/modules/calendar-sync.el @@ -144,6 +144,20 @@ Example: -21600 → 'UTC-6' or 'UTC-6:00'." (error (message "calendar-sync: Error loading state: %s" (error-message-string err)))))) +;;; Line Ending Normalization + +(defun calendar-sync--normalize-line-endings (content) + "Normalize line endings in CONTENT to Unix format (LF only). +Removes all carriage return characters (\\r) from CONTENT. +The iCalendar format (RFC 5545) uses CRLF line endings, but Emacs +and org-mode expect LF only. This function ensures consistent line +endings throughout the parsing pipeline. + +Returns CONTENT with all \\r characters removed." + (if (not (stringp content)) + content + (replace-regexp-in-string "\r" "" content))) + ;;; .ics Parsing (defun calendar-sync--split-events (ics-content) @@ -293,7 +307,7 @@ Events are sorted chronologically by start time." (defun calendar-sync--fetch-ics (url) "Fetch .ics file from URL using curl. -Returns .ics content as string, or nil on error. +Returns .ics content as string with normalized Unix line endings (LF only), or nil on error. Uses curl instead of url-retrieve-synchronously to avoid daemon mode hanging." (condition-case err (with-temp-buffer @@ -303,7 +317,7 @@ Uses curl instead of url-retrieve-synchronously to avoid daemon mode hanging." "-m" "10" ; Max 10 seconds url))) (if (= exit-code 0) - (buffer-string) + (calendar-sync--normalize-line-endings (buffer-string)) (setq calendar-sync--last-error (format "curl exited with code %d" exit-code)) (message "calendar-sync: Fetch error: %s" calendar-sync--last-error) nil))) -- cgit v1.2.3