Browse Source

Implement a global skipping condition

* lisp/org-agenda.el (org-agenda-skip-function-global): New option.
(org-agenda-skip-eval): New function.
(org-agenda-skip): Use `org-agenda-skip-eval' and also check for the
global skipping condition.

This was a request by John Wiegley
Carsten Dominik 14 years ago
parent
commit
a2ec41c79a
2 changed files with 50 additions and 15 deletions
  1. 10 4
      doc/org.texi
  2. 40 11
      lisp/org-agenda.el

+ 10 - 4
doc/org.texi

@@ -14093,11 +14093,17 @@ written in a way such that it does nothing in buffers that are not in
 @section Special agenda views
 @section Special agenda views
 @cindex agenda views, user-defined
 @cindex agenda views, user-defined
 
 
+@vindex org-agenda-skip-function
+@vindex org-agenda-skip-function-global
 Org provides a special hook that can be used to narrow down the selection
 Org provides a special hook that can be used to narrow down the selection
-made by these agenda views: @code{todo}, @code{alltodo}, @code{tags}, @code{tags-todo}, 
-@code{tags-tree}.  You may specify a function that is used at each match to verify 
-if the match should indeed be part of the agenda view, and if not, how 
-much should be skipped.
+made by these agenda views: @code{todo}, @code{alltodo}, @code{tags},
+@code{tags-todo}, @code{tags-tree}.  You may specify a function that is used
+at each match to verify if the match should indeed be part of the agenda
+view, and if not, how much should be skipped.  You can specify a global
+condition that will be applied to all agenda views, this condition would be
+stored in the variable @code{org-agenda-skip-function-global}.  More
+commonly, such a definition is applied only to specific custom searches,
+using @code{org-agenda-skip-function}.
 
 
 Let's say you want to produce a list of projects that contain a WAITING
 Let's say you want to produce a list of projects that contain a WAITING
 tag anywhere in the project tree.  Let's further assume that you have
 tag anywhere in the project tree.  Let's further assume that you have

+ 40 - 11
lisp/org-agenda.el

@@ -516,6 +516,23 @@ this one will be used."
  "Options concerning skipping parts of agenda files."
  "Options concerning skipping parts of agenda files."
  :tag "Org Agenda Skip"
  :tag "Org Agenda Skip"
  :group 'org-agenda)
  :group 'org-agenda)
+
+(defcustom org-agenda-skip-function-global nil
+  "Function to be called at each match during agenda construction.
+If this function returns nil, the current match should not be skipped.
+If the function decised to skip an agenda match, is must return the
+buffer position from which the search should be continued.
+This may also be a Lisp form, which will be evaluated.
+
+This variable will be applied to every agenda match, including
+tags/property searches and TODO lists.  So try to make the test function
+do its checking as efficiently as possible.  To implement a skipping
+condition just for specific agenda commands, use the variable
+`org-agenda-skip-function' which can be set in the options section
+of custom agenda commands."
+  :group 'org-agenda-skip
+  :type 'sexp)
+
 (defgroup org-agenda-daily/weekly nil
 (defgroup org-agenda-daily/weekly nil
   "Options concerning the daily/weekly agenda."
   "Options concerning the daily/weekly agenda."
   :tag "Org Agenda Daily/Weekly"
   :tag "Org Agenda Daily/Weekly"
@@ -3112,15 +3129,17 @@ Otherwise, the function must return a position from where the search
 should be continued.
 should be continued.
 This may also be a Lisp form, it will be evaluated.
 This may also be a Lisp form, it will be evaluated.
 Never set this variable using `setq' or so, because then it will apply
 Never set this variable using `setq' or so, because then it will apply
-to all future agenda commands.  Instead, bind it with `let' to scope
-it dynamically into the agenda-constructing command.  A good way to set
-it is through options in `org-agenda-custom-commands'.")
+to all future agenda commands.  If you do want a global skipping condition,
+use the option `org-agenda-skip-function-global' instead.
+The correct usage for `org-agenda-skip-function' is to bind it with
+`let' to scope it dynamically into the agenda-constructing command.
+A good way to set it is through options in `org-agenda-custom-commands'.")
 
 
 (defun org-agenda-skip ()
 (defun org-agenda-skip ()
   "Throw to `:skip' in places that should be skipped.
   "Throw to `:skip' in places that should be skipped.
 Also moves point to the end of the skipped region, so that search can
 Also moves point to the end of the skipped region, so that search can
 continue from there."
 continue from there."
-  (let ((p (point-at-bol)) to fp)
+  (let ((p (point-at-bol)) to)
     (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
     (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
 	 (get-text-property p :org-archived)
 	 (get-text-property p :org-archived)
 	 (org-end-of-subtree t)
 	 (org-end-of-subtree t)
@@ -3130,16 +3149,26 @@ continue from there."
 	 (org-end-of-subtree t)
 	 (org-end-of-subtree t)
 	 (throw :skip t))
 	 (throw :skip t))
     (if (equal (char-after p) ?#) (throw :skip t))
     (if (equal (char-after p) ?#) (throw :skip t))
-    (when (and (or (setq fp (functionp org-agenda-skip-function))
-		   (consp org-agenda-skip-function))
-	       (setq to (save-excursion
-			  (save-match-data
-			    (if fp
-				(funcall org-agenda-skip-function)
-			      (eval org-agenda-skip-function))))))
+    (when (setq to (or (org-agenda-skip-eval org-agenda-skip-function-global)
+		       (org-agenda-skip-eval org-agenda-skip-function)))
       (goto-char to)
       (goto-char to)
       (throw :skip t))))
       (throw :skip t))))
 
 
+(defun org-agenda-skip-eval (form)
+  "If FORM is a function or a list, call (or eval) is and return result.
+`save-excursion' and `save-match-data' are wrapped around the call, so point
+and match data are returned to the previous state no matter what these
+functions do."
+  (let (fp)
+    (and form
+	 (or (setq fp (functionp form))
+	     (consp form))
+	 (save-excursion
+	   (save-match-data
+	     (if fp
+		 (funcall form)
+	       (eval form)))))))
+
 (defvar org-agenda-markers nil
 (defvar org-agenda-markers nil
   "List of all currently active markers created by `org-agenda'.")
   "List of all currently active markers created by `org-agenda'.")
 (defvar org-agenda-last-marker-time (org-float-time)
 (defvar org-agenda-last-marker-time (org-float-time)