Skip to content

Instantly share code, notes, and snippets.

@vherrmann
Created January 3, 2026 22:23
Show Gist options
  • Select an option

  • Save vherrmann/4637284194b214f2a83964b6306883ba to your computer and use it in GitHub Desktop.

Select an option

Save vherrmann/4637284194b214f2a83964b6306883ba to your computer and use it in GitHub Desktop.
Rescheduling repeating todos in org mode without breaking regular schedule
(defun iko/org-is-static-repeater ()
;; Is this a repeater that uses the current date for rescheduling (.+) or
;; a „static“ repeater that uses the last scheduled date (++)?
(when-let ((repeater (org-get-repeat)))
(not (string-prefix-p ".+" repeater))))
(defun iko/org-entry-put-nil (EPOM PROPERTY VALUE)
(and VALUE (org-entry-put EPOM PROPERTY VALUE)))
(defun iko/org-ts-inactive→active (text)
(when (and text (string-match "\\[\\(.+\\)\\]" text))
(concat "<" (match-string 1 text) ">")))
(defun iko/org-ts-active→inactive (text)
(when (and text (string-match "<\\(.+\\)>" text))
(concat "[" (match-string 1 text) "]")))
(advice-add
'org-todo
:around
(defun iko/org-todo-schedule-fix (oldfun &rest r)
(if (iko/org-is-static-repeater)
(let ((prev-scheduled-stamp (org-entry-get nil "SCHEDULED"))
(prev-deadline-stamp (org-entry-get nil "DEADLINE"))
;; The original timestamps are stored as inactive timestamps
(orig-scheduled-stamp (iko/org-ts-inactive→active (org-entry-get nil "ORIG_SCHEDULED")))
(orig-deadline-stamp (iko/org-ts-inactive→active (org-entry-get nil "ORIG_DEADLINE"))))
(iko/org-entry-put-nil nil "SCHEDULED" (or orig-scheduled-stamp prev-scheduled-stamp))
(iko/org-entry-put-nil nil "DEADLINE" (or orig-deadline-stamp prev-deadline-stamp))
(unwind-protect
(apply oldfun r)
(let ((next-scheduled-stamp (org-entry-get nil "SCHEDULED"))
(next-deadline-stamp (org-entry-get nil "DEADLINE")))
(if (equal orig-scheduled-stamp next-scheduled-stamp)
(iko/org-entry-put-nil nil "SCHEDULED" prev-scheduled-stamp)
(iko/org-entry-put-nil nil "ORIG_SCHEDULED"
(iko/org-ts-active→inactive next-scheduled-stamp)))
(if (equal orig-deadline-stamp next-deadline-stamp)
(iko/org-entry-put-nil nil "DEADLINE" prev-deadline-stamp)
(iko/org-entry-put-nil nil "ORIG_DEADLINE"
(iko/org-ts-active→inactive next-deadline-stamp))))))
(apply oldfun r))))
(advice-add
'org-schedule
:before
(defun iko/org-schedule-schedule-fix (&rest r)
(when (and (iko/org-is-static-repeater)
(not (org-entry-get nil "ORIG_SCHEDULED")))
(iko/org-entry-put-nil nil "ORIG_SCHEDULED" (org-entry-get nil "SCHEDULED")))))
(advice-add
'org-deadline
:before
(defun iko/org-deadline-schedule-fix (&rest r)
(when (and (iko/org-is-static-repeater)
(not (org-entry-get nil "ORIG_DEADLINE")))
(iko/org-entry-put-nil nil "ORIG_DEADLINE" (org-entry-get nil "DEADLINE")))))
@vherrmann
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment