emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [O] Dimming ancestors in the agenda (relevant to indenting nested TO


From: Eric Abrahamsen
Subject: Re: [O] Dimming ancestors in the agenda (relevant to indenting nested TODOs in agenda views)
Date: Sat, 24 Sep 2011 21:51:39 +0800
User-agent: Gnus/5.110018 (No Gnus v0.18) Emacs/23.2 (gnu/linux)

Okay, here's an attempt at indicating nested todos in the todo agenda
view.

The more I futzed with comparing consecutive TODOs the hackier it
seemed, so I went with something more fundamental. Right now I think
this is a bigger solution than the problem warranted, but it might also
open the way to other interesting features, so I'm floating it here.

With the attached patch, and the variable
`org-agenda-todo-list-sublevels' set to anything but nil,
`org-agenda-get-todos' will put todos into nested lists, rather than a
flat list.

While that's happening, TODOs can be formatted differently to indicate
their depth within TODO subtrees. Currently that's hardcoded to the
venerable leading dots, but symbol values for
`org-agenda-todo-list-sublevels' could provide for a wider variety of
formatting options, or a custom function.

Then `org-finalize-agenda-entries' unwinds the nested lists back into a
flat list (using a "flatten" pattern straight out of Paul Graham),
applying the necessary filtering, highlighting and sorting functions
along the way. One bonus is that each level of TODO subtrees gets sorted
distinctly.

Two questions:

1. Is this buggy or broken or unnecessarily slow?
2. Is this justified? Can we do other cool stuff with this?

That's all. Hope it works!

Eric

diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el
index b1fa5f5..417566d 100644
--- a/lisp/org-agenda.el
+++ b/lisp/org-agenda.el
@@ -587,12 +587,19 @@ When nil, these trees are also scanned by agenda 
commands."
   :type 'boolean)
 
 (defcustom org-agenda-todo-list-sublevels t
-  "Non-nil means check also the sublevels of a TODO entry for TODO entries.
-When nil, the sublevels of a TODO entry are not checked, resulting in
-potentially much shorter TODO lists."
+  "How to display TODO entries that are sublevels of a TODO entry.
+When nil, the sublevels of a TODO entry are not returned,
+resulting in potentially much shorter TODO lists. When t, the
+default, show all TODO entries as a flat list. 'indent and 'fade
+change the way TODO entries that follow a parent TODO are
+displayed."
   :group 'org-agenda-skip
   :group 'org-agenda-todo-list
-  :type 'boolean)
+  :type '(choice
+         (const :tag "Create a flat list of sublevels" t)
+         (const :tag "Do not list sublevel todos" nil)
+         (const :tag "Indent sublevel todos" indent)
+         (const :tag "Fade out sublevel todos" fade)))
 
 (defcustom org-agenda-todo-ignore-with-date nil
   "Non-nil means don't show entries with a date in the global todo list.
@@ -4582,40 +4590,57 @@ the documentation of `org-diary'."
                                       (mapconcat 'identity
                                                  (org-split-string
                                                   org-select-this-todo-keyword 
"|") "\\|")
-                                    "\\)\\>"))
+                                      "\\)\\>"))
                           org-not-done-regexp)
                         "[^\n\r]*\\)"))
-        marker priority category category-pos tags todo-state ee txt beg end)
-    (goto-char (point-min))
-    (while (re-search-forward regexp nil t)
-      (catch :skip
-       (save-match-data
-         (beginning-of-line)
-         (org-agenda-skip)
-         (setq beg (point) end (save-excursion (outline-next-heading) (point)))
-         (when (org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item 
end)
-           (goto-char (1+ beg))
-           (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible))
-           (throw :skip nil)))
-       (goto-char (match-beginning 1))
-       (setq marker (org-agenda-new-marker (match-beginning 0))
-             category (org-get-category)
-             category-pos (get-text-property (point) 'org-category-position)
-             txt (match-string 1)
-             tags (org-get-tags-at (point))
-             txt (org-format-agenda-item "" txt category tags)
-             priority (1+ (org-get-priority txt))
-             todo-state (org-get-todo-state))
-       (org-add-props txt props
-         'org-marker marker 'org-hd-marker marker
-         'priority priority 'org-category category
-         'org-category-position category-pos
-         'type "todo" 'todo-state todo-state)
-       (push txt ee)
-       (if org-agenda-todo-list-sublevels
-           (goto-char (match-end 1))
-         (org-end-of-subtree 'invisible))))
-    (nreverse ee)))
+        (depth 0))
+
+    (flet ((mk-td (start finish)
+                 (goto-char start)
+                 (let (marker priority category category-pos tags todo-state 
ee txt beg end)
+                   (while (re-search-forward regexp finish t)
+                     (catch :skip
+                       (save-match-data
+                         (beginning-of-line)
+                         (org-agenda-skip)
+                         (setq beg (point) end (save-excursion 
(outline-next-heading) (point)))
+                         (when 
(org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item end)
+                           (goto-char (1+ beg))
+                           (or org-agenda-todo-list-sublevels 
(org-end-of-subtree 'invisible))
+                           (throw :skip nil)))
+                       (goto-char (match-beginning 1))
+                       (setq marker (org-agenda-new-marker (match-beginning 0))
+                             category (org-get-category)
+                             category-pos (get-text-property (point) 
'org-category-position)
+                             txt (concat (if
+                                             (> depth 0)
+                                             (make-string (* 2 depth) ?.)
+                                           "") (match-string 1))
+                             tags (org-get-tags-at (point))
+                             txt (org-format-agenda-item "" txt category tags 
depth)
+                             priority (1+ (org-get-priority txt))
+                             todo-state (org-get-todo-state))
+                       (org-add-props txt props
+                         'org-marker marker 'org-hd-marker marker
+                         'priority priority 'org-category category
+                         'org-category-position category-pos
+                         'type "todo" 'todo-state todo-state)
+                       (if (not org-agenda-todo-list-sublevels)
+                           (progn
+                             (push txt ee)
+                             (org-end-of-subtree 'invisible))
+                         (goto-char (match-end 0))
+                         (let* ((depth (1+ depth))
+                                (subtree-todos
+                                 (mk-td (point)
+                                        (save-excursion (org-end-of-subtree 
'invisible) (point)))))
+                           (when subtree-todos
+                             (setq txt (cons txt (nreverse subtree-todos))))
+                           (push txt ee)))))
+                   ee)))
+      (goto-char (point-min))
+      (nreverse (mk-td (point) (point-max))))))
+
 
 (defun org-agenda-todo-custom-ignore-p (time n)
   "Check whether timestamp is farther away then n number of days.
@@ -5785,12 +5810,18 @@ could bind the variable in the options section of a 
custom command.")
 
 (defun org-finalize-agenda-entries (list &optional nosort)
   "Sort and concatenate the agenda items."
-  (setq list (mapcar 'org-agenda-highlight-todo list))
-  (if nosort
-      list
-    (when org-agenda-before-sorting-filter-function
-      (setq list (delq nil (mapcar org-agenda-before-sorting-filter-function 
list))))
-    (mapconcat 'identity (sort list 'org-entries-lessp) "\n")))
+  (flet ((flatten (l)
+                (cond
+                 ((null l) nil)
+                 ((atom l) (if (and org-agenda-before-sorting-filter-function
+                                    (not 
(org-agenda-before-sorting-filter-function l)))
+                               nil
+                             (list (org-agenda-highlight-todo l))))
+                 (t (append (flatten (car l))
+                            (flatten (if nosort
+                                         (cdr l)
+                                       (sort (cdr l) 'org-entries-lessp))))))))
+    (mapconcat 'identity (flatten list) "\n")))
 
 (defun org-agenda-highlight-todo (x)
(let ((org-done-keywords org-done-keywords-for-agenda)
@@ -5926,6 +5957,10 @@ could bind the variable in the options section of a 
custom command.")
 
 (defun org-entries-lessp (a b)
   "Predicate for sorting agenda entries."
+  (when (consp a)
+    (setq a (car a)))
+  (when (consp b)
+    (setq b (car b)))
   ;; The following variables will be used when the form is evaluated.
   ;; So even though the compiler complains, keep them.
   (let* ((ss org-agenda-sorting-strategy-selected)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]