From 3feb2edd3a705811824348546f4edad2f595f8bb Mon Sep 17 00:00:00 2001 From: Ilya Shlyakhter Date: Wed, 21 Mar 2012 19:49:07 -0400 Subject: [PATCH] Tags/properties matcher: Fixed issues with todo-only matches lisp/org.el (org-scan-tags): Require todo-only argument, and document that it should be the same one set by org-make-tags-matcher. Fix documentation to explain that todo-only is really not-done-todo-only. (org-make-tags-matcher): If todo part of matcher starts with /!, matcher now always checks that the TODO keyword is present and is a not-done state. This matters e.g. for org-map-entries which unlike org-scan-tags does not do its own separate todo-only filtering. Added docs to explain matcher dependencies. (org-map-entries): Make sure todo-only is correctly passed from org-make-tags-matcher to org-scan-tags. * lisp/org-clock.el: (org-clock-get-table-data): Make sure todo-only does not leak when it is set by make-org-tags-macher. * lisp/org-crypt.el: (org-encrypt-entries, org-decrypt-entries): Make sure todo-only is correctly passed from org-make-tags-matcher to org-scan-tags. * contrib/lisp/contacts.el: (org-contacts-filter) : Make sure todo-only is correctly passed from org-make-tags-matcher to org-scan-tags. --- contrib/lisp/org-contacts.el | 6 ++++-- lisp/org-clock.el | 1 + lisp/org-crypt.el | 16 +++++++++------ lisp/org.el | 44 ++++++++++++++++++++++++++++++++---------- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/contrib/lisp/org-contacts.el b/contrib/lisp/org-contacts.el index bdd9996..b6d9e50 100644 --- a/contrib/lisp/org-contacts.el +++ b/contrib/lisp/org-contacts.el @@ -143,7 +143,8 @@ This overrides `org-email-link-description-format' if set." (defun org-contacts-filter (&optional name-match tags-match) "Search for a contact maching NAME-MATCH and TAGS-MATCH. If both match values are nil, return all contacts." - (let ((tags-matcher + (let* (todo-only + (tags-matcher (if tags-match (cdr (org-make-tags-matcher tags-match)) t)) @@ -161,7 +162,8 @@ If both match values are nil, return all contacts." (error "File %s is no in `org-mode'" file)) (org-scan-tags '(add-to-list 'markers (set-marker (make-marker) (point))) - `(and ,contacts-matcher ,tags-matcher ,name-matcher)))) + `(and ,contacts-matcher ,tags-matcher ,name-matcher) + todo-only))) (dolist (marker markers result) (org-with-point-at marker (add-to-list 'result diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 46d9af8..5fca941 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -2441,6 +2441,7 @@ TIME: The sum of all time spend in this tree, in minutes. This time (tags (plist-get params :tags)) (properties (plist-get params :properties)) (inherit-property-p (plist-get params :inherit-props)) + todo-only (matcher (if tags (cdr (org-make-tags-matcher tags)))) cc range-text st p time level hdl props tsp tbl) diff --git a/lisp/org-crypt.el b/lisp/org-crypt.el index f60c61e..7e7ba30 100644 --- a/lisp/org-crypt.el +++ b/lisp/org-crypt.el @@ -237,16 +237,20 @@ See `org-crypt-disable-auto-save'." (defun org-encrypt-entries () "Encrypt all top-level entries in the current buffer." (interactive) - (org-scan-tags - 'org-encrypt-entry - (cdr (org-make-tags-matcher org-crypt-tag-matcher)))) + (let (todo-only) + (org-scan-tags + 'org-encrypt-entry + (cdr (org-make-tags-matcher org-crypt-tag-matcher)) + todo-only))) (defun org-decrypt-entries () "Decrypt all entries in the current buffer." (interactive) - (org-scan-tags - 'org-decrypt-entry - (cdr (org-make-tags-matcher org-crypt-tag-matcher)))) + (let (todo-only) + (org-scan-tags + 'org-decrypt-entry + (cdr (org-make-tags-matcher org-crypt-tag-matcher)) + todo-only))) (defun org-crypt-use-before-save-magic () "Add a hook to automatically encrypt entries before a file is saved to disk." diff --git a/lisp/org.el b/lisp/org.el index 39f391c..79d3823 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -12818,7 +12818,7 @@ obtain a list of properties. Building the tags list for each entry in such a file becomes an N^2 operation - but with this variable set, it scales as N.") -(defun org-scan-tags (action matcher &optional todo-only start-level) +(defun org-scan-tags (action matcher todo-only &optional start-level) "Scan headline tags with inheritance and produce output ACTION. ACTION can be `sparse-tree' to produce a sparse tree in the current buffer, @@ -12828,7 +12828,9 @@ this case the return value is a list of all return values from these calls. MATCHER is a Lisp form to be evaluated, testing if a given set of tags qualifies a headline for inclusion. When TODO-ONLY is non-nil, -only lines with a TODO keyword are included in the output. +only lines with a not-done TODO keyword are included in the output. +This should be the same variable that was scoped into +and set by `org-make-tags-matcher' when it constructed MATCHER. START-LEVEL can be a string with asterisks, reducing the scope to headlines matching this string." @@ -12998,8 +13000,6 @@ headlines matching this string." (if (member x org-use-tag-inheritance) x nil)) tags))))) -(defvar todo-only) ;; dynamically scoped - (defun org-match-sparse-tree (&optional todo-only match) "Create a sparse tree according to tags string MATCH. MATCH can contain positive and negative selection of tags, like @@ -13046,9 +13046,29 @@ instead of the agenda files." (org-agenda-files)))))))) (defun org-make-tags-matcher (match) - "Create the TAGS/TODO matcher form for the selection string MATCH." - ;; todo-only is scoped dynamically into this function, and the function - ;; may change it if the matcher asks for it. + "Create the TAGS/TODO matcher form for the selection string MATCH. + +The variable `todo-only' is scoped dynamically into this function; it will be +set to t if the matcher restricts matching to TODO entries, +otherwise will not be touched. + +Returns a cons of the selection string MATCH and the constructed +lisp form implementing the matcher. The matcher is to be +evaluated at an Org entry, with point on the headline, +and returns t if the entry matches the +selection string MATCH. The returned lisp form references +two variables with information about the entry, which must be +bound around the form's evaluation: todo, the TODO keyword at the +entry (or nil of none); and tags-list, the list of all tags at the +entry including inherited ones. Additionally, the category +of the entry (if any) must be specified as the text property +'org-category on the headline. + +See also `org-scan-tags'. +" + (declare (special todo-only)) + (unless (boundp 'todo-only) + (error "org-make-tags-matcher expects todo-only to be scoped in")) (unless match ;; Get a new match request, with completion (let ((org-last-tags-completion-table @@ -13165,6 +13185,9 @@ instead of the agenda files." (setq matcher (if todomatcher (list 'and tagsmatcher todomatcher) tagsmatcher)) + (when todo-only + (setq matcher (list 'and '(member todo org-not-done-keywords) + matcher))) (cons match0 matcher))) (defun org-op-to-function (op &optional stringp) @@ -13878,7 +13901,8 @@ a *different* entry, you cannot use these techniques." org-done-keywords-for-agenda org-todo-keyword-alist-for-agenda org-drawers-for-agenda - org-tag-alist-for-agenda) + org-tag-alist-for-agenda + todo-only) (cond ((eq match t) (setq matcher t)) @@ -13911,7 +13935,7 @@ a *different* entry, you cannot use these techniques." (progn (org-prepare-agenda-buffers (list (buffer-file-name (current-buffer)))) - (setq res (org-scan-tags func matcher nil start-level))) + (setq res (org-scan-tags func matcher todo-only start-level))) ;; Get the right scope (cond ((and scope (listp scope) (symbolp (car scope))) @@ -13932,7 +13956,7 @@ a *different* entry, you cannot use these techniques." (save-restriction (widen) (goto-char (point-min)) - (setq res (append res (org-scan-tags func matcher)))))))))) + (setq res (append res (org-scan-tags func matcher todo-only)))))))))) res))) ;;;; Properties -- 1.7.9.3