7

I have the following agenda command for things that I want to do at home:

     ("h" "thing TODO at Home"
     (

      (tags-todo "+dailies+SCHEDULED<=\"<today>+1\"")
      (agenda "" ((org-agenda-ndays 1)
                  (org-agenda-filter-by-tag  '("-work" ))
                  (org-agenda-sorting-strategy
                   (quote ((agenda time-up priority-down tag-up) )))
                  (org-deadline-warning-days 0)
                  ))
      (tags "reading")
      (tags "writing")
      (tags-todo "REFILE")


      )

     )

I am using org-agenda-filter-by-tag to remove all the entries that are tagged work. (I have some file wide tags on the files). However, the agenda works, but is showing me also the entries tagged work. I also tried putting the org-agenda-filter-by-tag on the top of the definition of the block agenda but it is also not working.

Org-mode: 8.3.2 Emacs 24.5.1 OS: Mac OSX Yosemite 10.10.4

Thanks

4 Answers 4

10

Your first problem is that org-agenda-filter-by-tag is a function. Interactively, this will apply a filter, but in an agenda command like this, you're just assigning a value to it as a variable. Since functions and variables are in different namespaces, this doesn't cause an error, but it doesn't do anything either.

Unfortunately, the variable you do want, org-agenda-tag-filter-preset, is designed to work agenda-wide and can't be usefully set per-block (see the footnote for this manual entry).

If you're okay with having the filter set for the whole agenda, your command should look like this (and I apologize for changing your indentation setup):

("h" "thing TODO at Home"
 ((tags-todo "+dailies+SCHEDULED<=\"<today>+1\"")
  (agenda "" ((org-agenda-ndays 1)
              (org-agenda-sorting-strategy
               (quote ((agenda time-up priority-down tag-up))))
              (org-deadline-warning-days 0)))
  (tags "reading")
  (tags "writing")
  (tags-todo "REFILE"))
 ((org-agenda-tag-filter-preset '("-work"))))

If you want work tasks to show up in your tags and tags-todo blocks, you can use skip functions instead. For some reason, there is no out-of-the-box skip function for tag filtering, but I wrote one for this answer; with that code, your agenda command should look like this:

("h" "thing TODO at Home"
 ((tags-todo "+dailies+SCHEDULED<=\"<today>+1\"")
  (agenda "" ((org-agenda-ndays 1)
              (org-agenda-skip-function
               '(my/org-agenda-skip-without-match "-work"))
              (org-agenda-sorting-strategy
               (quote ((agenda time-up priority-down tag-up))))
              (org-deadline-warning-days 0)))
  (tags "reading")
  (tags "writing")
  (tags-todo "REFILE")))
2
  • Hi, Thanks a lot for the clarification. I actually want to remove "-work" tag globally (in all the blocks). Your proposed solutions gives an error when I use it I changed to ` (org-agenda-tag-filter-preset '("-work"))` and it works, if you fix your answer I will mark it as accepted. Thanks a lot! :)
    – mfcabrera
    Commented Nov 20, 2015 at 9:16
  • Fixed. Sorry about that. I really should have checked the documentation more closely. Commented Nov 20, 2015 at 15:05
2

Here's a simple solution with the built-in org filtering commands.

This only works if the headline is tagged explicitly. It does not work if the tag is inherited

(agenda ""
        ((org-agenda-skip-function
          '(org-agenda-skip-entry-if 'regexp ":work:"))))
0

To expand on Joe's excellent answer if you need to skip multiple tags:

(agenda ""
    ((org-agenda-skip-function
      '(org-agenda-skip-entry-if 'regexp ":work1:\\|:work2:"))))

in emacs regex | OR character needs to be escaped in its own very special way

0

I have used my/org-agenda-skip-without-match function but now I'm experiencing sometimes that it won't complete (emacs is stucked). I wasn't able to get know what is wrong.

I have found some more simple function at list.gnu.org

#+begin_src emacs-lisp
;;; Based on http://article.gmane.org/gmane.emacs.orgmode/41427
  (defun my-skip-tag(tag)
    "Skip entries that are tagged TAG"
    (let* ((entry-tags (org-get-tags-at (point))))
      (if (member tag entry-tags)
          (progn (outline-next-heading) (point))
        nil)))
#+end_src

#+begin_src emacs-lisp
(agenda "" 
 ((org-agenda-skip-function '(my-skip-tag" reward"))
  (org-agenda-overriding-header "Agenda (without rewards: ")))))
#+end_src

I have done some changes to be able to match multiple tags

(defun my-skip-based-on-tags-and (tags)
  "Skip entries based on the list of TAGS.
   Each element in TAGS should be a cons cell where the car is a sign
   and the cdr is tag. Sign '+' means to skip entries not tagged,
   sign '-' means to skip entries tagged."
  (let* ((entry-tags (org-get-tags-at (point)))
        (should-skip
         (seq-some ; filter that implements logical AND. Use `seq-every-p` for logical OR.
          (lambda (tag-sign)
            (let* ((sign (car tag-sign))    ; "+" or "-"
                   (tag  (cdr tag-sign))    ; name of the tag
                   (tag-found (member tag entry-tags))) ; is the tag at current point?
              (or (and (string= sign "+") (not tag-found)) ; skip if tag not found
                  (and (string= sign "-") tag-found))))   ; skip if tag found
          tags)))
    (when should-skip
      (outline-next-heading)
      (point))))

in agenda you would call it like this:

(agenda "" (
          (org-agenda-skip-function '(my-skip-based-on-tags-and '(("+" . "tag1")("+" . "tag2"))))
        ))

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.