Is it possible to filter on tags when agenda constructs its view? I have tried the following to show only work related appointments:
("j" "Jobb"
((agenda ""
((org-agenda-skip-function '(org-agenda-skip-entry-if 'notregexp":jobb:"))))
(tags-todo "jobb"))
((org-agenda-compact-blocks nil)))
This works only if the actual appointment is directly tagged, but not if the appointment inherits its tag from a parent headline like this:
* Tider :jobb:
** Millas arbetstider
<2012-04-11 ons 05:00-09:00>
<2012-04-12 tor 04:15-08:30>
<2012-04-13 fre 14:30-18:30>
Is there another way to do this so that appointments that inherits its tag shows up?
The issue is in how org-agenda-skip-entries-if
interacts with 'notregexp
. It will skip any entries that do not match :jobb:
. Even though the later entries inherit the tag, it is not explicitly listed and so they are skipped. There also does not seem to be any built-in method to match (or not match) on tags using org-agenda-skip-entries-if
. If there is such a function it would likely be the more efficient method of looking for the tags, but I'm not aware of such a function.
You instead have to create a custom function that will provide the desired search-format.
If you change your agenda command to:
("j" "Jobb"
((agenda ""
((org-agenda-skip-function '(zin/org-agenda-skip-tag "jobb" 't))))
(tags-todo "jobb"))
((org-agenda-compact-blocks nil)))
and define zin/org-agenda-skip-tag
as:
(defun zin/org-agenda-skip-tag (tag &optional others)
"Skip all entries that correspond to TAG.
If OTHERS is true, skip all entries that do not correspond to TAG."
(let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))
(current-headline (or (and (org-at-heading-p)
(point))
(save-excursion (org-back-to-heading)))))
(if others
(if (not (member tag (org-get-tags-at current-headline)))
next-headline
nil)
(if (member tag (org-get-tags-at current-headline))
next-headline
nil))))
You will get what I understand to be your desired agenda view. If I have it backwards and the entries on the next 3 days should not be present, you simply have to change the function to (zin/org-agenda-skip-tag "jobb")
or (zin/org-agenda-skip-tag "jobb" 'nil)
, they are equivalent in this case.
In this case test-new
is the name of the org-file I was using, it can be ignored. I also set both headlines to TODO
to have them visible when testing the function, since I was restricting the agenda to only the one file.
Week-agenda (W15):
Monday 9 April 2012 W15
Tuesday 10 April 2012
Wednesday 11 April 2012
test-new: 5:00- 9:00 TODO Millas arbetstider :jobb::
Thursday 12 April 2012
test-new: 4:15- 8:30 TODO Millas arbetstider :jobb::
Friday 13 April 2012
test-new: 14:30-18:30 TODO Millas arbetstider :jobb::
Saturday 14 April 2012
Sunday 15 April 2012
================================================================================
Headlines with TAGS match: jobb
test-new: TODO Tider :jobb:
test-new: TODO Millas arbetstider :jobb::
After using the function in Jonathan's answer for several months to do this kind of per-block filtering, I found myself wanting something capable of dealing with more sophisticated queries (like the match strings used by the other block types), and I figured I'd post it here for anyone who stumbles across this question in the future.
EDIT: The original implementation of my/org-match-at-point-p
is now somewhat out of date. The Org mode sources are now lexically scoped, which changes the contract of org-make-tags-matcher
. It used to be that the todo
and tags-list
variables needed to be dynamically scoped around the call to org-make-tags-matcher
, whereas now they seem to be passed to the function returned from the call. (Yay! This is so much better!) I've adapted the code below to match the new version, but I don't use Org mode much anymore, so it's only been lightly tested.
(defun my/org-match-at-point-p (match)
"Return non-nil if headline at point matches MATCH.
Here MATCH is a match string of the same format used by
`org-tags-view'."
(funcall (cdr (org-make-tags-matcher match))
(org-get-todo-state)
(org-get-tags-at)
(org-reduced-level (org-current-level))))
(defun my/org-agenda-skip-without-match (match)
"Skip current headline unless it matches MATCH.
Return nil if headline containing point matches MATCH (which
should be a match string of the same format used by
`org-tags-view'). If headline does not match, return the
position of the next headline in current buffer.
Intended for use with `org-agenda-skip-function', where this will
skip exactly those headlines that do not match."
(save-excursion
(unless (org-at-heading-p) (org-back-to-heading))
(let ((next-headline (save-excursion
(or (outline-next-heading) (point-max)))))
(if (my/org-match-at-point-p match) nil next-headline))))
In case you're still using the older version of Org mode, here is the original code. Note that this version assumes that the file in which my/org-match-at-point-p
is defined is lexically scoped; if not, you can safely replace the my/defun-dyn
macro with a simple defun
.
(defmacro my/defun-dyn (&rest def)
"As `defun', but always in dynamic scope.
A function defined in this way ignores the value of
`lexical-binding' and treats it as if it were nil.
\(fn NAME ARGLIST &optional DOCSTRING DECL &rest BODY)"
(declare (debug defun)
(indent defun)
(doc-string 3))
`(eval '(defun ,@def) nil))
(my/defun-dyn my/org-match-at-point-p (match &optional todo-only)
"Return non-nil if headline at point matches MATCH.
Here MATCH is a match string of the same format used by
`org-tags-view'.
If the optional argument TODO-ONLY is non-nil, do not declare a
match unless headline at point is a todo item."
(let ((todo (org-get-todo-state))
(tags-list (org-get-tags-at)))
(eval (cdr (org-make-tags-matcher match)))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With