diff options
author | Simon Parri <simonparri@ganzeria.com> | 2025-06-19 11:54:36 -0500 |
---|---|---|
committer | Simon Parri <simonparri@ganzeria.com> | 2025-06-19 11:54:36 -0500 |
commit | 1de52898ee74390ad37bd890489bedd7ac92c680 (patch) | |
tree | 8b7d4c05df435126d3e4abae1d1d0de9e2e21a19 /org-urgency.el | |
download | org-urgency-0.50.tar.gz org-urgency-0.50.zip |
Add version 0.50v0.50
Diffstat (limited to 'org-urgency.el')
-rw-r--r-- | org-urgency.el | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/org-urgency.el b/org-urgency.el new file mode 100644 index 0000000..4ae9923 --- /dev/null +++ b/org-urgency.el @@ -0,0 +1,177 @@ +;;; org-urgency.el --- Smart, rules-based Org-agenda sorting -*- lexical-binding: t; -*- + +;; Copyright (C) 2025 Simon Parri + +;; Author: Simon Parri <simonparri@ganzeria.com> +;; Keywords: calendar, outlines +;; Package-Requires: ((emacs "24.3") (compat "25.1") (org "9") (seq "1")) +;; Version: 0.50 + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This code implements something like Taskwarrior's urgency system for Org +;; Agenda. It has nothing to do with the "urgency" system mentioned in the +;; Org manual. The name is taken from Taskwarrior. + +;; The general idea is that each entry will have a certain urgency, and the +;; urgency is calculated by summing the non-nil results of calling each +;; function in `org-urgency-functions'. Currently the best way to learn how +;; to use the various urgency predicates is to read the source. See also +;; `org-urgency-list' for a helper to make defining `org-urgency-functions' +;; slightly less verbose, and `org-urgency-define' for how to define your own +;; predicates. + +;;; Code: + +(require 'org) +(require 'cl-macs) + +;;;###autoload +(defgroup org-urgency () + "Smart, rules-based Org-agenda sorting." + :group 'org-agenda) + +;;;###autoload +(defcustom org-urgency-functions () + "List of functions+arguments that determine the urgency of a given entry. + +Each element in this list should be of the form + +\\(FUNC . POST-ARGS) + +FUNC will be the function called, and it will be called with the first +argument being the heading in question (as passed to the function in +`org-agenda-cmp-user-defined'), and with POST-ARGS as the rest of the arguments. + +If, then, `org-urgency-functions' were set to + +\\((org-urgency-priority 10) + (org-urgency-state \"TODO\")) + +then the urgency of a heading H would be equivalent to + +\\(apply #\\='+ + (seq-remove #\\='null + (list + (org-urgency-priority h 10) + (org-urgency-state h \"TODO\" 10)))) + +See the relevant `org-urgency-' functions for details. + +Also see the function `org-urgency-list' for a shorthand way to assemble +an appropriate list for this variable." + :type 'sexp) + +(defun org-urgency--get (h prop) + "Get PROP of H." + (get-text-property 1 prop h)) + +;;;###autoload +(defmacro org-urgency-define (name args &rest body) + "Define `org-urgency-NAME' as a function. + +Its lambda-list will be `(H ,@ARGS N), and BODY is the body of the +function. (H is the heading, as passed to +`org-agenda-cmp-user-defined', and N is the coefficient/number passed by +the user.) + +Inside BODY, the function `get' is defined as a function that, given a +symbol, uses `org-urgency--get' to get the corresponding property from +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-%s" name)) (h ,@args n) + "Weight function for use in `org-urgency-functions'." + (cl-flet ((get (prop) + (org-urgency--get h prop))) + ,@body))) + +(org-urgency-define priority= (prio) + (when (= (or (get 'priority) 1001) prio) + n)) + +(org-urgency-define priority () + (* (or (get 'priority) 1001) n)) + +(org-urgency-define scheduled () + (when (org-get-scheduled-time (get 'org-marker)) + n)) + +(org-urgency-define deadline () + (when (org-get-deadline-time (get 'org-marker)) + n)) + +(org-urgency-define tag (tag) + (when (member tag (get 'tags)) + n)) + +(org-urgency-define habit () + (require 'org-habit) + (when (org-is-habit-p (get 'org-marker)) + n)) + +(org-urgency-define state (state) + (when (equal (get 'todo-state) state) + n)) + +(org-urgency-define effort () + (* (or (get 'effort-minutes) 60.0) n)) + +;;;###autoload +(defun org-urgency-list (list) + "Process LIST to make it a suitable value for `org-urgency-functions'. + +LIST should be a list of lists whose `car' is a symbol and whose `cdr' +is a list of arguments. An element such as + +\\(tag \"@home\" 10) + +will become + +\\(org-urgency-tag \"@home\" 10)" + (mapcar + (lambda (x) + (cons (intern (format "org-urgency-%s" (car x))) + (cdr x))) + list)) + +(defun org-urgency-calculate (h) + "Calculate the urgency of H." + (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 #'+)) + 0)) + +;;;###autoload +(defun org-urgency-compare (a b) + "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))) + (cond ((> a b) +1) + ((< a b) -1) + (t nil)))) + +(provide 'org-urgency) +;;; org-urgency.el ends here |