summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Parri <simonparri@ganzeria.com>2025-06-20 16:27:55 -0500
committerSimon Parri <simonparri@ganzeria.com>2025-06-20 16:34:15 -0500
commit4ab0f6c822a981fe498497731155da6b9360b4dc (patch)
treee389420c59385785906310a99795be3498cca459
parent0bbc0988e0e289549d65edbc47931c608cc4ae9b (diff)
downloadorg-urgency-4ab0f6c822a981fe498497731155da6b9360b4dc.tar.gz
org-urgency-4ab0f6c822a981fe498497731155da6b9360b4dc.zip
Make predicate functions' return values consistent with each other
Before, there might have been one predicate that, to get an urgency of 10, you'd have to pass an N of 0.01, and another that to get an urgency of 10 you'd have to pass an N of 20. Now, N's of the same order of magnitude produce changes of the same order of magnitude.
-rw-r--r--org-urgency.el118
1 files changed, 97 insertions, 21 deletions
diff --git a/org-urgency.el b/org-urgency.el
index 2e0fd53..4e50b87 100644
--- a/org-urgency.el
+++ b/org-urgency.el
@@ -44,6 +44,14 @@
;; is of the given state, whereas `org-urgency-by-effort' will multiply the
;; effort of the heading by the number passed, and return that.
+;; Note on the values of the N argument to the `org-urgency-by-' functions:
+
+;; Between two predicate functions, N values of the same order of magnitude
+;; will produce urgencies of the same order of magnitude. That is, if you
+;; pass an N of 10 to `org-urgency-by-deadline' and an N of 10 to
+;; `org-urgency-by-effort', you will get two urgencies of the same order of
+;; magnitude. (Any behavior to the contrary is a bug.)
+
;;; Code:
(require 'org)
@@ -104,22 +112,37 @@ H.
BODY should evaluate to a number, which will be added to the heading's
total urgency, or nil."
- (declare (indent 2))
- `(defun ,(intern (format "org-urgency-by-%s" name)) (h ,@args n)
- "Weight function for use in `org-urgency-functions'."
- (cl-flet ((get (prop)
- (org-urgency--get h prop)))
- ,@body)))
+ (declare (indent 2)
+ (doc-string 3))
+ (let ((doc
+ (when (stringp (car body))
+ (pop body))))
+ `(defun ,(intern (format "org-urgency-by-%s" name)) (h ,@args n)
+ ,@(when doc (list doc))
+ (cl-flet ((get (prop)
+ (org-urgency--get h prop)))
+ ,@body))))
(org-urgency-define priority= (prio)
+ "Urgency N when H has priority PRIO."
(when (= (get 'priority)
prio)
n))
(org-urgency-define priority ()
- (* (get 'priority) n))
+ "Urgency is H's priority multiplied by N.
+
+When N is 1, the urgency from this function is equal to the position of
+the priority of H in the range between `org-priority-highest' and
+`org-priority-lowest'.
+
+E.g. if H has a priority of [#A] and `org-priority-highest' and
+`org-priority-lowest' are ?A and ?C respectively, then when N is 1, H
+will have an urgency of 2 according to this function."
+ (* (/ (get 'priority) 1000) n))
(org-urgency-define scheduled? ()
+ "Urgency N when H is scheduled."
(when (org-get-scheduled-time (get 'org-marker))
n))
@@ -130,37 +153,59 @@ total urgency, or nil."
n))
(org-urgency-define deadline? ()
+ "Urgency N when H is deadlined."
(when (org-get-deadline-time (get 'org-marker))
n))
(org-urgency-define near-deadline ()
+ "Urgency is N times how close H is to its deadline.
+
+If H has no deadline, this function contributes nothing.
+
+When N is 1, the urgency from this function is equal to
+`org-deadline-warning-days' minus the number of days till H's deadline."
(when-let* ((deadline (org-get-deadline-time (get 'org-marker)))
- (remaining (float-time
+ (remaining (time-to-number-of-days
(time-subtract
deadline (org-current-time))))
(remaining (max remaining 0))
- (maximum (* org-deadline-warning-days 24 60 60))
+ (maximum org-deadline-warning-days)
(coeff (- maximum remaining)))
(* n coeff)))
(org-urgency-define tag? (tag)
+ "Urgency N when H has tag TAG."
(when (member tag (get 'tags))
n))
(org-urgency-define habit? ()
+ "Urgency N when H is a habit."
(require 'org-habit)
(when (org-is-habit-p (get 'org-marker))
n))
(org-urgency-define state? (state)
+ "Urgency N when H is in TODO state STATE."
(when (equal (get 'todo-state) state)
n))
(org-urgency-define effort ()
+ "Urgency is the effort of H multiplied by N.
+
+When N is 1, the urgency from this function is equal to the effort
+estimate, in minutes."
(* (or (get 'effort-minutes) 60.0) n))
(org-urgency-define random ()
- (random (concat (format-time-string "%Y %m %d %A ") h))
+ "Urgency is a random number between 0 and N.
+
+The text of H, along with the date of the current agenda is used to seed
+the random number. The system PRNG seed is restored after this function
+is called."
+ (random (concat (format-time-string
+ "%Y %m %d %A "
+ org-agenda-current-date)
+ h))
(prog1 (random n)
(random t)))
@@ -182,16 +227,29 @@ will become
(cdr x)))
list))
-(defun org-urgency-calculate (h)
- "Calculate the urgency of H."
+(defun org-urgency-calculate (h &optional keep-names)
+ "Caluclate the urgencies of H.
+
+If KEEP-NAMES is nil, simply return the list of urgency numbers.
+Otherwise, return a list of pairs of function+arguments and
+corresponding urgency number.
+
+Uses `org-urgency-functions', which see."
+ (thread-last
+ org-urgency-functions
+ (mapcar (lambda (x)
+ (cl-destructuring-bind (f &rest args) x
+ (if keep-names
+ (cons (cons f 'h args) (apply f h args))
+ (apply f h args)))))
+ (seq-remove #'null)))
+
+(defun org-urgency-total (h)
+ "Sum the various urgencies of H.
+
+Urgencies are calculated by `org-urgency-calulate', which see."
(if (not (equal (org-urgency--get h 'type) "diary"))
- (thread-last
- org-urgency-functions
- (mapcar (lambda (x)
- (cl-destructuring-bind (f &rest args) x
- (apply f h args))))
- (seq-remove #'null)
- (apply #'+))
+ (apply #'+ (org-urgency-calculate h))
0))
;;;###autoload
@@ -199,11 +257,29 @@ will become
"Compare heading A to heading B.
This function is suitable as a value for `org-agenda-cmp-user-defined'."
- (let ((a (org-urgency-calculate a))
- (b (org-urgency-calculate b)))
+ (let ((a (org-urgency-total a))
+ (b (org-urgency-total b)))
(cond ((> a b) +1)
((< a b) -1)
(t nil))))
+;;;###autoload
+(defun org-urgency-show ()
+ "Show a how the org-urgency rules apply to the current heading."
+ (interactive nil org-agenda-mode)
+ (unless (derived-mode-p '(org-agenda-mode))
+ (user-error "Must be called in an Org-Agenda mode buffer"))
+ (message
+ "%s"
+ (string-join
+ (mapcar
+ (lambda (x)
+ (format "%S :: %s"
+ (car x) (cdr x)))
+ (org-urgency-calculate
+ (org-current-line-string)
+ t))
+ "\n")))
+
(provide 'org-urgency)
;;; org-urgency.el ends here