10

I'm using org-habit, and the habit graphs show up nicely on the normal agenda view. However, I'd like to use the todo list with tag filtering, and there the habits look like normal todo items, without the habit graph.

How can I make the habit graph appear when using the todo list agenda view?

1
  • I don't think the consistency graphs are designed around showing up anywhere but 'agenda' type agendas (so no todo list, etc). What you may be able to do is customize a block agenda with blocks for both the tags todo list you want and the habits consistency graphs. Custom agendas can be a little tricky though. Commented Jun 25, 2015 at 18:21

2 Answers 2

6

This seems to do the trick:

(defvar my/org-habit-show-graphs-everywhere nil
  "If non-nil, show habit graphs in all types of agenda buffers.

Normally, habits display consistency graphs only in
\"agenda\"-type agenda buffers, not in other types of agenda
buffers.  Set this variable to any non-nil variable to show
consistency graphs in all Org mode agendas.")

(defun my/org-agenda-mark-habits ()
  "Mark all habits in current agenda for graph display.

This function enforces `my/org-habit-show-graphs-everywhere' by
marking all habits in the current agenda as such.  When run just
before `org-agenda-finalize' (such as by advice; unfortunately,
`org-agenda-finalize-hook' is run too late), this has the effect
of displaying consistency graphs for these habits.

When `my/org-habit-show-graphs-everywhere' is nil, this function
has no effect."
  (when (and my/org-habit-show-graphs-everywhere
         (not (get-text-property (point) 'org-series)))
    (let ((cursor (point))
          item data) 
      (while (setq cursor (next-single-property-change cursor 'org-marker))
        (setq item (get-text-property cursor 'org-marker))
        (when (and item (org-is-habit-p item)) 
          (with-current-buffer (marker-buffer item)
            (setq data (org-habit-parse-todo item))) 
          (put-text-property cursor
                             (next-single-property-change cursor 'org-marker)
                             'org-habit-p data))))))

(advice-add #'org-agenda-finalize :before #'my/org-agenda-mark-habits)

To explain further, it appears that every agenda function calls org-agenda-finalize once the agenda buffer has been mostly constructed, and this is the function which adds the habit graphs. Moreover, it just adds the graph to every item which has the org-habit-p text property (which encodes the details the graph will display). So all we need to do is go through and tag the habits with this information at some point prior to that.

Also, I chose to make this behavior depend on a variable because this should allow you to set the variable in custom agenda commands, if you want only some agendas to display habits. I haven't tested that, but there's no reason it shouldn't work.

EDIT: My original solution had problems with block agendas. It turns out that org-agenda-finalize is called once for each block, and then once for the agenda as a whole. When that final call happens, the agenda is read-only, so an error gets thrown if the agenda contains any habits. Since all the work has already been done by that point, it makes no sense to scan the agenda again anyway, and I just added a check for the 'org-series property, which is added to the whole agenda after the per-block calls and before the final read-only call.

1

You could use org-agenda-prefix-format with a call to org-habit-build-graph and related functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.