summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2016-12-03 09:04:42 +0100
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2016-12-03 23:35:42 +0100
commit3a4d16deab037188a12a0536ff7da10bc859d61b (patch)
tree6806c21336fd6fb2e79a8176bf85fa1e88b6aede
parent1658cb26ff9af4034ba6b9534e5db8b906127a74 (diff)
downloadorg-mode-3a4d16deab037188a12a0536ff7da10bc859d61b.tar.gz
Improve repeated entries handling
* lisp/org-agenda.el (org-agenda-show-future-repeats): (org-agenda-prefer-last-repeat): New variables. (org-agenda-repeating-timestamp-show-all): Remove variable. (org-agenda-get-timestamps): (org-agenda-get-deadlines): (org-agenda-get-scheduled): Use new variables.
-rw-r--r--etc/ORG-NEWS10
-rw-r--r--lisp/org-agenda.el243
2 files changed, 139 insertions, 114 deletions
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 9be2443..684d404 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -24,6 +24,9 @@ into
: (file (lambda () (sexp)))
** New features
+*** Agenda
+**** New variable : ~org-agenda-show-future-repeats~
+**** New variable : ~org-agenda-prefer-last-repeat~
*** Babel
**** Clojure: new setting ~org-babel-clojure-sync-nrepl-timeout~
@@ -66,6 +69,13 @@ value of the code will be displayed in the results section.
*** Horizontal rules are no longer ignored in LaTeX table math mode
+** Removed options
+
+*** ~org-agenda-repeating-timestamp-show-all~ is removed.
+
+For an equivalent to a ~nil~ value, set
+~org-agenda-show-future-repeats~ to nil and
+~org-agenda-prefer-last-repeat~ to ~t~.
* Version 9.0
** Incompatible changes
diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el
index da748af..fb6baff 100644
--- a/lisp/org-agenda.el
+++ b/lisp/org-agenda.el
@@ -1260,17 +1260,38 @@ Custom commands can set this variable in the options section."
:version "24.1"
:type 'boolean)
-(defcustom org-agenda-repeating-timestamp-show-all t
- "Non-nil means show all occurrences of a repeating stamp in the agenda.
-When set to a list of strings, only show occurrences of repeating
-stamps for these TODO keywords. When nil, only one occurrence is
-shown, either today or the nearest into the future."
+(defcustom org-agenda-show-future-repeats t
+ "Non-nil shows repeated entries in the future part of the agenda.
+When set to the symbol `next' only the first future repeat is shown."
:group 'org-agenda-daily/weekly
:type '(choice
- (const :tag "Show repeating stamps" t)
- (repeat :tag "Show repeating stamps for these TODO keywords"
- (string :tag "TODO Keyword"))
- (const :tag "Don't show repeating stamps" nil)))
+ (const :tag "Show all repeated entries" t)
+ (const :tag "Show next repeated entry" next)
+ (const :tag "Do not show repeated entries" nil))
+ :version "25.2"
+ :package-version '(Org . "9.1")
+ :safe #'symbolp)
+
+(defcustom org-agenda-prefer-last-repeat nil
+ "Non-nil sets date for repeated entries to their last repeat.
+
+When non-nil, a repeated entry is shows at its latest repeat
+date, possibly being today, instead of the its base date, even if
+it wasn't marked as done. This setting is useful if you do not
+always mark repeated entries as DONE and, yet, consider that
+reaching repeat date starts the task anew.
+
+When set to a list of strings, prefer last repeats only for
+entries with these TODO keywords."
+ :group 'org-agenda-daily/weekly
+ :type '(choice
+ (const :tag "Prefer last repeat" t)
+ (const :tag "Prefer base date" nil)
+ (repeat :tag "Prefer last repeat for entries with these TODO keywords"
+ (string :tag "TODO keyword")))
+ :version "25.2"
+ :package-version '(Org . "9.1")
+ :safe (lambda (x) (or (booleanp x) (consp x))))
(defcustom org-scheduled-past-days 10000
"Number of days to continue listing scheduled items not marked DONE.
@@ -5640,9 +5661,6 @@ displayed in agenda view."
(looking-at org-ts-regexp-both)
(match-string 0))))
(todo-state (org-get-todo-state))
- (show-all (or (eq org-agenda-repeating-timestamp-show-all t)
- (member todo-state
- org-agenda-repeating-timestamp-show-all)))
(warntime (get-text-property (point) 'org-appt-warntime))
(done? (member todo-state org-done-keywords)))
;; Possibly skip done tasks.
@@ -5651,22 +5669,27 @@ displayed in agenda view."
;; S-exp entry doesn't match current day: skip it.
(when (and sexp-entry (not (org-diary-sexp-entry sexp-entry "" date)))
(throw :skip nil))
- ;; When time-stamp doesn't match CURRENT but has a repeater,
- ;; make sure it repeats on CURRENT. Furthermore, if
- ;; SHOW-ALL is nil, ensure that repeats are only the first
- ;; before and the first after today.
- (when (and repeat
- (if show-all
- (/= current
- (org-agenda--timestamp-to-absolute
- repeat current 'future (current-buffer) pos))
- (and (/= current
- (org-agenda--timestamp-to-absolute
- repeat today 'past (current-buffer) pos))
- (/= current
- (org-agenda--timestamp-to-absolute
- repeat today 'future (current-buffer) pos)))))
- (throw :skip nil))
+ ;; A repeating time stamp is shown at its base date, and at
+ ;; every repeated date in the future.
+ (when repeat
+ (let* ((past
+ (if (or (eq org-agenda-prefer-last-repeat t)
+ (member todo-state org-agenda-prefer-last-repeat))
+ (org-agenda--timestamp-to-absolute
+ repeat today 'past (current-buffer) pos)
+ (org-agenda--timestamp-to-absolute repeat)))
+ (future
+ (cond
+ ((<= current today) past)
+ ((not org-agenda-show-future-repeats) past)
+ (t
+ (let ((base (if (eq org-agenda-show-future-repeats 'next)
+ (1+ today)
+ current)))
+ (org-agenda--timestamp-to-absolute
+ repeat base 'future (current-buffer) pos))))))
+ (when (and (/= current past) (/= current future))
+ (throw :skip nil))))
(save-excursion
(re-search-backward org-outline-regexp-bol nil t)
;; Possibly skip time-stamp when a deadline is set.
@@ -6067,22 +6090,29 @@ specification like [h]h:mm."
(pos (1- (match-beginning 1)))
(todo-state (save-match-data (org-get-todo-state)))
(done? (member todo-state org-done-keywords))
- (show-all (or (eq org-agenda-repeating-timestamp-show-all t)
- (member todo-state
- org-agenda-repeating-timestamp-show-all)))
- ;; DEADLINE is the bare deadline date, i.e., without
- ;; any repeater, or the last repeat if SHOW-ALL is
- ;; non-nil. REPEAT is closest repeat after CURRENT, if
- ;; all repeated time stamps are to be shown, or after
- ;; TODAY otherwise. REPEAT only applies to future
- ;; dates.
- (deadline (if show-all (org-agenda--timestamp-to-absolute s)
- (org-agenda--timestamp-to-absolute
- s today 'past (current-buffer) pos)))
+ ;; DEADLINE is the deadline date for the entry. It is
+ ;; either the base date or the last repeat, according
+ ;; to `org-agenda-prefer-last-repeat'.
+ (deadline
+ (if (or (eq org-agenda-prefer-last-repeat t)
+ (member todo-state org-agenda-prefer-last-repeat))
+ (org-agenda--timestamp-to-absolute
+ s today 'past (current-buffer) pos)
+ (org-agenda--timestamp-to-absolute s)))
+ ;; REPEAT is the future repeat closest from CURRENT,
+ ;; according to `org-agenda-show-future-repeats'. If
+ ;; the latter is nil, or if the time stamp has no
+ ;; repeat part, default to DEADLINE.
(repeat
- (if (< current today) deadline
- (org-agenda--timestamp-to-absolute
- s (if show-all current today) 'future (current-buffer) pos)))
+ (cond
+ ((<= current today) deadline)
+ ((not org-agenda-show-future-repeats) deadline)
+ (t
+ (let ((base (if (eq org-agenda-show-future-repeats 'next)
+ (1+ today)
+ current)))
+ (org-agenda--timestamp-to-absolute
+ s base 'future (current-buffer) pos)))))
(diff (- deadline current))
(suppress-prewarning
(let ((scheduled
@@ -6105,16 +6135,16 @@ specification like [h]h:mm."
(let ((org-deadline-warning-days suppress-prewarning))
(org-get-wdays s))
(org-get-wdays s))))
- ;; When to show a deadline in the calendar: if the
- ;; expiration is within WDAYS warning time. Past-due
- ;; deadlines are only shown on today agenda.
- (when (cond ((= current deadline) nil)
- ((< deadline today)
- (and (not today?)
- (or (< current today) (/= repeat current))))
- ((> deadline current)
- (or (not today?) (> diff wdays)))
- (t (/= repeat current)))
+ ;; Display deadlines items at base date (DEADLINE), today,
+ ;; if deadline is overdue or if the expiration of the
+ ;; upcoming deadline is within WDAYS warning time. Also,
+ ;; show any repeat past today.
+ (when (or (and (/= current deadline)
+ (/= current today)
+ (/= current repeat))
+ (and today?
+ (> deadline current)
+ (> diff wdays)))
(throw :skip nil))
;; Possibly skip done tasks.
(when (and done?
@@ -6125,8 +6155,8 @@ specification like [h]h:mm."
(re-search-backward "^\\*+[ \t]+" nil t)
(goto-char (match-end 0))
(let* ((category (org-get-category))
- (level
- (make-string (org-reduced-level (org-outline-level)) ?\s))
+ (level (make-string (org-reduced-level (org-outline-level))
+ ?\s))
(head (buffer-substring (point) (line-end-position)))
(inherited-tags
(or (eq org-agenda-show-inherited-tags 'always)
@@ -6148,23 +6178,16 @@ specification like [h]h:mm."
(item
(org-agenda-format-item
;; Insert appropriate suffixes before deadlines.
+ ;; Those only apply to today agenda.
(pcase-let ((`(,now ,future ,past)
org-agenda-deadline-leaders))
(cond
- ;; Future (i.e., repeated) deadlines are
- ;; displayed as new headlines.
- ((> current today) now)
- ;; When SHOW-ALL is nil, prefer repeated
- ;; deadlines over reminders of past deadlines.
- ((and (not show-all) (= repeat today)) now)
- ((= deadline current) now)
- ((< deadline current) (format past (- diff)))
- (t (format future diff))))
- head level category tags
- (and (or (= repeat current) (= deadline current))
- time)))
+ ((and today? (< deadline today)) (format past (- diff)))
+ ((and today? (> deadline today)) (format future diff))
+ (t now)))
+ head level category tags time))
(face (org-agenda-deadline-face
- (- 1 (/ (float (- deadline current)) (max wdays 1)))))
+ (- 1 (/ (float diff) (max wdays 1)))))
(upcoming? (and today? (> deadline today)))
(warntime (get-text-property (point) 'org-appt-warntime)))
(org-add-props item props
@@ -6178,9 +6201,7 @@ specification like [h]h:mm."
;; Overdue deadlines get the highest priority
;; increase, then imminent deadlines and eventually
;; more distant deadlines.
- (let ((adjust (cond ((not today?) 0)
- ((and (not show-all) (= repeat current)) 0)
- (t (- diff)))))
+ (let ((adjust (if today? (- diff) 0)))
(+ adjust (org-get-priority item)))
'todo-state todo-state
'type (if upcoming? "upcoming-deadline" "deadline")
@@ -6230,25 +6251,29 @@ scheduled items with an hour specification like [h]h:mm."
(pos (1- (match-beginning 1)))
(todo-state (save-match-data (org-get-todo-state)))
(donep (member todo-state org-done-keywords))
- (show-all (or (eq org-agenda-repeating-timestamp-show-all t)
- (member todo-state
- org-agenda-repeating-timestamp-show-all)))
- ;; SCHEDULE is the bare scheduled date, i.e., without
- ;; any repeater if non-nil, or last repeat if SHOW-ALL
- ;; is nil. REPEAT is the closest repeat after CURRENT,
- ;; if all repeated time stamps are to be shown, or
- ;; after TODAY otherwise. REPEAT only applies to
- ;; future dates.
- (schedule (if show-all (org-agenda--timestamp-to-absolute s)
- (org-agenda--timestamp-to-absolute
- s today 'past (current-buffer) pos)))
- (repeat (cond ((< current today) schedule)
- (show-all
- (org-agenda--timestamp-to-absolute
- s current 'future (current-buffer) pos))
- (t
- (org-agenda--timestamp-to-absolute
- s today 'future (current-buffer) pos))))
+ ;; SCHEDULE is the scheduled date for the entry. It is
+ ;; either the bare date or the last repeat, according
+ ;; to `org-agenda-prefer-last-repeat'.
+ (schedule
+ (if (or (eq org-agenda-prefer-last-repeat t)
+ (member todo-state org-agenda-prefer-last-repeat))
+ (org-agenda--timestamp-to-absolute
+ s today 'past (current-buffer) pos)
+ (org-agenda--timestamp-to-absolute s)))
+ ;; REPEAT is the future repeat closest from CURRENT,
+ ;; according to `org-agenda-show-future-repeats'. If
+ ;; the latter is nil, or if the time stamp has no
+ ;; repeat part, default to SCHEDULE.
+ (repeat
+ (cond
+ ((<= current today) schedule)
+ ((not org-agenda-show-future-repeats) schedule)
+ (t
+ (let ((base (if (eq org-agenda-show-future-repeats 'next)
+ (1+ today)
+ current)))
+ (org-agenda--timestamp-to-absolute
+ s base 'future (current-buffer) pos)))))
(diff (- current schedule))
(warntime (get-text-property (point) 'org-appt-warntime))
(pastschedp (< schedule today))
@@ -6265,9 +6290,7 @@ scheduled items with an hour specification like [h]h:mm."
(- org-agenda-skip-scheduled-delay-if-deadline))
((eq org-agenda-skip-scheduled-delay-if-deadline
'post-deadline)
- ;; Set delay to no later than DEADLINE. If
- ;; DEADLINE has a repeater, compare last schedule
- ;; repeat and last deadline repeat.
+ ;; Set delay to no later than DEADLINE.
(min (- schedule deadline) org-scheduled-delay-days))
(t 0))))
(ddays
@@ -6291,9 +6314,9 @@ scheduled items with an hour specification like [h]h:mm."
(when (or (and (> ddays 0) (< diff ddays))
(> diff org-scheduled-past-days)
(> schedule current)
- (and (< schedule current)
- (not todayp)
- (/= repeat current)))
+ (and (/= current schedule)
+ (/= current today)
+ (/= current repeat)))
(throw :skip nil)))
;; Possibly skip done tasks.
(when (and donep
@@ -6309,7 +6332,9 @@ scheduled items with an hour specification like [h]h:mm."
habitp))
nil)
(`repeated-after-deadline
- (>= repeat (time-to-days (org-get-deadline-time (point)))))
+ (let ((deadline (time-to-days
+ (org-get-deadline-time (point)))))
+ (and (<= schedule deadline) (> current deadline))))
(`not-today pastschedp)
(`t t)
(_ nil))
@@ -6336,8 +6361,8 @@ scheduled items with an hour specification like [h]h:mm."
(memq 'agenda
org-agenda-use-tag-inheritance)))))
(tags (org-get-tags-at nil (not inherited-tags)))
- (level
- (make-string (org-reduced-level (org-outline-level)) ?\s))
+ (level (make-string (org-reduced-level (org-outline-level))
+ ?\s))
(head (buffer-substring (point) (line-end-position)))
(time
(cond
@@ -6349,21 +6374,11 @@ scheduled items with an hour specification like [h]h:mm."
(t 'time)))
(item
(org-agenda-format-item
- (pcase-let ((`(,first ,next) org-agenda-scheduled-leaders))
- (cond
- ;; If CURRENT is in the future, don't use past
- ;; scheduled prefix.
- ((> current today) first)
- ;; SHOW-ALL focuses on future repeats. If one
- ;; such repeat happens today, ignore late
- ;; schedule reminder. However, still report
- ;; such reminders when repeat happens later.
- ((and (not show-all) (= repeat today)) first)
- ;; Initial report.
- ((= schedule current) first)
- ;; Subsequent reminders. Count from base
- ;; schedule.
- (t (format next (1+ diff)))))
+ (pcase-let ((`(,first ,past) org-agenda-scheduled-leaders))
+ ;; Show a reminder of a past scheduled today.
+ (if (and todayp pastschedp)
+ (format past (1+ diff))
+ first))
head level category tags time nil habitp))
(face (cond ((and (not habitp) pastschedp)
'org-scheduled-previously)