From b26745b985ecc209deb62548f8724de05359e081 Mon Sep 17 00:00:00 2001 From: Ihor Radchenko Date: Wed, 7 Feb 2024 13:21:34 +0100 Subject: [PATCH] org-agenda: Fix meaning of 'repeated-after-deadline value of `org-agenda-skip-scheduled-if-deadline-is-shown' * lisp/org-agenda.el (org-agenda-skip-scheduled-if-deadline-is-shown): Move 'repeated-after-deadline value into a new custom option. (org-agenda-skip-scheduled-repeats-after-deadline): Create a new custom option to make agenda hide scheduled entries repeated past deadline. * lisp/org-agenda.el (org-agenda-get-scheduled): Use the new custom option. Do not demand deadline to be actually shown when deciding whether to skip scheduled repeats past deadline. This fixes a bug when repeats continue to be displayed if past deadline is not displayed within agenda span. * doc/org-manual.org (Repeated tasks): Adjust manual entry, mentioning the new custom option. * etc/ORG-NEWS (~repeated-after-deadline~ value of ~org-agenda-skip-scheduled-repeats-after-deadline~ is moved to a new customization): Announce the change. * testing/lisp/test-org-agenda.el (test-org-agenda/skip-scheduled-repeats-after-deadline): Add new test. Reported-by: Morgan Smith Link: https://orgmode.org/list/874jft6vpj.fsf@localhost --- doc/org-manual.org | 14 ++++---- etc/ORG-NEWS | 17 ++++++++++ lisp/org-agenda.el | 37 +++++++++++++-------- testing/lisp/test-org-agenda.el | 57 +++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 21 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 2eb991a4a..1a025a139 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -6680,16 +6680,16 @@ special repeaters =++= and =.+=. For example: Marking this DONE shifts the date to exactly one hour from now. #+end_example -#+vindex: org-agenda-skip-scheduled-if-deadline-is-shown +#+vindex: org-agenda-skip-scheduled-repeats-after-deadline You may have both scheduling and deadline information for a specific task. If the repeater is set for the scheduling information only, you probably want the repeater to be ignored after the deadline. If so, -set the variable ~org-agenda-skip-scheduled-if-deadline-is-shown~ to -~repeated-after-deadline~. However, any scheduling information -without a repeater is no longer relevant once the task is done, and -thus, removed upon repeating the task. If you want both scheduling -and deadline information to repeat after the same interval, set the -same repeater for both timestamps. +set the variable ~org-agenda-skip-scheduled-repeats-after-deadline~ to +~t~. However, any scheduling information without a repeater is no +longer relevant once the task is done, and thus, removed upon +repeating the task. If you want both scheduling and deadline +information to repeat after the same interval, set the same repeater +for both timestamps. An alternative to using a repeater is to create a number of copies of a task subtree, with dates shifted in each copy. The command diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 965872d23..92d363b80 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -469,6 +469,23 @@ The change is breaking when ~org-use-property-inheritance~ is set to ~t~. The =TEST= parameter is better served by Emacs debugging tools. ** New and changed options +*** ~repeated-after-deadline~ value of ~org-agenda-skip-scheduled-repeats-after-deadline~ is moved to a new customization + +A new custom option ~org-agenda-skip-scheduled-repeats-after-deadline~ +is introduced in place of ~repeated-after-deadline~ value of +~org-agenda-skip-scheduled-repeats-after-deadline~. + +Introducing a new option allow more control over agenda display and +resolves a confusion about the meaning of ~repeated-after-deadline~. +~repeated-after-deadline~ has nothing to do with /showing/ deadline. +It just prevents agenda display repeated scheduled entries past +deadline. The following example illustrates the meaning: + +: * TODO Do me every day before Jan, 12th (included) +: SCHEDULED: <2024-01-03 Wed +1d> DEADLINE: <2024-01-05 Fri> + +The old customization will continue to work, ensuring backwards compatibility. + *** New custom setting ~org-icalendar-ttl~ for the ~ox-icalendar~ backend The option ~org-icalendar-ttl~ allows to advise a subscriber to the diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el index bfd715060..b270fbddc 100644 --- a/lisp/org-agenda.el +++ b/lisp/org-agenda.el @@ -894,17 +894,13 @@ the entry is scheduled today or was scheduled previously is not shown. When set to the symbol `not-today', skip scheduled previously, -but not scheduled today. - -When set to the symbol `repeated-after-deadline', skip scheduled -items if they are repeated beyond the current deadline." +but not scheduled today." :group 'org-agenda-skip :group 'org-agenda-daily/weekly :type '(choice (const :tag "Never" nil) (const :tag "Always" t) - (const :tag "Not when scheduled today" not-today) - (const :tag "When repeated past deadline" repeated-after-deadline))) + (const :tag "Not when scheduled today" not-today))) (defcustom org-agenda-skip-timestamp-if-deadline-is-shown nil "Non-nil means skip timestamp line if same entry shows because of deadline. @@ -1341,10 +1337,16 @@ When set to the symbol `next' only the first future repeat is shown." (const :tag "Show all repeated entries" t) (const :tag "Show next repeated entry" next) (const :tag "Do not show repeated entries" nil)) - :version "26.1" :package-version '(Org . "9.1") :safe #'symbolp) +(defcustom org-agenda-skip-scheduled-repeats-after-deadline nil + "Non-nil hides scheduled repeated entries past deadline." + :group 'org-agenda-daily/weekly + :type 'boolean + :package-version '(Org . "9.7") + :safe t) + (defcustom org-agenda-prefer-last-repeat nil "Non-nil sets date for repeated entries to their last repeat. @@ -6661,18 +6663,25 @@ scheduled items with an hour specification like [h]h:mm." ;; Skip entry if it already appears as a deadline, per ;; `org-agenda-skip-scheduled-if-deadline-is-shown'. This ;; doesn't apply to habits. + (when (or org-agenda-skip-scheduled-repeats-after-deadline + ;; FIXME: Backwards-compatibility. + (eq org-agenda-skip-scheduled-if-deadline-is-shown + 'repeated-after-deadline)) + (let ((deadline + (time-to-days + (when (org-element-property :deadline el) + (org-time-string-to-time + (org-element-interpret-data + (org-element-property :deadline el))))))) + (when (and (or (<= (org-agenda--timestamp-to-absolute s) deadline) + (not (= schedule current))) + (> current deadline)) + (throw :skip nil)))) (when (pcase org-agenda-skip-scheduled-if-deadline-is-shown ((guard (or (not (memq (line-beginning-position 0) deadline-pos)) habitp)) nil) - (`repeated-after-deadline - (let ((deadline (time-to-days - (when (org-element-property :deadline el) - (org-time-string-to-time - (org-element-interpret-data - (org-element-property :deadline el))))))) - (and (<= schedule deadline) (> current deadline)))) (`not-today pastschedp) (`t t) (_ nil)) diff --git a/testing/lisp/test-org-agenda.el b/testing/lisp/test-org-agenda.el index 976d88a9e..f98214b25 100644 --- a/testing/lisp/test-org-agenda.el +++ b/testing/lisp/test-org-agenda.el @@ -590,6 +590,63 @@ DEADLINE: " (cdr timestamp)))) (org-agenda nil "f") (buffer-string)))))))))))) +(ert-deftest test-org-agenda/skip-scheduled-repeats-after-deadline () + "Test `org-agenda-skip-scheduled-repeats-after-deadline'." + (cl-assert (not org-agenda-sticky) nil "precondition violation") + (cl-assert (not (org-test-agenda--agenda-buffers)) + nil "precondition violation") + (dolist (org-agenda-skip-scheduled-repeats-after-deadline '(nil t)) + (org-test-at-time "2024-01-01 8:00" + (org-test-with-temp-text-in-file " +* TODO Do me every day before Jan, 12th (included) +SCHEDULED: <2024-01-03 Wed +1d> DEADLINE: <2024-01-05 Fri> +" + (let ((org-agenda-span 'week) + (org-agenda-files `(,(buffer-file-name)))) + ;; NOTE: Be aware that `org-agenda-list' may or may not display + ;; past scheduled items depending whether the date is today + ;; `org-today' or not. + (org-agenda-list nil "<2024-01-01 Mon>") + (set-buffer org-agenda-buffer-name) + (if org-agenda-skip-scheduled-repeats-after-deadline + (should + ;; Not displayed after deadline. + (string-match-p + "Week-agenda (W01): +Monday 1 January 2024 W01 + [^:]+:In 4 d.: TODO Do me every day before Jan, 12th (included) +Tuesday 2 January 2024 +Wednesday 3 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) +Thursday 4 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) +Friday 5 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) + [^:]+:Deadline: TODO Do me every day before Jan, 12th (included) +Saturday 6 January 2024 +Sunday 7 January 2024" + (buffer-string))) + (should + ;; Displayed after deadline. + (string-match-p + "Week-agenda (W01): +Monday 1 January 2024 W01 + [^:]+:In 4 d.: TODO Do me every day before Jan, 12th (included) +Tuesday 2 January 2024 +Wednesday 3 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) +Thursday 4 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) +Friday 5 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) + [^:]+:Deadline: TODO Do me every day before Jan, 12th (included) +Saturday 6 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included) +Sunday 7 January 2024 + [^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)" + (buffer-string)))))) + (org-test-agenda--kill-all-agendas)))) + (ert-deftest test-org-agenda/goto-date () "Test `org-agenda-goto-date'." (unwind-protect