86 lines
3.1 KiB
Text
86 lines
3.1 KiB
Text
|
;;;;;
|
||
|
title: Filtering org tasks
|
||
|
tags: tips, emacs, org-mode
|
||
|
date: 2013-08-25 00:38
|
||
|
format: md
|
||
|
;;;;;
|
||
|
|
||
|
I want to be able to easily see a list of tasks that are relevant to
|
||
|
the currently loaded desktop file. As I use `desktop.el` as a kind of
|
||
|
project system, this means I only want the tasks for the project I'm
|
||
|
currently working on.
|
||
|
|
||
|
First I wrote the `tagify` function, because `org-mode` tags can't
|
||
|
contain `.` or `-` characters (among others I'm sure, but these are
|
||
|
the only ones that have caused me any trouble so far). It's a simple
|
||
|
string replacement:
|
||
|
|
||
|
``` emacs-lisp
|
||
|
(defun tagify (str)
|
||
|
"Remove dots, replace - with _ in STR."
|
||
|
(replace-regexp-in-string
|
||
|
"-" "_" (replace-regexp-in-string "\\." "" (downcase str))))
|
||
|
```
|
||
|
|
||
|
Then I wrote a function to filter the task list by not showing
|
||
|
anything that wasn't tagged with the name of the currently loaded
|
||
|
desktop, unless it isn't tagged at all or no desktop has been loaded.
|
||
|
And set this function to be the value of
|
||
|
`org-agenda-before-sorting-filter-function`.
|
||
|
|
||
|
``` emacs-lisp
|
||
|
(defun filter-by-desktop (entry)
|
||
|
"Return ENTRY if it has no tags or a tag corresponding to the desktop."
|
||
|
(require 'desktop)
|
||
|
(let ((label (when desktop-dirname
|
||
|
(tagify (file-name-base
|
||
|
(directory-file-name
|
||
|
(expand-file-name desktop-dirname))))))
|
||
|
(tags (get-text-property 0 'tags entry)))
|
||
|
(when (or (null desktop-dirname) (null tags) (member label tags))
|
||
|
entry)))
|
||
|
|
||
|
(setq org-agenda-before-sorting-filter-function #'filter-by-desktop)
|
||
|
```
|
||
|
|
||
|
This works fine. I keep untagged tasks in the list as well because
|
||
|
they might be important at all times and I don't want them falling
|
||
|
through the cracks. I also want a complete list if no desktop has been
|
||
|
loaded so I can browse through my tasks and decide what I'm going to
|
||
|
do next.
|
||
|
|
||
|
The downside of this solution is that I have to close my current
|
||
|
project in order to see the whole list.
|
||
|
|
||
|
Then I discovered the `/` key in the agenda buffer. I can't believe I
|
||
|
didn't notice this key before. Anyway, that changed my solution.
|
||
|
|
||
|
Instead of setting `org-agenda-before-sorting-filter-function` I add a
|
||
|
hook to the `org-agenda-finalize-hook`. The `filter-by-desktop`
|
||
|
function looks a little different now:
|
||
|
|
||
|
``` emacs-lisp
|
||
|
(defun org-init-filter-by-desktop ()
|
||
|
"Filter agenda by current label."
|
||
|
(when desktop-dirname
|
||
|
(let ((label (tagify (file-name-base
|
||
|
(directory-file-name
|
||
|
(expand-file-name desktop-dirname))))))
|
||
|
(org-agenda-filter-apply (cons label nil) 'tag))))
|
||
|
|
||
|
(add-hook 'org-agenda-finalize-hook 'org-init-filter-by-desktop)
|
||
|
```
|
||
|
|
||
|
I don't need to compare any tags now, and if I want to see my entire
|
||
|
list of tasks I can easily just press `/ /`. Since it is easier to get
|
||
|
back to the overview of my tasks it also doesn't bother me so much
|
||
|
that this way any untagged tasks don't show up in the filtered buffer.
|
||
|
|
||
|
I haven't stopped using `/` since I discovered it. Filtering in this
|
||
|
way is one of the things I like about `ibuffer` as well, now for
|
||
|
`org-mode` it works excellently as well.
|
||
|
|
||
|
<!-- Local Variables: -->
|
||
|
<!-- mode: markdown -->
|
||
|
<!-- End: -->
|