Let’s say it is Saturday and you have a repeating task for your exercise sheet like
1
2
| ** TODO [#A] Übungsblatt: Modern Discrete Probability
DEADLINE: <2026-01-08 Thu +1w> SCHEDULED: <2026-01-03 Sat +1w>
|
that is usually scheduled for Saturday. Let us further assume you do not want do today for whatever reason.
In that case it would be very convenient to be able to reschedule the task without changing the general behavior of it being scheduled for Saturdays.
The following config achieves this by adding properties ORIG_SCHEDULED and ORIG_DEADLINE when changing the todo state such that the original timestamps can be recovered after changing them with org-schedule or org-schedule.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| (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")))))
|