diff --git a/home/roles/emacs/doom/config.el b/home/roles/emacs/doom/config.el index 3919559..7623942 100644 --- a/home/roles/emacs/doom/config.el +++ b/home/roles/emacs/doom/config.el @@ -97,6 +97,7 @@ (defun my/org-caldav-sync-with-rbw () "Run org-caldav-sync with credentials from rbw embedded in URL." (interactive) + (require 'org) (require 'org-caldav) (let* ((password (my/get-rbw-password "nextcloud-caldav")) ;; Embed credentials in URL (url-encode password in case of special chars) @@ -157,6 +158,32 @@ ;; Note: Create 'tasks' calendar in Nextcloud first, keep it private. (:calendar-id "tasks" :files ("~/org/todo.org")))) + + ;; Handle UNTIL in recurring events + ;; org-caldav ignores UNTIL from RRULE - events repeat forever. + ;; This advice extracts UNTIL and adds a DEADLINE without repeater, + ;; which Org 9.7+ interprets as the recurrence end date. + (defun my/org-caldav-add-until-deadline (orig-fun eventdata-alist) + "Advice to add DEADLINE for UNTIL in recurring events." + (let ((result (funcall orig-fun eventdata-alist))) + (let* ((rrule-props (alist-get 'rrule-props eventdata-alist)) + (until-str (cadr (assq 'UNTIL rrule-props)))) + (when until-str + (save-excursion + (org-back-to-heading t) + ;; Store original UNTIL for reference + (org-entry-put nil "CALDAV_UNTIL" until-str) + ;; Parse UNTIL: format is YYYYMMDD or YYYYMMDDTHHMMSSZ + (when (string-match "^\\([0-9]\\{4\\}\\)\\([0-9]\\{2\\}\\)\\([0-9]\\{2\\}\\)" until-str) + (let* ((year (string-to-number (match-string 1 until-str))) + (month (string-to-number (match-string 2 until-str))) + (day (string-to-number (match-string 3 until-str))) + (deadline-ts (format "<%d-%02d-%02d>" year month day))) + (org-add-planning-info 'deadline deadline-ts)))))) + result)) + + (advice-add 'org-caldav-insert-org-event-or-todo + :around #'my/org-caldav-add-until-deadline) ) (defun my/get-rbw-password (alias)