summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Dominik <carsten.dominik@gmail.com>2009-03-04 11:23:59 +0100
committerCarsten Dominik <carsten.dominik@gmail.com>2009-03-04 11:38:02 +0100
commitd685f0fc8705a2703072aa56b607dec554896e78 (patch)
tree28fcbbe1840084ef8999e223d8ae9e6f21c973e6
parent92de421e931cfe0c1a807a9c003895d88d7336c3 (diff)
downloadorg-mode-d685f0fc8705a2703072aa56b607dec554896e78.tar.gz
Mapping: Remove inheritance penalty when scanning for tags
Running a command that would use the tag scanner could suffer a large slow-down when many entries match, because the tag list with inheritance forces each matching entry to walk the hierarchy. Now, it is possible to avoid this penalty by using the variable `org-scanner-tags', or by binding the `org-trust-scanner-tags' to t around calls to `org-get-tags-at' and `org-entry-properties' when retrieving tags and properties for the current entry in the scanner/mapper.
-rwxr-xr-xlisp/ChangeLog5
-rw-r--r--lisp/org.el88
2 files changed, 62 insertions, 31 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a66e70f..c0f531d 100755
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -5,6 +5,11 @@
case-sensitive.
(org-scan-tags): Use the internal tags list instead of creating it
from scratch.
+ (org-trust-scanner-tags, org-scanner-tags): New variables.
+ (org-scan-tags): Set `org-scanner-tags'.
+ (org-get-tags-at): Take advantage of `org-trust-scanner-tags'.
+ (org-map-entries): Document the possible speedup using scanner
+ tags.
2009-03-03 Carsten Dominik <carsten.dominik@gmail.com>
diff --git a/lisp/org.el b/lisp/org.el
index 22c5c92..378da96 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -9758,6 +9758,17 @@ ACTION can be `set', `up', `down', or a character."
;;;; Tags
(defvar org-agenda-archives-mode)
+(defvar org-scanner-tags nil
+ "The current tag list while the tags scanner is running.")
+(defvar org-trust-scanner-tags nil
+ "NEVER SET THIS VARIABLE, this is for internal dynamical scoping only.
+When this is non-nil, the function `org-get-tags-at' will return the value
+of `org-scanner-tags' instead of building the list by itself. This
+can lead to large speed-ups when the tags scanner is used in a file with
+many entries, and when the list of tags is retrieved, for example to
+obtain a list of properties. Building the tags list for each entry in such
+a file becomes an N^2 operation.")
+
(defun org-scan-tags (action matcher &optional todo-only)
"Scan headline tags with inheritance and produce output ACTION.
@@ -9820,7 +9831,8 @@ only lines with a TODO keyword are included in the output."
(setq tags-list
(if org-use-tag-inheritance
(apply 'append (mapcar 'cdr (reverse tags-alist)))
- tags))
+ tags)
+ org-scanner-tags tags-list)
(when org-use-tag-inheritance
(setcdr (car tags-alist)
(mapcar (lambda (x)
@@ -10157,34 +10169,39 @@ the tags of the current headline come last.
When LOCAL is non-nil, only return tags from the current headline,
ignore inherited ones."
(interactive)
- (let (tags ltags lastpos parent)
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (or pos (point)))
- (save-match-data
- (catch 'done
- (condition-case nil
- (progn
- (org-back-to-heading t)
- (while (not (equal lastpos (point)))
- (setq lastpos (point))
- (when (looking-at (org-re "[^\r\n]+?:\\([[:alnum:]_@:]+\\):[ \t]*$"))
- (setq ltags (org-split-string
- (org-match-string-no-properties 1) ":"))
- (when parent
- (setq ltags (mapcar 'org-add-prop-inherited ltags)))
- (setq tags (append
- (if parent
- (org-remove-uniherited-tags ltags)
- ltags)
- tags)))
- (or org-use-tag-inheritance (throw 'done t))
- (if local (throw 'done t))
- (org-up-heading-all 1)
- (setq parent t)))
- (error nil)))))
- (append (org-remove-uniherited-tags org-file-tags) tags))))
+ (if (and org-trust-scanner-tags
+ (or (not pos) (equal pos (point)))
+ (not local))
+ org-scanner-tags
+ (let (tags ltags lastpos parent)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (or pos (point)))
+ (save-match-data
+ (catch 'done
+ (condition-case nil
+ (progn
+ (org-back-to-heading t)
+ (while (not (equal lastpos (point)))
+ (setq lastpos (point))
+ (when (looking-at
+ (org-re "[^\r\n]+?:\\([[:alnum:]_@:]+\\):[ \t]*$"))
+ (setq ltags (org-split-string
+ (org-match-string-no-properties 1) ":"))
+ (when parent
+ (setq ltags (mapcar 'org-add-prop-inherited ltags)))
+ (setq tags (append
+ (if parent
+ (org-remove-uniherited-tags ltags)
+ ltags)
+ tags)))
+ (or org-use-tag-inheritance (throw 'done t))
+ (if local (throw 'done t))
+ (org-up-heading-all 1)
+ (setq parent t)))
+ (error nil)))))
+ (append (org-remove-uniherited-tags org-file-tags) tags)))))
(defun org-add-prop-inherited (s)
(add-text-properties 0 (length s) '(inherited t) s)
@@ -10673,7 +10690,16 @@ the scanner. The following items can be given here:
will be used as value for `org-agenda-skip-function', so whenever
the the function returns t, FUNC will not be called for that
entry and search will continue from the point where the
- function leaves it."
+ function leaves it.
+
+If your function needs to retrieve the tags including inherited tags
+at the *current* entry, you can use the value of the variable
+`org-scanner-tags' which will be much faster than getting the value
+with `org-get-tags-at'. If your function gets properties with
+`org-entry-properties' at the *current* entry, bind `org-trust-scanner-tags'
+to t around the call to `org-entry-properties' to get the same speedup.
+Note that if your function moves around to retrieve tags and properties at
+a *different* entry, you cannot use these techniques."
(let* ((org-agenda-archives-mode nil) ; just to make sure
(org-agenda-skip-archived-trees (memq 'archive skip))
(org-agenda-skip-comment-trees (memq 'comment skip))
@@ -10878,7 +10904,7 @@ If WHICH is nil or `all', get all properties. If WHICH is
)
(when (memq which '(all standard))
- ;; Get the standard properties, like :PORP: ...
+ ;; Get the standard properties, like :PROP: ...
(setq range (org-get-property-block beg end))
(when range
(goto-char (car range))